From 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf Mon Sep 17 00:00:00 2001 From: scuri Date: Fri, 17 Oct 2008 06:10:33 +0000 Subject: First commit - moving from LuaForge to SourceForge --- src/.cvsignore | 9 + src/COPYRIGHT | 32 + src/Makefile | 26 + src/README | 11 + src/cd.c | 748 + src/cd.def | 379 + src/cd.rc | 19 + src/cd_active.c | 1007 ++ src/cd_attributes.c | 1017 ++ src/cd_bitmap.c | 293 + src/cd_freetype.def | 247 + src/cd_freetype.mak | 39 + src/cd_freetype.rc | 20 + src/cd_image.c | 441 + src/cd_pdflib.def | 188 + src/cd_pdflib.mak | 135 + src/cd_pdflib.rc | 20 + src/cd_primitives.c | 702 + src/cd_text.c | 632 + src/cd_util.c | 285 + src/cd_vectortext.c | 4853 +++++++ src/cdcontextplus.mak | 25 + src/cdlua3.mak | 12 + src/cdlua5.mak | 13 + src/cdluacontextplus5.mak | 16 + src/cdluaim5.mak | 15 + src/cdluapdf3.mak | 15 + src/cdluapdf5.mak | 16 + src/cdpdf.def | 2 + src/cdpdf.mak | 12 + src/config.mak | 47 + src/drv/cd0emf.c | 17 + src/drv/cd0prn.c | 17 + src/drv/cd0wmf.c | 16 + src/drv/cdcgm.c | 1135 ++ src/drv/cddebug.c | 729 + src/drv/cddgn.c | 1696 +++ src/drv/cddxf.c | 1184 ++ src/drv/cdirgb.c | 2135 +++ src/drv/cdmf.c | 1188 ++ src/drv/cdpdf.c | 1491 ++ src/drv/cdpicture.c | 1133 ++ src/drv/cdps.c | 1836 +++ src/drv/cgm.c | 2281 +++ src/drv/cgm.h | 156 + src/freetype2/autofit/afangles.c | 292 + src/freetype2/autofit/afangles.h | 7 + src/freetype2/autofit/afcjk.c | 1506 ++ src/freetype2/autofit/afcjk.h | 41 + src/freetype2/autofit/afdummy.c | 62 + src/freetype2/autofit/afdummy.h | 43 + src/freetype2/autofit/aferrors.h | 40 + src/freetype2/autofit/afglobal.c | 289 + src/freetype2/autofit/afglobal.h | 67 + src/freetype2/autofit/afhints.c | 1264 ++ src/freetype2/autofit/afhints.h | 333 + src/freetype2/autofit/afindic.c | 134 + src/freetype2/autofit/afindic.h | 41 + src/freetype2/autofit/aflatin.c | 2166 +++ src/freetype2/autofit/aflatin.h | 209 + src/freetype2/autofit/aflatin2.c | 2286 +++ src/freetype2/autofit/aflatin2.h | 40 + src/freetype2/autofit/afloader.c | 530 + src/freetype2/autofit/afloader.h | 73 + src/freetype2/autofit/afmodule.c | 97 + src/freetype2/autofit/afmodule.h | 37 + src/freetype2/autofit/aftypes.h | 349 + src/freetype2/autofit/afwarp.c | 338 + src/freetype2/autofit/afwarp.h | 64 + src/freetype2/autofit/autofit.c | 40 + src/freetype2/base/ftapi.c | 121 + src/freetype2/base/ftbase.c | 38 + src/freetype2/base/ftbbox.c | 659 + src/freetype2/base/ftbdf.c | 88 + src/freetype2/base/ftbitmap.c | 630 + src/freetype2/base/ftcalc.c | 822 ++ src/freetype2/base/ftdbgmem.c | 998 ++ src/freetype2/base/ftdebug.c | 246 + src/freetype2/base/ftgasp.c | 61 + src/freetype2/base/ftgloadr.c | 394 + src/freetype2/base/ftglyph.c | 682 + src/freetype2/base/ftgxval.c | 129 + src/freetype2/base/ftinit.c | 163 + src/freetype2/base/ftlcdfil.c | 351 + src/freetype2/base/ftmac.c | 1096 ++ src/freetype2/base/ftmm.c | 202 + src/freetype2/base/ftnames.c | 94 + src/freetype2/base/ftobjs.c | 3993 ++++++ src/freetype2/base/ftotval.c | 83 + src/freetype2/base/ftoutln.c | 1088 ++ src/freetype2/base/ftpatent.c | 281 + src/freetype2/base/ftpfr.c | 132 + src/freetype2/base/ftrfork.c | 728 + src/freetype2/base/ftstream.c | 842 ++ src/freetype2/base/ftstroke.c | 2010 +++ src/freetype2/base/ftsynth.c | 159 + src/freetype2/base/ftsystem.c | 301 + src/freetype2/base/fttrigon.c | 546 + src/freetype2/base/fttype1.c | 94 + src/freetype2/base/ftutil.c | 501 + src/freetype2/base/ftwinfnt.c | 51 + src/freetype2/base/ftxf86.c | 40 + src/freetype2/bdf/bdf.c | 34 + src/freetype2/bdf/bdf.h | 295 + src/freetype2/bdf/bdfdrivr.c | 848 ++ src/freetype2/bdf/bdfdrivr.h | 76 + src/freetype2/bdf/bdferror.h | 44 + src/freetype2/bdf/bdflib.c | 2472 ++++ src/freetype2/cache/ftcache.c | 31 + src/freetype2/cache/ftcbasic.c | 811 ++ src/freetype2/cache/ftccache.c | 592 + src/freetype2/cache/ftccache.h | 317 + src/freetype2/cache/ftccback.h | 90 + src/freetype2/cache/ftccmap.c | 413 + src/freetype2/cache/ftcerror.h | 40 + src/freetype2/cache/ftcglyph.c | 211 + src/freetype2/cache/ftcglyph.h | 322 + src/freetype2/cache/ftcimage.c | 163 + src/freetype2/cache/ftcimage.h | 107 + src/freetype2/cache/ftcmanag.c | 732 + src/freetype2/cache/ftcmanag.h | 175 + src/freetype2/cache/ftcmru.c | 357 + src/freetype2/cache/ftcmru.h | 247 + src/freetype2/cache/ftcsbits.c | 401 + src/freetype2/cache/ftcsbits.h | 98 + src/freetype2/cff/cff.c | 29 + src/freetype2/cff/cffcmap.c | 220 + src/freetype2/cff/cffcmap.h | 69 + src/freetype2/cff/cffdrivr.c | 499 + src/freetype2/cff/cffdrivr.h | 39 + src/freetype2/cff/cfferrs.h | 41 + src/freetype2/cff/cffgload.c | 2634 ++++ src/freetype2/cff/cffgload.h | 208 + src/freetype2/cff/cffload.c | 1598 +++ src/freetype2/cff/cffload.h | 79 + src/freetype2/cff/cffobjs.c | 782 ++ src/freetype2/cff/cffobjs.h | 165 + src/freetype2/cff/cffparse.c | 688 + src/freetype2/cff/cffparse.h | 69 + src/freetype2/cff/cfftoken.h | 97 + src/freetype2/cff/cfftypes.h | 270 + src/freetype2/cid/ciderrs.h | 40 + src/freetype2/cid/cidgload.c | 433 + src/freetype2/cid/cidgload.h | 51 + src/freetype2/cid/cidload.c | 644 + src/freetype2/cid/cidload.h | 53 + src/freetype2/cid/cidobjs.c | 480 + src/freetype2/cid/cidobjs.h | 154 + src/freetype2/cid/cidparse.c | 226 + src/freetype2/cid/cidparse.h | 123 + src/freetype2/cid/cidriver.c | 163 + src/freetype2/cid/cidriver.h | 39 + src/freetype2/cid/cidtoken.h | 103 + src/freetype2/cid/type1cid.c | 29 + src/freetype2/freetype/config/ftconfig.h | 363 + src/freetype2/freetype/config/ftheader.h | 729 + src/freetype2/freetype/config/ftmodule.h | 32 + src/freetype2/freetype/config/ftoption.h | 669 + src/freetype2/freetype/config/ftstdlib.h | 180 + src/freetype2/freetype/freetype.h | 3434 +++++ src/freetype2/freetype/ftbbox.h | 94 + src/freetype2/freetype/ftbdf.h | 200 + src/freetype2/freetype/ftbitmap.h | 206 + src/freetype2/freetype/ftcache.h | 1110 ++ src/freetype2/freetype/ftchapters.h | 100 + src/freetype2/freetype/fterrdef.h | 239 + src/freetype2/freetype/fterrors.h | 206 + src/freetype2/freetype/ftgasp.h | 113 + src/freetype2/freetype/ftglyph.h | 575 + src/freetype2/freetype/ftgxval.h | 358 + src/freetype2/freetype/ftgzip.h | 102 + src/freetype2/freetype/ftimage.h | 1237 ++ src/freetype2/freetype/ftincrem.h | 331 + src/freetype2/freetype/ftlcdfil.h | 166 + src/freetype2/freetype/ftlist.h | 273 + src/freetype2/freetype/ftlzw.h | 99 + src/freetype2/freetype/ftmac.h | 272 + src/freetype2/freetype/ftmm.h | 378 + src/freetype2/freetype/ftmodapi.h | 406 + src/freetype2/freetype/ftmoderr.h | 155 + src/freetype2/freetype/ftotval.h | 198 + src/freetype2/freetype/ftoutln.h | 526 + src/freetype2/freetype/ftpfr.h | 172 + src/freetype2/freetype/ftrender.h | 229 + src/freetype2/freetype/ftsizes.h | 159 + src/freetype2/freetype/ftsnames.h | 170 + src/freetype2/freetype/ftstroke.h | 716 + src/freetype2/freetype/ftsynth.h | 73 + src/freetype2/freetype/ftsystem.h | 346 + src/freetype2/freetype/fttrigon.h | 350 + src/freetype2/freetype/fttypes.h | 583 + src/freetype2/freetype/ftwinfnt.h | 263 + src/freetype2/freetype/ftxf86.h | 80 + src/freetype2/freetype/internal/autohint.h | 205 + src/freetype2/freetype/internal/ftcalc.h | 153 + src/freetype2/freetype/internal/ftdebug.h | 244 + src/freetype2/freetype/internal/ftdriver.h | 252 + src/freetype2/freetype/internal/ftgloadr.h | 168 + src/freetype2/freetype/internal/ftmemory.h | 368 + src/freetype2/freetype/internal/ftobjs.h | 820 ++ src/freetype2/freetype/internal/ftrfork.h | 184 + src/freetype2/freetype/internal/ftserv.h | 327 + src/freetype2/freetype/internal/ftstream.h | 539 + src/freetype2/freetype/internal/fttrace.h | 133 + src/freetype2/freetype/internal/ftvalid.h | 150 + src/freetype2/freetype/internal/internal.h | 50 + src/freetype2/freetype/internal/pcftypes.h | 56 + src/freetype2/freetype/internal/psaux.h | 879 ++ src/freetype2/freetype/internal/pshints.h | 687 + src/freetype2/freetype/internal/services/svbdf.h | 57 + .../freetype/internal/services/svgldict.h | 60 + src/freetype2/freetype/internal/services/svgxval.h | 72 + src/freetype2/freetype/internal/services/svkern.h | 51 + src/freetype2/freetype/internal/services/svmm.h | 79 + src/freetype2/freetype/internal/services/svotval.h | 55 + src/freetype2/freetype/internal/services/svpfr.h | 66 + .../freetype/internal/services/svpostnm.h | 58 + .../freetype/internal/services/svpscmap.h | 129 + .../freetype/internal/services/svpsinfo.h | 60 + src/freetype2/freetype/internal/services/svsfnt.h | 80 + .../freetype/internal/services/svttcmap.h | 78 + src/freetype2/freetype/internal/services/svtteng.h | 53 + .../freetype/internal/services/svttglyf.h | 48 + .../freetype/internal/services/svwinfnt.h | 50 + .../freetype/internal/services/svxf86nm.h | 55 + src/freetype2/freetype/internal/sfnt.h | 762 + src/freetype2/freetype/internal/t1types.h | 252 + src/freetype2/freetype/internal/tttypes.h | 1543 +++ src/freetype2/freetype/t1tables.h | 450 + src/freetype2/freetype/ttnameid.h | 1132 ++ src/freetype2/freetype/tttables.h | 756 + src/freetype2/freetype/tttags.h | 99 + src/freetype2/freetype/ttunpat.h | 59 + src/freetype2/ft2build.h | 39 + src/freetype2/gxvalid/gxvalid.c | 46 + src/freetype2/gxvalid/gxvalid.h | 107 + src/freetype2/gxvalid/gxvbsln.c | 333 + src/freetype2/gxvalid/gxvcommn.c | 1758 +++ src/freetype2/gxvalid/gxvcommn.h | 560 + src/freetype2/gxvalid/gxverror.h | 51 + src/freetype2/gxvalid/gxvfeat.c | 343 + src/freetype2/gxvalid/gxvfeat.h | 172 + src/freetype2/gxvalid/gxvfgen.c | 482 + src/freetype2/gxvalid/gxvjust.c | 630 + src/freetype2/gxvalid/gxvkern.c | 876 ++ src/freetype2/gxvalid/gxvlcar.c | 223 + src/freetype2/gxvalid/gxvmod.c | 285 + src/freetype2/gxvalid/gxvmod.h | 46 + src/freetype2/gxvalid/gxvmort.c | 285 + src/freetype2/gxvalid/gxvmort.h | 93 + src/freetype2/gxvalid/gxvmort0.c | 137 + src/freetype2/gxvalid/gxvmort1.c | 258 + src/freetype2/gxvalid/gxvmort2.c | 282 + src/freetype2/gxvalid/gxvmort4.c | 125 + src/freetype2/gxvalid/gxvmort5.c | 226 + src/freetype2/gxvalid/gxvmorx.c | 183 + src/freetype2/gxvalid/gxvmorx.h | 67 + src/freetype2/gxvalid/gxvmorx0.c | 103 + src/freetype2/gxvalid/gxvmorx1.c | 274 + src/freetype2/gxvalid/gxvmorx2.c | 285 + src/freetype2/gxvalid/gxvmorx4.c | 55 + src/freetype2/gxvalid/gxvmorx5.c | 217 + src/freetype2/gxvalid/gxvopbd.c | 217 + src/freetype2/gxvalid/gxvprop.c | 301 + src/freetype2/gxvalid/gxvtrak.c | 277 + src/freetype2/gzip/adler32.c | 48 + src/freetype2/gzip/ftgzip.c | 682 + src/freetype2/gzip/infblock.c | 387 + src/freetype2/gzip/infblock.h | 36 + src/freetype2/gzip/infcodes.c | 250 + src/freetype2/gzip/infcodes.h | 31 + src/freetype2/gzip/inffixed.h | 151 + src/freetype2/gzip/inflate.c | 273 + src/freetype2/gzip/inftrees.c | 465 + src/freetype2/gzip/inftrees.h | 63 + src/freetype2/gzip/infutil.c | 86 + src/freetype2/gzip/infutil.h | 98 + src/freetype2/gzip/zconf.h | 278 + src/freetype2/gzip/zlib.h | 830 ++ src/freetype2/gzip/zutil.c | 181 + src/freetype2/gzip/zutil.h | 215 + src/freetype2/lzw/ftlzw.c | 413 + src/freetype2/lzw/ftzopen.c | 398 + src/freetype2/lzw/ftzopen.h | 171 + src/freetype2/otvalid/otvalid.c | 30 + src/freetype2/otvalid/otvalid.h | 72 + src/freetype2/otvalid/otvbase.c | 318 + src/freetype2/otvalid/otvcommn.c | 1055 ++ src/freetype2/otvalid/otvcommn.h | 436 + src/freetype2/otvalid/otverror.h | 43 + src/freetype2/otvalid/otvgdef.c | 219 + src/freetype2/otvalid/otvgpos.c | 1013 ++ src/freetype2/otvalid/otvgpos.h | 36 + src/freetype2/otvalid/otvgsub.c | 584 + src/freetype2/otvalid/otvjstf.c | 258 + src/freetype2/otvalid/otvmod.c | 242 + src/freetype2/otvalid/otvmod.h | 39 + src/freetype2/pcf/README | 114 + src/freetype2/pcf/pcf.c | 36 + src/freetype2/pcf/pcf.h | 237 + src/freetype2/pcf/pcfdrivr.c | 668 + src/freetype2/pcf/pcfdrivr.h | 44 + src/freetype2/pcf/pcferror.h | 40 + src/freetype2/pcf/pcfread.c | 1267 ++ src/freetype2/pcf/pcfread.h | 45 + src/freetype2/pcf/pcfutil.c | 104 + src/freetype2/pcf/pcfutil.h | 55 + src/freetype2/pfr/pfr.c | 29 + src/freetype2/pfr/pfrcmap.c | 163 + src/freetype2/pfr/pfrcmap.h | 46 + src/freetype2/pfr/pfrdrivr.c | 207 + src/freetype2/pfr/pfrdrivr.h | 39 + src/freetype2/pfr/pfrerror.h | 40 + src/freetype2/pfr/pfrgload.c | 828 ++ src/freetype2/pfr/pfrgload.h | 49 + src/freetype2/pfr/pfrload.c | 938 ++ src/freetype2/pfr/pfrload.h | 118 + src/freetype2/pfr/pfrobjs.c | 576 + src/freetype2/pfr/pfrobjs.h | 96 + src/freetype2/pfr/pfrsbit.c | 680 + src/freetype2/pfr/pfrsbit.h | 36 + src/freetype2/pfr/pfrtypes.h | 362 + src/freetype2/psaux/afmparse.c | 960 ++ src/freetype2/psaux/afmparse.h | 87 + src/freetype2/psaux/psaux.c | 34 + src/freetype2/psaux/psauxerr.h | 41 + src/freetype2/psaux/psauxmod.c | 139 + src/freetype2/psaux/psauxmod.h | 38 + src/freetype2/psaux/psconv.c | 466 + src/freetype2/psaux/psconv.h | 71 + src/freetype2/psaux/psobjs.c | 1698 +++ src/freetype2/psaux/psobjs.h | 212 + src/freetype2/psaux/t1cmap.c | 333 + src/freetype2/psaux/t1cmap.h | 105 + src/freetype2/psaux/t1decode.c | 1474 ++ src/freetype2/psaux/t1decode.h | 64 + src/freetype2/pshinter/pshalgo.c | 2291 +++ src/freetype2/pshinter/pshalgo.h | 255 + src/freetype2/pshinter/pshglob.c | 750 + src/freetype2/pshinter/pshglob.h | 196 + src/freetype2/pshinter/pshinter.c | 28 + src/freetype2/pshinter/pshmod.c | 121 + src/freetype2/pshinter/pshmod.h | 39 + src/freetype2/pshinter/pshnterr.h | 40 + src/freetype2/pshinter/pshrec.c | 1215 ++ src/freetype2/pshinter/pshrec.h | 176 + src/freetype2/psnames/psmodule.c | 458 + src/freetype2/psnames/psmodule.h | 38 + src/freetype2/psnames/psnamerr.h | 41 + src/freetype2/psnames/psnames.c | 25 + src/freetype2/psnames/pstables.h | 4090 ++++++ src/freetype2/raster/ftmisc.h | 83 + src/freetype2/raster/ftraster.c | 3369 +++++ src/freetype2/raster/ftraster.h | 46 + src/freetype2/raster/ftrend1.c | 273 + src/freetype2/raster/ftrend1.h | 44 + src/freetype2/raster/raster.c | 26 + src/freetype2/raster/rasterrs.h | 41 + src/freetype2/sfnt/sfdriver.c | 618 + src/freetype2/sfnt/sfdriver.h | 38 + src/freetype2/sfnt/sferrors.h | 41 + src/freetype2/sfnt/sfnt.c | 41 + src/freetype2/sfnt/sfobjs.c | 1070 ++ src/freetype2/sfnt/sfobjs.h | 54 + src/freetype2/sfnt/ttbdf.c | 250 + src/freetype2/sfnt/ttbdf.h | 46 + src/freetype2/sfnt/ttcmap.c | 2356 ++++ src/freetype2/sfnt/ttcmap.h | 85 + src/freetype2/sfnt/ttkern.c | 292 + src/freetype2/sfnt/ttkern.h | 52 + src/freetype2/sfnt/ttload.c | 1176 ++ src/freetype2/sfnt/ttload.h | 112 + src/freetype2/sfnt/ttmtx.c | 465 + src/freetype2/sfnt/ttmtx.h | 55 + src/freetype2/sfnt/ttpost.c | 521 + src/freetype2/sfnt/ttpost.h | 46 + src/freetype2/sfnt/ttsbit.c | 1501 ++ src/freetype2/sfnt/ttsbit.h | 79 + src/freetype2/sfnt/ttsbit0.c | 996 ++ src/freetype2/sfnt/ttsbit0.h | 7 + src/freetype2/smooth/ftgrays.c | 1983 +++ src/freetype2/smooth/ftgrays.h | 57 + src/freetype2/smooth/ftsmerrs.h | 41 + src/freetype2/smooth/ftsmooth.c | 467 + src/freetype2/smooth/ftsmooth.h | 49 + src/freetype2/smooth/smooth.c | 26 + src/freetype2/truetype/truetype.c | 36 + src/freetype2/truetype/ttdriver.c | 418 + src/freetype2/truetype/ttdriver.h | 38 + src/freetype2/truetype/tterrors.h | 40 + src/freetype2/truetype/ttgload.c | 1957 +++ src/freetype2/truetype/ttgload.h | 49 + src/freetype2/truetype/ttgxvar.c | 1536 ++ src/freetype2/truetype/ttgxvar.h | 182 + src/freetype2/truetype/ttinterp.c | 7809 +++++++++++ src/freetype2/truetype/ttinterp.h | 311 + src/freetype2/truetype/ttobjs.c | 937 ++ src/freetype2/truetype/ttobjs.h | 459 + src/freetype2/truetype/ttpload.c | 523 + src/freetype2/truetype/ttpload.h | 75 + src/freetype2/type1/t1afm.c | 385 + src/freetype2/type1/t1afm.h | 54 + src/freetype2/type1/t1driver.c | 313 + src/freetype2/type1/t1driver.h | 38 + src/freetype2/type1/t1errors.h | 40 + src/freetype2/type1/t1gload.c | 422 + src/freetype2/type1/t1gload.h | 46 + src/freetype2/type1/t1load.c | 2221 +++ src/freetype2/type1/t1load.h | 102 + src/freetype2/type1/t1objs.c | 566 + src/freetype2/type1/t1objs.h | 171 + src/freetype2/type1/t1parse.c | 479 + src/freetype2/type1/t1parse.h | 135 + src/freetype2/type1/t1tokens.h | 134 + src/freetype2/type1/type1.c | 33 + src/freetype2/type42/t42drivr.c | 232 + src/freetype2/type42/t42drivr.h | 38 + src/freetype2/type42/t42error.h | 40 + src/freetype2/type42/t42objs.c | 647 + src/freetype2/type42/t42objs.h | 124 + src/freetype2/type42/t42parse.c | 1167 ++ src/freetype2/type42/t42parse.h | 90 + src/freetype2/type42/t42types.h | 54 + src/freetype2/type42/type42.c | 25 + src/freetype2/winfonts/fnterrs.h | 41 + src/freetype2/winfonts/winfnt.c | 1122 ++ src/freetype2/winfonts/winfnt.h | 167 + src/gdiplus/cdcontextplus.def | 9 + src/gdiplus/cdgdiplus.def | 9 + src/gdiplus/cdwclpp.cpp | 206 + src/gdiplus/cdwdbufp.cpp | 152 + src/gdiplus/cdwemfp.cpp | 105 + src/gdiplus/cdwgdiplus.c | 42 + src/gdiplus/cdwimgp.cpp | 65 + src/gdiplus/cdwinp.cpp | 2337 ++++ src/gdiplus/cdwinp.h | 112 + src/gdiplus/cdwnativep.cpp | 138 + src/gdiplus/cdwprnp.cpp | 158 + src/intcgm/bparse.c | 1660 +++ src/intcgm/bparse.h | 117 + src/intcgm/circle.c | 100 + src/intcgm/circle.h | 3 + src/intcgm/ellipse.c | 143 + src/intcgm/ellipse.h | 3 + src/intcgm/intcgm.h | 84 + src/intcgm/intcgm1.c | 291 + src/intcgm/intcgm2.c | 1653 +++ src/intcgm/intcgm2.h | 52 + src/intcgm/intcgm4.c | 1265 ++ src/intcgm/intcgm4.h | 28 + src/intcgm/intcgm6.c | 253 + src/intcgm/intcgm6.h | 15 + src/intcgm/list.c | 117 + src/intcgm/list.h | 30 + src/intcgm/sism.c | 392 + src/intcgm/sism.h | 3 + src/intcgm/tparse.c | 1370 ++ src/intcgm/tparse.h | 101 + src/intcgm/types.h | 225 + src/lua3/cdlua.c | 4366 ++++++ src/lua3/cdlua.def | 7 + src/lua3/cdluactx.c | 950 ++ src/lua3/cdluapdf.c | 43 + src/lua3/cdluapdf.def | 2 + src/lua3/cdvoid.c | 126 + src/lua3/cdvoid.h | 17 + src/lua3/toluacd.c | 585 + src/lua3/toluawd.c | 228 + src/lua5/cdlua5.c | 1819 +++ src/lua5/cdlua5.def | 13 + src/lua5/cdlua5_active.c | 2163 +++ src/lua5/cdlua5_canvas.c | 2343 ++++ src/lua5/cdlua5ctx.c | 802 ++ src/lua5/cdluacontextplus5.c | 44 + src/lua5/cdluacontextplus5.def | 4 + src/lua5/cdluaim5.c | 265 + src/lua5/cdluaim5.def | 4 + src/lua5/cdluapdf5.c | 53 + src/lua5/cdluapdf5.def | 4 + src/lua5/cdvoid5.c | 130 + src/lua5/cdvoid5.h | 18 + src/make_uname | 16 + src/make_uname.bat | 57 + src/pdflib/flate/adler32.c | 144 + src/pdflib/flate/compress.c | 79 + src/pdflib/flate/crc32.c | 424 + src/pdflib/flate/crc32.h | 441 + src/pdflib/flate/deflate.c | 1740 +++ src/pdflib/flate/deflate.h | 334 + src/pdflib/flate/inffast.c | 319 + src/pdflib/flate/inffast.h | 11 + src/pdflib/flate/inffixed.h | 94 + src/pdflib/flate/inflate.c | 1369 ++ src/pdflib/flate/inflate.h | 115 + src/pdflib/flate/inftrees.c | 330 + src/pdflib/flate/inftrees.h | 55 + src/pdflib/flate/trees.c | 1220 ++ src/pdflib/flate/trees.h | 131 + src/pdflib/flate/uncompr.c | 62 + src/pdflib/flate/zconf.h | 280 + src/pdflib/flate/zlib.h | 1360 ++ src/pdflib/flate/zprefix.h | 134 + src/pdflib/flate/zutil.c | 319 + src/pdflib/flate/zutil.h | 276 + src/pdflib/font/ft_cid.c | 295 + src/pdflib/font/ft_cid.h | 63 + src/pdflib/font/ft_corefont.c | 411 + src/pdflib/font/ft_corefont.h | 2642 ++++ src/pdflib/font/ft_font.c | 532 + src/pdflib/font/ft_font.h | 267 + src/pdflib/font/ft_generr.h | 109 + src/pdflib/font/ft_hostfont.c | 24 + src/pdflib/font/ft_pdffont.c | 18 + src/pdflib/font/ft_pdffont.h | 26 + src/pdflib/font/ft_truetype.c | 2310 ++++ src/pdflib/font/ft_truetype.h | 558 + src/pdflib/font/ft_type1.c | 39 + src/pdflib/pdcore/pc_aes.c | 32 + src/pdflib/pdcore/pc_aes.h | 53 + src/pdflib/pdcore/pc_aescbc.c | 53 + src/pdflib/pdcore/pc_aeslocal.h | 53 + src/pdflib/pdcore/pc_arc4.c | 61 + src/pdflib/pdcore/pc_arc4.h | 60 + src/pdflib/pdcore/pc_chartabs.c | 613 + src/pdflib/pdcore/pc_chartabs.h | 13851 +++++++++++++++++++ src/pdflib/pdcore/pc_classic.h | 24 + src/pdflib/pdcore/pc_config.h | 388 + src/pdflib/pdcore/pc_contain.c | 518 + src/pdflib/pdcore/pc_contain.h | 110 + src/pdflib/pdcore/pc_core.c | 1190 ++ src/pdflib/pdcore/pc_core.h | 270 + src/pdflib/pdcore/pc_crypt.c | 27 + src/pdflib/pdcore/pc_crypt.h | 27 + src/pdflib/pdcore/pc_ctype.c | 309 + src/pdflib/pdcore/pc_ctype.h | 77 + src/pdflib/pdcore/pc_digsig.c | 20 + src/pdflib/pdcore/pc_digsig.h | 17 + src/pdflib/pdcore/pc_ebcdic.c | 27 + src/pdflib/pdcore/pc_ebcdic.h | 35 + src/pdflib/pdcore/pc_encoding.c | 2549 ++++ src/pdflib/pdcore/pc_encoding.h | 295 + src/pdflib/pdcore/pc_exports.h | 24 + src/pdflib/pdcore/pc_file.c | 1548 +++ src/pdflib/pdcore/pc_file.h | 150 + src/pdflib/pdcore/pc_generr.h | 444 + src/pdflib/pdcore/pc_geom.c | 681 + src/pdflib/pdcore/pc_geom.h | 116 + src/pdflib/pdcore/pc_md5.c | 307 + src/pdflib/pdcore/pc_md5.h | 59 + src/pdflib/pdcore/pc_optparse.c | 1383 ++ src/pdflib/pdcore/pc_optparse.h | 292 + src/pdflib/pdcore/pc_output.c | 1126 ++ src/pdflib/pdcore/pc_output.h | 203 + src/pdflib/pdcore/pc_prefix.h | 17 + src/pdflib/pdcore/pc_pstok.h | 15 + src/pdflib/pdcore/pc_resource.c | 1906 +++ src/pdflib/pdcore/pc_resource.h | 124 + src/pdflib/pdcore/pc_scan.c | 19 + src/pdflib/pdcore/pc_scan.h | 15 + src/pdflib/pdcore/pc_scantok.h | 14 + src/pdflib/pdcore/pc_scope.c | 26 + src/pdflib/pdcore/pc_scope.h | 23 + src/pdflib/pdcore/pc_strconst.h | 5 + src/pdflib/pdcore/pc_string.c | 514 + src/pdflib/pdcore/pc_string.h | 267 + src/pdflib/pdcore/pc_unicode.c | 1886 +++ src/pdflib/pdcore/pc_unicode.h | 283 + src/pdflib/pdcore/pc_util.c | 2726 ++++ src/pdflib/pdcore/pc_util.h | 268 + src/pdflib/pdcore/pc_xmp.c | 31 + src/pdflib/pdcore/pc_xmp.h | 27 + src/pdflib/pdflib/p_3d.c | 22 + src/pdflib/pdflib/p_actions.c | 1155 ++ src/pdflib/pdflib/p_afm.c | 756 + src/pdflib/pdflib/p_annots.c | 2078 +++ src/pdflib/pdflib/p_block.c | 26 + src/pdflib/pdflib/p_bmp.c | 795 ++ src/pdflib/pdflib/p_ccitt.c | 186 + src/pdflib/pdflib/p_cid.c | 198 + src/pdflib/pdflib/p_color.c | 1130 ++ src/pdflib/pdflib/p_color.h | 109 + src/pdflib/pdflib/p_defopt.h | 494 + src/pdflib/pdflib/p_document.c | 1939 +++ src/pdflib/pdflib/p_draw.c | 410 + src/pdflib/pdflib/p_encoding.c | 187 + src/pdflib/pdflib/p_fields.c | 30 + src/pdflib/pdflib/p_filter.c | 120 + src/pdflib/pdflib/p_font.c | 2513 ++++ src/pdflib/pdflib/p_font.h | 225 + src/pdflib/pdflib/p_generr.h | 705 + src/pdflib/pdflib/p_gif.c | 744 + src/pdflib/pdflib/p_gstate.c | 451 + src/pdflib/pdflib/p_hkscmyk.h | 28 + src/pdflib/pdflib/p_hkslab.h | 26 + src/pdflib/pdflib/p_hyper.c | 1449 ++ src/pdflib/pdflib/p_icc.c | 32 + src/pdflib/pdflib/p_icc.h | 24 + src/pdflib/pdflib/p_icc9809.h | 38 + src/pdflib/pdflib/p_icclib.c | 62 + src/pdflib/pdflib/p_icclib.h | 38 + src/pdflib/pdflib/p_image.c | 2253 +++ src/pdflib/pdflib/p_image.h | 358 + src/pdflib/pdflib/p_intern.h | 1027 ++ src/pdflib/pdflib/p_jpeg.c | 1560 +++ src/pdflib/pdflib/p_jpx.c | 73 + src/pdflib/pdflib/p_kerning.c | 21 + src/pdflib/pdflib/p_keyconn.h | 827 ++ src/pdflib/pdflib/p_layer.c | 36 + src/pdflib/pdflib/p_layer.h | 24 + src/pdflib/pdflib/p_mbox.c | 943 ++ src/pdflib/pdflib/p_object.c | 257 + src/pdflib/pdflib/p_opi.c | 21 + src/pdflib/pdflib/p_page.c | 2261 +++ src/pdflib/pdflib/p_page.h | 34 + src/pdflib/pdflib/p_pantlab.h | 28 + src/pdflib/pdflib/p_params.c | 1306 ++ src/pdflib/pdflib/p_params.h | 373 + src/pdflib/pdflib/p_pattern.c | 231 + src/pdflib/pdflib/p_pdi.c | 28 + src/pdflib/pdflib/p_pfm.c | 406 + src/pdflib/pdflib/p_photoshp.c | 23 + src/pdflib/pdflib/p_png.c | 855 ++ src/pdflib/pdflib/p_shading.c | 381 + src/pdflib/pdflib/p_subsett.c | 26 + src/pdflib/pdflib/p_table.c | 26 + src/pdflib/pdflib/p_tagged.c | 53 + src/pdflib/pdflib/p_tagged.h | 25 + src/pdflib/pdflib/p_template.c | 246 + src/pdflib/pdflib/p_text.c | 3715 +++++ src/pdflib/pdflib/p_textflow.c | 27 + src/pdflib/pdflib/p_tiff.c | 1169 ++ src/pdflib/pdflib/p_truetype.c | 301 + src/pdflib/pdflib/p_type1.c | 427 + src/pdflib/pdflib/p_type3.c | 740 + src/pdflib/pdflib/p_util.c | 733 + src/pdflib/pdflib/p_xgstate.c | 514 + src/pdflib/pdflib/p_xmp.c | 25 + src/pdflib/pdflib/pdflib.c | 4052 ++++++ src/pdflib/pdflib/pdflib.h | 1572 +++ src/rgb2map.c | 976 ++ src/sim/cd_truetype.c | 181 + src/sim/cd_truetype.h | 46 + src/sim/cdfontex.c | 669 + src/sim/sim.c | 328 + src/sim/sim.h | 58 + src/sim/sim_linepolyfill.c | 1000 ++ src/sim/sim_other.c | 411 + src/sim/sim_primitives.c | 524 + src/sim/sim_text.c | 371 + src/sim/truetype.h | 46 + src/tecmake_compact.mak | 1080 ++ src/wd.c | 473 + src/wdhdcpy.c | 101 + src/win32/cdwclp.c | 551 + src/win32/cdwdbuf.c | 169 + src/win32/cdwdib.c | 662 + src/win32/cdwemf.c | 117 + src/win32/cdwimg.c | 83 + src/win32/cdwin.c | 2368 ++++ src/win32/cdwin.h | 181 + src/win32/cdwnative.c | 209 + src/win32/cdwprn.c | 184 + src/win32/cdwwmf.c | 109 + src/win32/wmf_emf.c | 2121 +++ src/x11/cdx11.c | 2447 ++++ src/x11/cdx11.h | 85 + src/x11/cdxclp.c | 136 + src/x11/cdxdbuf.c | 156 + src/x11/cdximg.c | 52 + src/x11/cdxnative.c | 165 + src/x11/xvertex.c | 1440 ++ src/x11/xvertex.h | 31 + src/xrender/cdxrender.c | 1139 ++ src/xrender/cdxrplus.c | 26 + 674 files changed, 319702 insertions(+) create mode 100644 src/.cvsignore create mode 100644 src/COPYRIGHT create mode 100644 src/Makefile create mode 100644 src/README create mode 100644 src/cd.c create mode 100644 src/cd.def create mode 100644 src/cd.rc create mode 100644 src/cd_active.c create mode 100644 src/cd_attributes.c create mode 100644 src/cd_bitmap.c create mode 100644 src/cd_freetype.def create mode 100644 src/cd_freetype.mak create mode 100644 src/cd_freetype.rc create mode 100644 src/cd_image.c create mode 100644 src/cd_pdflib.def create mode 100644 src/cd_pdflib.mak create mode 100644 src/cd_pdflib.rc create mode 100644 src/cd_primitives.c create mode 100644 src/cd_text.c create mode 100644 src/cd_util.c create mode 100644 src/cd_vectortext.c create mode 100644 src/cdcontextplus.mak create mode 100644 src/cdlua3.mak create mode 100644 src/cdlua5.mak create mode 100644 src/cdluacontextplus5.mak create mode 100644 src/cdluaim5.mak create mode 100644 src/cdluapdf3.mak create mode 100644 src/cdluapdf5.mak create mode 100644 src/cdpdf.def create mode 100644 src/cdpdf.mak create mode 100644 src/config.mak create mode 100644 src/drv/cd0emf.c create mode 100644 src/drv/cd0prn.c create mode 100644 src/drv/cd0wmf.c create mode 100644 src/drv/cdcgm.c create mode 100644 src/drv/cddebug.c create mode 100644 src/drv/cddgn.c create mode 100644 src/drv/cddxf.c create mode 100644 src/drv/cdirgb.c create mode 100644 src/drv/cdmf.c create mode 100644 src/drv/cdpdf.c create mode 100644 src/drv/cdpicture.c create mode 100644 src/drv/cdps.c create mode 100644 src/drv/cgm.c create mode 100644 src/drv/cgm.h create mode 100644 src/freetype2/autofit/afangles.c create mode 100644 src/freetype2/autofit/afangles.h create mode 100644 src/freetype2/autofit/afcjk.c create mode 100644 src/freetype2/autofit/afcjk.h create mode 100644 src/freetype2/autofit/afdummy.c create mode 100644 src/freetype2/autofit/afdummy.h create mode 100644 src/freetype2/autofit/aferrors.h create mode 100644 src/freetype2/autofit/afglobal.c create mode 100644 src/freetype2/autofit/afglobal.h create mode 100644 src/freetype2/autofit/afhints.c create mode 100644 src/freetype2/autofit/afhints.h create mode 100644 src/freetype2/autofit/afindic.c create mode 100644 src/freetype2/autofit/afindic.h create mode 100644 src/freetype2/autofit/aflatin.c create mode 100644 src/freetype2/autofit/aflatin.h create mode 100644 src/freetype2/autofit/aflatin2.c create mode 100644 src/freetype2/autofit/aflatin2.h create mode 100644 src/freetype2/autofit/afloader.c create mode 100644 src/freetype2/autofit/afloader.h create mode 100644 src/freetype2/autofit/afmodule.c create mode 100644 src/freetype2/autofit/afmodule.h create mode 100644 src/freetype2/autofit/aftypes.h create mode 100644 src/freetype2/autofit/afwarp.c create mode 100644 src/freetype2/autofit/afwarp.h create mode 100644 src/freetype2/autofit/autofit.c create mode 100644 src/freetype2/base/ftapi.c create mode 100644 src/freetype2/base/ftbase.c create mode 100644 src/freetype2/base/ftbbox.c create mode 100644 src/freetype2/base/ftbdf.c create mode 100644 src/freetype2/base/ftbitmap.c create mode 100644 src/freetype2/base/ftcalc.c create mode 100644 src/freetype2/base/ftdbgmem.c create mode 100644 src/freetype2/base/ftdebug.c create mode 100644 src/freetype2/base/ftgasp.c create mode 100644 src/freetype2/base/ftgloadr.c create mode 100644 src/freetype2/base/ftglyph.c create mode 100644 src/freetype2/base/ftgxval.c create mode 100644 src/freetype2/base/ftinit.c create mode 100644 src/freetype2/base/ftlcdfil.c create mode 100644 src/freetype2/base/ftmac.c create mode 100644 src/freetype2/base/ftmm.c create mode 100644 src/freetype2/base/ftnames.c create mode 100644 src/freetype2/base/ftobjs.c create mode 100644 src/freetype2/base/ftotval.c create mode 100644 src/freetype2/base/ftoutln.c create mode 100644 src/freetype2/base/ftpatent.c create mode 100644 src/freetype2/base/ftpfr.c create mode 100644 src/freetype2/base/ftrfork.c create mode 100644 src/freetype2/base/ftstream.c create mode 100644 src/freetype2/base/ftstroke.c create mode 100644 src/freetype2/base/ftsynth.c create mode 100644 src/freetype2/base/ftsystem.c create mode 100644 src/freetype2/base/fttrigon.c create mode 100644 src/freetype2/base/fttype1.c create mode 100644 src/freetype2/base/ftutil.c create mode 100644 src/freetype2/base/ftwinfnt.c create mode 100644 src/freetype2/base/ftxf86.c create mode 100644 src/freetype2/bdf/bdf.c create mode 100644 src/freetype2/bdf/bdf.h create mode 100644 src/freetype2/bdf/bdfdrivr.c create mode 100644 src/freetype2/bdf/bdfdrivr.h create mode 100644 src/freetype2/bdf/bdferror.h create mode 100644 src/freetype2/bdf/bdflib.c create mode 100644 src/freetype2/cache/ftcache.c create mode 100644 src/freetype2/cache/ftcbasic.c create mode 100644 src/freetype2/cache/ftccache.c create mode 100644 src/freetype2/cache/ftccache.h create mode 100644 src/freetype2/cache/ftccback.h create mode 100644 src/freetype2/cache/ftccmap.c create mode 100644 src/freetype2/cache/ftcerror.h create mode 100644 src/freetype2/cache/ftcglyph.c create mode 100644 src/freetype2/cache/ftcglyph.h create mode 100644 src/freetype2/cache/ftcimage.c create mode 100644 src/freetype2/cache/ftcimage.h create mode 100644 src/freetype2/cache/ftcmanag.c create mode 100644 src/freetype2/cache/ftcmanag.h create mode 100644 src/freetype2/cache/ftcmru.c create mode 100644 src/freetype2/cache/ftcmru.h create mode 100644 src/freetype2/cache/ftcsbits.c create mode 100644 src/freetype2/cache/ftcsbits.h create mode 100644 src/freetype2/cff/cff.c create mode 100644 src/freetype2/cff/cffcmap.c create mode 100644 src/freetype2/cff/cffcmap.h create mode 100644 src/freetype2/cff/cffdrivr.c create mode 100644 src/freetype2/cff/cffdrivr.h create mode 100644 src/freetype2/cff/cfferrs.h create mode 100644 src/freetype2/cff/cffgload.c create mode 100644 src/freetype2/cff/cffgload.h create mode 100644 src/freetype2/cff/cffload.c create mode 100644 src/freetype2/cff/cffload.h create mode 100644 src/freetype2/cff/cffobjs.c create mode 100644 src/freetype2/cff/cffobjs.h create mode 100644 src/freetype2/cff/cffparse.c create mode 100644 src/freetype2/cff/cffparse.h create mode 100644 src/freetype2/cff/cfftoken.h create mode 100644 src/freetype2/cff/cfftypes.h create mode 100644 src/freetype2/cid/ciderrs.h create mode 100644 src/freetype2/cid/cidgload.c create mode 100644 src/freetype2/cid/cidgload.h create mode 100644 src/freetype2/cid/cidload.c create mode 100644 src/freetype2/cid/cidload.h create mode 100644 src/freetype2/cid/cidobjs.c create mode 100644 src/freetype2/cid/cidobjs.h create mode 100644 src/freetype2/cid/cidparse.c create mode 100644 src/freetype2/cid/cidparse.h create mode 100644 src/freetype2/cid/cidriver.c create mode 100644 src/freetype2/cid/cidriver.h create mode 100644 src/freetype2/cid/cidtoken.h create mode 100644 src/freetype2/cid/type1cid.c create mode 100644 src/freetype2/freetype/config/ftconfig.h create mode 100644 src/freetype2/freetype/config/ftheader.h create mode 100644 src/freetype2/freetype/config/ftmodule.h create mode 100644 src/freetype2/freetype/config/ftoption.h create mode 100644 src/freetype2/freetype/config/ftstdlib.h create mode 100644 src/freetype2/freetype/freetype.h create mode 100644 src/freetype2/freetype/ftbbox.h create mode 100644 src/freetype2/freetype/ftbdf.h create mode 100644 src/freetype2/freetype/ftbitmap.h create mode 100644 src/freetype2/freetype/ftcache.h create mode 100644 src/freetype2/freetype/ftchapters.h create mode 100644 src/freetype2/freetype/fterrdef.h create mode 100644 src/freetype2/freetype/fterrors.h create mode 100644 src/freetype2/freetype/ftgasp.h create mode 100644 src/freetype2/freetype/ftglyph.h create mode 100644 src/freetype2/freetype/ftgxval.h create mode 100644 src/freetype2/freetype/ftgzip.h create mode 100644 src/freetype2/freetype/ftimage.h create mode 100644 src/freetype2/freetype/ftincrem.h create mode 100644 src/freetype2/freetype/ftlcdfil.h create mode 100644 src/freetype2/freetype/ftlist.h create mode 100644 src/freetype2/freetype/ftlzw.h create mode 100644 src/freetype2/freetype/ftmac.h create mode 100644 src/freetype2/freetype/ftmm.h create mode 100644 src/freetype2/freetype/ftmodapi.h create mode 100644 src/freetype2/freetype/ftmoderr.h create mode 100644 src/freetype2/freetype/ftotval.h create mode 100644 src/freetype2/freetype/ftoutln.h create mode 100644 src/freetype2/freetype/ftpfr.h create mode 100644 src/freetype2/freetype/ftrender.h create mode 100644 src/freetype2/freetype/ftsizes.h create mode 100644 src/freetype2/freetype/ftsnames.h create mode 100644 src/freetype2/freetype/ftstroke.h create mode 100644 src/freetype2/freetype/ftsynth.h create mode 100644 src/freetype2/freetype/ftsystem.h create mode 100644 src/freetype2/freetype/fttrigon.h create mode 100644 src/freetype2/freetype/fttypes.h create mode 100644 src/freetype2/freetype/ftwinfnt.h create mode 100644 src/freetype2/freetype/ftxf86.h create mode 100644 src/freetype2/freetype/internal/autohint.h create mode 100644 src/freetype2/freetype/internal/ftcalc.h create mode 100644 src/freetype2/freetype/internal/ftdebug.h create mode 100644 src/freetype2/freetype/internal/ftdriver.h create mode 100644 src/freetype2/freetype/internal/ftgloadr.h create mode 100644 src/freetype2/freetype/internal/ftmemory.h create mode 100644 src/freetype2/freetype/internal/ftobjs.h create mode 100644 src/freetype2/freetype/internal/ftrfork.h create mode 100644 src/freetype2/freetype/internal/ftserv.h create mode 100644 src/freetype2/freetype/internal/ftstream.h create mode 100644 src/freetype2/freetype/internal/fttrace.h create mode 100644 src/freetype2/freetype/internal/ftvalid.h create mode 100644 src/freetype2/freetype/internal/internal.h create mode 100644 src/freetype2/freetype/internal/pcftypes.h create mode 100644 src/freetype2/freetype/internal/psaux.h create mode 100644 src/freetype2/freetype/internal/pshints.h create mode 100644 src/freetype2/freetype/internal/services/svbdf.h create mode 100644 src/freetype2/freetype/internal/services/svgldict.h create mode 100644 src/freetype2/freetype/internal/services/svgxval.h create mode 100644 src/freetype2/freetype/internal/services/svkern.h create mode 100644 src/freetype2/freetype/internal/services/svmm.h create mode 100644 src/freetype2/freetype/internal/services/svotval.h create mode 100644 src/freetype2/freetype/internal/services/svpfr.h create mode 100644 src/freetype2/freetype/internal/services/svpostnm.h create mode 100644 src/freetype2/freetype/internal/services/svpscmap.h create mode 100644 src/freetype2/freetype/internal/services/svpsinfo.h create mode 100644 src/freetype2/freetype/internal/services/svsfnt.h create mode 100644 src/freetype2/freetype/internal/services/svttcmap.h create mode 100644 src/freetype2/freetype/internal/services/svtteng.h create mode 100644 src/freetype2/freetype/internal/services/svttglyf.h create mode 100644 src/freetype2/freetype/internal/services/svwinfnt.h create mode 100644 src/freetype2/freetype/internal/services/svxf86nm.h create mode 100644 src/freetype2/freetype/internal/sfnt.h create mode 100644 src/freetype2/freetype/internal/t1types.h create mode 100644 src/freetype2/freetype/internal/tttypes.h create mode 100644 src/freetype2/freetype/t1tables.h create mode 100644 src/freetype2/freetype/ttnameid.h create mode 100644 src/freetype2/freetype/tttables.h create mode 100644 src/freetype2/freetype/tttags.h create mode 100644 src/freetype2/freetype/ttunpat.h create mode 100644 src/freetype2/ft2build.h create mode 100644 src/freetype2/gxvalid/gxvalid.c create mode 100644 src/freetype2/gxvalid/gxvalid.h create mode 100644 src/freetype2/gxvalid/gxvbsln.c create mode 100644 src/freetype2/gxvalid/gxvcommn.c create mode 100644 src/freetype2/gxvalid/gxvcommn.h create mode 100644 src/freetype2/gxvalid/gxverror.h create mode 100644 src/freetype2/gxvalid/gxvfeat.c create mode 100644 src/freetype2/gxvalid/gxvfeat.h create mode 100644 src/freetype2/gxvalid/gxvfgen.c create mode 100644 src/freetype2/gxvalid/gxvjust.c create mode 100644 src/freetype2/gxvalid/gxvkern.c create mode 100644 src/freetype2/gxvalid/gxvlcar.c create mode 100644 src/freetype2/gxvalid/gxvmod.c create mode 100644 src/freetype2/gxvalid/gxvmod.h create mode 100644 src/freetype2/gxvalid/gxvmort.c create mode 100644 src/freetype2/gxvalid/gxvmort.h create mode 100644 src/freetype2/gxvalid/gxvmort0.c create mode 100644 src/freetype2/gxvalid/gxvmort1.c create mode 100644 src/freetype2/gxvalid/gxvmort2.c create mode 100644 src/freetype2/gxvalid/gxvmort4.c create mode 100644 src/freetype2/gxvalid/gxvmort5.c create mode 100644 src/freetype2/gxvalid/gxvmorx.c create mode 100644 src/freetype2/gxvalid/gxvmorx.h create mode 100644 src/freetype2/gxvalid/gxvmorx0.c create mode 100644 src/freetype2/gxvalid/gxvmorx1.c create mode 100644 src/freetype2/gxvalid/gxvmorx2.c create mode 100644 src/freetype2/gxvalid/gxvmorx4.c create mode 100644 src/freetype2/gxvalid/gxvmorx5.c create mode 100644 src/freetype2/gxvalid/gxvopbd.c create mode 100644 src/freetype2/gxvalid/gxvprop.c create mode 100644 src/freetype2/gxvalid/gxvtrak.c create mode 100644 src/freetype2/gzip/adler32.c create mode 100644 src/freetype2/gzip/ftgzip.c create mode 100644 src/freetype2/gzip/infblock.c create mode 100644 src/freetype2/gzip/infblock.h create mode 100644 src/freetype2/gzip/infcodes.c create mode 100644 src/freetype2/gzip/infcodes.h create mode 100644 src/freetype2/gzip/inffixed.h create mode 100644 src/freetype2/gzip/inflate.c create mode 100644 src/freetype2/gzip/inftrees.c create mode 100644 src/freetype2/gzip/inftrees.h create mode 100644 src/freetype2/gzip/infutil.c create mode 100644 src/freetype2/gzip/infutil.h create mode 100644 src/freetype2/gzip/zconf.h create mode 100644 src/freetype2/gzip/zlib.h create mode 100644 src/freetype2/gzip/zutil.c create mode 100644 src/freetype2/gzip/zutil.h create mode 100644 src/freetype2/lzw/ftlzw.c create mode 100644 src/freetype2/lzw/ftzopen.c create mode 100644 src/freetype2/lzw/ftzopen.h create mode 100644 src/freetype2/otvalid/otvalid.c create mode 100644 src/freetype2/otvalid/otvalid.h create mode 100644 src/freetype2/otvalid/otvbase.c create mode 100644 src/freetype2/otvalid/otvcommn.c create mode 100644 src/freetype2/otvalid/otvcommn.h create mode 100644 src/freetype2/otvalid/otverror.h create mode 100644 src/freetype2/otvalid/otvgdef.c create mode 100644 src/freetype2/otvalid/otvgpos.c create mode 100644 src/freetype2/otvalid/otvgpos.h create mode 100644 src/freetype2/otvalid/otvgsub.c create mode 100644 src/freetype2/otvalid/otvjstf.c create mode 100644 src/freetype2/otvalid/otvmod.c create mode 100644 src/freetype2/otvalid/otvmod.h create mode 100644 src/freetype2/pcf/README create mode 100644 src/freetype2/pcf/pcf.c create mode 100644 src/freetype2/pcf/pcf.h create mode 100644 src/freetype2/pcf/pcfdrivr.c create mode 100644 src/freetype2/pcf/pcfdrivr.h create mode 100644 src/freetype2/pcf/pcferror.h create mode 100644 src/freetype2/pcf/pcfread.c create mode 100644 src/freetype2/pcf/pcfread.h create mode 100644 src/freetype2/pcf/pcfutil.c create mode 100644 src/freetype2/pcf/pcfutil.h create mode 100644 src/freetype2/pfr/pfr.c create mode 100644 src/freetype2/pfr/pfrcmap.c create mode 100644 src/freetype2/pfr/pfrcmap.h create mode 100644 src/freetype2/pfr/pfrdrivr.c create mode 100644 src/freetype2/pfr/pfrdrivr.h create mode 100644 src/freetype2/pfr/pfrerror.h create mode 100644 src/freetype2/pfr/pfrgload.c create mode 100644 src/freetype2/pfr/pfrgload.h create mode 100644 src/freetype2/pfr/pfrload.c create mode 100644 src/freetype2/pfr/pfrload.h create mode 100644 src/freetype2/pfr/pfrobjs.c create mode 100644 src/freetype2/pfr/pfrobjs.h create mode 100644 src/freetype2/pfr/pfrsbit.c create mode 100644 src/freetype2/pfr/pfrsbit.h create mode 100644 src/freetype2/pfr/pfrtypes.h create mode 100644 src/freetype2/psaux/afmparse.c create mode 100644 src/freetype2/psaux/afmparse.h create mode 100644 src/freetype2/psaux/psaux.c create mode 100644 src/freetype2/psaux/psauxerr.h create mode 100644 src/freetype2/psaux/psauxmod.c create mode 100644 src/freetype2/psaux/psauxmod.h create mode 100644 src/freetype2/psaux/psconv.c create mode 100644 src/freetype2/psaux/psconv.h create mode 100644 src/freetype2/psaux/psobjs.c create mode 100644 src/freetype2/psaux/psobjs.h create mode 100644 src/freetype2/psaux/t1cmap.c create mode 100644 src/freetype2/psaux/t1cmap.h create mode 100644 src/freetype2/psaux/t1decode.c create mode 100644 src/freetype2/psaux/t1decode.h create mode 100644 src/freetype2/pshinter/pshalgo.c create mode 100644 src/freetype2/pshinter/pshalgo.h create mode 100644 src/freetype2/pshinter/pshglob.c create mode 100644 src/freetype2/pshinter/pshglob.h create mode 100644 src/freetype2/pshinter/pshinter.c create mode 100644 src/freetype2/pshinter/pshmod.c create mode 100644 src/freetype2/pshinter/pshmod.h create mode 100644 src/freetype2/pshinter/pshnterr.h create mode 100644 src/freetype2/pshinter/pshrec.c create mode 100644 src/freetype2/pshinter/pshrec.h create mode 100644 src/freetype2/psnames/psmodule.c create mode 100644 src/freetype2/psnames/psmodule.h create mode 100644 src/freetype2/psnames/psnamerr.h create mode 100644 src/freetype2/psnames/psnames.c create mode 100644 src/freetype2/psnames/pstables.h create mode 100644 src/freetype2/raster/ftmisc.h create mode 100644 src/freetype2/raster/ftraster.c create mode 100644 src/freetype2/raster/ftraster.h create mode 100644 src/freetype2/raster/ftrend1.c create mode 100644 src/freetype2/raster/ftrend1.h create mode 100644 src/freetype2/raster/raster.c create mode 100644 src/freetype2/raster/rasterrs.h create mode 100644 src/freetype2/sfnt/sfdriver.c create mode 100644 src/freetype2/sfnt/sfdriver.h create mode 100644 src/freetype2/sfnt/sferrors.h create mode 100644 src/freetype2/sfnt/sfnt.c create mode 100644 src/freetype2/sfnt/sfobjs.c create mode 100644 src/freetype2/sfnt/sfobjs.h create mode 100644 src/freetype2/sfnt/ttbdf.c create mode 100644 src/freetype2/sfnt/ttbdf.h create mode 100644 src/freetype2/sfnt/ttcmap.c create mode 100644 src/freetype2/sfnt/ttcmap.h create mode 100644 src/freetype2/sfnt/ttkern.c create mode 100644 src/freetype2/sfnt/ttkern.h create mode 100644 src/freetype2/sfnt/ttload.c create mode 100644 src/freetype2/sfnt/ttload.h create mode 100644 src/freetype2/sfnt/ttmtx.c create mode 100644 src/freetype2/sfnt/ttmtx.h create mode 100644 src/freetype2/sfnt/ttpost.c create mode 100644 src/freetype2/sfnt/ttpost.h create mode 100644 src/freetype2/sfnt/ttsbit.c create mode 100644 src/freetype2/sfnt/ttsbit.h create mode 100644 src/freetype2/sfnt/ttsbit0.c create mode 100644 src/freetype2/sfnt/ttsbit0.h create mode 100644 src/freetype2/smooth/ftgrays.c create mode 100644 src/freetype2/smooth/ftgrays.h create mode 100644 src/freetype2/smooth/ftsmerrs.h create mode 100644 src/freetype2/smooth/ftsmooth.c create mode 100644 src/freetype2/smooth/ftsmooth.h create mode 100644 src/freetype2/smooth/smooth.c create mode 100644 src/freetype2/truetype/truetype.c create mode 100644 src/freetype2/truetype/ttdriver.c create mode 100644 src/freetype2/truetype/ttdriver.h create mode 100644 src/freetype2/truetype/tterrors.h create mode 100644 src/freetype2/truetype/ttgload.c create mode 100644 src/freetype2/truetype/ttgload.h create mode 100644 src/freetype2/truetype/ttgxvar.c create mode 100644 src/freetype2/truetype/ttgxvar.h create mode 100644 src/freetype2/truetype/ttinterp.c create mode 100644 src/freetype2/truetype/ttinterp.h create mode 100644 src/freetype2/truetype/ttobjs.c create mode 100644 src/freetype2/truetype/ttobjs.h create mode 100644 src/freetype2/truetype/ttpload.c create mode 100644 src/freetype2/truetype/ttpload.h create mode 100644 src/freetype2/type1/t1afm.c create mode 100644 src/freetype2/type1/t1afm.h create mode 100644 src/freetype2/type1/t1driver.c create mode 100644 src/freetype2/type1/t1driver.h create mode 100644 src/freetype2/type1/t1errors.h create mode 100644 src/freetype2/type1/t1gload.c create mode 100644 src/freetype2/type1/t1gload.h create mode 100644 src/freetype2/type1/t1load.c create mode 100644 src/freetype2/type1/t1load.h create mode 100644 src/freetype2/type1/t1objs.c create mode 100644 src/freetype2/type1/t1objs.h create mode 100644 src/freetype2/type1/t1parse.c create mode 100644 src/freetype2/type1/t1parse.h create mode 100644 src/freetype2/type1/t1tokens.h create mode 100644 src/freetype2/type1/type1.c create mode 100644 src/freetype2/type42/t42drivr.c create mode 100644 src/freetype2/type42/t42drivr.h create mode 100644 src/freetype2/type42/t42error.h create mode 100644 src/freetype2/type42/t42objs.c create mode 100644 src/freetype2/type42/t42objs.h create mode 100644 src/freetype2/type42/t42parse.c create mode 100644 src/freetype2/type42/t42parse.h create mode 100644 src/freetype2/type42/t42types.h create mode 100644 src/freetype2/type42/type42.c create mode 100644 src/freetype2/winfonts/fnterrs.h create mode 100644 src/freetype2/winfonts/winfnt.c create mode 100644 src/freetype2/winfonts/winfnt.h create mode 100644 src/gdiplus/cdcontextplus.def create mode 100644 src/gdiplus/cdgdiplus.def create mode 100644 src/gdiplus/cdwclpp.cpp create mode 100644 src/gdiplus/cdwdbufp.cpp create mode 100644 src/gdiplus/cdwemfp.cpp create mode 100644 src/gdiplus/cdwgdiplus.c create mode 100644 src/gdiplus/cdwimgp.cpp create mode 100644 src/gdiplus/cdwinp.cpp create mode 100644 src/gdiplus/cdwinp.h create mode 100644 src/gdiplus/cdwnativep.cpp create mode 100644 src/gdiplus/cdwprnp.cpp create mode 100644 src/intcgm/bparse.c create mode 100644 src/intcgm/bparse.h create mode 100644 src/intcgm/circle.c create mode 100644 src/intcgm/circle.h create mode 100644 src/intcgm/ellipse.c create mode 100644 src/intcgm/ellipse.h create mode 100644 src/intcgm/intcgm.h create mode 100644 src/intcgm/intcgm1.c create mode 100644 src/intcgm/intcgm2.c create mode 100644 src/intcgm/intcgm2.h create mode 100644 src/intcgm/intcgm4.c create mode 100644 src/intcgm/intcgm4.h create mode 100644 src/intcgm/intcgm6.c create mode 100644 src/intcgm/intcgm6.h create mode 100644 src/intcgm/list.c create mode 100644 src/intcgm/list.h create mode 100644 src/intcgm/sism.c create mode 100644 src/intcgm/sism.h create mode 100644 src/intcgm/tparse.c create mode 100644 src/intcgm/tparse.h create mode 100644 src/intcgm/types.h create mode 100644 src/lua3/cdlua.c create mode 100644 src/lua3/cdlua.def create mode 100644 src/lua3/cdluactx.c create mode 100644 src/lua3/cdluapdf.c create mode 100644 src/lua3/cdluapdf.def create mode 100644 src/lua3/cdvoid.c create mode 100644 src/lua3/cdvoid.h create mode 100644 src/lua3/toluacd.c create mode 100644 src/lua3/toluawd.c create mode 100644 src/lua5/cdlua5.c create mode 100644 src/lua5/cdlua5.def create mode 100644 src/lua5/cdlua5_active.c create mode 100644 src/lua5/cdlua5_canvas.c create mode 100644 src/lua5/cdlua5ctx.c create mode 100644 src/lua5/cdluacontextplus5.c create mode 100644 src/lua5/cdluacontextplus5.def create mode 100644 src/lua5/cdluaim5.c create mode 100644 src/lua5/cdluaim5.def create mode 100644 src/lua5/cdluapdf5.c create mode 100644 src/lua5/cdluapdf5.def create mode 100644 src/lua5/cdvoid5.c create mode 100644 src/lua5/cdvoid5.h create mode 100644 src/make_uname create mode 100644 src/make_uname.bat create mode 100644 src/pdflib/flate/adler32.c create mode 100644 src/pdflib/flate/compress.c create mode 100644 src/pdflib/flate/crc32.c create mode 100644 src/pdflib/flate/crc32.h create mode 100644 src/pdflib/flate/deflate.c create mode 100644 src/pdflib/flate/deflate.h create mode 100644 src/pdflib/flate/inffast.c create mode 100644 src/pdflib/flate/inffast.h create mode 100644 src/pdflib/flate/inffixed.h create mode 100644 src/pdflib/flate/inflate.c create mode 100644 src/pdflib/flate/inflate.h create mode 100644 src/pdflib/flate/inftrees.c create mode 100644 src/pdflib/flate/inftrees.h create mode 100644 src/pdflib/flate/trees.c create mode 100644 src/pdflib/flate/trees.h create mode 100644 src/pdflib/flate/uncompr.c create mode 100644 src/pdflib/flate/zconf.h create mode 100644 src/pdflib/flate/zlib.h create mode 100644 src/pdflib/flate/zprefix.h create mode 100644 src/pdflib/flate/zutil.c create mode 100644 src/pdflib/flate/zutil.h create mode 100644 src/pdflib/font/ft_cid.c create mode 100644 src/pdflib/font/ft_cid.h create mode 100644 src/pdflib/font/ft_corefont.c create mode 100644 src/pdflib/font/ft_corefont.h create mode 100644 src/pdflib/font/ft_font.c create mode 100644 src/pdflib/font/ft_font.h create mode 100644 src/pdflib/font/ft_generr.h create mode 100644 src/pdflib/font/ft_hostfont.c create mode 100644 src/pdflib/font/ft_pdffont.c create mode 100644 src/pdflib/font/ft_pdffont.h create mode 100644 src/pdflib/font/ft_truetype.c create mode 100644 src/pdflib/font/ft_truetype.h create mode 100644 src/pdflib/font/ft_type1.c create mode 100644 src/pdflib/pdcore/pc_aes.c create mode 100644 src/pdflib/pdcore/pc_aes.h create mode 100644 src/pdflib/pdcore/pc_aescbc.c create mode 100644 src/pdflib/pdcore/pc_aeslocal.h create mode 100644 src/pdflib/pdcore/pc_arc4.c create mode 100644 src/pdflib/pdcore/pc_arc4.h create mode 100644 src/pdflib/pdcore/pc_chartabs.c create mode 100644 src/pdflib/pdcore/pc_chartabs.h create mode 100644 src/pdflib/pdcore/pc_classic.h create mode 100644 src/pdflib/pdcore/pc_config.h create mode 100644 src/pdflib/pdcore/pc_contain.c create mode 100644 src/pdflib/pdcore/pc_contain.h create mode 100644 src/pdflib/pdcore/pc_core.c create mode 100644 src/pdflib/pdcore/pc_core.h create mode 100644 src/pdflib/pdcore/pc_crypt.c create mode 100644 src/pdflib/pdcore/pc_crypt.h create mode 100644 src/pdflib/pdcore/pc_ctype.c create mode 100644 src/pdflib/pdcore/pc_ctype.h create mode 100644 src/pdflib/pdcore/pc_digsig.c create mode 100644 src/pdflib/pdcore/pc_digsig.h create mode 100644 src/pdflib/pdcore/pc_ebcdic.c create mode 100644 src/pdflib/pdcore/pc_ebcdic.h create mode 100644 src/pdflib/pdcore/pc_encoding.c create mode 100644 src/pdflib/pdcore/pc_encoding.h create mode 100644 src/pdflib/pdcore/pc_exports.h create mode 100644 src/pdflib/pdcore/pc_file.c create mode 100644 src/pdflib/pdcore/pc_file.h create mode 100644 src/pdflib/pdcore/pc_generr.h create mode 100644 src/pdflib/pdcore/pc_geom.c create mode 100644 src/pdflib/pdcore/pc_geom.h create mode 100644 src/pdflib/pdcore/pc_md5.c create mode 100644 src/pdflib/pdcore/pc_md5.h create mode 100644 src/pdflib/pdcore/pc_optparse.c create mode 100644 src/pdflib/pdcore/pc_optparse.h create mode 100644 src/pdflib/pdcore/pc_output.c create mode 100644 src/pdflib/pdcore/pc_output.h create mode 100644 src/pdflib/pdcore/pc_prefix.h create mode 100644 src/pdflib/pdcore/pc_pstok.h create mode 100644 src/pdflib/pdcore/pc_resource.c create mode 100644 src/pdflib/pdcore/pc_resource.h create mode 100644 src/pdflib/pdcore/pc_scan.c create mode 100644 src/pdflib/pdcore/pc_scan.h create mode 100644 src/pdflib/pdcore/pc_scantok.h create mode 100644 src/pdflib/pdcore/pc_scope.c create mode 100644 src/pdflib/pdcore/pc_scope.h create mode 100644 src/pdflib/pdcore/pc_strconst.h create mode 100644 src/pdflib/pdcore/pc_string.c create mode 100644 src/pdflib/pdcore/pc_string.h create mode 100644 src/pdflib/pdcore/pc_unicode.c create mode 100644 src/pdflib/pdcore/pc_unicode.h create mode 100644 src/pdflib/pdcore/pc_util.c create mode 100644 src/pdflib/pdcore/pc_util.h create mode 100644 src/pdflib/pdcore/pc_xmp.c create mode 100644 src/pdflib/pdcore/pc_xmp.h create mode 100644 src/pdflib/pdflib/p_3d.c create mode 100644 src/pdflib/pdflib/p_actions.c create mode 100644 src/pdflib/pdflib/p_afm.c create mode 100644 src/pdflib/pdflib/p_annots.c create mode 100644 src/pdflib/pdflib/p_block.c create mode 100644 src/pdflib/pdflib/p_bmp.c create mode 100644 src/pdflib/pdflib/p_ccitt.c create mode 100644 src/pdflib/pdflib/p_cid.c create mode 100644 src/pdflib/pdflib/p_color.c create mode 100644 src/pdflib/pdflib/p_color.h create mode 100644 src/pdflib/pdflib/p_defopt.h create mode 100644 src/pdflib/pdflib/p_document.c create mode 100644 src/pdflib/pdflib/p_draw.c create mode 100644 src/pdflib/pdflib/p_encoding.c create mode 100644 src/pdflib/pdflib/p_fields.c create mode 100644 src/pdflib/pdflib/p_filter.c create mode 100644 src/pdflib/pdflib/p_font.c create mode 100644 src/pdflib/pdflib/p_font.h create mode 100644 src/pdflib/pdflib/p_generr.h create mode 100644 src/pdflib/pdflib/p_gif.c create mode 100644 src/pdflib/pdflib/p_gstate.c create mode 100644 src/pdflib/pdflib/p_hkscmyk.h create mode 100644 src/pdflib/pdflib/p_hkslab.h create mode 100644 src/pdflib/pdflib/p_hyper.c create mode 100644 src/pdflib/pdflib/p_icc.c create mode 100644 src/pdflib/pdflib/p_icc.h create mode 100644 src/pdflib/pdflib/p_icc9809.h create mode 100644 src/pdflib/pdflib/p_icclib.c create mode 100644 src/pdflib/pdflib/p_icclib.h create mode 100644 src/pdflib/pdflib/p_image.c create mode 100644 src/pdflib/pdflib/p_image.h create mode 100644 src/pdflib/pdflib/p_intern.h create mode 100644 src/pdflib/pdflib/p_jpeg.c create mode 100644 src/pdflib/pdflib/p_jpx.c create mode 100644 src/pdflib/pdflib/p_kerning.c create mode 100644 src/pdflib/pdflib/p_keyconn.h create mode 100644 src/pdflib/pdflib/p_layer.c create mode 100644 src/pdflib/pdflib/p_layer.h create mode 100644 src/pdflib/pdflib/p_mbox.c create mode 100644 src/pdflib/pdflib/p_object.c create mode 100644 src/pdflib/pdflib/p_opi.c create mode 100644 src/pdflib/pdflib/p_page.c create mode 100644 src/pdflib/pdflib/p_page.h create mode 100644 src/pdflib/pdflib/p_pantlab.h create mode 100644 src/pdflib/pdflib/p_params.c create mode 100644 src/pdflib/pdflib/p_params.h create mode 100644 src/pdflib/pdflib/p_pattern.c create mode 100644 src/pdflib/pdflib/p_pdi.c create mode 100644 src/pdflib/pdflib/p_pfm.c create mode 100644 src/pdflib/pdflib/p_photoshp.c create mode 100644 src/pdflib/pdflib/p_png.c create mode 100644 src/pdflib/pdflib/p_shading.c create mode 100644 src/pdflib/pdflib/p_subsett.c create mode 100644 src/pdflib/pdflib/p_table.c create mode 100644 src/pdflib/pdflib/p_tagged.c create mode 100644 src/pdflib/pdflib/p_tagged.h create mode 100644 src/pdflib/pdflib/p_template.c create mode 100644 src/pdflib/pdflib/p_text.c create mode 100644 src/pdflib/pdflib/p_textflow.c create mode 100644 src/pdflib/pdflib/p_tiff.c create mode 100644 src/pdflib/pdflib/p_truetype.c create mode 100644 src/pdflib/pdflib/p_type1.c create mode 100644 src/pdflib/pdflib/p_type3.c create mode 100644 src/pdflib/pdflib/p_util.c create mode 100644 src/pdflib/pdflib/p_xgstate.c create mode 100644 src/pdflib/pdflib/p_xmp.c create mode 100644 src/pdflib/pdflib/pdflib.c create mode 100644 src/pdflib/pdflib/pdflib.h create mode 100644 src/rgb2map.c create mode 100644 src/sim/cd_truetype.c create mode 100644 src/sim/cd_truetype.h create mode 100644 src/sim/cdfontex.c create mode 100644 src/sim/sim.c create mode 100644 src/sim/sim.h create mode 100644 src/sim/sim_linepolyfill.c create mode 100644 src/sim/sim_other.c create mode 100644 src/sim/sim_primitives.c create mode 100644 src/sim/sim_text.c create mode 100644 src/sim/truetype.h create mode 100644 src/tecmake_compact.mak create mode 100644 src/wd.c create mode 100644 src/wdhdcpy.c create mode 100644 src/win32/cdwclp.c create mode 100644 src/win32/cdwdbuf.c create mode 100644 src/win32/cdwdib.c create mode 100644 src/win32/cdwemf.c create mode 100644 src/win32/cdwimg.c create mode 100644 src/win32/cdwin.c create mode 100644 src/win32/cdwin.h create mode 100644 src/win32/cdwnative.c create mode 100644 src/win32/cdwprn.c create mode 100644 src/win32/cdwwmf.c create mode 100644 src/win32/wmf_emf.c create mode 100644 src/x11/cdx11.c create mode 100644 src/x11/cdx11.h create mode 100644 src/x11/cdxclp.c create mode 100644 src/x11/cdxdbuf.c create mode 100644 src/x11/cdximg.c create mode 100644 src/x11/cdxnative.c create mode 100644 src/x11/xvertex.c create mode 100644 src/x11/xvertex.h create mode 100644 src/xrender/cdxrender.c create mode 100644 src/xrender/cdxrplus.c (limited to 'src') diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..b3d66c3 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,9 @@ +so_locations +*.dep +*.wdep +*.loh +.plan +.project +*.err +*.make +umake_uname.bat \ No newline at end of file diff --git a/src/COPYRIGHT b/src/COPYRIGHT new file mode 100644 index 0000000..35888b6 --- /dev/null +++ b/src/COPYRIGHT @@ -0,0 +1,32 @@ +CD License +----------- + +CD is licensed under the terms of the MIT license reproduced below. +This means that CD is free software and can be used for both academic +and commercial purposes at absolutely no cost. + +=============================================================================== + +Copyright (C) 1994-2008 Tecgraf, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +=============================================================================== + +(end of COPYRIGHT) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..930214d --- /dev/null +++ b/src/Makefile @@ -0,0 +1,26 @@ + +.PHONY: do_all cd_freetype cd cd_pdflib cdpdf cdcontextplus cdlua3 cdluapdf3 cdlua5 cdluapdf5 cdluacontextplus5 cdluaim5 +do_all: cd_freetype cd cd_pdflib cdpdf cdcontextplus cdlua3 cdluapdf3 cdlua5 cdluapdf5 cdluacontextplus5 cdluaim5 + +cd_freetype: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cd_freetype +cd: + @$(MAKE) --no-print-directory -f tecmake_compact.mak +cd_pdflib: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cd_pdflib +cdpdf: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdpdf +cdcontextplus: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdcontextplus +cdlua3: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdlua3 +cdluapdf3: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdluapdf3 +cdlua5: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdlua5 +cdluapdf5: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdluapdf5 +cdluacontextplus5: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdluacontextplus5 +cdluaim5: + @$(MAKE) --no-print-directory -f tecmake_compact.mak MF=cdluaim5 diff --git a/src/README b/src/README new file mode 100644 index 0000000..1eae080 --- /dev/null +++ b/src/README @@ -0,0 +1,11 @@ +README for CD + + CD (Canvas Draw) is a platform-independent graphics library. It is implemented in several platforms using native graphics libraries: Microsoft Windows (GDI) and X-Windows (XLIB). + The library contains functions to support both vector and image applications, and the visualization surface can be either a window or a more abstract surface, such as Image, Clipboard, Metafile, PS, and so on. + + Build instructions and usage are available in the CD documentation. + + For complete information, visit CD's web site at http://www.tecgraf.puc-rio.br/cd + or access its documentation in the HTML folder. + +(end of README) diff --git a/src/cd.c b/src/cd.c new file mode 100644 index 0000000..536f7ef --- /dev/null +++ b/src/cd.c @@ -0,0 +1,748 @@ +/** \file + * \brief External API + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" +#include "cdirgb.h" + + +const char cd_ident[] = + "$CD: " CD_VERSION " " CD_COPYRIGHT " $\n" + "$URL: www.tecgraf.puc-rio.br/cd $\n"; + +static char *tecver = "TECVERID.str:CD:LIB:"CD_VERSION; + +char* cdVersion(void) +{ + (void)cd_ident; + (void)tecver; + return CD_VERSION; +} + +char* cdVersionDate(void) +{ + return CD_VERSION_DATE; +} + +int cdVersionNumber(void) +{ + return CD_VERSION_NUMBER; +} + +static void cd_setdefaultfunc(cdCanvas* canvas) +{ + /* default simulation functions */ + canvas->cxGetTextSize = cdgettextsizeEX; + canvas->cxGetFontDim = cdgetfontdimEX; + canvas->cxRect = cdrectSIM; +} + +static void cd_setdefaultattrib(cdCanvas* canvas) +{ + /* clipping attributes */ + canvas->clip_mode = CD_CLIPOFF; + + /* color attributes */ + canvas->foreground = CD_BLACK; + canvas->background = CD_WHITE; + + canvas->back_opacity = CD_TRANSPARENT; + canvas->write_mode = CD_REPLACE; + + /* primitive attributes */ + canvas->mark_type = CD_STAR; + canvas->mark_size = 10; + + canvas->line_width = 1; + canvas->line_style = CD_CONTINUOUS; + canvas->line_cap = CD_CAPFLAT; + canvas->line_join = CD_MITER; + + canvas->hatch_style = CD_HORIZONTAL; + canvas->interior_style = CD_SOLID; + canvas->fill_mode = CD_EVENODD; + + strcpy(canvas->font_type_face, "System"); + canvas->font_style = CD_PLAIN; + canvas->font_size = CD_STANDARD; + + canvas->text_alignment = CD_BASE_LEFT; + + canvas->matrix[0] = 1; /* identity */ + canvas->matrix[3] = 1; + + /* o resto recebeu zero no memset */ +} + +static void cd_updatedefaultattrib(cdCanvas* canvas) +{ + cdCanvasActivate(canvas); + + if (canvas->cxBackground) canvas->cxBackground(canvas->ctxcanvas, canvas->background); + if (canvas->cxForeground) canvas->cxForeground(canvas->ctxcanvas, canvas->foreground); + if (canvas->cxBackOpacity) canvas->cxBackOpacity(canvas->ctxcanvas, canvas->back_opacity); + if (canvas->cxWriteMode) canvas->cxWriteMode(canvas->ctxcanvas, canvas->write_mode); + if (canvas->cxLineStyle) canvas->cxLineStyle(canvas->ctxcanvas, canvas->line_style); + if (canvas->cxLineWidth) canvas->cxLineWidth(canvas->ctxcanvas, canvas->line_width); + if (canvas->cxLineCap) canvas->cxLineCap(canvas->ctxcanvas, canvas->line_cap); + if (canvas->cxLineJoin) canvas->cxLineJoin(canvas->ctxcanvas, canvas->line_join); + if (canvas->cxHatch) canvas->cxHatch(canvas->ctxcanvas, canvas->hatch_style); + if (canvas->cxInteriorStyle) canvas->cxInteriorStyle(canvas->ctxcanvas, canvas->interior_style); + if (canvas->cxFont) canvas->cxFont(canvas->ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + if (canvas->cxTextAlignment) canvas->cxTextAlignment(canvas->ctxcanvas, canvas->text_alignment); + if (canvas->cxTextOrientation) canvas->cxTextOrientation(canvas->ctxcanvas, canvas->text_orientation); +} + +cdCanvas* cdCreateCanvasf(cdContext *context, const char* format, ...) +{ + char data[1024]; + va_list arglist; + va_start(arglist, format); + vsprintf(data, format, arglist); + + return cdCreateCanvas(context, data); +} + +cdCanvas *cdCreateCanvas(cdContext* context, void *data_str) +{ + cdCanvas *canvas; + + /* usefull for NULL drivers, that do nothing and exist only for portability */ + if (!context) + return NULL; + + { + static int first = 1; + char* env = getenv("CD_QUIET"); + if (first && env && strcmp(env, "NO")==0) + { + printf("CD "CD_VERSION" "CD_COPYRIGHT"\n"); + first = 0; + } + } + + /* alocates and initialize everything with 0s */ + canvas = (cdCanvas*)malloc(sizeof(cdCanvas)); + memset(canvas, 0, sizeof(cdCanvas)); + + canvas->signature[0] = 'C'; + canvas->signature[1] = 'D'; + + canvas->vector_font = cdCreateVectorFont(canvas); + canvas->simulation = cdCreateSimulation(canvas); + + canvas->context = context; + + /* initialize default attributes, must be before creating the canvas */ + cd_setdefaultattrib(canvas); + + context->cxCreateCanvas(canvas, data_str); + if (!canvas->ctxcanvas) + { + cdKillVectorFont(canvas->vector_font); + cdKillSimulation(canvas->simulation); + memset(canvas, 0, sizeof(cdCanvas)); + free(canvas); + return NULL; + } + + /* functions that can do nothing, must be before InitTable */ + cd_setdefaultfunc(canvas); + + /* initialize canvas table */ + context->cxInitTable(canvas); + + /* update the default atributes, must be after InitTable */ + cd_updatedefaultattrib(canvas); + + /* must be after creating the canvas, so that we know canvas width and height */ + canvas->clip_rect.xmax = canvas->w-1; + canvas->clip_rect.ymax = canvas->h-1; + + wdSetDefaults(canvas); + + return canvas; +} + +/* re-declared here to ignore CD_NO_OLD_INTERFACE definition */ +int cdActivate(cdCanvas* canvas); +cdCanvas* cdActiveCanvas(void); + +void cdKillCanvas(cdCanvas *canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas == cdActiveCanvas()) + cdActivate(NULL); + else + cdCanvasDeactivate(canvas); + + canvas->cxKillCanvas(canvas->ctxcanvas); + + if (canvas->pattern) free(canvas->pattern); + if (canvas->stipple) free(canvas->stipple); + if (canvas->poly) free(canvas->poly); + if (canvas->clip_poly) free(canvas->clip_poly); + if (canvas->fpoly) free(canvas->fpoly); + if (canvas->clip_fpoly) free(canvas->clip_fpoly); + if (canvas->line_dashes) free(canvas->line_dashes); + + cdKillVectorFont(canvas->vector_font); + cdKillSimulation(canvas->simulation); + + memset(canvas, 0, sizeof(cdCanvas)); + free(canvas); +} + +cdContext* cdCanvasGetContext(cdCanvas *canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + return canvas->context; +} + +int cdCanvasActivate(cdCanvas *canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (!canvas->cxActivate) return CD_OK; + + if (canvas->cxActivate(canvas->ctxcanvas) == CD_ERROR) + return CD_ERROR; + + return CD_OK; +} + +void cdCanvasDeactivate(cdCanvas *canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxDeactivate) return; + canvas->cxDeactivate(canvas->ctxcanvas); +} + +unsigned long cdContextCaps(cdContext *context) +{ + if (!context) + return (unsigned long)CD_ERROR; + return context->caps; +} + +int cdCanvasSimulate(cdCanvas* canvas, int mode) +{ + int sim_mode; + cdContext* context; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + context = canvas->context; + + sim_mode = canvas->sim_mode; + if (mode == CD_QUERY || cdCanvasGetContext(canvas) == CD_IMAGERGB) + return sim_mode; + + cd_setdefaultfunc(canvas); + context->cxInitTable(canvas); + + canvas->sim_mode = mode; + if (mode == CD_SIM_NONE) + return sim_mode; + + /* when simulation is active must not set driver transform */ + canvas->cxTransform = NULL; + + if (mode & CD_SIM_LINE) + { + canvas->cxLine = cdlineSIM; + canvas->cxFLine = NULL; + } + + if (mode & CD_SIM_RECT) + { + canvas->cxRect = cdrectSIM; + canvas->cxFRect = NULL; + } + + if (mode & CD_SIM_BOX) + { + canvas->cxBox = cdboxSIM; + canvas->cxFBox = NULL; + } + + if (mode & CD_SIM_ARC) + { + canvas->cxArc = cdarcSIM; + canvas->cxFArc = NULL; + } + + if (mode & CD_SIM_SECTOR) + { + canvas->cxSector = cdsectorSIM; + canvas->cxFSector = NULL; + } + + if (mode & CD_SIM_CHORD) + { + canvas->cxChord = cdchordSIM; + canvas->cxFChord = NULL; + } + + if (mode & CD_SIM_TEXT) + { + canvas->cxText = cdtextSIM; + canvas->cxFText = NULL; + canvas->cxNativeFont = NULL; + canvas->cxFont = cdfontSIM; + canvas->cxGetFontDim = cdgetfontdimSIM; + canvas->cxGetTextSize = cdgettextsizeSIM; + canvas->cxTextOrientation = NULL; + + cdSimInitText(canvas->simulation); + canvas->cxFont(canvas->ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + } + else + canvas->cxFont(canvas->ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + + if (mode & CD_SIM_POLYLINE || mode & CD_SIM_POLYGON) + canvas->cxFPoly = NULL; + + return sim_mode; +} + +cdState* cdCanvasSaveState(cdCanvas* canvas) +{ + cdState* state; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + state = (cdState*)malloc(sizeof(cdState)); + memcpy(state, canvas, sizeof(cdCanvas)); + + if (state->pattern) + { + int size = state->pattern_w*state->pattern_h*sizeof(long); + state->pattern = (long*)malloc(size); + memcpy(state->pattern, canvas->pattern, size); + } + + if (state->stipple) + { + int size = state->stipple_w*state->stipple_h; + state->stipple = (unsigned char*)malloc(size); + memcpy(state->stipple, canvas->stipple, size); + } + + if (state->clip_poly) + { + int size = state->clip_poly_n*sizeof(cdPoint); + state->clip_poly = (cdPoint*)malloc(size); + memcpy(state->clip_poly, canvas->clip_poly, size); + } + + if (state->clip_fpoly) + { + int size = state->clip_poly_n*sizeof(cdfPoint); + state->clip_fpoly = (cdfPoint*)malloc(size); + memcpy(state->clip_fpoly, canvas->clip_fpoly, size); + } + + if (state->line_dashes) + { + int size = state->line_dashes_count*sizeof(int); + state->line_dashes = (int*)malloc(size); + memcpy(state->line_dashes, canvas->line_dashes, size); + } + + return state; +} + +void cdReleaseState(cdState* state) +{ + assert(state); + if (!state) return; + + if (state->stipple) + free(state->stipple); + + if (state->pattern) + free(state->pattern); + + if (state->clip_poly) + free(state->clip_poly); + + if (state->clip_fpoly) + free(state->clip_fpoly); + + if (state->line_dashes) + free(state->line_dashes); + + free(state); + free(state); +} + +void cdCanvasRestoreState(cdCanvas* canvas, cdState* state) +{ + assert(canvas); + assert(state); + if (!state || !_cdCheckCanvas(canvas)) return; + + /* clippling must be done in low level because origin and invert y axis */ + canvas->clip_poly_n = state->clip_poly_n; + + if (canvas->clip_poly) + { + free(canvas->clip_poly); + canvas->clip_poly = NULL; + } + + if (canvas->clip_fpoly) + { + free(canvas->clip_fpoly); + canvas->clip_fpoly = NULL; + } + + if (state->clip_poly) + { + int size = state->clip_poly_n*sizeof(cdPoint); + canvas->clip_poly = (cdPoint*)malloc(size); + memcpy(canvas->clip_poly, state->clip_poly, size); + } + + if (state->clip_fpoly) + { + int size = state->clip_poly_n*sizeof(cdfPoint); + canvas->clip_fpoly = (cdfPoint*)malloc(size); + memcpy(canvas->clip_fpoly, state->clip_fpoly, size); + } + + cdCanvasClip(canvas, CD_CLIPOFF); + if (canvas->clip_fpoly) + canvas->cxFPoly(canvas->ctxcanvas, CD_CLIP, state->clip_fpoly, state->clip_poly_n); + else if (canvas->clip_poly) + canvas->cxPoly(canvas->ctxcanvas, CD_CLIP, state->clip_poly, state->clip_poly_n); + cdCanvasClipArea(canvas, state->clip_rect.xmin, state->clip_rect.xmax, state->clip_rect.ymin, state->clip_rect.ymax); + if (canvas->cxFClipArea) + canvas->cxFClipArea(canvas->ctxcanvas, state->clip_frect.xmin, state->clip_frect.xmax, state->clip_frect.ymin, state->clip_frect.ymax); + else if (canvas->cxClipArea) + canvas->cxClipArea(canvas->ctxcanvas, state->clip_rect.xmin, state->clip_rect.xmax, state->clip_rect.ymin, state->clip_rect.ymax); + cdCanvasClip(canvas, state->clip_mode); + + /* regular attributes */ + cdCanvasSetBackground(canvas, state->background); + cdCanvasSetForeground(canvas, state->foreground); + cdCanvasBackOpacity(canvas, state->back_opacity); + cdCanvasWriteMode(canvas, state->write_mode); + cdCanvasLineStyle(canvas, state->line_style); + cdCanvasLineWidth(canvas, state->line_width); + cdCanvasLineCap(canvas, state->line_cap); + cdCanvasLineJoin(canvas, state->line_join); + cdCanvasFillMode(canvas, state->fill_mode); + cdCanvasLineStyleDashes(canvas, state->line_dashes, state->line_dashes_count); + cdCanvasHatch(canvas, state->hatch_style); + if (state->stipple) cdCanvasStipple(canvas, state->stipple_w, state->stipple_h, state->stipple); + if (state->pattern) cdCanvasPattern(canvas, state->pattern_w, state->pattern_h, state->pattern); + cdCanvasInteriorStyle(canvas, state->interior_style); + if (state->native_font[0]) + cdCanvasNativeFont(canvas, state->native_font); + else + cdCanvasFont(canvas, state->font_type_face, state->font_style, state->font_size); + cdCanvasTextAlignment(canvas, state->text_alignment); + cdCanvasTextOrientation(canvas, state->text_orientation); + cdCanvasMarkType(canvas, state->mark_type); + cdCanvasMarkSize(canvas, state->mark_size); + cdCanvasOrigin(canvas, state->origin.x, state->origin.y); + if (state->use_matrix) + cdCanvasTransform(canvas, state->matrix); + wdCanvasWindow(canvas, state->window.xmin, state->window.xmax, state->window.ymin, state->window.ymax); + wdCanvasViewport(canvas, state->viewport.xmin, state->viewport.xmax, state->viewport.ymin, state->viewport.ymax); + cdCanvasSimulate(canvas, state->sim_mode); + + /* complex clipping regions are not saved */ + /* driver internal attributes are not saved */ +} + +static cdAttribute* cd_findattrib(cdCanvas *canvas, const char* name, int *a) +{ + int i; + + for (i=0; i < canvas->attrib_n; i++) + { + if (strcmp(name, canvas->attrib_list[i]->name) == 0) + { + if (a) *a = i; + return canvas->attrib_list[i]; + } + } + + return NULL; +} + +void cdRegisterAttribute(cdCanvas *canvas, cdAttribute* attrib) +{ + cdAttribute* old_attrib; + int a; + + assert(canvas); + assert(attrib); + if (!attrib || !_cdCheckCanvas(canvas)) return; + + old_attrib = cd_findattrib(canvas, attrib->name, &a); + + if (old_attrib) + canvas->attrib_list[a] = attrib; + else + { + canvas->attrib_list[canvas->attrib_n] = attrib; + canvas->attrib_n++; + } +} + +void cdCanvasSetAttribute(cdCanvas* canvas, const char* name, char *data) +{ + cdAttribute* attrib; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + attrib = cd_findattrib(canvas, name, NULL); + if (attrib && attrib->set) + attrib->set(canvas->ctxcanvas, data); +} + +void cdCanvasSetfAttribute(cdCanvas* canvas, const char* name, const char* format, ...) +{ + char data[1024]; + va_list arglist; + va_start(arglist, format); + vsprintf(data, format, arglist); + + cdCanvasSetAttribute(canvas, name, data); +} + +char* cdCanvasGetAttribute(cdCanvas* canvas, const char* name) +{ + cdAttribute* attrib; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + attrib = cd_findattrib(canvas, name, NULL); + if (attrib && attrib->get) + return attrib->get(canvas->ctxcanvas); + + return NULL; +} + +int cdCanvasPlay(cdCanvas* canvas, cdContext* context, int xmin, int xmax, int ymin, int ymax, void *data) +{ + assert(context); + assert(canvas); + if (!_cdCheckCanvas(canvas) || !context || !context->cxPlay) return CD_ERROR; + + /* the all can be 0 here, do not use cdCheckBoxSize */ + if (xmin > xmax) _cdSwapInt(xmin, xmax); + if (ymin > ymax) _cdSwapInt(ymin, ymax); + + return context->cxPlay(canvas, xmin, xmax, ymin, ymax, data); +} + +int cdContextRegisterCallback(cdContext *context, int cb, cdCallback func) +{ + assert(context); + if (!context || !context->cxRegisterCallback) return CD_ERROR; + return context->cxRegisterCallback(cb, func); +} + +void cdCanvasFlush(cdCanvas* canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxFlush) return; + canvas->cxFlush(canvas->ctxcanvas); +} + +void cdCanvasClear(cdCanvas* canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxClear) return; + canvas->cxClear(canvas->ctxcanvas); +} + +int cdCanvasUpdateYAxis(cdCanvas* canvas, int* y) +{ + assert(canvas); + assert(y); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + if(canvas->invert_yaxis) + { + *y = _cdInvertYAxis(canvas, *y); + + if (canvas->use_origin) + *y -= 2*canvas->origin.y; + } + + return *y; +} + +double cdfCanvasUpdateYAxis(cdCanvas* canvas, double* y) +{ + assert(canvas); + assert(y); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + if(canvas->invert_yaxis) + { + *y = _cdInvertYAxis(canvas, *y); + + if (canvas->use_origin) + *y -= 2*canvas->origin.y; + } + + return *y; +} + +int cdCanvasInvertYAxis(cdCanvas* canvas, int y) +{ + int yi; + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + yi = _cdInvertYAxis(canvas, y); + + if (canvas->use_origin) + yi -= 2*canvas->origin.y; + + return yi; +} + +double cdfCanvasInvertYAxis(cdCanvas* canvas, double y) +{ + double yi; + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + yi = _cdInvertYAxis(canvas, y); + + if (canvas->use_origin) + yi -= 2*canvas->origin.y; + + return yi; +} + +void cdCanvasGetSize(cdCanvas* canvas, int *width, int *height, double *width_mm, double *height_mm) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (width) *width = canvas->w; + if (height) *height = canvas->h; + if (width_mm) *width_mm = canvas->w_mm; + if (height_mm) *height_mm = canvas->h_mm; +} + +void cdCanvasMM2Pixel(cdCanvas* canvas, double mm_dx, double mm_dy, int *dx, int *dy) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (dx) *dx = cdRound(mm_dx*canvas->xres); + if (dy) *dy = cdRound(mm_dy*canvas->yres); +} + +void cdCanvasPixel2MM(cdCanvas* canvas, int dx, int dy, double *mm_dx, double *mm_dy) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (mm_dx) *mm_dx = ((double)dx)/canvas->xres; + if (mm_dy) *mm_dy = ((double)dy)/canvas->yres; +} + +void cdfCanvasMM2Pixel(cdCanvas* canvas, double mm_dx, double mm_dy, double *dx, double *dy) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (dx) *dx = mm_dx*canvas->xres; + if (dy) *dy = mm_dy*canvas->yres; +} + +void cdfCanvasPixel2MM(cdCanvas* canvas, double dx, double dy, double *mm_dx, double *mm_dy) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (mm_dx) *mm_dx = dx/canvas->xres; + if (mm_dy) *mm_dy = dy/canvas->yres; +} + +/***** Context Plus Functions ********/ + +static int use_context_plus = 0; +static cdContext* context_plus[NUM_CONTEXTPLUS] = {NULL, NULL, NULL, NULL, NULL, NULL}; + +int cdUseContextPlus(int use) +{ + if (use == CD_QUERY) + return use_context_plus; + + { + int old_use_context_plus = use_context_plus; + use_context_plus = use; + return old_use_context_plus; + } +} + +void cdInitContextPlusList(cdContext* ctx_list[]) +{ + int ctx; + for (ctx = 0; ctx < NUM_CONTEXTPLUS; ctx++) + if (ctx_list[ctx] != NULL) + context_plus[ctx] = ctx_list[ctx]; +} + +cdContext* cdGetContextPlus(int ctx) +{ + if (ctx < 0 || ctx >= NUM_CONTEXTPLUS) + return NULL; + + return context_plus[ctx]; +} + +/***** OLD Compatibility Functions ********/ + +int cdRegisterCallback(cdContext *context, int cb, cdCallback func) +{ + return cdContextRegisterCallback(context, cb, func); +} + +cdContext* cdGetContext(cdCanvas* canvas) +{ + return cdCanvasGetContext(canvas); +} + +int * cdGetClipPoly(int *n) +{ + if (n) *n = 0; + return NULL; +} + +double* wdGetClipPoly(int *n) +{ + if (n) *n = 0; + return NULL; +} diff --git a/src/cd.def b/src/cd.def new file mode 100644 index 0000000..27be188 --- /dev/null +++ b/src/cd.def @@ -0,0 +1,379 @@ +EXPORTS + cdContextWMF + cdContextCGM + cdContextClipboard + cdContextDGN + cdContextDXF + cdContextEMF + cdContextImage + cdContextImageRGB + cdContextPS + cdContextPrinter + cdContextNativeWindow + cdContextMetafile + cdContextDBuffer + cdContextDBufferRGB + cdContextPicture + cdContextDebug + + cdRedImage + cdGreenImage + cdBlueImage + cdAlphaImage + cdGetScreenColorPlanes + cdGetScreenSize + cdUseContextPlus + + cdinittableMF + cdkillcanvasMF + cdcreatecanvasMF + + cdVersion + cdVersionDate + cdCreateCanvas + cdCreateCanvasf + cdKillCanvas + cdGetContext + cdContextCaps + cdActivate + cdActiveCanvas + cdSimulate + cdFlush + cdClear + cdSaveState + cdRestoreState + cdSetAttribute + cdSetfAttribute + cdGetAttribute + cdRegisterAttribute + cdReleaseState + + cdRegisterCallback + cdPlay + + cdGetCanvasSize + cdMM2Pixel + cdPixel2MM + cdOrigin + cdUpdateYAxis + cdCanvasTransform + + cdClip + cdClipArea + cdGetClipPoly + cdGetClipArea + + cdPixel + cdMark + cdLine + cdBegin + cdVertex + cdEnd + cdRect + cdBox + cdArc + cdSector + cdText + + cdBackground + cdForeground + cdBackOpacity + cdWriteMode + cdLineStyle + cdLineWidth + cdInteriorStyle + cdHatch + cdStipple + cdGetStipple + cdPattern + cdGetPattern + cdFont + cdGetFont + cdNativeFont + cdTextAlignment + cdTextOrientation + cdMarkType + cdMarkSize + + cdVectorFont + cdVectorTextDirection + cdVectorTextTransform + cdVectorTextSize + cdGetVectorTextSize + cdVectorCharSize + cdVectorText + cdMultiLineVectorText + cdGetVectorTextBounds + + cdFontDim + cdTextSize + cdTextBox + cdTextBounds + + cdGetColorPlanes + cdEncodeColor + cdDecodeColor + cdEncodeAlpha + cdDecodeAlpha + cdPalette + + cdGetImageRGB + cdPutImageRectRGB + cdPutImageRectRGBA + cdPutImageRectMap + cdRGB2Map + + cdCreateImage + cdGetImage + cdPutImageRect + cdKillImage + cdScrollArea + + cdCreateBitmap + cdInitBitmap + cdKillBitmap + cdBitmapGetData + cdBitmapSetRect + cdPutBitmap + cdGetBitmap + cdBitmapRGB2Map + + wdWindow + wdGetWindow + wdViewport + wdGetViewport + wdWorld2Canvas + wdCanvas2World + + wdClipArea + wdGetClipArea + wdGetClipPoly + + wdHardcopy + + wdPixel + wdMark + wdLine + wdVertex + wdRect + wdBox + wdArc + wdSector + wdText + + wdPutImageRect + wdPutImageRectRGB + wdPutImageRectRGBA + wdPutImageRectMap + wdPutBitmap + + wdLineWidth + wdFont + wdMarkSize + wdFontDim + wdTextSize + wdTextBox + wdTextBounds + wdStipple + wdPattern + wdGetFont + + wdVectorTextDirection + wdVectorTextSize + wdGetVectorTextSize + wdVectorCharSize + wdVectorText + wdMultiLineVectorText + wdGetVectorTextBounds + + cdwCreateCanvas + cdwInitTable + cdwKillCanvas + cdwRestoreDC + + cdLineStyleDashes + cdRegionBox + wdRegionBox + cdChord + cdOffsetRegion + cdPointInRegion + cdRegionCombineMode + cdLineJoin + cdLineCap + cdFillMode + wdChord + wdOffsetRegion + wdPointInRegion + cdGetFileName + wdWorld2CanvasSize + cdParsePangoFont + cdParseIupWinFont + cdParseXWinFont + cdGetFontSizePixels + cdGetFontSizePoints + cdStrEqualNoCase + + wdCanvasLineWidth + wdCanvasMarkSize + wdCanvasVectorCharSize + wdCanvasGetClipArea + wdCanvasIsPointInRegion + wdCanvasFont + wdCanvasArc + wdCanvasBox + wdCanvasCanvas2World + wdCanvasChord + wdCanvasClipArea + wdCanvasGetFont + wdCanvasGetFontDim + wdCanvasGetRegionBox + wdCanvasGetTextBounds + wdCanvasGetTextBox + wdCanvasGetTextSize + wdCanvasGetVectorTextBounds + wdCanvasGetVectorTextSize + wdCanvasGetViewport + wdCanvasGetWindow + wdCanvasHardcopy + wdCanvasLine + wdCanvasMark + wdCanvasMultiLineVectorText + wdCanvasOffsetRegion + wdCanvasPattern + wdCanvasPixel + wdCanvasPutBitmap + wdCanvasPutImageRect + wdCanvasPutImageRectMap + wdCanvasPutImageRectRGB + wdCanvasPutImageRectRGBA + wdCanvasRect + wdCanvasSector + wdCanvasStipple + wdCanvasText + wdCanvasVectorText + wdCanvasVectorTextDirection + wdCanvasVectorTextSize + wdCanvasVertex + wdCanvasViewport + wdCanvasWindow + wdCanvasWorld2Canvas + wdCanvasWorld2CanvasSize + + cdCanvasGetContext + cdCanvasCreateImage + cdCanvasSaveState + cdCanvasVectorFont + cdCanvasGetAttribute + cdCanvasNativeFont + cdCanvasTextOrientation + cdCanvasVectorTextTransform + cdCanvasActivate + cdCanvasSimulate + cdCanvasFillMode + cdCanvasMarkSize + cdCanvasMarkType + cdCanvasTextAlignment + cdCanvasFont + cdCanvasBackOpacity + cdCanvasClip + cdCanvasGetClipArea + cdCanvasGetColorPlanes + cdCanvasHatch + cdCanvasInteriorStyle + cdCanvasIsPointInRegion + cdCanvasLineCap + cdCanvasLineJoin + cdCanvasLineStyle + cdCanvasLineWidth + cdCanvasPlay + cdCanvasRegionCombineMode + cdCanvasVectorCharSize + cdCanvasWriteMode + cdCanvasUpdateYAxis + cdCanvasInvertYAxis + cdfCanvasUpdateYAxis + cdfCanvasInvertYAxis + cdContextRegisterCallback + cdCanvasBackground + cdCanvasForeground + cdCanvasGetPattern + cdCanvasGetStipple + cdCanvasDeactivate + cdCanvasClear + cdCanvasFlush + cdCanvasRestoreState + cdCanvasSetAttribute + cdCanvasSetfAttribute + cdCanvasGetFont + cdCanvasPattern + cdCanvasArc + cdCanvasBegin + cdCanvasBox + cdCanvasChord + cdCanvasClipArea + cdCanvasEnd + cdCanvasGetBitmap + cdCanvasGetFontDim + cdCanvasGetImage + cdCanvasGetImageRGB + cdCanvasGetOrigin + cdCanvasGetRegionBox + cdCanvasGetSize + cdCanvasGetTextBounds + cdCanvasGetTextBox + cdCanvasGetTextSize + cdCanvasGetVectorTextBounds + cdCanvasGetVectorTextSize + cdCanvasLine + cdCanvasLineStyleDashes + cdCanvasMark + cdCanvasMM2Pixel + cdCanvasMultiLineVectorText + cdCanvasOffsetRegion + cdCanvasOrigin + cdCanvasPalette + cdCanvasPixel + cdCanvasPixel2MM + cdCanvasPutBitmap + cdCanvasPutImageRect + cdCanvasPutImageRectMap + cdCanvasPutImageRectRGB + cdCanvasPutImageRectRGBA + cdCanvasRect + cdCanvasScrollArea + cdCanvasSector + cdCanvasStipple + cdCanvasText + cdCanvasVectorText + cdCanvasVectorTextDirection + cdCanvasVectorTextSize + cdCanvasVertex + + cdfCanvasGetClipArea + cdfCanvasArc + cdfCanvasBox + cdfCanvasChord + cdfCanvasClipArea + cdfCanvasGetOrigin + cdfCanvasLine + cdfCanvasMM2Pixel + cdfCanvasOrigin + cdfCanvasPixel2MM + cdfCanvasRect + cdfCanvasSector + cdfCanvasText + cdfCanvasVertex + cdCanvasGetTransform + cdCanvasTransformMultiply + cdCanvasTransformRotate + cdCanvasTransformScale + cdCanvasTransformTranslate + cdTextTranslatePoint + cdRotatePointY + cdCanvasSetForeground + cdCanvasSetBackground + cdCanvasTransformPoint + cdfCanvasTransformPoint + + cdInitContextPlusList + cdGetContextPlus diff --git a/src/cd.rc b/src/cd.rc new file mode 100644 index 0000000..42c3f8c --- /dev/null +++ b/src/cd.rc @@ -0,0 +1,19 @@ +1 VERSIONINFO + FILEVERSION 5,0,1,0 + PRODUCTVERSION 5,0,1,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "www.tecgraf.puc-rio.br/cd\0" + VALUE "CompanyName", "Tecgraf/PUC-Rio\0" + VALUE "FileDescription", "CD - Canvas Draw, A 2D Graphics Library\0" + VALUE "FileVersion", "5.0.1\0" + VALUE "LegalCopyright", "Copyright © 1994-2008 Tecgraf, PUC-Rio.\0" + VALUE "OriginalFilename", "cd.dll\0" + VALUE "ProductName", "CD for Windows\0" + VALUE "ProductVersion", "5.0.1\0" + END + END +END diff --git a/src/cd_active.c b/src/cd_active.c new file mode 100644 index 0000000..0ae489a --- /dev/null +++ b/src/cd_active.c @@ -0,0 +1,1007 @@ +/** \file + * \brief OLD API that needs the cdActivate call + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#ifdef CD_NO_OLD_INTERFACE +#undef CD_NO_OLD_INTERFACE +#endif + +#include "cd.h" +#include "wd.h" + +static cdCanvas *active_canvas = NULL; + +int cdActivate(cdCanvas *canvas) +{ + /* if is the active canvas, just update canvas state */ + if (active_canvas && canvas == active_canvas) + { + if (cdCanvasActivate(canvas) == CD_ERROR) + { + active_canvas = NULL; + return CD_ERROR; + } + + return CD_OK; + } + + /* if exists an active canvas, deactivate it */ + if (active_canvas) + cdCanvasDeactivate(active_canvas); + + /* allow to active a NULL canvas, the user may restore a previous canvas that was NULL */ + if (canvas == NULL) + { + active_canvas = NULL; + return CD_ERROR; + } + + /* do the activation */ + active_canvas = canvas; + + if (cdCanvasActivate(canvas) == CD_ERROR) + { + active_canvas = NULL; + return CD_ERROR; + } + + return CD_OK; +} + +cdCanvas* cdActiveCanvas(void) +{ + return active_canvas; +} + +int cdSimulate(int mode) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasSimulate(active_canvas, mode); +} + +cdState* cdSaveState(void) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasSaveState(active_canvas); +} + +void cdRestoreState(cdState* state) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasRestoreState(active_canvas, state); +} + +void cdFlush(void) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasFlush(active_canvas); +} + +void cdClear(void) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasClear(active_canvas); +} + +void cdSetAttribute(const char* name, char *data) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasSetAttribute(active_canvas, name, data); +} + +void cdSetfAttribute(const char* name, const char* format, ...) +{ + char data[1024]; + va_list arglist; + + assert(active_canvas); + if (!active_canvas) return; + + va_start(arglist, format); + vsprintf(data, format, arglist); + + cdCanvasSetAttribute(active_canvas, name, data); +} + +char* cdGetAttribute(const char* name) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasGetAttribute(active_canvas, name); +} + +int cdPlay(cdContext* context, int xmin, int xmax, int ymin, int ymax, void *data) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasPlay(active_canvas, context, xmin, xmax, ymin, ymax, data); +} + +int cdClip(int mode) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasClip(active_canvas, mode); +} + +void cdClipArea(int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasClipArea(active_canvas, xmin, xmax, ymin, ymax); +} + +int cdGetClipArea(int *xmin, int *xmax, int *ymin, int *ymax) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasGetClipArea(active_canvas, xmin, xmax, ymin, ymax); +} + +int cdPointInRegion(int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasIsPointInRegion(active_canvas, x, y); +} + +void cdOffsetRegion(int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasOffsetRegion(active_canvas, x, y); +} + +void cdRegionBox(int *xmin, int *xmax, int *ymin, int *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetRegionBox(active_canvas, xmin, xmax, ymin, ymax); +} + +void cdGetCanvasSize(int *width, int *height, double *width_mm, double *height_mm) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetSize(active_canvas, width, height, width_mm, height_mm); +} + +void cdMM2Pixel(double mm_dx, double mm_dy, int *dx, int *dy) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasMM2Pixel(active_canvas, mm_dx, mm_dy, dx, dy); +} + +void cdPixel2MM(int dx, int dy, double *mm_dx, double *mm_dy) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPixel2MM(active_canvas, dx, dy, mm_dx, mm_dy); +} + +void cdOrigin(int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasOrigin(active_canvas, x, y); +} + +int cdUpdateYAxis(int *y) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasUpdateYAxis(active_canvas, y); +} + +void cdPixel(int x, int y, long color) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPixel(active_canvas, x, y, color); +} + +void cdMark(int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasMark(active_canvas, x, y); +} + +void cdLine(int x1, int y1, int x2, int y2) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasLine(active_canvas, x1, y1, x2, y2); +} + +void cdBegin(int mode) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasBegin(active_canvas, mode); +} + +void cdVertex(int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasVertex(active_canvas, x, y); +} + +void cdEnd(void) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasEnd(active_canvas); +} + +void cdRect(int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasRect(active_canvas, xmin, xmax, ymin, ymax); +} + +void cdBox(int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasBox(active_canvas, xmin, xmax, ymin, ymax); +} + +void cdArc(int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasArc(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void cdSector(int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasSector(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void cdChord(int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasChord(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void cdText(int x, int y, const char *s) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasText(active_canvas, x, y, s); +} + +int cdBackOpacity(int opacity) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasBackOpacity(active_canvas, opacity); +} + +int cdWriteMode(int mode) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasWriteMode(active_canvas, mode); +} + +int cdLineStyle(int style) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasLineStyle(active_canvas, style); +} + +int cdLineJoin(int join) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasLineJoin(active_canvas, join); +} + +int cdLineCap(int cap) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasLineCap(active_canvas, cap); +} + +int cdRegionCombineMode(int mode) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasRegionCombineMode(active_canvas, mode); +} + +void cdLineStyleDashes(const int* dashes, int count) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasLineStyleDashes(active_canvas, dashes, count); +} + +int cdLineWidth(int width) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasLineWidth(active_canvas, width); +} + +int cdFillMode(int mode) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasFillMode(active_canvas, mode); +} + +int cdInteriorStyle (int style) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasInteriorStyle(active_canvas, style); +} + +int cdHatch(int style) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasHatch(active_canvas, style); +} + +void cdStipple(int w, int h, const unsigned char *stipple) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasStipple(active_canvas, w, h, stipple); +} + +unsigned char* cdGetStipple(int *w, int *h) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasGetStipple(active_canvas, w, h); +} + +void cdPattern(int w, int h, const long *pattern) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPattern(active_canvas, w, h, pattern); +} + +long* cdGetPattern(int* w, int* h) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasGetPattern(active_canvas, w, h); +} + +void cdFont(int type_face, int style, int size) +{ + static const char * family[] = + { + "System", /* CD_SYSTEM */ + "Courier", /* CD_COURIER */ + "Times", /* CD_TIMES_ROMAN */ + "Helvetica" /* CD_HELVETICA */ + }; + + assert(active_canvas); + assert(type_face>=CD_SYSTEM && type_face<=CD_NATIVE); + if (!active_canvas) return; + if (type_faceCD_NATIVE) return; + + if (type_face == CD_NATIVE) + { + char* native_font = cdCanvasNativeFont(active_canvas, NULL); + cdCanvasNativeFont(active_canvas, native_font); + } + else + cdCanvasFont(active_canvas, family[type_face], style, size); +} + +void cdGetFont(int *type_face, int *style, int *size) +{ + char family[1024]; + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetFont(active_canvas, family, style, size); + + if (type_face) + { + if (strcmp(family, "System")==0) + *type_face = CD_SYSTEM; + else if (strcmp(family, "Courier")==0) + *type_face = CD_COURIER; + else if (strcmp(family, "Times")==0) + *type_face = CD_TIMES_ROMAN; + else if (strcmp(family, "Helvetica")==0) + *type_face = CD_HELVETICA; + else + *type_face = CD_NATIVE; + } +} + +char* cdNativeFont(const char* font) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasNativeFont(active_canvas, font); +} + +int cdTextAlignment(int alignment) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasTextAlignment(active_canvas, alignment); +} + +double cdTextOrientation(double angle) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasTextOrientation(active_canvas, angle); +} + +int cdMarkType(int type) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasMarkType(active_canvas, type); +} + +int cdMarkSize(int size) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasMarkSize(active_canvas, size); +} + +long cdBackground(long color) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasBackground(active_canvas, color); +} + +long cdForeground(long color) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasForeground(active_canvas, color); +} + +void cdFontDim(int *max_width, int *height, int *ascent, int *descent) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetFontDim(active_canvas, max_width, height, ascent, descent); +} + +void cdTextSize(const char *s, int *width, int *height) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetTextSize(active_canvas, s, width, height); +} + +void cdTextBounds(int x, int y, const char *s, int *rect) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetTextBounds(active_canvas, x, y, s, rect); +} + +void cdTextBox(int x, int y, const char *s, int *xmin, int *xmax, int *ymin, int *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetTextBox(active_canvas, x, y, s, xmin, xmax, ymin, ymax); +} + +int cdGetColorPlanes(void) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasGetColorPlanes(active_canvas); +} + +void cdPalette(int n, const long *palette, int mode) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPalette(active_canvas, n, palette, mode); +} + +void cdGetImageRGB(unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetImageRGB(active_canvas, r, g, b, x, y, w, h); +} + +void cdPutImageRectRGB(int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPutImageRectRGB(active_canvas, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void cdPutImageRectRGBA(int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPutImageRectRGBA(active_canvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void cdPutImageRectMap(int iw, int ih, const unsigned char *index, const long *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPutImageRectMap(active_canvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); +} + +cdImage* cdCreateImage(int w, int h) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasCreateImage(active_canvas, w, h); +} + +void cdGetImage(cdImage* image, int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetImage(active_canvas, image, x, y); +} + +void cdPutImageRect(cdImage* image, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPutImageRect(active_canvas, image, x, y, xmin, xmax, ymin, ymax); +} + +void cdScrollArea(int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasScrollArea(active_canvas, xmin, xmax, ymin, ymax, dx, dy); +} + +void cdPutBitmap(cdBitmap* bitmap, int x, int y, int w, int h) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasPutBitmap(active_canvas, bitmap, x, y, w, h); +} + +void cdGetBitmap(cdBitmap* bitmap, int x, int y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetBitmap(active_canvas, bitmap, x, y); +} + +void wdWindow(double xmin, double xmax, double ymin, double ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasWindow(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdGetWindow (double *xmin, double *xmax, double *ymin, double *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetWindow(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdViewport(int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasViewport(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdGetViewport (int *xmin, int *xmax, int *ymin, int *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetViewport(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdWorld2Canvas(double xw, double yw, int *xv, int *yv) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasWorld2Canvas(active_canvas, xw, yw, xv, yv); +} + +void wdWorld2CanvasSize(double hw, double vw, int *hv, int *vv) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasWorld2CanvasSize(active_canvas, hw, vw, hv, vv); +} + +void wdCanvas2World(int xv, int yv, double *xw, double *yw) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasCanvas2World(active_canvas, xv, yv, xw, yw); +} + +void wdClipArea(double xmin, double xmax, double ymin, double ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasClipArea(active_canvas, xmin, xmax, ymin, ymax); +} + +int wdPointInRegion(double x, double y) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return wdCanvasIsPointInRegion(active_canvas, x, y); +} + +void wdOffsetRegion(double x, double y) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasOffsetRegion(active_canvas, x, y); +} + +void wdRegionBox(double *xmin, double *xmax, double *ymin, double *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetRegionBox(active_canvas, xmin, xmax, ymin, ymax); +} + +int wdGetClipArea(double *xmin, double *xmax, double *ymin, double *ymax) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return wdCanvasGetClipArea(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdLine (double x1, double y1, double x2, double y2) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasLine(active_canvas, x1, y1, x2, y2); +} + +void wdBox (double xmin, double xmax, double ymin, double ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasBox(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdRect(double xmin, double xmax, double ymin, double ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasRect(active_canvas, xmin, xmax, ymin, ymax); +} + +void wdArc(double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasArc(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void wdSector(double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasSector(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void wdChord(double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasChord(active_canvas, xc, yc, w, h, angle1, angle2); +} + +void wdText(double x, double y, const char *s) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasText(active_canvas, x, y, s); +} + +void wdVertex(double x, double y) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasVertex(active_canvas, x, y); +} + +void wdMark(double x, double y) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasMark(active_canvas, x, y); +} + +void wdPixel(double x, double y, long color) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPixel(active_canvas, x, y, color); +} + +void wdPutImageRect(cdImage* image, double x, double y, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPutImageRect(active_canvas, image, x, y, xmin, xmax, ymin, ymax); +} + +void wdPutImageRectRGB(int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPutImageRectRGB(active_canvas, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void wdPutImageRectRGBA(int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPutImageRectRGBA(active_canvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void wdPutImageRectMap(int iw, int ih, const unsigned char *index, const long *colors, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPutImageRectMap(active_canvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void wdPutBitmap(cdBitmap* bitmap, double x, double y, double w, double h) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPutBitmap(active_canvas, bitmap, x, y, w, h); +} + +double wdLineWidth(double width_mm) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return wdCanvasLineWidth(active_canvas, width_mm); +} + +void wdFont(int type_face, int style, double size_mm) +{ + static const char * family[] = + { + "System", /* CD_SYSTEM */ + "Courier", /* CD_COURIER */ + "Times Roman", /* CD_TIMES_ROMAN */ + "Helvetica" /* CD_HELVETICA */ + }; + + assert(active_canvas); + if (!active_canvas) return; + if (type_faceCD_HELVETICA) return; + + wdCanvasFont(active_canvas, family[type_face], style, (int)(size_mm*CD_MM2PT + 0.5)); +} + +void wdGetFont(int *type_face, int *style, double *size) +{ + char family[1024]; + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetFont(active_canvas, family, style, size); + + if (type_face) + { + if (strcmp(family, "System")==0) + *type_face = CD_SYSTEM; + else if (strcmp(family, "Courier")==0) + *type_face = CD_COURIER; + else if (strcmp(family, "Times Roman")==0) + *type_face = CD_TIMES_ROMAN; + else if (strcmp(family, "Helvetica")==0) + *type_face = CD_HELVETICA; + else + *type_face = CD_NATIVE; + } +} + +double wdMarkSize(double size_mm) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return wdCanvasMarkSize(active_canvas, size_mm); +} + +void wdFontDim(double *max_width, double *height, double *ascent, double *descent) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetFontDim(active_canvas, max_width, height, ascent, descent); +} + +void wdTextSize(const char *s, double *width, double *height) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetTextSize(active_canvas, s, width, height); +} + +void wdTextBox(double x, double y, const char *s, double *xmin, double *xmax, double *ymin, double *ymax) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetTextBox(active_canvas, x, y, s, xmin, xmax, ymin, ymax); +} + +void wdTextBounds(double x, double y, const char *s, double *rect) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetTextBounds(active_canvas, x, y, s, rect); +} + +void wdPattern(int w, int h, const long *color, double w_mm, double h_mm) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasPattern(active_canvas, w, h, color, w_mm, h_mm); +} + +void wdStipple(int w, int h, const unsigned char *fgbg, double w_mm, double h_mm) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasStipple(active_canvas, w, h, fgbg, w_mm, h_mm); +} + +void wdHardcopy(cdContext* ctx, void *data, cdCanvas *canvas, void(*draw_func)(void)) +{ + wdCanvasHardcopy(canvas, ctx, data, (void(*)(cdCanvas*))draw_func); +} + +void cdVectorText(int x, int y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasVectorText(active_canvas, x, y, s); +} + +void cdMultiLineVectorText(int x, int y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasMultiLineVectorText(active_canvas, x, y, s); +} + +char *cdVectorFont(const char *filename) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasVectorFont(active_canvas, filename); +} + +void cdVectorTextDirection(int x1, int y1, int x2, int y2) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasVectorTextDirection(active_canvas, x1, y1, x2, y2); +} + +double* cdVectorTextTransform(const double* matrix) +{ + assert(active_canvas); + if (!active_canvas) return NULL; + return cdCanvasVectorTextTransform(active_canvas, matrix); +} + +void cdVectorTextSize(int size_x, int size_y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasVectorTextSize(active_canvas, size_x, size_y, s); +} + +int cdVectorCharSize(int size) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return cdCanvasVectorCharSize(active_canvas, size); +} + +void cdGetVectorTextSize(const char* s, int *x, int *y) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetVectorTextSize(active_canvas, s, x, y); +} + +void cdGetVectorTextBounds(const char* s, int x, int y, int *rect) +{ + assert(active_canvas); + if (!active_canvas) return; + cdCanvasGetVectorTextBounds(active_canvas, s, x, y, rect); +} + +void wdVectorTextDirection(double x1, double y1, double x2, double y2) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasVectorTextDirection(active_canvas, x1, y1, x2, y2); +} + +void wdVectorTextSize(double size_x, double size_y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasVectorTextSize(active_canvas, size_x, size_y, s); +} + +void wdGetVectorTextSize(const char* s, double *x, double *y) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetVectorTextSize(active_canvas, s, x, y); +} + +double wdVectorCharSize(double size) +{ + assert(active_canvas); + if (!active_canvas) return CD_ERROR; + return wdCanvasVectorCharSize(active_canvas, size); +} + +void wdVectorText(double x, double y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasVectorText(active_canvas, x, y, s); +} + +void wdMultiLineVectorText(double x, double y, const char* s) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasMultiLineVectorText(active_canvas, x, y, s); +} + +void wdGetVectorTextBounds(const char* s, double x, double y, double *rect) +{ + assert(active_canvas); + if (!active_canvas) return; + wdCanvasGetVectorTextBounds(active_canvas, s, x, y, rect); +} + diff --git a/src/cd_attributes.c b/src/cd_attributes.c new file mode 100644 index 0000000..7b825e4 --- /dev/null +++ b/src/cd_attributes.c @@ -0,0 +1,1017 @@ +/** \file + * \brief External API + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "cd_private.h" + + +int cdCanvasClip(cdCanvas* canvas, int mode) +{ + int clip_mode; + + assert(canvas); + assert(mode==CD_QUERY || (mode>=CD_CLIPOFF && mode<=CD_CLIPREGION)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (modeCD_CLIPREGION) return CD_ERROR; + + clip_mode = canvas->clip_mode; + + if (mode == CD_QUERY || + mode == clip_mode || + (mode == CD_CLIPPOLYGON && !canvas->clip_poly && !canvas->clip_fpoly)) + return clip_mode; + + if (canvas->cxClip) + canvas->clip_mode = canvas->cxClip(canvas->ctxcanvas, mode); + else + canvas->clip_mode = mode; + + return clip_mode; +} + +void cdCanvasClipArea(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->origin.x; + xmax += canvas->origin.x; + ymin += canvas->origin.y; + ymax += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + if (xmin == canvas->clip_rect.xmin && + xmax == canvas->clip_rect.xmax && + ymin == canvas->clip_rect.ymin && + ymax == canvas->clip_rect.ymax) + return; + + if (canvas->cxClipArea) + canvas->cxClipArea(canvas->ctxcanvas, xmin, xmax, ymin, ymax); + else if (canvas->cxFClipArea) + canvas->cxFClipArea(canvas->ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); + + canvas->clip_rect.xmin = xmin; + canvas->clip_rect.xmax = xmax; + canvas->clip_rect.ymin = ymin; + canvas->clip_rect.ymax = ymax; + canvas->clip_frect.xmin = (double)xmin; + canvas->clip_frect.xmax = (double)xmax; + canvas->clip_frect.ymin = (double)ymin; + canvas->clip_frect.ymax = (double)ymax; +} + +int cdCanvasGetClipArea(cdCanvas* canvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + int _xmin, _xmax, _ymin, _ymax; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + _xmin = canvas->clip_rect.xmin; + _xmax = canvas->clip_rect.xmax; + _ymin = canvas->clip_rect.ymin; + _ymax = canvas->clip_rect.ymax; + + if (canvas->invert_yaxis) + { + _ymin = _cdInvertYAxis(canvas, _ymin); + _ymax = _cdInvertYAxis(canvas, _ymax); + _cdSwapInt(_ymin, _ymax); + } + + if (canvas->use_origin) + { + _xmin -= canvas->origin.x; + _xmax -= canvas->origin.x; + _ymin -= canvas->origin.y; + _ymax -= canvas->origin.y; + } + + if (xmin) *xmin = _xmin; + if (xmax) *xmax = _xmax; + if (ymin) *ymin = _ymin; + if (ymax) *ymax = _ymax; + + return canvas->clip_mode; +} + +void cdfCanvasClipArea(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!cdfCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->forigin.x; + xmax += canvas->forigin.x; + ymin += canvas->forigin.y; + ymax += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapDouble(ymin, ymax); + } + + if (xmin == canvas->clip_frect.xmin && + xmax == canvas->clip_frect.xmax && + ymin == canvas->clip_frect.ymin && + ymax == canvas->clip_frect.ymax) + return; + + if (canvas->cxFClipArea) + canvas->cxFClipArea(canvas->ctxcanvas, xmin, xmax, ymin, ymax); + else if (canvas->cxClipArea) + canvas->cxClipArea(canvas->ctxcanvas, _cdRound(xmin), _cdRound(xmax), _cdRound(ymin), _cdRound(ymax)); + + canvas->clip_frect.xmin = xmin; + canvas->clip_frect.xmax = xmax; + canvas->clip_frect.ymin = ymin; + canvas->clip_frect.ymax = ymax; + canvas->clip_rect.xmin = _cdRound(xmin); + canvas->clip_rect.xmax = _cdRound(xmax); + canvas->clip_rect.ymin = _cdRound(ymin); + canvas->clip_rect.ymax = _cdRound(ymax); +} + +int cdfCanvasGetClipArea(cdCanvas* canvas, double *xmin, double *xmax, double *ymin, double *ymax) +{ + double _xmin, _xmax, _ymin, _ymax; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + _xmin = canvas->clip_frect.xmin; + _xmax = canvas->clip_frect.xmax; + _ymin = canvas->clip_frect.ymin; + _ymax = canvas->clip_frect.ymax; + + if (canvas->invert_yaxis) + { + _ymin = _cdInvertYAxis(canvas, _ymin); + _ymax = _cdInvertYAxis(canvas, _ymax); + _cdSwapDouble(_ymin, _ymax); + } + + if (canvas->use_origin) + { + _xmin -= canvas->forigin.x; + _xmax -= canvas->forigin.x; + _ymin -= canvas->forigin.y; + _ymax -= canvas->forigin.y; + } + + if (xmin) *xmin = _xmin; + if (xmax) *xmax = _xmax; + if (ymin) *ymin = _ymin; + if (ymax) *ymax = _ymax; + + return canvas->clip_mode; +} + +int cdCanvasIsPointInRegion(cdCanvas* canvas, int x, int y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxIsPointInRegion) return CD_ERROR; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + return canvas->cxIsPointInRegion(canvas->ctxcanvas, x, y); +} + +void cdCanvasOffsetRegion(cdCanvas* canvas, int x, int y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxOffsetRegion) return; + + if (canvas->invert_yaxis) + y = -y; + + canvas->cxOffsetRegion(canvas->ctxcanvas, x, y); +} + +void cdCanvasGetRegionBox(cdCanvas* canvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + int _xmin, _xmax, _ymin, _ymax; + assert(canvas); + if (!_cdCheckCanvas(canvas) || !canvas->cxGetRegionBox) return; + + canvas->cxGetRegionBox(canvas->ctxcanvas, &_xmin, &_xmax, &_ymin, &_ymax); + + if (canvas->invert_yaxis) + { + _ymin = _cdInvertYAxis(canvas, _ymin); + _ymax = _cdInvertYAxis(canvas, _ymax); + _cdSwapInt(_ymin, _ymax); + } + + if (canvas->use_origin) + { + _xmin -= canvas->origin.x; + _xmax -= canvas->origin.x; + _ymin -= canvas->origin.y; + _ymax -= canvas->origin.y; + } + + if (xmin) *xmin = _xmin; + if (xmax) *xmax = _xmax; + if (ymin) *ymin = _ymin; + if (ymax) *ymax = _ymax; +} + +void cdCanvasOrigin(cdCanvas* canvas, int x, int y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + canvas->origin.x = x; + canvas->origin.y = y; + + if (canvas->origin.x == 0 && canvas->origin.y == 0) + canvas->use_origin = 0; + else + canvas->use_origin = 1; + + canvas->forigin.x = (double)canvas->origin.x; + canvas->forigin.y = (double)canvas->origin.y; +} + + +void cdfCanvasOrigin(cdCanvas* canvas, double x, double y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + canvas->forigin.x = x; + canvas->forigin.y = y; + + if (canvas->forigin.x == 0 && canvas->forigin.y == 0) + canvas->use_origin = 0; + else + canvas->use_origin = 1; + + canvas->origin.x = _cdRound(canvas->forigin.x); + canvas->origin.y = _cdRound(canvas->forigin.y); +} + +void cdCanvasGetOrigin(cdCanvas* canvas, int *x, int *y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (x) *x = canvas->origin.x; + if (y) *y = canvas->origin.y; +} + +void cdfCanvasGetOrigin(cdCanvas* canvas, double *x, double *y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (x) *x = canvas->forigin.x; + if (y) *y = canvas->forigin.y; +} + +#define CD_TRANSFORM_X(_x, _y, _matrix) (_x*_matrix[0] + _y*_matrix[2] + _matrix[4]) +#define CD_TRANSFORM_Y(_x, _y, _matrix) (_x*_matrix[1] + _y*_matrix[3] + _matrix[5]) + +void cdfMatrixTransformPoint(double* matrix, double x, double y, double *rx, double *ry) +{ + *rx = CD_TRANSFORM_X(x, y, matrix); + *ry = CD_TRANSFORM_Y(x, y, matrix); +} + +void cdMatrixTransformPoint(double* matrix, int x, int y, int *rx, int *ry) +{ + double t; + t = CD_TRANSFORM_X(x, y, matrix); *rx = _cdRound(t); + t = CD_TRANSFORM_Y(x, y, matrix); *ry = _cdRound(t); +} + +void cdCanvasTransformPoint(cdCanvas* canvas, int x, int y, int *tx, int *ty) +{ + double *matrix; + double t; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + matrix = canvas->matrix; + t = CD_TRANSFORM_X(x, y, matrix); *tx = _cdRound(t); + t = CD_TRANSFORM_Y(x, y, matrix); *ty = _cdRound(t); +} + +void cdfCanvasTransformPoint(cdCanvas* canvas, double x, double y, double *tx, double *ty) +{ + double *matrix; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + matrix = canvas->matrix; + *tx = CD_TRANSFORM_X(x, y, matrix); + *ty = CD_TRANSFORM_Y(x, y, matrix); +} + +void cdMatrixInverse(const double* matrix, double* inv_matrix) +{ + double det = matrix[0] * matrix[3] - matrix[1] * matrix[2]; + + if (fabs(det) < 0.00001) + { + inv_matrix[0] = 1; + inv_matrix[1] = 0; + inv_matrix[2] = 0; + inv_matrix[3] = 1; + inv_matrix[4] = 0; + inv_matrix[5] = 0; + return; + } + + inv_matrix[0] = matrix[3]/det; + inv_matrix[1] = -matrix[1]/det; + inv_matrix[2] = -matrix[2]/det; + inv_matrix[3] = matrix[0]/det; + inv_matrix[4] = -(matrix[4] * inv_matrix[0] + matrix[5] * inv_matrix[2]); + inv_matrix[5] = -(matrix[4] * inv_matrix[1] + matrix[5] * inv_matrix[3]); +} + +#define _cdIsIndentity(_matrix) (_matrix[0] == 1 && _matrix[1] == 0 && \ + _matrix[2] == 0 && _matrix[3] == 1 && \ + _matrix[4] == 0 && _matrix[5] == 0) + +double* cdCanvasGetTransform(cdCanvas* canvas) +{ + static double matrix[6]; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + memcpy(matrix, canvas->matrix, sizeof(double)*6); + return matrix; +} + +void cdCanvasTransform(cdCanvas* canvas, const double* matrix) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!matrix || _cdIsIndentity(matrix)) + { + canvas->use_matrix = 0; + memset(canvas->matrix, 0, sizeof(double)*6); + canvas->matrix[0] = 1; /* reset to identity */ + canvas->matrix[3] = 1; + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, NULL); + + return; + } + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, matrix); + + memcpy(canvas->matrix, matrix, sizeof(double)*6); + canvas->use_matrix = 1; +} + +/* mul_matrix = matrix * mul_matrix (left multiply) */ +void cdMatrixMultiply(const double* matrix, double* mul_matrix) +{ + double tmp_matrix[6]; + tmp_matrix[0] = matrix[0] * mul_matrix[0] + matrix[1] * mul_matrix[2]; + tmp_matrix[1] = matrix[0] * mul_matrix[1] + matrix[1] * mul_matrix[3]; + tmp_matrix[2] = matrix[2] * mul_matrix[0] + matrix[3] * mul_matrix[2]; + tmp_matrix[3] = matrix[2] * mul_matrix[1] + matrix[3] * mul_matrix[3]; + tmp_matrix[4] = matrix[4] * mul_matrix[0] + matrix[5] * mul_matrix[2] + mul_matrix[4]; + tmp_matrix[5] = matrix[4] * mul_matrix[1] + matrix[5] * mul_matrix[3] + mul_matrix[5]; + + memcpy(mul_matrix, tmp_matrix, sizeof(double)*6); +} + +void cdCanvasTransformMultiply(cdCanvas* canvas, const double* matrix) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + cdMatrixMultiply(matrix, canvas->matrix); + + if (_cdIsIndentity(canvas->matrix)) + canvas->use_matrix = 0; + else + canvas->use_matrix = 1; + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, canvas->use_matrix? canvas->matrix: NULL); +} + +void cdCanvasTransformRotate(cdCanvas* canvas, double angle) +{ + double tmp_matrix[4]; + double* matrix, cos_ang, sin_ang; + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + matrix = canvas->matrix; + + cos_ang = cos(angle * CD_DEG2RAD); + sin_ang = sin(angle * CD_DEG2RAD); + + tmp_matrix[0] = cos_ang * matrix[0] + sin_ang * matrix[2]; + tmp_matrix[1] = cos_ang * matrix[1] + sin_ang * matrix[3]; + tmp_matrix[2] = -sin_ang * matrix[0] + cos_ang * matrix[2]; + tmp_matrix[3] = -sin_ang * matrix[1] + cos_ang * matrix[3]; + + matrix[0] = tmp_matrix[0]; + matrix[1] = tmp_matrix[1]; + matrix[2] = tmp_matrix[2]; + matrix[3] = tmp_matrix[3]; + + if (_cdIsIndentity(matrix)) + canvas->use_matrix = 0; + else + canvas->use_matrix = 1; + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, canvas->use_matrix? matrix: NULL); +} + +void cdCanvasTransformScale(cdCanvas* canvas, double sx, double sy) +{ + double* matrix; + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + matrix = canvas->matrix; + + matrix[0] = sx * matrix[0]; + matrix[1] = sx * matrix[1]; + matrix[2] = sy * matrix[2]; + matrix[3] = sy * matrix[3]; + + if (_cdIsIndentity(matrix)) + canvas->use_matrix = 0; + else + canvas->use_matrix = 1; + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, canvas->use_matrix? matrix: NULL); +} + +void cdCanvasTransformTranslate(cdCanvas* canvas, double dx, double dy) +{ + double* matrix; + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + matrix = canvas->matrix; + + matrix[4] = dx * matrix[0] + dy * matrix[2] + matrix[4]; + matrix[5] = dx * matrix[1] + dy * matrix[3] + matrix[5]; + + if (_cdIsIndentity(matrix)) + canvas->use_matrix = 0; + else + canvas->use_matrix = 1; + + if (canvas->cxTransform) + canvas->cxTransform(canvas->ctxcanvas, canvas->use_matrix? matrix: NULL); +} + +int cdCanvasBackOpacity(cdCanvas* canvas, int opacity) +{ + int back_opacity; + + assert(canvas); + assert(opacity==CD_QUERY || (opacity>=CD_OPAQUE && opacity<=CD_TRANSPARENT)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (opacityCD_TRANSPARENT) return CD_ERROR; + + back_opacity = canvas->back_opacity; + + if (opacity == CD_QUERY || opacity == back_opacity) + return back_opacity; + + if (canvas->cxBackOpacity) + canvas->back_opacity = canvas->cxBackOpacity(canvas->ctxcanvas, opacity); + else + canvas->back_opacity = opacity; + + return back_opacity; +} + +int cdCanvasWriteMode(cdCanvas* canvas, int mode) +{ + int write_mode; + + assert(canvas); + assert(mode==CD_QUERY || (mode>=CD_REPLACE && mode<=CD_NOT_XOR)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (modeCD_NOT_XOR) return CD_ERROR; + + write_mode = canvas->write_mode; + + if (mode == CD_QUERY || mode == write_mode) + return write_mode; + + if (canvas->cxWriteMode) + canvas->write_mode = canvas->cxWriteMode(canvas->ctxcanvas, mode); + else + canvas->write_mode = mode; + + return write_mode; +} + +int cdCanvasLineStyle(cdCanvas* canvas, int style) +{ + int line_style; + + assert(canvas); + assert(style==CD_QUERY || (style>=CD_CONTINUOUS && style<=CD_CUSTOM)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (styleCD_CUSTOM) return CD_ERROR; + + line_style = canvas->line_style; + + if (style == CD_QUERY || style == line_style) + return line_style; + + if (style == CD_CUSTOM && !canvas->line_dashes_count) + return line_style; + + if (canvas->cxLineStyle) + canvas->line_style = canvas->cxLineStyle(canvas->ctxcanvas, style); + else + canvas->line_style = style; + + return line_style; +} + +int cdCanvasLineJoin(cdCanvas* canvas, int join) +{ + int line_join; + + assert(canvas); + assert(join==CD_QUERY || (join>=CD_MITER && join<=CD_ROUND)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (joinCD_ROUND) return CD_ERROR; + + line_join = canvas->line_join; + + if (join == CD_QUERY || join == line_join) + return line_join; + + if (canvas->cxLineJoin) + canvas->line_join = canvas->cxLineJoin(canvas->ctxcanvas, join); + else + canvas->line_join = join; + + return line_join; +} + +int cdCanvasLineCap(cdCanvas* canvas, int cap) +{ + int line_cap; + + assert(canvas); + assert(cap==CD_QUERY || (cap>=CD_CAPFLAT && cap<=CD_CAPROUND)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (capCD_CAPROUND) return CD_ERROR; + + line_cap = canvas->line_cap; + + if (cap == CD_QUERY || cap == line_cap) + return line_cap; + + if (canvas->cxLineCap) + canvas->line_cap = canvas->cxLineCap(canvas->ctxcanvas, cap); + else + canvas->line_cap = cap; + + return line_cap; +} + +int cdCanvasRegionCombineMode(cdCanvas* canvas, int mode) +{ + int combine_mode; + + assert(canvas); + assert(mode==CD_QUERY || (mode>=CD_UNION && mode<=CD_NOTINTERSECT)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (modeCD_NOTINTERSECT) return CD_ERROR; + + combine_mode = canvas->combine_mode; + + if (mode == CD_QUERY || mode == combine_mode) + return combine_mode; + + canvas->combine_mode = mode; + + return combine_mode; +} + +void cdCanvasLineStyleDashes(cdCanvas* canvas, const int* dashes, int count) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->line_dashes) + { + free(canvas->line_dashes); + canvas->line_dashes = NULL; + } + + if (dashes) + { + canvas->line_dashes = malloc(count*sizeof(int)); + canvas->line_dashes_count = count; + memcpy(canvas->line_dashes, dashes, count*sizeof(int)); + } +} + +int cdCanvasLineWidth(cdCanvas* canvas, int width) +{ + int line_width; + + assert(canvas); + assert(width==CD_QUERY || width>0); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (width!=CD_QUERY && width<=0) return CD_ERROR; + + line_width = canvas->line_width; + + if (width == CD_QUERY || width == line_width) + return line_width; + + if (canvas->cxLineWidth) + canvas->line_width = canvas->cxLineWidth(canvas->ctxcanvas, width); + else + canvas->line_width = width; + + return line_width; +} + +int cdCanvasFillMode(cdCanvas* canvas, int mode) +{ + int fill_mode; + + assert(canvas); + assert(mode==CD_QUERY || (mode>=CD_EVENODD && mode<=CD_WINDING)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (modeCD_WINDING) return CD_ERROR; + + fill_mode = canvas->fill_mode; + + if (mode == CD_QUERY || mode == fill_mode) + return fill_mode; + + canvas->fill_mode = mode; + + return fill_mode; +} + +int cdCanvasInteriorStyle (cdCanvas* canvas, int style) +{ + int interior_style; + + assert(canvas); + assert(style==CD_QUERY || (style>=CD_SOLID && style<=CD_HOLLOW)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (styleCD_HOLLOW) return CD_ERROR; + + interior_style = canvas->interior_style; + + if ( style == CD_QUERY || style == interior_style) + return interior_style; + + if ((style == CD_PATTERN && !canvas->pattern_size) || + (style == CD_STIPPLE && !canvas->stipple_size)) + return interior_style; + + if (style == CD_HOLLOW) + { + canvas->interior_style = CD_HOLLOW; + return interior_style; + } + + if (canvas->cxInteriorStyle) + canvas->interior_style = canvas->cxInteriorStyle(canvas->ctxcanvas, style); + else + canvas->interior_style = style; + + return interior_style; +} + +int cdCanvasHatch(cdCanvas* canvas, int style) +{ + int hatch_style; + + assert(canvas); + assert(style==CD_QUERY || (style>=CD_HORIZONTAL && style<=CD_DIAGCROSS)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (styleCD_DIAGCROSS) return CD_ERROR; + + hatch_style = canvas->hatch_style; + + if (style == CD_QUERY) + return hatch_style; + + if (canvas->cxHatch) + canvas->hatch_style = canvas->cxHatch(canvas->ctxcanvas, style); + else + canvas->hatch_style = style; + + canvas->interior_style = CD_HATCH; + + return hatch_style; +} + +void cdCanvasStipple(cdCanvas* canvas, int w, int h, const unsigned char *stipple) +{ + assert(canvas); + assert(stipple); + assert(w>0); + assert(h>0); + if (!_cdCheckCanvas(canvas)) return; + if (w <= 0 || h <= 0 || !stipple) + return; + + if (canvas->cxStipple) + canvas->cxStipple(canvas->ctxcanvas, w, h, stipple); + + if (w*h > canvas->stipple_size) /* realoca array dos pontos */ + { + int newsize = w*h; + canvas->stipple = (unsigned char*)realloc(canvas->stipple, newsize); + canvas->stipple_size = newsize; + + if (!canvas->stipple) + { + canvas->stipple_size = 0; + return; + } + } + + memcpy(canvas->stipple, stipple, w*h); + + canvas->interior_style = CD_STIPPLE; + canvas->stipple_w = w; + canvas->stipple_h = h; +} + +unsigned char* cdCanvasGetStipple(cdCanvas* canvas, int* w, int* h) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + if (!canvas->stipple_size) + return NULL; + + if (w) *w = canvas->stipple_w; + if (h) *h = canvas->stipple_h; + + return canvas->stipple; +} + +void cdCanvasPattern(cdCanvas* canvas, int w, int h, const long *pattern) +{ + assert(canvas); + assert(pattern); + assert(w>0); + assert(h>0); + if (!_cdCheckCanvas(canvas)) return; + if (w <= 0 || h <= 0 || !pattern) + return; + + if (canvas->cxPattern) + canvas->cxPattern(canvas->ctxcanvas, w, h, pattern); + + if (w*h > canvas->pattern_size) /* realoca array dos pontos */ + { + int newsize = w*h; + + if (canvas->pattern) free(canvas->pattern); + canvas->pattern = (long*)malloc(newsize*sizeof(long)); + canvas->pattern_size = newsize; + + if (!canvas->pattern) + { + canvas->pattern_size = 0; + return; + } + } + + memcpy(canvas->pattern, pattern, w*h*sizeof(long)); + + canvas->interior_style = CD_PATTERN; + canvas->pattern_w = w; + canvas->pattern_h = h; +} + +long * cdCanvasGetPattern(cdCanvas* canvas, int* w, int* h) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + if (!canvas->pattern_size) + return NULL; + + if (w) *w = canvas->pattern_w; + if (h) *h = canvas->pattern_h; + + return canvas->pattern; +} + +int cdCanvasMarkType(cdCanvas* canvas, int type) +{ + int mark_type; + + assert(canvas); + assert(type==CD_QUERY || (type>=CD_PLUS && type<=CD_HOLLOW_DIAMOND)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (typeCD_HOLLOW_DIAMOND) return CD_ERROR; + + mark_type = canvas->mark_type; + + if (type == CD_QUERY || type == mark_type) + return mark_type; + + canvas->mark_type = type; + + return mark_type; +} + +int cdCanvasMarkSize(cdCanvas* canvas, int size) +{ + int mark_size; + + assert(canvas); + assert(size == CD_QUERY || size>0); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (size != CD_QUERY && size<=0) return CD_ERROR; + + mark_size = canvas->mark_size; + + if (size == CD_QUERY || size == mark_size) + return mark_size; + + canvas->mark_size = size; + + return mark_size; +} + +long cdCanvasBackground(cdCanvas* canvas, long color) +{ + long background; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + background = canvas->background; + + if (color == CD_QUERY || color == background) + return background; + + if (canvas->cxBackground) + canvas->background = canvas->cxBackground(canvas->ctxcanvas, color); + else + canvas->background = color; + + return background; +} + +long cdCanvasForeground(cdCanvas* canvas, long color) +{ + long foreground; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + foreground = canvas->foreground; + + if (color == CD_QUERY || color == foreground) + return foreground; + + if (canvas->cxForeground) + canvas->foreground = canvas->cxForeground(canvas->ctxcanvas, color); + else + canvas->foreground = color; + + return foreground; +} + +void cdCanvasSetBackground(cdCanvas* canvas, long color) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (color == canvas->background) + return; + + if (canvas->cxBackground) + canvas->background = canvas->cxBackground(canvas->ctxcanvas, color); + else + canvas->background = color; +} + +void cdCanvasSetForeground(cdCanvas* canvas, long color) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (color == canvas->foreground) + return; + + if (canvas->cxForeground) + canvas->foreground = canvas->cxForeground(canvas->ctxcanvas, color); + else + canvas->foreground = color; +} + +/****************/ +/* color coding */ +/****************/ + +long cdEncodeColor(unsigned char r, unsigned char g, unsigned char b) +{ + return (((unsigned long)r) << 16) | + (((unsigned long)g) << 8) | + (((unsigned long)b) << 0); +} + +void cdDecodeColor(long color, unsigned char *r, unsigned char *g, unsigned char *b) +{ + *r = cdRed(color); + *g = cdGreen(color); + *b = cdBlue(color); +} + +unsigned char cdDecodeAlpha(long color) +{ + unsigned char alpha = cdReserved(color); + return ~alpha; +} + +long cdEncodeAlpha(long color, unsigned char alpha) +{ + alpha = ~alpha; + return (((unsigned long)alpha) << 24) | (color & 0xFFFFFF); +} + +int cdCanvasGetColorPlanes(cdCanvas* canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + return canvas->bpp; +} + +void cdCanvasPalette(cdCanvas* canvas, int n, const long *palette, int mode) +{ + assert(canvas); + assert(n>0); + assert(palette); + assert(mode>=CD_POLITE && mode<=CD_FORCE); + if (!_cdCheckCanvas(canvas)) return; + if (!palette) return; + if (n <= 0 || canvas->bpp > 8) + return; + + if (canvas->cxPalette) + canvas->cxPalette(canvas->ctxcanvas, n, palette, mode); +} + diff --git a/src/cd_bitmap.c b/src/cd_bitmap.c new file mode 100644 index 0000000..234668c --- /dev/null +++ b/src/cd_bitmap.c @@ -0,0 +1,293 @@ +/** \file + * \brief cdBitmap implementation + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "cdirgb.h" + +#include "cd_private.h" + + +typedef struct _cdBitmapData +{ + void *buffer; + + unsigned char *index; /* pointers into buffer */ + unsigned char *r; + unsigned char *g; + unsigned char *b; + unsigned char *a; + + long* colors; + + int xmin, xmax, ymin, ymax; +} cdBitmapData; + + +cdBitmap* cdCreateBitmap(int w, int h, int type) +{ + int num_channel; + int size = w * h; + cdBitmap* bitmap; + cdBitmapData* data; + + assert(w>0); + assert(h>0); + if (w <= 0) return NULL; + if (h <= 0) return NULL; + + switch (type) + { + case CD_RGB: + num_channel = 3; + break; + case CD_RGBA: + num_channel = 4; + break; + case CD_MAP: + num_channel = 1; + break; + default: + return NULL; + } + + bitmap = (cdBitmap*)malloc(sizeof(cdBitmap)); + data = (cdBitmapData*)malloc(sizeof(cdBitmapData)); + memset(data, 0, sizeof(cdBitmapData)); + + bitmap->w = w; + bitmap->h = h; + bitmap->type = type; + bitmap->data = data; + + data->buffer = malloc(size*num_channel); + if (!data->buffer) + { + free(data); + free(bitmap); + return NULL; + } + + if (type == CD_RGB) + { + data->r = data->buffer; + data->g = data->r + size; + data->b = data->g + size; + memset(data->r, 255, 3*size); /* white */ + } + + if (type == CD_RGBA) + { + data->a = data->b + size; + memset(data->a, 0, size); /* transparent */ + } + + if (type == CD_MAP) + { + data->index = data->buffer; + data->colors = (long*)calloc(256, sizeof(long)); + memset(data->index, 0, size); /* index=0 */ + } + + data->xmin = 0; + data->ymin = 0; + data->xmax = bitmap->w-1; + data->ymax = bitmap->h-1; + + return bitmap; +} + +cdBitmap* cdInitBitmap(int w, int h, int type, ...) +{ + va_list arglist; + cdBitmap* bitmap; + cdBitmapData* data; + + assert(w>0); + assert(h>0); + if (w <= 0) return NULL; + if (h <= 0) return NULL; + + if (type != CD_RGB && + type != CD_RGBA && + type != CD_MAP) + return NULL; + + bitmap = (cdBitmap*)malloc(sizeof(cdBitmap)); + data = (cdBitmapData*)malloc(sizeof(cdBitmapData)); + memset(data, 0, sizeof(cdBitmapData)); + + bitmap->w = w; + bitmap->h = h; + bitmap->type = type; + bitmap->data = data; + + va_start(arglist, type); + + if (type == CD_RGB) + { + data->r = va_arg(arglist, unsigned char*); + data->g = va_arg(arglist, unsigned char*); + data->b = va_arg(arglist, unsigned char*); + } + + if (type == CD_RGBA) + data->a = va_arg(arglist, unsigned char*); + + if (type == CD_MAP) + { + data->index = va_arg(arglist, unsigned char*); + data->colors = va_arg(arglist, long*); + } + + data->xmin = 0; + data->ymin = 0; + data->xmax = bitmap->w-1; + data->ymax = bitmap->h-1; + + return bitmap; +} + +void cdKillBitmap(cdBitmap* bitmap) +{ + cdBitmapData* data; + + assert(bitmap); + assert(bitmap->data); + if (!bitmap) return; + if (!bitmap->data) return; + + data = (cdBitmapData*)bitmap->data; + + if (data->buffer) + { + free(data->buffer); + + if (bitmap->type == CD_MAP) + free(data->colors); + } + + free(data); + free(bitmap); +} + +void cdCanvasGetBitmap(cdCanvas* canvas, cdBitmap* bitmap, int x, int y) +{ + cdBitmapData* data; + + assert(bitmap); + assert(bitmap->data); + if (!bitmap) return; + if (!bitmap->data) return; + + data = (cdBitmapData*)bitmap->data; + + if (bitmap->type == CD_RGB || bitmap->type == CD_RGBA) + cdCanvasGetImageRGB(canvas, data->r, data->g, data->b, x, y, bitmap->w, bitmap->h); +} + +void cdBitmapRGB2Map(cdBitmap* bitmap_rgb, cdBitmap* bitmap_map) +{ + cdBitmapData* data_rgb; + cdBitmapData* data_map; + + assert(bitmap_rgb); + assert(bitmap_rgb->data); + assert(bitmap_map); + assert(bitmap_map->data); + if (!bitmap_rgb) return; + if (!bitmap_rgb->data) return; + if (!bitmap_map) return; + if (!bitmap_map->data) return; + + data_rgb = (cdBitmapData*)bitmap_rgb->data; + data_map = (cdBitmapData*)bitmap_map->data; + + if ((bitmap_rgb->type != CD_RGB && bitmap_rgb->type != CD_RGBA) || (bitmap_map->type != CD_MAP)) + return; + + cdRGB2Map(bitmap_rgb->w, bitmap_rgb->h, data_rgb->r, data_rgb->g, data_rgb->b, data_map->index, bitmap_map->type, data_map->colors); +} + +unsigned char* cdBitmapGetData(cdBitmap* bitmap, int dataptr) +{ + cdBitmapData* data; + + assert(bitmap); + assert(bitmap->data); + if (!bitmap) return NULL; + if (!bitmap->data) return NULL; + + data = (cdBitmapData*)bitmap->data; + + switch(dataptr) + { + case CD_IRED: + return data->r; + case CD_IGREEN: + return data->g; + case CD_IBLUE: + return data->b; + case CD_IALPHA: + return data->a; + case CD_INDEX: + return data->index; + case CD_COLORS: + return (unsigned char*)data->colors; + } + + return NULL; +} + +void cdBitmapSetRect(cdBitmap* bitmap, int xmin, int xmax, int ymin, int ymax) +{ + cdBitmapData* data; + + assert(bitmap); + assert(bitmap->data); + if (!bitmap) return; + if (!bitmap->data) return; + + data = (cdBitmapData*)bitmap->data; + + data->xmin = xmin; + data->xmax = xmax; + data->ymin = ymin; + data->ymax = ymax; +} + +void cdCanvasPutBitmap(cdCanvas* canvas, cdBitmap* bitmap, int x, int y, int w, int h) +{ + cdBitmapData* data; + + assert(bitmap); + assert(bitmap->data); + if (!bitmap) return; + if (!bitmap->data) return; + + data = (cdBitmapData*)bitmap->data; + + switch(bitmap->type) + { + case CD_RGB: + cdCanvasPutImageRectRGB(canvas, bitmap->w, bitmap->h, data->r, data->g, data->b, x, y, w, h, data->xmin, data->xmax, data->ymin, data->ymax); + break; + case CD_RGBA: + cdCanvasPutImageRectRGBA(canvas, bitmap->w, bitmap->h, data->r, data->g, data->b, data->a, x, y, w, h, data->xmin, data->xmax, data->ymin, data->ymax); + break; + case CD_MAP: + cdCanvasPutImageRectMap(canvas, bitmap->w, bitmap->h, data->index, data->colors, x, y, w, h, data->xmin, data->xmax, data->ymin, data->ymax); + break; + } +} diff --git a/src/cd_freetype.def b/src/cd_freetype.def new file mode 100644 index 0000000..1cfc413 --- /dev/null +++ b/src/cd_freetype.def @@ -0,0 +1,247 @@ +EXPORTS + FTC_CMapCache_Lookup + FTC_CMapCache_New + FTC_ImageCache_Lookup + FTC_ImageCache_LookupScaler + FTC_ImageCache_New + FTC_Manager_Done + FTC_Manager_LookupFace + FTC_Manager_LookupSize + FTC_Manager_New + FTC_Manager_RemoveFaceID + FTC_Manager_Reset + FTC_Node_Unref + FTC_SBitCache_Lookup + FTC_SBitCache_LookupScaler + FTC_SBitCache_New + FT_Activate_Size + FT_Add_Default_Modules + FT_Add_Module + FT_Angle_Diff + FT_Atan2 + FT_Attach_File + FT_Attach_Stream + FT_Bitmap_Convert + FT_Bitmap_Copy + FT_Bitmap_Done + FT_Bitmap_Embolden + FT_Bitmap_New + FT_CMap_Done + FT_CMap_New + FT_CeilFix + FT_ClassicKern_Free + FT_ClassicKern_Validate + FT_Cos + FT_DivFix + FT_Done_Face + FT_Done_FreeType + FT_Done_Glyph + FT_Done_GlyphSlot + FT_Done_Library + FT_Done_Memory + FT_Done_Size + FT_Face_CheckTrueTypePatents + FT_Face_SetUnpatentedHinting + FT_FloorFix + FT_Get_BDF_Charset_ID + FT_Get_BDF_Property + FT_Get_CMap_Format + FT_Get_CMap_Language_ID + FT_Get_Char_Index + FT_Get_Charmap_Index + FT_Get_First_Char + FT_Get_Gasp + FT_Get_Glyph + FT_Get_Glyph_Name + FT_Get_Kerning + FT_Get_MM_Var + FT_Get_Module + FT_Get_Module_Interface + FT_Get_Multi_Master + FT_Get_Name_Index + FT_Get_Next_Char + FT_Get_PFR_Advance + FT_Get_PFR_Kerning + FT_Get_PFR_Metrics + FT_Get_PS_Font_Info + FT_Get_PS_Font_Private + FT_Get_Postscript_Name + FT_Get_Renderer + FT_Get_Sfnt_Name + FT_Get_Sfnt_Name_Count + FT_Get_Sfnt_Table + FT_Get_SubGlyph_Info + FT_Get_Track_Kerning + FT_Get_TrueType_Engine_Type + FT_Get_WinFNT_Header + FT_Get_X11_Font_Format + FT_GlyphLoader_Add + FT_GlyphLoader_CheckPoints + FT_GlyphLoader_CheckSubGlyphs + FT_GlyphLoader_CopyPoints + FT_GlyphLoader_CreateExtra + FT_GlyphLoader_Done + FT_GlyphLoader_New + FT_GlyphLoader_Prepare + FT_GlyphLoader_Reset + FT_GlyphLoader_Rewind + FT_GlyphSlot_Embolden + FT_GlyphSlot_Oblique + FT_GlyphSlot_Own_Bitmap + FT_Glyph_Copy + FT_Glyph_Get_CBox + FT_Glyph_Stroke + FT_Glyph_StrokeBorder + FT_Glyph_To_Bitmap + FT_Glyph_Transform + FT_Has_PS_Glyph_Names + FT_Init_FreeType + FT_Library_SetLcdFilter + FT_Library_Version + FT_List_Add + FT_List_Finalize + FT_List_Find + FT_List_Insert + FT_List_Iterate + FT_List_Remove + FT_List_Up + FT_Load_Char + FT_Load_Glyph + FT_Load_Sfnt_Table + FT_Lookup_Renderer + FT_Match_Size + FT_Matrix_Invert + FT_Matrix_Multiply + FT_MulDiv + FT_MulDiv_No_Round + FT_MulFix + FT_New_Face + FT_New_GlyphSlot + FT_New_Library + FT_New_Memory + FT_New_Memory_Face + FT_New_Size + FT_OpenType_Free + FT_OpenType_Validate + FT_Open_Face + FT_Outline_Check + FT_Outline_Copy + FT_Outline_Decompose + FT_Outline_Done + FT_Outline_Done_Internal + FT_Outline_Embolden + FT_Outline_GetInsideBorder + FT_Outline_GetOutsideBorder + FT_Outline_Get_BBox + FT_Outline_Get_Bitmap + FT_Outline_Get_CBox + FT_Outline_Get_Orientation + FT_Outline_New + FT_Outline_New_Internal + FT_Outline_Render + FT_Outline_Reverse + FT_Outline_Transform + FT_Outline_Translate + FT_Raccess_Get_DataOffsets + FT_Raccess_Get_HeaderInfo + FT_Raccess_Guess + FT_Remove_Module + FT_Render_Glyph + FT_Render_Glyph_Internal + FT_Request_Metrics + FT_Request_Size + FT_RoundFix + FT_Select_Charmap + FT_Select_Metrics + FT_Select_Size + FT_Set_Char_Size + FT_Set_Charmap + FT_Set_Debug_Hook + FT_Set_MM_Blend_Coordinates + FT_Set_MM_Design_Coordinates + FT_Set_Pixel_Sizes + FT_Set_Renderer + FT_Set_Transform + FT_Set_Var_Blend_Coordinates + FT_Set_Var_Design_Coordinates + FT_Sfnt_Table_Info + FT_Sin + FT_SqrtFixed + FT_Stream_Close + FT_Stream_EnterFrame + FT_Stream_ExitFrame + FT_Stream_ExtractFrame + FT_Stream_Free + FT_Stream_GetChar + FT_Stream_GetLong + FT_Stream_GetLongLE + FT_Stream_GetOffset + FT_Stream_GetShort + FT_Stream_GetShortLE + FT_Stream_New + FT_Stream_Open + FT_Stream_OpenGzip + FT_Stream_OpenLZW + FT_Stream_OpenMemory + FT_Stream_Pos + FT_Stream_Read + FT_Stream_ReadAt + FT_Stream_ReadChar + FT_Stream_ReadFields + FT_Stream_ReadLong + FT_Stream_ReadLongLE + FT_Stream_ReadOffset + FT_Stream_ReadShort + FT_Stream_ReadShortLE + FT_Stream_ReleaseFrame + FT_Stream_Seek + FT_Stream_Skip + FT_Stream_TryRead + FT_Stroker_BeginSubPath + FT_Stroker_ConicTo + FT_Stroker_CubicTo + FT_Stroker_Done + FT_Stroker_EndSubPath + FT_Stroker_Export + FT_Stroker_ExportBorder + FT_Stroker_GetBorderCounts + FT_Stroker_GetCounts + FT_Stroker_LineTo + FT_Stroker_New + FT_Stroker_ParseOutline + FT_Stroker_Rewind + FT_Stroker_Set + FT_Tan + FT_Trace_Get_Count + FT_Trace_Get_Name + FT_TrueTypeGX_Free + FT_TrueTypeGX_Validate + FT_Vector_From_Polar + FT_Vector_Length + FT_Vector_Polarize + FT_Vector_Rotate + FT_Vector_Transform + FT_Vector_Unit + TT_New_Context + TT_RunIns + ft_corner_is_flat + ft_corner_orientation + ft_debug_init + ft_glyphslot_alloc_bitmap + ft_glyphslot_free_bitmap + ft_glyphslot_set_bitmap + ft_highpow2 + ft_mem_alloc + ft_mem_dup + ft_mem_free + ft_mem_qalloc + ft_mem_qrealloc + ft_mem_realloc + ft_mem_strcpyn + ft_mem_strdup + ft_module_get_service + ft_service_list_lookup + ft_synthesize_vertical_metrics + ft_validator_error + ft_validator_init + ft_validator_run diff --git a/src/cd_freetype.mak b/src/cd_freetype.mak new file mode 100644 index 0000000..857c5b2 --- /dev/null +++ b/src/cd_freetype.mak @@ -0,0 +1,39 @@ +PROJNAME = cd +LIBNAME = freetype +OPT = YES + +# Changes to freetype-2.3.5 (search for CDLIB): +# freetype2\freetype\config\ftconfig.h +# were changed to configure the library. +SRC := \ + autofit/autofit.c bdf/bdf.c cff/cff.c base/ftbase.c cache/ftcache.c \ + gzip/ftgzip.c lzw/ftlzw.c gxvalid/gxvalid.c otvalid/otvalid.c pcf/pcf.c \ + pfr/pfr.c psaux/psaux.c pshinter/pshinter.c psnames/psnames.c raster/raster.c \ + sfnt/sfnt.c smooth/smooth.c truetype/truetype.c type1/type1.c cid/type1cid.c \ + type42/type42.c winfonts/winfnt.c \ + base/ftapi.c base/ftbbox.c base/ftbdf.c base/ftbitmap.c base/ftdebug.c \ + base/ftgasp.c base/ftglyph.c base/ftgxval.c base/ftinit.c base/ftlcdfil.c \ + base/ftmm.c base/ftotval.c base/ftpatent.c base/ftpfr.c base/ftstroke.c \ + base/ftsynth.c base/ftsystem.c base/fttype1.c base/ftwinfnt.c base/ftxf86.c +SRC := $(addprefix freetype2/, $(SRC)) + +DEFINES += FT2_BUILD_LIBRARY +INCLUDES = freetype2 +DEF_FILE = cd_freetype.def + +ifneq ($(findstring dll, $(TEC_UNAME)), ) + SRC += cd_freetype.rc +endif + +ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + # To be compatible with the existing DLLs + LIBNAME = freetype6 +endif + +ifneq ($(findstring bc5, $(TEC_UNAME)), ) + FLAGS = -w-8004 +endif + +ifneq ($(findstring Darwin, $(TEC_UNAME)), ) + DEFINES += DARWIN_NO_CARBON +endif diff --git a/src/cd_freetype.rc b/src/cd_freetype.rc new file mode 100644 index 0000000..84d8c5b --- /dev/null +++ b/src/cd_freetype.rc @@ -0,0 +1,20 @@ +1 VERSIONINFO + FILEVERSION 2,3,5,0 + PRODUCTVERSION 2,3,5,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "www.freetype.org\0" + VALUE "CompanyName", "The FreeType Project\0" + VALUE "FileDescription", "FreeType - software font engine\0" + VALUE "FileVersion", "2.3.5\0" + VALUE "LegalCopyright", "Copyright © 1996-2007 David Turner, Robert Wilhelm, and Werner Lemberg.\0" + VALUE "OriginalFilename", "freetype6.dll\0" + VALUE "ProductName", "FreeType for Windows\0" + VALUE "ProductVersion", "2.3.5\0" + VALUE "PrivateBuild", "Build by Tecgraf/PUC-Rio for CD\0" + END + END +END diff --git a/src/cd_image.c b/src/cd_image.c new file mode 100644 index 0000000..002d288 --- /dev/null +++ b/src/cd_image.c @@ -0,0 +1,441 @@ +/** \file + * \brief External API - Images + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "cd_private.h" + + +void cdCanvasGetImageRGB(cdCanvas* canvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + assert(canvas); + assert(r); + assert(g); + assert(b); + assert(w>0); + assert(h>0); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (canvas->cxGetImageRGB) + canvas->cxGetImageRGB(canvas->ctxcanvas, r, g, b, x, y, w, h); +} + +void cdRGB2Gray(int width, int height, const unsigned char* red, const unsigned char* green, const unsigned char* blue, unsigned char* index, long *color) +{ + int c, i, count; + for (c = 0; c < 256; c++) + color[c] = cdEncodeColor((unsigned char)c, (unsigned char)c, (unsigned char)c); + + count = width*height; + for (i=0; i0); + assert(ih>0); + assert(r); + assert(g); + assert(b); + if (!_cdCheckCanvas(canvas)) return; + + if (w == 0) w = iw; + if (h == 0) h = ih; + if (xmax == 0) xmax = iw - 1; + if (ymax == 0) ymax = ih - 1; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + cdNormalizeLimits(iw, ih, &xmin, &xmax, &ymin, &ymax); + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (canvas->bpp <= 8) + { + int height = ymax-ymin+1; + unsigned char* map = (unsigned char*)malloc(iw * height); + int pal_size = 1L << canvas->bpp; + long colors[256]; + + if (!map) + return; + + if (pal_size == 2) /* probably a laser printer, use a gray image for better results */ + cdRGB2Gray(iw, height, r+ymin*iw, g+ymin*iw, b+ymin*iw, map, colors); + else + cdRGB2Map(iw, height, r+ymin*iw, g+ymin*iw, b+ymin*iw, map, pal_size, colors); + + canvas->cxPutImageRectMap(canvas->ctxcanvas, iw, height, map, colors, x, y, w, h, xmin, xmax, 0, height-1); + + free(map); + } + else + canvas->cxPutImageRectRGB(canvas->ctxcanvas, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); +} + +void cdCanvasPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + assert(iw>0); + assert(ih>0); + assert(r); + assert(g); + assert(b); + if (!_cdCheckCanvas(canvas)) return; + + if (w == 0) w = iw; + if (h == 0) h = ih; + if (xmax == 0) xmax = iw - 1; + if (ymax == 0) ymax = ih - 1; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + cdNormalizeLimits(iw, ih, &xmin, &xmax, &ymin, &ymax); + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (!canvas->cxPutImageRectRGBA) + { + if (canvas->cxGetImageRGB) + cdSimPutImageRectRGBA(canvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); + else + canvas->cxPutImageRectRGB(canvas->ctxcanvas, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); + } + else + canvas->cxPutImageRectRGBA(canvas->ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static long* cd_getgraycolormap(void) +{ + static long color_map[256] = {1}; + + if (color_map[0]) + { + int c; + for (c = 0; c < 256; c++) + color_map[c] = cdEncodeColor((unsigned char)c, (unsigned char)c, (unsigned char)c); + } + + return color_map; +} + +void cdCanvasPutImageRectMap(cdCanvas* canvas, int iw, int ih, const unsigned char *index, const long *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + assert(index); + assert(iw>0); + assert(ih>0); + if (!_cdCheckCanvas(canvas)) return; + + if (w == 0) w = iw; + if (h == 0) h = ih; + if (xmax == 0) xmax = iw - 1; + if (ymax == 0) ymax = ih - 1; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + cdNormalizeLimits(iw, ih, &xmin, &xmax, &ymin, &ymax); + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (colors == NULL) + colors = cd_getgraycolormap(); + + canvas->cxPutImageRectMap(canvas->ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); +} + +cdImage* cdCanvasCreateImage(cdCanvas* canvas, int w, int h) +{ + cdImage *image; + cdCtxImage *ctximage; + + assert(canvas); + assert(w>0); + assert(h>0); + if (!_cdCheckCanvas(canvas)) return NULL; + if (w <= 0) return NULL; + if (h <= 0) return NULL; + if (!canvas->cxCreateImage) return NULL; + + ctximage = canvas->cxCreateImage(canvas->ctxcanvas, w, h); + if (!ctximage) + return NULL; + + image = (cdImage*)malloc(sizeof(cdImage)); + + image->cxGetImage = canvas->cxGetImage; + image->cxPutImageRect = canvas->cxPutImageRect; + image->cxKillImage = canvas->cxKillImage; + image->w = w; + image->h = h; + image->ctximage = ctximage; + + return image; +} + +void cdCanvasGetImage(cdCanvas* canvas, cdImage* image, int x, int y) +{ + assert(canvas); + assert(image); + if (!_cdCheckCanvas(canvas)) return; + if (!image) return; + if (image->cxGetImage != canvas->cxGetImage) return; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + canvas->cxGetImage(canvas->ctxcanvas, image->ctximage, x, y); +} + +void cdCanvasPutImageRect(cdCanvas* canvas, cdImage* image, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + assert(image); + if (!_cdCheckCanvas(canvas)) return; + if (!image) return; + if (image->cxPutImageRect != canvas->cxPutImageRect) return; + + if (xmax == 0) xmax = image->w - 1; + if (ymax == 0) ymax = image->h - 1; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + cdNormalizeLimits(image->w, image->h, &xmin, &xmax, &ymin, &ymax); + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + canvas->cxPutImageRect(canvas->ctxcanvas, image->ctximage, x, y, xmin, xmax, ymin, ymax); +} + +void cdKillImage(cdImage* image) +{ + assert(image); + if (!image) return; + + image->cxKillImage(image->ctximage); + memset(image, 0, sizeof(cdImage)); + free(image); +} + +void cdCanvasScrollArea(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + if (!canvas->cxScrollArea) return; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (dx == 0 && dy == 0) + return; + + if (canvas->use_origin) + { + xmin += canvas->origin.x; + xmax += canvas->origin.x; + ymin += canvas->origin.y; + ymax += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + dy = -dy; + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + canvas->cxScrollArea(canvas->ctxcanvas, xmin, xmax, ymin, ymax, dx, dy); +} + +unsigned char cdZeroOrderInterpolation(int width, int height, const unsigned char *map, float xl, float yl) +{ + int x0 = (int)(xl-0.5f); + int y0 = (int)(yl-0.5f); + x0 = x0<0? 0: x0>width-1? width-1: x0; + y0 = y0<0? 0: y0>height-1? height-1: y0; + return map[y0*width + x0]; +} + +unsigned char cdBilinearInterpolation(int width, int height, const unsigned char *map, float xl, float yl) +{ + unsigned char fll, fhl, flh, fhh; + int x0, y0, x1, y1; + float t, u; + + if (xl < 0.5) + { + x1 = x0 = 0; + t = 0; + } + else if (xl > width-0.5) + { + x1 = x0 = width-1; + t = 0; + } + else + { + x0 = (int)(xl-0.5f); + x1 = x0+1; + t = xl - (x0+0.5f); + } + + if (yl < 0.5) + { + y1 = y0 = 0; + u = 0; + } + else if (yl > height-0.5) + { + y1 = y0 = height-1; + u = 0; + } + else + { + y0 = (int)(yl-0.5f); + y1 = y0+1; + u = yl - (y0+0.5f); + } + + fll = map[y0*width + x0]; + fhl = map[y0*width + x1]; + flh = map[y1*width + x0]; + fhh = map[y1*width + x1]; + + return (unsigned char)((fhh - flh - fhl + fll) * u * t + + (fhl - fll) * t + + (flh - fll) * u + + fll); +} + +void cdImageRGBInitInverseTransform(int w, int h, int xmin, int xmax, int ymin, int ymax, float *xfactor, float *yfactor, const double* matrix, double* inv_matrix) +{ + *xfactor = (float)(xmax-xmin)/(float)(w-1); + *yfactor = (float)(ymax-ymin)/(float)(h-1); + cdMatrixInverse(matrix, inv_matrix); +} + +void cdImageRGBInverseTransform(int t_x, int t_y, float *i_x, float *i_y, float xfactor, float yfactor, int xmin, int ymin, int x, int y, double *inv_matrix) +{ + double rx, ry; + cdfMatrixTransformPoint(inv_matrix, t_x, t_y, &rx, &ry); + *i_x = xfactor*((float)rx - x) + xmin; + *i_y = yfactor*((float)ry - y) + ymin; +} + +void cdImageRGBCalcDstLimits(cdCanvas* canvas, int x, int y, int w, int h, int *xmin, int *xmax, int *ymin, int *ymax, int* rect) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, + t_x, t_y, t_w, t_h; + + /* calculate the bounding box of the transformed rectangle */ + cdMatrixTransformPoint(canvas->matrix, x, y, &t_x, &t_y); + if (rect) { rect[0] = t_x; rect[1] = t_y; } + t_xmax = t_xmin = t_x; t_ymax = t_ymin = t_y; + cdMatrixTransformPoint(canvas->matrix, x+w-1, y, &t_x, &t_y); + if (rect) { rect[2] = t_x; rect[3] = t_y; } + if (t_x > t_xmax) t_xmax = t_x; + if (t_x < t_xmin) t_xmin = t_x; + if (t_y > t_ymax) t_ymax = t_y; + if (t_y < t_ymin) t_ymin = t_y; + cdMatrixTransformPoint(canvas->matrix, x+w-1, y+h-1, &t_x, &t_y); + if (rect) { rect[4] = t_x; rect[5] = t_y; } + if (t_x > t_xmax) t_xmax = t_x; + if (t_x < t_xmin) t_xmin = t_x; + if (t_y > t_ymax) t_ymax = t_y; + if (t_y < t_ymin) t_ymin = t_y; + cdMatrixTransformPoint(canvas->matrix, x, y+h-1, &t_x, &t_y); + if (rect) { rect[6] = t_x; rect[7] = t_y; } + if (t_x > t_xmax) t_xmax = t_x; + if (t_x < t_xmin) t_xmin = t_x; + if (t_y > t_ymax) t_ymax = t_y; + if (t_y < t_ymin) t_ymin = t_y; + + t_x = t_xmin; + t_y = t_ymin; + t_w = t_xmax-t_xmin+1; + t_h = t_ymax-t_ymin+1; + + /* check if inside the canvas */ + if (t_x > (canvas->w-1) || t_y > (canvas->h-1) || + (t_x+t_w) < 0 || (t_y+t_h) < 0) + return; + + /* fit to canvas area */ + if (t_x < 0) t_x = 0; + if (t_y < 0) t_y = 0; + if ((t_x+t_w) > (canvas->w-1)) t_w = (canvas->w-1)-t_x; + if ((t_y+t_h) > (canvas->h-1)) t_h = (canvas->h-1)-t_y; + + /* define the destiny limits */ + *xmin = t_x; + *ymin = t_y; + *xmax = t_x+t_w-1; + *ymax = t_y+t_h-1; +} diff --git a/src/cd_pdflib.def b/src/cd_pdflib.def new file mode 100644 index 0000000..5c0cd7c --- /dev/null +++ b/src/cd_pdflib.def @@ -0,0 +1,188 @@ +EXPORTS + PDF_activate_item + PDF_add_bookmark + PDF_add_bookmark2 + PDF_add_launchlink + PDF_add_locallink + PDF_add_nameddest + PDF_add_note + PDF_add_note2 + PDF_add_pdflink + PDF_add_table_cell + PDF_add_textflow + PDF_add_thumbnail + PDF_add_weblink + PDF_arc + PDF_arcn + PDF_attach_file + PDF_attach_file2 + PDF_begin_document + PDF_begin_document_callback + PDF_begin_font + PDF_begin_glyph + PDF_begin_item + PDF_begin_layer + PDF_begin_mc + PDF_begin_page + PDF_begin_page_ext + PDF_begin_pattern + PDF_begin_template + PDF_begin_template_ext + PDF_boot + PDF_check_context + PDF_circle + PDF_clip + PDF_close + PDF_close_image + PDF_close_pdi + PDF_close_pdi_document + PDF_close_pdi_page + PDF_closepath + PDF_closepath_fill_stroke + PDF_closepath_stroke + PDF_concat + PDF_continue_text + PDF_continue_text2 + PDF_create_3dview + PDF_create_action + PDF_create_annotation + PDF_create_bookmark + PDF_create_field + PDF_create_fieldgroup + PDF_create_gstate + PDF_create_pvf + PDF_create_textflow + PDF_curveto + PDF_define_layer + PDF_delete + PDF_delete_pvf + PDF_delete_table + PDF_delete_textflow + PDF_encoding_set_char + PDF_end_document + PDF_end_font + PDF_end_glyph + PDF_end_item + PDF_end_layer + PDF_end_mc + PDF_end_page + PDF_end_page_ext + PDF_end_pattern + PDF_end_template + PDF_endpath + PDF_fill + PDF_fill_imageblock + PDF_fill_pdfblock + PDF_fill_stroke + PDF_fill_textblock + PDF_findfont + PDF_fit_image + PDF_fit_pdi_page + PDF_fit_table + PDF_fit_textflow + PDF_fit_textline + PDF_get_api + PDF_get_apiname + PDF_get_buffer + PDF_get_errmsg + PDF_get_errnum + PDF_get_kern_amount + PDF_get_majorversion + PDF_get_minorversion + PDF_get_opaque + PDF_get_parameter + PDF_get_pdi_parameter + PDF_get_pdi_value + PDF_get_value + PDF_info_font + PDF_info_matchbox + PDF_info_table + PDF_info_textflow + PDF_info_textline + PDF_initgraphics + PDF_lineto + PDF_load_3ddata + PDF_load_font + PDF_load_iccprofile + PDF_load_image + PDF_makespotcolor + PDF_mc_point + PDF_moveto + PDF_new + PDF_new2 + PDF_open_CCITT + PDF_open_file + PDF_open_image + PDF_open_image_file + PDF_open_mem + PDF_open_pdi + PDF_open_pdi_callback + PDF_open_pdi_document + PDF_open_pdi_page + PDF_pcos_get_number + PDF_pcos_get_stream + PDF_pcos_get_string + PDF_place_image + PDF_place_pdi_page + PDF_process_pdi + PDF_rcurveto + PDF_rect + PDF_restore + PDF_resume_page + PDF_rlineto + PDF_rmoveto + PDF_rotate + PDF_save + PDF_scale + PDF_set_border_color + PDF_set_border_dash + PDF_set_border_style + PDF_set_gstate + PDF_set_info + PDF_set_info2 + PDF_set_layer_dependency + PDF_set_parameter + PDF_set_text_pos + PDF_set_value + PDF_setcolor + PDF_setdash + PDF_setdashpattern + PDF_setflat + PDF_setfont + PDF_setgray + PDF_setgray_fill + PDF_setgray_stroke + PDF_setlinecap + PDF_setlinejoin + PDF_setlinewidth + PDF_setmatrix + PDF_setmiterlimit + PDF_setpolydash + PDF_setrgbcolor + PDF_setrgbcolor_fill + PDF_setrgbcolor_stroke + PDF_shading + PDF_shading_pattern + PDF_shfill + PDF_show + PDF_show2 + PDF_show_boxed + PDF_show_boxed2 + PDF_show_xy + PDF_show_xy2 + PDF_shutdown + PDF_skew + PDF_stringwidth + PDF_stringwidth2 + PDF_stroke + PDF_suspend_page + PDF_translate + PDF_utf16_to_utf8 + PDF_utf32_to_utf16 + PDF_utf8_to_utf16 + PDF_xshow + pdf_catch + pdf_exit_try + pdf_jbuf + pdf_rethrow + pdf_throw diff --git a/src/cd_pdflib.mak b/src/cd_pdflib.mak new file mode 100644 index 0000000..194c36a --- /dev/null +++ b/src/cd_pdflib.mak @@ -0,0 +1,135 @@ +PROJNAME = cd +LIBNAME = pdflib +OPT = YES + +DEF_FILE = cd_pdflib.def + +ifeq ($(TEC_UNAME), ppc) + DEFINES = WORDS_BIGENDIAN +endif +ifeq ($(TEC_UNAME), mips) + DEFINES = WORDS_BIGENDIAN +endif +ifeq ($(TEC_UNAME), sparc) + DEFINES = WORDS_BIGENDIAN +endif + +# Changes to PDFlib-Lite-7.0.0p3 (search for CDPDF): +# pdflib/pdcore/pc_config.h - added default PDF_PLATFORM +# pdflib/pdflib/p_intern.h - removed support for other image formats, leave this to IM */ +# pdflib/pdflib/p_png.c - added some type casts, fixed position of pdf_png_read_data, renamed flate to pdf_comp_flate. +# pdflib/pdflib/p_gif.c - added missing pdf_cleanup_gif +# pdflib/pdflib/p_jpeg.c - added missing pdf_cleanup_jpeg +# pdflib/pdflib/p_tiff.c - fixed pdf_is_TIFF_file definition +# pdflib/pdflib/p_image.h - replaced toff_t by pdc_uint32 + +srcdir := pdflib/font +INCLUDES := $(INCLUDES) $(srcdir) +SRCFONT := \ + $(srcdir)/ft_cid.c \ + $(srcdir)/ft_corefont.c \ + $(srcdir)/ft_font.c \ + $(srcdir)/ft_hostfont.c \ + $(srcdir)/ft_pdffont.c \ + $(srcdir)/ft_truetype.c \ + $(srcdir)/ft_type1.c + +srcdir := pdflib/flate +INCLUDES := $(INCLUDES) $(srcdir) +SRCFLATE := \ + $(srcdir)/adler32.c \ + $(srcdir)/compress.c \ + $(srcdir)/crc32.c \ + $(srcdir)/deflate.c \ + $(srcdir)/inffast.c \ + $(srcdir)/inflate.c \ + $(srcdir)/inftrees.c \ + $(srcdir)/trees.c \ + $(srcdir)/uncompr.c \ + $(srcdir)/zutil.c + +srcdir := pdflib/pdcore +INCLUDES := $(INCLUDES) $(srcdir) +SRCPDCORE := \ + $(srcdir)/pc_aes.c \ + $(srcdir)/pc_aescbc.c \ + $(srcdir)/pc_arc4.c \ + $(srcdir)/pc_chartabs.c \ + $(srcdir)/pc_contain.c \ + $(srcdir)/pc_core.c \ + $(srcdir)/pc_crypt.c \ + $(srcdir)/pc_ctype.c \ + $(srcdir)/pc_digsig.c \ + $(srcdir)/pc_ebcdic.c \ + $(srcdir)/pc_encoding.c \ + $(srcdir)/pc_file.c \ + $(srcdir)/pc_geom.c \ + $(srcdir)/pc_md5.c \ + $(srcdir)/pc_optparse.c \ + $(srcdir)/pc_output.c \ + $(srcdir)/pc_resource.c \ + $(srcdir)/pc_scan.c \ + $(srcdir)/pc_scope.c \ + $(srcdir)/pc_string.c \ + $(srcdir)/pc_unicode.c \ + $(srcdir)/pc_util.c \ + $(srcdir)/pc_xmp.c + +srcdir := pdflib/pdflib +INCLUDES := $(INCLUDES) $(srcdir) +SRCPDFLIB := \ + $(srcdir)/p_3d.c \ + $(srcdir)/p_actions.c \ + $(srcdir)/p_afm.c \ + $(srcdir)/p_annots.c \ + $(srcdir)/p_block.c \ + $(srcdir)/p_bmp.c \ + $(srcdir)/p_ccitt.c \ + $(srcdir)/p_cid.c \ + $(srcdir)/p_color.c \ + $(srcdir)/p_document.c \ + $(srcdir)/p_draw.c \ + $(srcdir)/p_encoding.c \ + $(srcdir)/p_fields.c \ + $(srcdir)/p_filter.c \ + $(srcdir)/p_font.c \ + $(srcdir)/p_gif.c \ + $(srcdir)/p_gstate.c \ + $(srcdir)/p_hyper.c \ + $(srcdir)/p_icc.c \ + $(srcdir)/p_icclib.c \ + $(srcdir)/p_image.c \ + $(srcdir)/p_jpeg.c \ + $(srcdir)/p_jpx.c \ + $(srcdir)/p_kerning.c \ + $(srcdir)/p_layer.c \ + $(srcdir)/p_mbox.c \ + $(srcdir)/p_object.c \ + $(srcdir)/p_opi.c \ + $(srcdir)/p_page.c \ + $(srcdir)/p_params.c \ + $(srcdir)/p_pattern.c \ + $(srcdir)/p_pdi.c \ + $(srcdir)/p_pfm.c \ + $(srcdir)/p_photoshp.c \ + $(srcdir)/p_png.c \ + $(srcdir)/p_shading.c \ + $(srcdir)/p_subsett.c \ + $(srcdir)/p_table.c \ + $(srcdir)/p_tagged.c \ + $(srcdir)/p_template.c \ + $(srcdir)/p_text.c \ + $(srcdir)/p_textflow.c \ + $(srcdir)/p_tiff.c \ + $(srcdir)/p_truetype.c \ + $(srcdir)/p_type1.c \ + $(srcdir)/p_type3.c \ + $(srcdir)/p_util.c \ + $(srcdir)/p_xgstate.c \ + $(srcdir)/p_xmp.c + +SRC := pdflib/pdflib/pdflib.c $(SRCPDFLIB) $(SRCPDCORE) $(SRCFLATE) $(SRCFONT) + +ifneq ($(findstring dll, $(TEC_UNAME)), ) + SRC += cd_pdflib.rc +endif diff --git a/src/cd_pdflib.rc b/src/cd_pdflib.rc new file mode 100644 index 0000000..89691d0 --- /dev/null +++ b/src/cd_pdflib.rc @@ -0,0 +1,20 @@ +1 VERSIONINFO + FILEVERSION 7,0,2,0 + PRODUCTVERSION 7,0,2,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "www.pdflib.com\0" + VALUE "CompanyName", "PDFlib GmbH\0" + VALUE "FileDescription", "PDFlib - a library for generating PDF on the fly\0" + VALUE "FileVersion", "7.0.2\0" + VALUE "LegalCopyright", "Copyright © 1997-2007 PDFlib GmbH\0" + VALUE "OriginalFilename", "pdflib.dll\0" + VALUE "ProductName", "PDFlib Lite for Windows\0" + VALUE "ProductVersion", "7.0.2\0" + VALUE "PrivateBuild", "Build by Tecgraf/PUC-Rio for CD (removed support for image formats)\0" + END + END +END diff --git a/src/cd_primitives.c b/src/cd_primitives.c new file mode 100644 index 0000000..b1a19ba --- /dev/null +++ b/src/cd_primitives.c @@ -0,0 +1,702 @@ +/** \file + * \brief External API - Primitives + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "cd_private.h" + +#define _CD_POLY_BLOCK 100 + +void cdCanvasPixel(cdCanvas* canvas, int x, int y, long color) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + canvas->cxPixel(canvas->ctxcanvas, x, y, color); +} + +void cdCanvasMark(cdCanvas* canvas, int x, int y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->mark_size == 1) + { + cdCanvasPixel(canvas, x, y, canvas->foreground); + return; + } + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + cdSimMark(canvas, x, y); +} + +void cdCanvasLine(cdCanvas* canvas, int x1, int y1, int x2, int y2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (x1 == x2 && y1 == y2) + { + cdCanvasPixel(canvas, x1, y1, canvas->foreground); + return; + } + + if (canvas->use_origin) + { + x1 += canvas->origin.x; + y1 += canvas->origin.y; + x2 += canvas->origin.x; + y2 += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + y1 = _cdInvertYAxis(canvas, y1); + y2 = _cdInvertYAxis(canvas, y2); + } + + canvas->cxLine(canvas->ctxcanvas, x1, y1, x2, y2); +} + +void cdfCanvasLine(cdCanvas* canvas, double x1, double y1, double x2, double y2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (x1 == x2 && y1 == y2) + { + cdCanvasPixel(canvas, _cdRound(x1), _cdRound(y1), canvas->foreground); + return; + } + + if (canvas->use_origin) + { + x1 += canvas->forigin.x; + y1 += canvas->forigin.y; + x2 += canvas->forigin.x; + y2 += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + { + y1 = _cdInvertYAxis(canvas, y1); + y2 = _cdInvertYAxis(canvas, y2); + } + + if (canvas->cxFLine) + canvas->cxFLine(canvas->ctxcanvas, x1, y1, x2, y2); + else + canvas->cxLine(canvas->ctxcanvas, _cdRound(x1), _cdRound(y1), _cdRound(x2), _cdRound(y2)); +} + +void cdCanvasBegin(cdCanvas* canvas, int mode) +{ + assert(canvas); + assert(mode>=CD_FILL); + if (!_cdCheckCanvas(canvas)) return; + + if (mode == CD_REGION) + { + if (!canvas->cxNewRegion) return; + + canvas->new_region = 1; + canvas->poly_n = 0; + canvas->cxNewRegion(canvas->ctxcanvas); + return; + } + + canvas->sim_poly = 0; + + if (canvas->interior_style == CD_HOLLOW && mode == CD_FILL) + mode = CD_CLOSED_LINES; + + /* simulacao de linhas */ + if ((mode == CD_CLOSED_LINES || mode == CD_OPEN_LINES || mode == CD_BEZIER) && + canvas->sim_mode & CD_SIM_POLYLINE) + canvas->sim_poly = 1; + + /* simulacao de poligonos preenchidos */ + if (mode == CD_FILL && canvas->sim_mode & CD_SIM_POLYGON) + canvas->sim_poly = 1; + + canvas->use_fpoly = -1; + canvas->poly_n = 0; + canvas->poly_mode = mode; +} + +void cdCanvasVertex(cdCanvas* canvas, int x, int y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + if (canvas->use_fpoly == 1) return; /* integer vertex inside a real poligon */ + + if (!canvas->poly) + { + canvas->poly = (cdPoint*)malloc(sizeof(cdPoint)*(_CD_POLY_BLOCK+1)); /* always add 1 so we add another point at the end if necessary */ + canvas->poly_size = _CD_POLY_BLOCK; + } + + canvas->use_fpoly = 0; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (canvas->poly_n == canvas->poly_size) + { + canvas->poly_size += _CD_POLY_BLOCK; + canvas->poly = (cdPoint*)realloc(canvas->poly, sizeof(cdPoint) * (canvas->poly_size+1)); + } + + if (canvas->poly_mode != CD_BEZIER && + canvas->poly_n > 0 && + canvas->poly[canvas->poly_n-1].x == x && + canvas->poly[canvas->poly_n-1].y == y) + return; /* avoid duplicate points, if not a bezier */ + + canvas->poly[canvas->poly_n].x = x; + canvas->poly[canvas->poly_n].y = y; + canvas->poly_n++; +} + +void cdfCanvasVertex(cdCanvas* canvas, double x, double y) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!canvas->cxFPoly) + { + cdCanvasVertex(canvas, _cdRound(x), _cdRound(y)); + return; + } + + if (canvas->use_fpoly == 0) return; /* real vertex inside a integer poligon */ + + if (!canvas->fpoly) + { + canvas->fpoly = (cdfPoint*)malloc(sizeof(cdfPoint)*(_CD_POLY_BLOCK+1)); + canvas->fpoly_size = _CD_POLY_BLOCK; + } + + canvas->use_fpoly = 1; + + if (canvas->use_origin) + { + x += canvas->forigin.x; + y += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (canvas->poly_n == canvas->fpoly_size) + { + canvas->fpoly_size += _CD_POLY_BLOCK; + canvas->fpoly = (cdfPoint*)realloc(canvas->fpoly, sizeof(cdfPoint) * (canvas->fpoly_size+1)); + } + + canvas->fpoly[canvas->poly_n].x = x; + canvas->fpoly[canvas->poly_n].y = y; + canvas->poly_n++; +} + +void cdCanvasEnd(cdCanvas* canvas) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->new_region && canvas->poly_n == 0) + { + canvas->new_region = 0; + if (canvas->clip_mode == CD_CLIPREGION) cdCanvasClip(canvas, CD_CLIPREGION); + return; + } + + if (canvas->poly_mode==CD_OPEN_LINES && canvas->poly_n < 2) + { + canvas->poly_n = 0; + return; + } + + if (canvas->poly_mode==CD_BEZIER && (canvas->poly_n < 4 || ((canvas->poly_n-4)%3 != 0))) + { + canvas->poly_n = 0; + return; + } + + if ((canvas->poly_mode == CD_CLOSED_LINES || + canvas->poly_mode == CD_FILL || + canvas->poly_mode == CD_CLIP) && canvas->poly_n < 3) + { + canvas->poly_n = 0; + return; + } + + if (canvas->sim_poly) + cdpolySIM(canvas->ctxcanvas, canvas->poly_mode, canvas->poly, canvas->poly_n); + else + { + if (canvas->use_fpoly) + canvas->cxFPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->fpoly, canvas->poly_n); + else + canvas->cxPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->poly, canvas->poly_n); + } + + if (canvas->poly_mode == CD_CLIP) + { + canvas->clip_poly_n = canvas->poly_n; + + if (canvas->clip_fpoly) + { + free(canvas->clip_fpoly); + canvas->clip_fpoly = NULL; + } + + if (canvas->clip_poly) + { + free(canvas->clip_poly); + canvas->clip_poly = NULL; + } + + if (canvas->use_fpoly) + { + canvas->clip_fpoly = (cdfPoint*)malloc((canvas->poly_n+1) * sizeof(cdfPoint)); + memcpy(canvas->clip_fpoly, canvas->fpoly, canvas->poly_n * sizeof(cdfPoint)); + } + else + { + canvas->clip_poly = (cdPoint*)malloc((canvas->poly_n+1) * sizeof(cdPoint)); + memcpy(canvas->clip_poly, canvas->poly, canvas->poly_n * sizeof(cdPoint)); + } + } + + canvas->poly_n = 0; + canvas->use_fpoly = -1; +} + +void cdCanvasRect(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->origin.x; + xmax += canvas->origin.x; + ymin += canvas->origin.y; + ymax += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + canvas->cxRect(canvas->ctxcanvas, xmin, xmax, ymin, ymax); +} + +void cdfCanvasRect(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (!cdfCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->origin.x; + xmax += canvas->origin.x; + ymin += canvas->origin.y; + ymax += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapDouble(ymin, ymax); + } + + if (canvas->cxFRect) + canvas->cxFRect(canvas->ctxcanvas, xmin, xmax, ymin, ymax); + else + canvas->cxRect(canvas->ctxcanvas, _cdRound(xmin), _cdRound(xmax), _cdRound(ymin), _cdRound(ymax)); +} + +void cdCanvasBox(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->interior_style == CD_HOLLOW) + { + cdCanvasRect(canvas, xmin, xmax, ymin, ymax); + return; + } + + if (!cdCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->origin.x; + xmax += canvas->origin.x; + ymin += canvas->origin.y; + ymax += canvas->origin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + canvas->cxBox(canvas->ctxcanvas, xmin, xmax, ymin, ymax); +} + +void cdfCanvasBox(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (canvas->interior_style == CD_HOLLOW) + { + cdfCanvasRect(canvas, xmin, xmax, ymin, ymax); + return; + } + + if (!cdfCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) + return; + + if (canvas->use_origin) + { + xmin += canvas->forigin.x; + xmax += canvas->forigin.x; + ymin += canvas->forigin.y; + ymax += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + { + ymin = _cdInvertYAxis(canvas, ymin); + ymax = _cdInvertYAxis(canvas, ymax); + _cdSwapDouble(ymin, ymax); + } + + if (canvas->cxFBox) + canvas->cxFBox(canvas->ctxcanvas, xmin, xmax, ymin, ymax); + else + canvas->cxBox(canvas->ctxcanvas, _cdRound(xmin), _cdRound(xmax), _cdRound(ymin), _cdRound(ymax)); +} + +static void normAngles(double *angle1, double *angle2) +{ + *angle1 = fmod(*angle1,360); + *angle2 = fmod(*angle2,360); + if (*angle2 <= *angle1) *angle2 += 360; +} + +void cdCanvasArc(cdCanvas* canvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->use_origin) + { + xc += canvas->origin.x; + yc += canvas->origin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + canvas->cxArc(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); +} + +void cdfCanvasArc(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->use_origin) + { + xc += canvas->forigin.x; + yc += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + + if (canvas->cxFArc) + canvas->cxFArc(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); + else + canvas->cxArc(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); +} + +void cdCanvasSector(cdCanvas* canvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->interior_style == CD_HOLLOW) + { + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + if (fabs(angle2-angle1) < 360) + { + int xi,yi,xf,yf; + + xi = xc + cdRound(w*cos(CD_DEG2RAD*angle1)/2.0); + yi = yc + cdRound(h*sin(CD_DEG2RAD*angle1)/2.0); + + xf = xc + cdRound(w*cos(CD_DEG2RAD*angle2)/2.0); + yf = yc + cdRound(h*sin(CD_DEG2RAD*angle2)/2.0); + + cdCanvasLine(canvas, xi, yi, xc, yc); + cdCanvasLine(canvas, xc, yc, xf, yf); + } + + return; + } + + if (canvas->use_origin) + { + xc += canvas->origin.x; + yc += canvas->origin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + canvas->cxSector(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); +} + +void cdfCanvasSector(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->interior_style == CD_HOLLOW) + { + cdfCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + if (fabs(angle2-angle1) < 360) + { + double xi,yi,xf,yf; + + xi = xc + w*cos(CD_DEG2RAD*angle1)/2.0; + yi = yc + h*sin(CD_DEG2RAD*angle1)/2.0; + + xf = xc + w*cos(CD_DEG2RAD*angle2)/2.0; + yf = yc + h*sin(CD_DEG2RAD*angle2)/2.0; + + cdfCanvasLine(canvas, xi, yi, xc, yc); + cdfCanvasLine(canvas, xc, yc, xf, yf); + } + + return; + } + + if (canvas->use_origin) + { + xc += canvas->forigin.x; + yc += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + if (canvas->cxFSector) + canvas->cxFSector(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); + else + canvas->cxSector(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); +} + +void cdCanvasChord(cdCanvas* canvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->interior_style == CD_HOLLOW) + { + int xi,yi,xf,yf; + + xi = xc + cdRound(w*cos(CD_DEG2RAD*angle1)/2.0); + yi = yc + cdRound(h*sin(CD_DEG2RAD*angle1)/2.0); + + xf = xc + cdRound(w*cos(CD_DEG2RAD*angle2)/2.0); + yf = yc + cdRound(h*sin(CD_DEG2RAD*angle2)/2.0); + + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + if (fabs(angle2-angle1) < 360) + cdCanvasLine(canvas, xi, yi, xf, yf); + + return; + } + + if (canvas->use_origin) + { + xc += canvas->origin.x; + yc += canvas->origin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + canvas->cxChord(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); +} + +void cdfCanvasChord(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (angle1 == angle2 || w == 0 || h == 0) + return; + + normAngles(&angle1, &angle2); + + if (canvas->interior_style == CD_HOLLOW) + { + double xi,yi,xf,yf; + + xi = xc + w*cos(CD_DEG2RAD*angle1)/2.0; + yi = yc + h*sin(CD_DEG2RAD*angle1)/2.0; + + xf = xc + w*cos(CD_DEG2RAD*angle2)/2.0; + yf = yc + h*sin(CD_DEG2RAD*angle2)/2.0; + + cdfCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + if (fabs(angle2-angle1) < 360) + cdfCanvasLine(canvas, xi, yi, xf, yf); + + return; + } + + if (canvas->use_origin) + { + xc += canvas->forigin.x; + yc += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + yc = _cdInvertYAxis(canvas, yc); + + if (canvas->cxFChord) + canvas->cxFChord(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); + else + canvas->cxChord(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); +} + +void cdCanvasGetEllipseBox(int xc, int yc, int w, int h, double a1, double a2, int *xmin, int *xmax, int *ymin, int *ymax) +{ +#define _BBOX() \ + if (x > *xmax) *xmax = x; \ + if (y > *ymax) *ymax = y; \ + if (x < *xmin) *xmin = x; \ + if (y < *ymin) *ymin = y; + + int x, y; + + *xmin = (int)(xc+w/2*cos(a1*CD_DEG2RAD)); + *ymin = (int)(yc+h/2*sin(a1*CD_DEG2RAD)); + *xmax = *xmin; + *ymax = *ymin; + + x = (int)(xc+w/2*cos(a2*CD_DEG2RAD)); + y = (int)(yc+h/2*sin(a2*CD_DEG2RAD)); + _BBOX() + + if (a1 > a2) + { + x = xc+w/2; + y = yc; + _BBOX() + } + if ((a1<90 && 90a2 && a2>90) || (a2a2 && a2>180) || (a2a2 && a2>270) || (a2 +#include +#include +#include +#include +#include + + +#include "cd.h" +#include "cd_private.h" + + +void cdCanvasText(cdCanvas* canvas, int x, int y, const char *s) +{ + assert(canvas); + assert(s); + if (!_cdCheckCanvas(canvas)) return; + + if (s[0] == 0) + return; + + if (canvas->use_origin) + { + x += canvas->origin.x; + y += canvas->origin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + canvas->cxText(canvas->ctxcanvas, x, y, s); +} + +void cdfCanvasText(cdCanvas* canvas, double x, double y, const char *s) +{ + assert(canvas); + assert(s); + if (!_cdCheckCanvas(canvas)) return; + + if (s[0] == 0) + return; + + if (canvas->use_origin) + { + x += canvas->forigin.x; + y += canvas->forigin.y; + } + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + if (canvas->cxFText) + canvas->cxFText(canvas->ctxcanvas, x, y, s); + else + canvas->cxText(canvas->ctxcanvas, _cdRound(x), _cdRound(y), s); +} + +int cdGetFontSizePixels(cdCanvas* canvas, int size) +{ + if (size < 0) + size = -size; + else + { + double size_mm = (double)size/CD_MM2PT; + size = cdRound(size_mm*canvas->xres); + } + + if (size == 0) + size = 1; + + return size; +} + +int cdGetFontSizePoints(cdCanvas* canvas, int size) +{ + if (size < 0) + { + double size_mm = ((double)-size)/canvas->xres; + size = cdRound(size_mm * CD_MM2PT); + } + + if (size == 0) + size = 1; + + return size; +} + +int cdCanvasFont(cdCanvas* canvas, const char* type_face, int style, int size) +{ + assert(canvas); + assert(style>=-1 && style<=CD_STRIKEOUT); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (!type_face || type_face[0]==0) + type_face = canvas->font_type_face; + if (style==-1) + style = canvas->font_style; + if (size==0) + size = canvas->font_size; + + if (strcmp(type_face, canvas->font_type_face)==0 && + style == canvas->font_style && + size == canvas->font_size) + return 1; + + if (canvas->cxFont(canvas->ctxcanvas, type_face, style, size)) + { + strcpy(canvas->font_type_face, type_face); + canvas->font_style = style; + canvas->font_size = size; + canvas->native_font[0] = 0; + return 1; + } + + return 0; +} + +void cdCanvasGetFont(cdCanvas* canvas, char *type_face, int *style, int *size) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + + if (type_face) strcpy(type_face, canvas->font_type_face); + if (style) *style = canvas->font_style; + if (size) *size = canvas->font_size; +} + +char* cdCanvasNativeFont(cdCanvas* canvas, const char* font) +{ + static char native_font[1024] = ""; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return NULL; + + strcpy(native_font, canvas->native_font); + + if (!font || font[0] == 0) + return native_font; + + if (font == (char*)CD_QUERY) + { + char style[200] = " "; + if (canvas->font_style&CD_BOLD) + strcat(style, "Bold "); + if (canvas->font_style&CD_ITALIC) + strcat(style, "Italic "); + if (canvas->font_style&CD_UNDERLINE) + strcat(style, "Underline "); + if (canvas->font_style&CD_STRIKEOUT) + strcat(style, "Strikeout "); + + sprintf(native_font, "%s,%s %d", canvas->font_type_face, style, canvas->font_size); + return native_font; + } + + if (canvas->cxNativeFont) + { + if (canvas->cxNativeFont(canvas->ctxcanvas, font)) + strcpy(canvas->native_font, font); + } + else + { + char type_face[1024]; + int size, style = CD_PLAIN; + + if (!cdParseIupWinFont(font, type_face, &style, &size)) + { + if (!cdParseXWinFont(font, type_face, &style, &size)) + { + if (!cdParsePangoFont(font, type_face, &style, &size)) + return native_font; + } + } + + if (cdCanvasFont(canvas, type_face, style, size)) + strcpy(canvas->native_font, font); + } + + return native_font; +} + +int cdCanvasTextAlignment(cdCanvas* canvas, int alignment) +{ + int text_alignment; + + assert(canvas); + assert(alignment==CD_QUERY || (alignment>=CD_NORTH && alignment<=CD_BASE_RIGHT)); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + if (alignmentCD_BASE_RIGHT); + + text_alignment = canvas->text_alignment; + + if (alignment == CD_QUERY || alignment == text_alignment) + return text_alignment; + + if (canvas->cxTextAlignment) + canvas->text_alignment = canvas->cxTextAlignment(canvas->ctxcanvas, alignment); + else + canvas->text_alignment = alignment; + + return text_alignment; +} + +double cdCanvasTextOrientation(cdCanvas* canvas, double angle) +{ + double text_orientation; + + assert(canvas); + if (!_cdCheckCanvas(canvas)) return CD_ERROR; + + text_orientation = canvas->text_orientation; + + if (angle == CD_QUERY || angle == text_orientation) + return text_orientation; + + if (canvas->cxTextOrientation) + canvas->text_orientation = canvas->cxTextOrientation(canvas->ctxcanvas, angle); + else + canvas->text_orientation = angle; + + return text_orientation; +} + +void cdCanvasGetFontDim(cdCanvas* canvas, int *max_width, int *height, int *ascent, int *descent) +{ + assert(canvas); + if (!_cdCheckCanvas(canvas)) return; + canvas->cxGetFontDim(canvas->ctxcanvas, max_width, height, ascent, descent); +} + +void cdCanvasGetTextSize(cdCanvas* canvas, const char *s, int *width, int *height) +{ + assert(canvas); + assert(s); + if (!_cdCheckCanvas(canvas)) return; + canvas->cxGetTextSize(canvas->ctxcanvas, s, width, height); +} + +void cdTextTranslatePoint(cdCanvas* canvas, int x, int y, int w, int h, int baseline, int *rx, int *ry) +{ + /* move to left */ + switch (canvas->text_alignment) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + *rx = x - w; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + *rx = x - w/2; + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + *rx = x; + break; + } + + /* move to bottom */ + switch (canvas->text_alignment) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + if (canvas->invert_yaxis) + *ry = y + baseline; + else + *ry = y - baseline; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + *ry = y; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + if (canvas->invert_yaxis) + *ry = y + h; + else + *ry = y - h; + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + if (canvas->invert_yaxis) + *ry = y + h/2; + else + *ry = y - h/2; + break; + } +} + +void cdCanvasGetTextBounds(cdCanvas* canvas, int x, int y, const char *s, int *rect) +{ + int w, h, ascent, height, baseline; + int xmin, xmax, ymin, ymax; + int old_invert_yaxis = canvas->invert_yaxis; + + cdCanvasGetTextSize(canvas, s, &w, &h); + cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + /* in this case we are always upwards */ + canvas->invert_yaxis = 0; + + /* move to bottom-left */ + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin); + + xmax = xmin + w-1; + ymax = ymin + h-1; + + if (canvas->text_orientation) + { + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + + cdRotatePoint(canvas, xmin, ymin, x, y, &rect[0], &rect[1], sin_theta, cos_theta); + cdRotatePoint(canvas, xmax, ymin, x, y, &rect[2], &rect[3], sin_theta, cos_theta); + cdRotatePoint(canvas, xmax, ymax, x, y, &rect[4], &rect[5], sin_theta, cos_theta); + cdRotatePoint(canvas, xmin, ymax, x, y, &rect[6], &rect[7], sin_theta, cos_theta); + } + else + { + rect[0] = xmin; rect[1] = ymin; + rect[2] = xmax; rect[3] = ymin; + rect[4] = xmax; rect[5] = ymax; + rect[6] = xmin; rect[7] = ymax; + } + + canvas->invert_yaxis = old_invert_yaxis; +} + +void cdCanvasGetTextBox(cdCanvas* canvas, int x, int y, const char *s, int *xmin, int *xmax, int *ymin, int *ymax) +{ + int rect[8]; + int _xmin, _xmax, _ymin, _ymax; + + cdCanvasGetTextBounds(canvas, x, y, s, rect); + + _xmin = rect[0]; + _ymin = rect[1]; + _xmax = rect[0]; + _ymax = rect[1]; + + if(rect[2] < _xmin) _xmin = rect[2]; + if(rect[4] < _xmin) _xmin = rect[4]; + if(rect[6] < _xmin) _xmin = rect[6]; + + if(rect[3] < _ymin) _ymin = rect[3]; + if(rect[5] < _ymin) _ymin = rect[5]; + if(rect[7] < _ymin) _ymin = rect[7]; + + if(rect[2] > _xmax) _xmax = rect[2]; + if(rect[4] > _xmax) _xmax = rect[4]; + if(rect[6] > _xmax) _xmax = rect[6]; + + if(rect[3] > _ymax) _ymax = rect[3]; + if(rect[5] > _ymax) _ymax = rect[5]; + if(rect[7] > _ymax) _ymax = rect[7]; + + if (xmin) *xmin = _xmin; + if (xmax) *xmax = _xmax; + if (ymin) *ymin = _ymin; + if (ymax) *ymax = _ymax; +} + +/**************************************************************/ +/* Native Font Format, compatible with Pango Font Description */ +/**************************************************************/ + +/* +The string contains the font name, the style and the size. +Style can be a free combination of some names separated by spaces. +Font name can be a list of font family names separated by comma. +*/ + +#define isspace(_x) (_x == ' ') + +static int cd_find_style_name(const char *name, int len, int *style) +{ +#define CD_STYLE_NUM_NAMES 21 + static struct { const char* name; int style; } cd_style_names[CD_STYLE_NUM_NAMES] = { + {"Normal", 0}, + {"Oblique", CD_ITALIC}, + {"Italic", CD_ITALIC}, + {"Small-Caps", 0}, + {"Ultra-Light", 0}, + {"Light", 0}, + {"Medium", 0}, + {"Semi-Bold", CD_BOLD}, + {"Bold", CD_BOLD}, + {"Ultra-Bold", CD_BOLD}, + {"Heavy", 0}, + {"Ultra-Condensed",0}, + {"Extra-Condensed",0}, + {"Condensed", 0}, + {"Semi-Condensed", 0}, + {"Semi-Expanded", 0}, + {"Expanded", 0}, + {"Extra-Expanded", 0}, + {"Ultra-Expanded", 0}, + {"Underline", CD_UNDERLINE}, + {"Strikeout", CD_STRIKEOUT} + }; + + int i; + for (i = 0; i < CD_STYLE_NUM_NAMES; i++) + { + if (strncmp(cd_style_names[i].name, name, len)==0) + { + *style = cd_style_names[i].style; + return 1; + } + } + + return 0; +} + +static const char * cd_getword(const char *str, const char *last, int *wordlen) +{ + const char *result; + + while (last > str && isspace(*(last - 1))) + last--; + + result = last; + while (result > str && !isspace (*(result - 1))) + result--; + + *wordlen = last - result; + + return result; +} + +int cdParsePangoFont(const char *nativefont, char *type_face, int *style, int *size) +{ + const char *p, *last; + int len, wordlen; + + len = (int)strlen(nativefont); + last = nativefont + len; + p = cd_getword(nativefont, last, &wordlen); + + /* Look for a size at the end of the string */ + if (wordlen != 0) + { + int new_size = atoi(p); + if (new_size != 0) + { + *size = new_size; + last = p; + } + } + + /* Now parse style words */ + p = cd_getword(nativefont, last, &wordlen); + while (wordlen != 0) + { + int new_style = 0; + + if (!cd_find_style_name(p, wordlen, &new_style)) + break; + else + { + *style |= new_style; + + last = p; + p = cd_getword(nativefont, last, &wordlen); + } + } + + /* Remainder is font family list. */ + + /* Trim off trailing white space */ + while (last > nativefont && isspace(*(last - 1))) + last--; + + /* Trim off trailing commas */ + if (last > nativefont && *(last - 1) == ',') + last--; + + /* Again, trim off trailing white space */ + while (last > nativefont && isspace(*(last - 1))) + last--; + + /* Trim off leading white space */ + while (last > nativefont && isspace(*nativefont)) + nativefont++; + + if (nativefont != last) + { + len = (last - nativefont); + strncpy(type_face, nativefont, len); + type_face[len] = 0; + return 1; + } + else + return 0; +} + +int cdParseIupWinFont(const char *nativefont, char *type_face, int *style, int *size) +{ + int c; + + if (strstr(nativefont, ":") == NULL) + return 0; + + c = strcspn(nativefont, ":"); /* extract type_face */ + if (c == 0) return 0; + strncpy(type_face, nativefont, c); + type_face[c]='\0'; + nativefont += c+1; + + if(nativefont[0] == ':') /* check for attributes */ + nativefont++; + else + { + *style = 0; + while(strlen(nativefont)) /* extract style (bold/italic etc) */ + { + char style_str[20]; + + c = strcspn(nativefont, ":,"); + if (c == 0) + break; + + strncpy(style_str, nativefont, c); + style_str[c] = '\0'; + + if(!strcmp(style_str, "BOLD")) + *style |= CD_BOLD; + else if(!strcmp(style_str,"ITALIC")) + *style |= CD_ITALIC; + else if(!strcmp(style_str,"UNDERLINE")) + *style |= CD_UNDERLINE; + else if(!strcmp(style_str,"STRIKEOUT")) + *style |= CD_STRIKEOUT; + + nativefont += c; + + if(nativefont[0] == ':') /* end attribute list */ + { + nativefont++; + break; + } + + nativefont++; /* skip separator */ + } + } + + /* extract size in points */ + if (sscanf(nativefont, "%d", size) != 1) + return 0; + + if (*size == 0) + return 0; + + return 1; +} + +int cdParseXWinFont(const char *nativefont, char *type_face, int *style, int *size) +{ + char style1[10], style2[10]; + char* token; + char font[1024]; + + if (nativefont[0] != '-') + return 0; + + strcpy(font, nativefont+1); /* skip first '-' */ + + *style = 0; + + /* fndry */ + token = strtok(font, "-"); + if (!token) return 0; + + /* fmly */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(type_face, token); + + /* wght */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(style1, token); + if (strstr("bold", style1)) + *style |= CD_BOLD; + + /* slant */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(style2, token); + if (*style2 == 'i' || *style2 == 'o') + *style |= CD_ITALIC; + + /* sWdth */ + token = strtok(NULL, "-"); + if (!token) return 0; + /* adstyl */ + token = strtok(NULL, "-"); + if (!token) return 0; + + /* pxlsz */ + token = strtok(NULL, "-"); + if (!token) return 0; + *size = -atoi(token); /* size in pixels */ + + if (*size < 0) + return 1; + + /* ptSz */ + token = strtok(NULL, "-"); + if (!token) return 0; + *size = atoi(token)/10; /* size in deci-points */ + + if (*size > 0) + return 1; + + return 0; +} diff --git a/src/cd_util.c b/src/cd_util.c new file mode 100644 index 0000000..033fac6 --- /dev/null +++ b/src/cd_util.c @@ -0,0 +1,285 @@ +/** \file + * \brief Utilities + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include + + +#include "cd.h" + +#include "cd_private.h" + + +int cdRound(double x) +{ + return _cdRound(x); +} + +/* Returns a table to speed up zoom in discrete zoom rotines. + Adds the min parameter and allocates the table using malloc. + The table should be used when mapping from destiny coordinates to + source coordinates (src_pos = tab[dst_pos]). + dst_len is the full destiny size range. + src_len is only the zoomed region size, usually max-min+1. +*/ +int* cdGetZoomTable(int dst_len, int src_len, int src_min) +{ + int dst_i, src_i; + double factor; + int* tab = (int*)malloc(dst_len*sizeof(int)); + + factor = (double)(src_len) / (double)(dst_len); + + for(dst_i = 0; dst_i < dst_len; dst_i++) + { + src_i = cdRound((factor*(dst_i + 0.5)) - 0.5); + tab[dst_i] = src_i + src_min; + } + + return tab; +} + +/* funcao usada para calcular os retangulos efetivos de zoom + de imagens clientes. Pode ser usada para os eixos X e Y. + + canvas_size - tamanho do canvas (canvas->w, canvas->h) + cnv_rect_pos - posicao no canvas onde a regiao sera´ desenhada (x, y) + cnv_rect_size - tamanho da regiao no canvas com zoom (w, h) + img_rect_pos - posicao na imagem da regiao a ser desenhada (min) + img_rect_size - tamanho da regiao na imagem (max-min+1) + + calcula o melhor tamanho a ser usado + retorna 0 se o retangulo resultante e´ nulo +*/ +int cdCalcZoom(int canvas_size, + int cnv_rect_pos, int cnv_rect_size, + int *new_cnv_rect_pos, int *new_cnv_rect_size, + int img_rect_pos, int img_rect_size, + int *new_img_rect_pos, int *new_img_rect_size, + int is_horizontal) +{ + int offset; + float zoom_factor = (float)img_rect_size / (float)cnv_rect_size; + + /* valores default sem otimizacao */ + *new_cnv_rect_size = cnv_rect_size, *new_cnv_rect_pos = cnv_rect_pos; + *new_img_rect_size = img_rect_size, *new_img_rect_pos = img_rect_pos; + + if (cnv_rect_size > 0) + { + /* se posicao no canvas > tamanho do canvas, fora da janela, nao desenha nada */ + if (cnv_rect_pos >= canvas_size) + return 0; + + /* se posicao no canvas + tamanho da regiao no canvas < 0, fora da janela, nao desenha nada */ + if (cnv_rect_pos+cnv_rect_size < 0) + return 0; + + /* se posicao no canvas < 0, entao comeca fora do canvas melhor posicao no canvas e' 0 + E o tamanho e' reduzido do valor negativo */ + if (cnv_rect_pos < 0) + { + /* valores ajustados para cair numa vizinhanca de um pixel da imagem */ + offset = (int)ceil(cnv_rect_pos*zoom_factor); /* offset is <0 */ + offset = (int)ceil(offset/zoom_factor); + *new_cnv_rect_pos -= offset; + *new_cnv_rect_size += offset; + } + + /* se posicao no canvas + tamanho da regiao no canvas > tamanho do canvas, + termina fora do canvas entao + o tamanho da regiao no canvas e' o tamanho do canvas reduzido da posicao */ + if (*new_cnv_rect_pos+*new_cnv_rect_size > canvas_size) + { + offset = (int)((*new_cnv_rect_pos+*new_cnv_rect_size - canvas_size)*zoom_factor); + *new_cnv_rect_size -= (int)(offset/zoom_factor); /* offset is >0 */ + } + } + else + { + /* cnv_rect_size tamanho negativo, significa imagem top down */ + /* calculos adicionados pela Paula */ + + /* se posicao no canvas + tamanho no canvas (xmin+1) >= tamanho do canvas, fora da janela, nao desenha nada */ + if (cnv_rect_pos+cnv_rect_size >= canvas_size) + return 0; + + /* se posicao da imagem com zoom (xmax) < 0, fora da janela, nao desenha nada */ + if (cnv_rect_pos < 0) + return 0; + + /* se posicao com zoom (xmax) >= tamanho do canvas, posicao da imagem com zoom e' o tamanho do canvas menos um + tambem o tamanho e' reduzido do valor negativo */ + if (cnv_rect_pos >= canvas_size) + { + *new_cnv_rect_pos = canvas_size-1; + *new_cnv_rect_size = cnv_rect_size + (cnv_rect_pos - *new_cnv_rect_pos); + } + + /* se posicao + tamanho com zoom (xmin+1) < 0, + entao o tamanho com zoom e' a posição + 1 */ + if (cnv_rect_pos+cnv_rect_size < 0) + *new_cnv_rect_size = -(*new_cnv_rect_pos + 1); + } + + /* agora ja' tenho tamanho e posicao da regiao no canvas, + tenho que obter tamanho e posicao dentro da imagem original, + baseado nos novos valores */ + + /* tamanho da regiao na imagem e' a conversao de zoom para real do tamanho no canvas */ + *new_img_rect_size = (int)(*new_cnv_rect_size * zoom_factor + 0.5); + + if (is_horizontal) + { + /* em X, o offset dentro da imagem so' existe se houver diferenca entre a posicao inicial da + imagem e a posicao otimizada (ambas da imagem com zoom) */ + if (*new_cnv_rect_pos != cnv_rect_pos) + { + offset = *new_cnv_rect_pos - cnv_rect_pos; /* offset is >0 */ + *new_img_rect_pos += (int)(offset*zoom_factor); + } + } + else + { + /* em Y, o offset dentro da imagem so' existe se houver diferenca entre a posicao + final (posição inicial + tamanho) da imagem e a posicao otimizada (ambas da + imagem com zoom) */ + if ((cnv_rect_pos + cnv_rect_size) != (*new_cnv_rect_pos + *new_cnv_rect_size)) + { + /* offset is >0, because Y axis is from top to bottom */ + offset = (cnv_rect_pos + cnv_rect_size) - (*new_cnv_rect_pos + *new_cnv_rect_size); + *new_img_rect_pos += (int)(offset*zoom_factor); + } + } + + return 1; +} + +int cdGetFileName(const char* strdata, char* filename) +{ + const char* start = strdata; + if (!strdata || strdata[0] == 0) return 0; + + if (strdata[0] == '\"') + { + strdata++; /* the first " */ + while(*strdata && *strdata != '\"') + *filename++ = *strdata++; + strdata++; /* the last " */ + } + else + { + while(*strdata && *strdata != ' ') + *filename++ = *strdata++; + } + + if (*strdata == ' ') + strdata++; + + *filename = 0; + return (int)(strdata - start); +} + +void cdNormalizeLimits(int w, int h, int *xmin, int *xmax, int *ymin, int *ymax) +{ + *xmin = *xmin < 0? 0: *xmin < w? *xmin: (w - 1); + *ymin = *ymin < 0? 0: *ymin < h? *ymin: (h - 1); + *xmax = *xmax < 0? 0: *xmax < w? *xmax: (w - 1); + *ymax = *ymax < 0? 0: *ymax < h? *ymax: (h - 1); +} + +int cdCheckBoxSize(int *xmin, int *xmax, int *ymin, int *ymax) +{ + if (*xmin > *xmax) _cdSwapInt(*xmin, *xmax); + if (*ymin > *ymax) _cdSwapInt(*ymin, *ymax); + + if ((*xmax-*xmin+1) <= 0) + return 0; + + if ((*ymax-*ymin+1) <= 0) + return 0; + + return 1; +} + +int cdfCheckBoxSize(double *xmin, double *xmax, double *ymin, double *ymax) +{ + if (*xmin > *xmax) _cdSwapDouble(*xmin, *xmax); + if (*ymin > *ymax) _cdSwapDouble(*ymin, *ymax); + + if ((*xmax-*xmin+1) <= 0) + return 0; + + if ((*ymax-*ymin+1) <= 0) + return 0; + + return 1; +} + +void cdRotatePoint(cdCanvas* canvas, int x, int y, int cx, int cy, int *rx, int *ry, double sin_theta, double cos_theta) +{ + double t; + + /* translate to (cx,cy) */ + x = x - cx; + y = y - cy; + + /* rotate */ + if (canvas->invert_yaxis) + { + t = (x * cos_theta) + (y * sin_theta); *rx = _cdRound(t); + t = -(x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + else + { + t = (x * cos_theta) - (y * sin_theta); *rx = _cdRound(t); + t = (x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + + /* translate back */ + *rx = *rx + cx; + *ry = *ry + cy; +} + +void cdRotatePointY(cdCanvas* canvas, int x, int y, int cx, int cy, int *ry, double sin_theta, double cos_theta) +{ + double t; + + /* translate to (cx,cy) */ + x = x - cx; + y = y - cy; + + /* rotate */ + if (canvas->invert_yaxis) + { + t = -(x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + else + { + t = (x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + + /* translate back */ + *ry = *ry + cy; +} + +int cdStrEqualNoCase(const char* str1, const char* str2) +{ + int i = 0; + if (str1 == str2) return 1; + if (!str1 || !str2 || tolower(*str1) != tolower(*str2)) return 0; + + while (str1[i] && str2[i] && tolower(str1[i])==tolower(str2[i])) + i++; + if (str1[i] == str2[i]) return 1; + + return 0; +} + diff --git a/src/cd_vectortext.c b/src/cd_vectortext.c new file mode 100644 index 0000000..9886a3b --- /dev/null +++ b/src/cd_vectortext.c @@ -0,0 +1,4853 @@ +/** \file + * \brief Vector Text + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" + + +#define MULTILINE_MAXLEN 10240 + +typedef struct cdOperation +{ + char operation; + signed char x, y; +} cdOperation; + +typedef struct cdCaracter +{ + int right, center, operations; + cdOperation *op; +} cdCaracter; + +struct _cdVectorFont +{ + char name[256]; /* font name */ + char file_name[10240]; /* font file name */ + cdCaracter *chars; /* array of characters */ + + int top, /* from baseline to top */ + cap, /* from baseline to cap (top of chars) */ + half, /* half between top and bottom UNUSED */ + bottom; /* from baseline to bottom (negative) */ + double point_size_x, point_size_y; /* internal char size proportional to "top" */ + double current_cos, current_sin; /* text direction */ + int space, line_space; /* space between chars and vf_lines */ + + /* general transformation matrix */ + int text_transf; + double text_matrix[6]; + + cdCanvas* canvas; +}; + +static unsigned char vf_ansi2ascii[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, +/* 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, */ + 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 155, 156, 157, 158, 159, +/* 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, */ + 225, 237, 243, 250, 241, 209, 170, 176, 191, 169, 166, 189, 188, 173, 174, 175, 167, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 172, 171, 190, 168, +/* 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, */ + 192, 193, 194, 195, 142, 143, 146, 128, 200, 144, 202, 203, 204, 205, 206, 207, 208, 165, 210, 211, 212, 213, 153, 215, 216, 217, 218, 219, 154, 221, 222, 223, +/* 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, */ + 133, 160, 131, 227, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139, 240, 164, 149, 162, 147, 245, 148, 247, 248, 151, 163, 150, 129, 253, 254, 152 +}; + +/******************************************************/ +/* descricao do fonte default */ +/******************************************************/ + +static int vf_default_top = 28; +static int vf_default_cap = 28; +static int vf_default_half = 14; +static int vf_default_bottom = -7; + +static cdOperation vf_default_char_33[] = { +{'m', 1, 21}, +{'l', 1, 7}, +{'m', 1, 2}, +{'l', 0, 1}, +{'l', 1, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +}; +static cdOperation vf_default_char_34[] = { +{'m', 1, 21}, +{'l', 0, 20}, +{'l', 0, 14}, +{'m', 1, 20}, +{'l', 0, 14}, +{'m', 1, 21}, +{'l', 2, 20}, +{'l', 0, 14}, +{'m', 10, 21}, +{'l', 9, 20}, +{'l', 9, 14}, +{'m', 10, 20}, +{'l', 9, 14}, +{'m', 10, 21}, +{'l', 11, 20}, +{'l', 9, 14}, +}; +static cdOperation vf_default_char_35[] = { +{'m', 8, 21}, +{'l', 1, -7}, +{'m', 14, 21}, +{'l', 7, -7}, +{'m', 1, 10}, +{'l', 15, 10}, +{'m', 0, 4}, +{'l', 14, 4}, +}; +static cdOperation vf_default_char_36[] = { +{'m', 5, 25}, +{'l', 5, -4}, +{'m', 9, 25}, +{'l', 9, -4}, +{'m', 13, 18}, +{'l', 12, 17}, +{'l', 13, 16}, +{'l', 14, 17}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 9, 21}, +{'l', 5, 21}, +{'l', 2, 20}, +{'l', 0, 18}, +{'l', 0, 16}, +{'l', 1, 14}, +{'l', 2, 13}, +{'l', 4, 12}, +{'l', 10, 10}, +{'l', 12, 9}, +{'l', 14, 7}, +{'m', 0, 16}, +{'l', 2, 14}, +{'l', 4, 13}, +{'l', 10, 11}, +{'l', 12, 10}, +{'l', 13, 9}, +{'l', 14, 7}, +{'l', 14, 3}, +{'l', 12, 1}, +{'l', 9, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 0, 3}, +{'l', 0, 4}, +{'l', 1, 5}, +{'l', 2, 4}, +{'l', 1, 3}, +}; +static cdOperation vf_default_char_37[] = { +{'m', 18, 21}, +{'l', 0, 0}, +{'m', 5, 21}, +{'l', 7, 19}, +{'l', 7, 17}, +{'l', 6, 15}, +{'l', 4, 14}, +{'l', 2, 14}, +{'l', 0, 16}, +{'l', 0, 18}, +{'l', 1, 20}, +{'l', 3, 21}, +{'l', 5, 21}, +{'l', 7, 20}, +{'l', 10, 19}, +{'l', 13, 19}, +{'l', 16, 20}, +{'l', 18, 21}, +{'m', 14, 7}, +{'l', 12, 6}, +{'l', 11, 4}, +{'l', 11, 2}, +{'l', 13, 0}, +{'l', 15, 0}, +{'l', 17, 1}, +{'l', 18, 3}, +{'l', 18, 5}, +{'l', 16, 7}, +{'l', 14, 7}, +}; +static cdOperation vf_default_char_38[] = { +{'m', 18, 13}, +{'l', 17, 12}, +{'l', 18, 11}, +{'l', 19, 12}, +{'l', 19, 13}, +{'l', 18, 14}, +{'l', 17, 14}, +{'l', 16, 13}, +{'l', 15, 11}, +{'l', 13, 6}, +{'l', 11, 3}, +{'l', 9, 1}, +{'l', 7, 0}, +{'l', 4, 0}, +{'l', 1, 1}, +{'l', 0, 3}, +{'l', 0, 6}, +{'l', 1, 8}, +{'l', 7, 12}, +{'l', 9, 14}, +{'l', 10, 16}, +{'l', 10, 18}, +{'l', 9, 20}, +{'l', 7, 21}, +{'l', 5, 20}, +{'l', 4, 18}, +{'l', 4, 16}, +{'l', 5, 13}, +{'l', 7, 10}, +{'l', 12, 3}, +{'l', 14, 1}, +{'l', 17, 0}, +{'l', 18, 0}, +{'l', 19, 1}, +{'l', 19, 2}, +{'m', 4, 0}, +{'l', 2, 1}, +{'l', 1, 3}, +{'l', 1, 6}, +{'l', 2, 8}, +{'l', 4, 10}, +{'m', 4, 16}, +{'l', 5, 14}, +{'l', 13, 3}, +{'l', 15, 1}, +{'l', 17, 0}, +}; +static cdOperation vf_default_char_39[] = { +{'m', 1, 19}, +{'l', 0, 20}, +{'l', 1, 21}, +{'l', 2, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 15}, +}; +static cdOperation vf_default_char_40[] = { +{'m', 7, 25}, +{'l', 5, 23}, +{'l', 3, 20}, +{'l', 1, 16}, +{'l', 0, 11}, +{'l', 0, 7}, +{'l', 1, 2}, +{'l', 3, -2}, +{'l', 5, -5}, +{'l', 7, -7}, +{'m', 5, 23}, +{'l', 3, 19}, +{'l', 2, 16}, +{'l', 1, 11}, +{'l', 1, 7}, +{'l', 2, 2}, +{'l', 3, -1}, +{'l', 5, -5}, +}; +static cdOperation vf_default_char_41[] = { +{'m', 0, 25}, +{'l', 2, 23}, +{'l', 4, 20}, +{'l', 6, 16}, +{'l', 7, 11}, +{'l', 7, 7}, +{'l', 6, 2}, +{'l', 4, -2}, +{'l', 2, -5}, +{'l', 0, -7}, +{'m', 2, 23}, +{'l', 4, 19}, +{'l', 5, 16}, +{'l', 6, 11}, +{'l', 6, 7}, +{'l', 5, 2}, +{'l', 4, -1}, +{'l', 2, -5}, +}; +static cdOperation vf_default_char_42[] = { +{'m', 5, 21}, +{'l', 5, 9}, +{'m', 0, 18}, +{'l', 10, 12}, +{'m', 10, 18}, +{'l', 0, 12}, +}; +static cdOperation vf_default_char_43[] = { +{'m', 9, 18}, +{'l', 9, 0}, +{'m', 0, 9}, +{'l', 18, 9}, +}; +static cdOperation vf_default_char_44[] = { +{'m', 2, 1}, +{'l', 1, 0}, +{'l', 0, 1}, +{'l', 1, 2}, +{'l', 2, 1}, +{'l', 2, -1}, +{'l', 1, -3}, +{'l', 0, -4}, +}; +static cdOperation vf_default_char_45[] = { +{'m', 0, 9}, +{'l', 18, 9}, +}; +static cdOperation vf_default_char_46[] = { +{'m', 1, 2}, +{'l', 0, 1}, +{'l', 1, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +}; +static cdOperation vf_default_char_47[] = { +{'m', 0, -3}, +{'l', 14, 21}, +}; +static cdOperation vf_default_char_48[] = { +{'m', 6, 21}, +{'l', 3, 20}, +{'l', 1, 17}, +{'l', 0, 12}, +{'l', 0, 9}, +{'l', 1, 4}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 4}, +{'l', 14, 9}, +{'l', 14, 12}, +{'l', 13, 17}, +{'l', 11, 20}, +{'l', 8, 21}, +{'l', 6, 21}, +}; +static cdOperation vf_default_char_49[] = { +{'m', 0, 17}, +{'l', 2, 18}, +{'l', 5, 21}, +{'l', 5, 0}, +}; +static cdOperation vf_default_char_50[] = { +{'m', 1, 16}, +{'l', 1, 17}, +{'l', 2, 19}, +{'l', 3, 20}, +{'l', 5, 21}, +{'l', 9, 21}, +{'l', 11, 20}, +{'l', 12, 19}, +{'l', 13, 17}, +{'l', 13, 15}, +{'l', 12, 13}, +{'l', 10, 10}, +{'l', 0, 0}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_51[] = { +{'m', 2, 21}, +{'l', 13, 21}, +{'l', 7, 13}, +{'l', 10, 13}, +{'l', 12, 12}, +{'l', 13, 11}, +{'l', 14, 8}, +{'l', 14, 6}, +{'l', 13, 3}, +{'l', 11, 1}, +{'l', 8, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +{'l', 0, 4}, +}; +static cdOperation vf_default_char_52[] = { +{'m', 10, 21}, +{'l', 0, 7}, +{'l', 15, 7}, +{'m', 10, 21}, +{'l', 10, 0}, +}; +static cdOperation vf_default_char_53[] = { +{'m', 12, 21}, +{'l', 2, 21}, +{'l', 1, 12}, +{'l', 2, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +{'l', 11, 13}, +{'l', 13, 11}, +{'l', 14, 8}, +{'l', 14, 6}, +{'l', 13, 3}, +{'l', 11, 1}, +{'l', 8, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +{'l', 0, 4}, +}; +static cdOperation vf_default_char_54[] = { +{'m', 12, 18}, +{'l', 11, 20}, +{'l', 8, 21}, +{'l', 6, 21}, +{'l', 3, 20}, +{'l', 1, 17}, +{'l', 0, 12}, +{'l', 0, 7}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 7, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 7}, +{'l', 12, 10}, +{'l', 10, 12}, +{'l', 7, 13}, +{'l', 6, 13}, +{'l', 3, 12}, +{'l', 1, 10}, +{'l', 0, 7}, +}; +static cdOperation vf_default_char_55[] = { +{'m', 14, 21}, +{'l', 4, 0}, +{'m', 0, 21}, +{'l', 14, 21}, +}; +static cdOperation vf_default_char_56[] = { +{'m', 5, 21}, +{'l', 2, 20}, +{'l', 1, 18}, +{'l', 1, 16}, +{'l', 2, 14}, +{'l', 4, 13}, +{'l', 8, 12}, +{'l', 11, 11}, +{'l', 13, 9}, +{'l', 14, 7}, +{'l', 14, 4}, +{'l', 13, 2}, +{'l', 12, 1}, +{'l', 9, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +{'l', 0, 4}, +{'l', 0, 7}, +{'l', 1, 9}, +{'l', 3, 11}, +{'l', 6, 12}, +{'l', 10, 13}, +{'l', 12, 14}, +{'l', 13, 16}, +{'l', 13, 18}, +{'l', 12, 20}, +{'l', 9, 21}, +{'l', 5, 21}, +}; +static cdOperation vf_default_char_57[] = { +{'m', 13, 14}, +{'l', 12, 11}, +{'l', 10, 9}, +{'l', 7, 8}, +{'l', 6, 8}, +{'l', 3, 9}, +{'l', 1, 11}, +{'l', 0, 14}, +{'l', 0, 15}, +{'l', 1, 18}, +{'l', 3, 20}, +{'l', 6, 21}, +{'l', 7, 21}, +{'l', 10, 20}, +{'l', 12, 18}, +{'l', 13, 14}, +{'l', 13, 9}, +{'l', 12, 4}, +{'l', 10, 1}, +{'l', 7, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 1, 3}, +}; +static cdOperation vf_default_char_58[] = { +{'m', 1, 14}, +{'l', 0, 13}, +{'l', 1, 12}, +{'l', 2, 13}, +{'l', 1, 14}, +{'m', 1, 2}, +{'l', 0, 1}, +{'l', 1, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +}; +static cdOperation vf_default_char_59[] = { +{'m', 1, 14}, +{'l', 0, 13}, +{'l', 1, 12}, +{'l', 2, 13}, +{'l', 1, 14}, +{'m', 2, 1}, +{'l', 1, 0}, +{'l', 0, 1}, +{'l', 1, 2}, +{'l', 2, 1}, +{'l', 2, -1}, +{'l', 1, -3}, +{'l', 0, -4}, +}; +static cdOperation vf_default_char_60[] = { +{'m', 16, 18}, +{'l', 0, 9}, +{'l', 16, 0}, +}; +static cdOperation vf_default_char_61[] = { +{'m', 0, 12}, +{'l', 18, 12}, +{'m', 0, 6}, +{'l', 18, 6}, +}; +static cdOperation vf_default_char_62[] = { +{'m', 0, 18}, +{'l', 16, 9}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_63[] = { +{'m', 0, 16}, +{'l', 0, 17}, +{'l', 1, 19}, +{'l', 2, 20}, +{'l', 4, 21}, +{'l', 8, 21}, +{'l', 10, 20}, +{'l', 11, 19}, +{'l', 12, 17}, +{'l', 12, 15}, +{'l', 11, 13}, +{'l', 10, 12}, +{'l', 6, 10}, +{'l', 6, 7}, +{'m', 6, 2}, +{'l', 5, 1}, +{'l', 6, 0}, +{'l', 7, 1}, +{'l', 6, 2}, +}; +static cdOperation vf_default_char_64[] = { +{'m', 15, 13}, +{'l', 14, 15}, +{'l', 12, 16}, +{'l', 9, 16}, +{'l', 7, 15}, +{'l', 6, 14}, +{'l', 5, 11}, +{'l', 5, 8}, +{'l', 6, 6}, +{'l', 8, 5}, +{'l', 11, 5}, +{'l', 13, 6}, +{'l', 14, 8}, +{'m', 9, 16}, +{'l', 7, 14}, +{'l', 6, 11}, +{'l', 6, 8}, +{'l', 7, 6}, +{'l', 8, 5}, +{'m', 15, 16}, +{'l', 14, 8}, +{'l', 14, 6}, +{'l', 16, 5}, +{'l', 18, 5}, +{'l', 20, 7}, +{'l', 21, 10}, +{'l', 21, 12}, +{'l', 20, 15}, +{'l', 19, 17}, +{'l', 17, 19}, +{'l', 15, 20}, +{'l', 12, 21}, +{'l', 9, 21}, +{'l', 6, 20}, +{'l', 4, 19}, +{'l', 2, 17}, +{'l', 1, 15}, +{'l', 0, 12}, +{'l', 0, 9}, +{'l', 1, 6}, +{'l', 2, 4}, +{'l', 4, 2}, +{'l', 6, 1}, +{'l', 9, 0}, +{'l', 12, 0}, +{'l', 15, 1}, +{'l', 17, 2}, +{'l', 18, 3}, +{'m', 16, 16}, +{'l', 15, 8}, +{'l', 15, 6}, +{'l', 16, 5}, +}; +static cdOperation vf_default_char_65[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +}; +static cdOperation vf_default_char_66[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 9, 21}, +{'l', 12, 20}, +{'l', 13, 19}, +{'l', 14, 17}, +{'l', 14, 15}, +{'l', 13, 13}, +{'l', 12, 12}, +{'l', 9, 11}, +{'m', 0, 11}, +{'l', 9, 11}, +{'l', 12, 10}, +{'l', 13, 9}, +{'l', 14, 7}, +{'l', 14, 4}, +{'l', 13, 2}, +{'l', 12, 1}, +{'l', 9, 0}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_67[] = { +{'m', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +}; +static cdOperation vf_default_char_68[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 7, 21}, +{'l', 10, 20}, +{'l', 12, 18}, +{'l', 13, 16}, +{'l', 14, 13}, +{'l', 14, 8}, +{'l', 13, 5}, +{'l', 12, 3}, +{'l', 10, 1}, +{'l', 7, 0}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_69[] = { +{'m', 13, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'l', 13, 0}, +{'m', 0, 11}, +{'l', 8, 11}, +}; +static cdOperation vf_default_char_70[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 13, 21}, +{'m', 0, 11}, +{'l', 8, 11}, +}; +static cdOperation vf_default_char_71[] = { +{'m', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 15, 8}, +{'m', 10, 8}, +{'l', 15, 8}, +}; +static cdOperation vf_default_char_72[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 14, 21}, +{'l', 14, 0}, +{'m', 0, 11}, +{'l', 14, 11}, +}; +static cdOperation vf_default_char_73[] = { +{'m', 0, 21}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_74[] = { +{'m', 10, 21}, +{'l', 10, 5}, +{'l', 9, 2}, +{'l', 8, 1}, +{'l', 6, 0}, +{'l', 4, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +{'l', 0, 5}, +{'l', 0, 7}, +}; +static cdOperation vf_default_char_75[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 14, 21}, +{'l', 0, 7}, +{'m', 5, 12}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_76[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 0}, +{'l', 12, 0}, +}; +static cdOperation vf_default_char_77[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 16, 0}, +}; +static cdOperation vf_default_char_78[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 14, 0}, +{'m', 14, 21}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_79[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +}; +static cdOperation vf_default_char_80[] = { +{'m', 0, 10}, +{'l', 9, 10}, +{'l', 12, 11}, +{'l', 13, 12}, +{'l', 14, 14}, +{'l', 14, 17}, +{'l', 13, 19}, +{'l', 12, 20}, +{'l', 9, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_81[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 9, 4}, +{'l', 15, -2}, +}; +static cdOperation vf_default_char_82[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 9, 21}, +{'l', 12, 20}, +{'l', 13, 19}, +{'l', 14, 17}, +{'l', 14, 15}, +{'l', 13, 13}, +{'l', 12, 12}, +{'l', 9, 11}, +{'l', 0, 11}, +{'m', 7, 11}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_83[] = { +{'m', 14, 18}, +{'l', 12, 20}, +{'l', 9, 21}, +{'l', 5, 21}, +{'l', 2, 20}, +{'l', 0, 18}, +{'l', 0, 16}, +{'l', 1, 14}, +{'l', 2, 13}, +{'l', 4, 12}, +{'l', 10, 10}, +{'l', 12, 9}, +{'l', 13, 8}, +{'l', 14, 6}, +{'l', 14, 3}, +{'l', 12, 1}, +{'l', 9, 0}, +{'l', 5, 0}, +{'l', 2, 1}, +{'l', 0, 3}, +}; +static cdOperation vf_default_char_84[] = { +{'m', 7, 21}, +{'l', 7, 0}, +{'m', 0, 21}, +{'l', 14, 21}, +}; +static cdOperation vf_default_char_85[] = { +{'m', 0, 21}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 21}, +}; +static cdOperation vf_default_char_86[] = { +{'m', 0, 21}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 0}, +}; +static cdOperation vf_default_char_87[] = { +{'m', 0, 21}, +{'l', 5, 0}, +{'m', 10, 21}, +{'l', 5, 0}, +{'m', 10, 21}, +{'l', 15, 0}, +{'m', 20, 21}, +{'l', 15, 0}, +}; +static cdOperation vf_default_char_88[] = { +{'m', 0, 21}, +{'l', 14, 0}, +{'m', 14, 21}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_89[] = { +{'m', 0, 21}, +{'l', 8, 11}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 11}, +}; +static cdOperation vf_default_char_90[] = { +{'m', 14, 21}, +{'l', 0, 0}, +{'m', 0, 21}, +{'l', 14, 21}, +{'m', 0, 0}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_91[] = { +{'m', 0, 19}, +{'l', 0, -1}, +{'m', 1, 19}, +{'l', 1, -1}, +{'m', 0, 19}, +{'l', 5, 19}, +{'m', 0, -1}, +{'l', 5, -1}, +}; +static cdOperation vf_default_char_92[] = { +{'m', 0, 21}, +{'l', 14, -3}, +}; +static cdOperation vf_default_char_93[] = { +{'m', 4, 19}, +{'l', 4, -1}, +{'m', 5, 19}, +{'l', 5, -1}, +{'m', 0, 19}, +{'l', 5, 19}, +{'m', 0, -1}, +{'l', 5, -1}, +}; +static cdOperation vf_default_char_94[] = { +{'m', 8, 18}, +{'l', 3, 14}, +{'l', 8, 19}, +{'l', 13, 14}, +{'l', 8, 18}, +{'l', 8, 18}, +}; +static cdOperation vf_default_char_95[] = { +{'m', 0, -7}, +{'l', 16, -7}, +}; +static cdOperation vf_default_char_96[] = { +{'m', 2, 21}, +{'l', 1, 20}, +{'l', 0, 18}, +{'l', 0, 16}, +{'l', 1, 15}, +{'l', 2, 16}, +{'l', 1, 17}, +}; +static cdOperation vf_default_char_97[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_98[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 11}, +{'l', 2, 13}, +{'l', 4, 14}, +{'l', 7, 14}, +{'l', 9, 13}, +{'l', 11, 11}, +{'l', 12, 8}, +{'l', 12, 6}, +{'l', 11, 3}, +{'l', 9, 1}, +{'l', 7, 0}, +{'l', 4, 0}, +{'l', 2, 1}, +{'l', 0, 3}, +}; +static cdOperation vf_default_char_99[] = { +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_100[] = { +{'m', 12, 21}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_101[] = { +{'m', 0, 8}, +{'l', 12, 8}, +{'l', 12, 10}, +{'l', 11, 12}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_102[] = { +{'m', 8, 21}, +{'l', 6, 21}, +{'l', 4, 20}, +{'l', 3, 17}, +{'l', 3, 0}, +{'m', 0, 14}, +{'l', 7, 14}, +}; +static cdOperation vf_default_char_103[] = { +{'m', 12, 14}, +{'l', 12, -2}, +{'l', 11, -5}, +{'l', 10, -6}, +{'l', 8, -7}, +{'l', 5, -7}, +{'l', 3, -6}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_104[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 0, 10}, +{'l', 3, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +{'l', 10, 13}, +{'l', 11, 10}, +{'l', 11, 0}, +}; +static cdOperation vf_default_char_105[] = { +{'m', 2, 21}, +{'l', 3, 20}, +{'l', 4, 21}, +{'l', 3, 22}, +{'l', 2, 21}, +{'m', 3, 14}, +{'l', 3, 0}, +}; +static cdOperation vf_default_char_106[] = { +{'m', 4, 21}, +{'l', 5, 20}, +{'l', 6, 21}, +{'l', 5, 22}, +{'l', 4, 21}, +{'m', 5, 14}, +{'l', 5, -3}, +{'l', 4, -6}, +{'l', 2, -7}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_107[] = { +{'m', 0, 21}, +{'l', 0, 0}, +{'m', 10, 14}, +{'l', 0, 4}, +{'m', 4, 8}, +{'l', 11, 0}, +}; +static cdOperation vf_default_char_108[] = { +{'m', 0, 21}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_109[] = { +{'m', 0, 14}, +{'l', 0, 0}, +{'m', 0, 10}, +{'l', 3, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +{'l', 10, 13}, +{'l', 11, 10}, +{'l', 11, 0}, +{'m', 11, 10}, +{'l', 14, 13}, +{'l', 16, 14}, +{'l', 19, 14}, +{'l', 21, 13}, +{'l', 22, 10}, +{'l', 22, 0}, +}; +static cdOperation vf_default_char_110[] = { +{'m', 0, 14}, +{'l', 0, 0}, +{'m', 0, 10}, +{'l', 3, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +{'l', 10, 13}, +{'l', 11, 10}, +{'l', 11, 0}, +}; +static cdOperation vf_default_char_111[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +}; +static cdOperation vf_default_char_112[] = { +{'m', 0, 14}, +{'l', 0, -7}, +{'m', 0, 11}, +{'l', 2, 13}, +{'l', 4, 14}, +{'l', 7, 14}, +{'l', 9, 13}, +{'l', 11, 11}, +{'l', 12, 8}, +{'l', 12, 6}, +{'l', 11, 3}, +{'l', 9, 1}, +{'l', 7, 0}, +{'l', 4, 0}, +{'l', 2, 1}, +{'l', 0, 3}, +}; +static cdOperation vf_default_char_113[] = { +{'m', 12, 14}, +{'l', 12, -7}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +}; +static cdOperation vf_default_char_114[] = { +{'m', 0, 14}, +{'l', 0, 0}, +{'m', 0, 8}, +{'l', 1, 11}, +{'l', 3, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +}; +static cdOperation vf_default_char_115[] = { +{'m', 11, 11}, +{'l', 10, 13}, +{'l', 7, 14}, +{'l', 4, 14}, +{'l', 1, 13}, +{'l', 0, 11}, +{'l', 1, 9}, +{'l', 3, 8}, +{'l', 8, 7}, +{'l', 10, 6}, +{'l', 11, 4}, +{'l', 11, 3}, +{'l', 10, 1}, +{'l', 7, 0}, +{'l', 4, 0}, +{'l', 1, 1}, +{'l', 0, 3}, +}; +static cdOperation vf_default_char_116[] = { +{'m', 3, 21}, +{'l', 3, 4}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'m', 0, 14}, +{'l', 7, 14}, +}; +static cdOperation vf_default_char_117[] = { +{'m', 0, 14}, +{'l', 0, 4}, +{'l', 1, 1}, +{'l', 3, 0}, +{'l', 6, 0}, +{'l', 8, 1}, +{'l', 11, 4}, +{'m', 11, 14}, +{'l', 11, 0}, +}; +static cdOperation vf_default_char_118[] = { +{'m', 0, 14}, +{'l', 6, 0}, +{'m', 12, 14}, +{'l', 6, 0}, +}; +static cdOperation vf_default_char_119[] = { +{'m', 0, 14}, +{'l', 4, 0}, +{'m', 8, 14}, +{'l', 4, 0}, +{'m', 8, 14}, +{'l', 12, 0}, +{'m', 16, 14}, +{'l', 12, 0}, +}; +static cdOperation vf_default_char_120[] = { +{'m', 0, 14}, +{'l', 11, 0}, +{'m', 11, 14}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_121[] = { +{'m', 1, 14}, +{'l', 7, 0}, +{'m', 13, 14}, +{'l', 7, 0}, +{'l', 5, -4}, +{'l', 3, -6}, +{'l', 1, -7}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_122[] = { +{'m', 11, 14}, +{'l', 0, 0}, +{'m', 0, 14}, +{'l', 11, 14}, +{'m', 0, 0}, +{'l', 11, 0}, +}; +static cdOperation vf_default_char_123[] = { +{'m', 5, 25}, +{'l', 3, 24}, +{'l', 2, 23}, +{'l', 1, 21}, +{'l', 1, 19}, +{'l', 2, 17}, +{'l', 3, 16}, +{'l', 4, 14}, +{'l', 4, 12}, +{'l', 2, 10}, +{'m', 3, 24}, +{'l', 2, 22}, +{'l', 2, 20}, +{'l', 3, 18}, +{'l', 4, 17}, +{'l', 5, 15}, +{'l', 5, 13}, +{'l', 4, 11}, +{'l', 0, 9}, +{'l', 4, 7}, +{'l', 5, 5}, +{'l', 5, 3}, +{'l', 4, 1}, +{'l', 3, 0}, +{'l', 2, -2}, +{'l', 2, -4}, +{'l', 3, -6}, +{'m', 2, 8}, +{'l', 4, 6}, +{'l', 4, 4}, +{'l', 3, 2}, +{'l', 2, 1}, +{'l', 1, -1}, +{'l', 1, -3}, +{'l', 2, -5}, +{'l', 3, -6}, +{'l', 5, -7}, +}; +static cdOperation vf_default_char_124[] = { +{'m', 0, 21}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_125[] = { +{'m', 0, 25}, +{'l', 2, 24}, +{'l', 3, 23}, +{'l', 4, 21}, +{'l', 4, 19}, +{'l', 3, 17}, +{'l', 2, 16}, +{'l', 1, 14}, +{'l', 1, 12}, +{'l', 3, 10}, +{'m', 2, 24}, +{'l', 3, 22}, +{'l', 3, 20}, +{'l', 2, 18}, +{'l', 1, 17}, +{'l', 0, 15}, +{'l', 0, 13}, +{'l', 1, 11}, +{'l', 5, 9}, +{'l', 1, 7}, +{'l', 0, 5}, +{'l', 0, 3}, +{'l', 1, 1}, +{'l', 2, 0}, +{'l', 3, -2}, +{'l', 3, -4}, +{'l', 2, -6}, +{'m', 3, 8}, +{'l', 1, 6}, +{'l', 1, 4}, +{'l', 2, 2}, +{'l', 3, 1}, +{'l', 4, -1}, +{'l', 4, -3}, +{'l', 3, -5}, +{'l', 2, -6}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_126[] = { +{'m', 0, 16}, +{'l', 5, 19}, +{'l', 9, 16}, +{'l', 13, 18}, +}; +static cdOperation vf_default_char_127[] = { +{'m', 0, 7}, +{'l', 0, 0}, +{'l', 12, 0}, +{'l', 12, 7}, +{'l', 6, 16}, +{'l', 0, 7}, +{'m', 6, 6}, +{'l', 6, 6}, +}; +static cdOperation vf_default_char_128[] = { +{'m', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'m', 8, 0}, +{'l', 8, -1}, +{'l', 7, -1}, +{'l', 7, 0}, +{'m', 3, -4}, +{'l', 3, -6}, +{'l', 4, -7}, +{'l', 10, -7}, +{'l', 12, -5}, +{'l', 12, -4}, +{'l', 10, -2}, +{'l', 8, -1}, +}; +static cdOperation vf_default_char_129[] = { +{'m', 0, 14}, +{'l', 0, 4}, +{'l', 1, 1}, +{'l', 3, 0}, +{'l', 6, 0}, +{'l', 8, 1}, +{'l', 11, 4}, +{'m', 11, 14}, +{'l', 11, 0}, +{'m', 2, 19}, +{'l', 1, 18}, +{'l', 2, 17}, +{'l', 3, 18}, +{'l', 2, 19}, +{'m', 10, 19}, +{'l', 9, 18}, +{'l', 10, 17}, +{'l', 11, 18}, +{'l', 10, 19}, +}; +static cdOperation vf_default_char_130[] = { +{'m', 0, 8}, +{'l', 12, 8}, +{'l', 12, 10}, +{'l', 11, 12}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 10, 22}, +{'l', 5, 17}, +}; +static cdOperation vf_default_char_131[] = { +{'m', 13, 14}, +{'l', 13, 0}, +{'m', 13, 11}, +{'l', 11, 13}, +{'l', 9, 14}, +{'l', 6, 14}, +{'l', 4, 13}, +{'l', 2, 11}, +{'l', 1, 8}, +{'l', 1, 6}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 9, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'m', 3, 16}, +{'l', 8, 21}, +{'l', 13, 16}, +}; +static cdOperation vf_default_char_132[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 2, 19}, +{'l', 1, 18}, +{'l', 2, 17}, +{'l', 3, 18}, +{'l', 2, 19}, +{'m', 10, 19}, +{'l', 9, 18}, +{'l', 10, 17}, +{'l', 11, 18}, +{'l', 10, 19}, +}; +static cdOperation vf_default_char_133[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 3, 22}, +{'l', 8, 17}, +}; +static cdOperation vf_default_char_134[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 5, 19}, +{'l', 4, 18}, +{'l', 5, 17}, +{'l', 7, 17}, +{'l', 8, 18}, +{'l', 7, 19}, +{'l', 5, 19}, +}; +static cdOperation vf_default_char_135[] = { +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 6, 0}, +{'l', 6, -1}, +{'l', 9, -2}, +{'l', 10, -5}, +{'l', 8, -7}, +{'l', 4, -7}, +{'l', 3, -5}, +}; +static cdOperation vf_default_char_136[] = { +{'m', 2, 8}, +{'l', 14, 8}, +{'l', 14, 10}, +{'l', 13, 12}, +{'l', 12, 13}, +{'l', 10, 14}, +{'l', 7, 14}, +{'l', 5, 13}, +{'l', 3, 11}, +{'l', 2, 8}, +{'l', 2, 6}, +{'l', 3, 3}, +{'l', 5, 1}, +{'l', 7, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'m', 4, 16}, +{'l', 9, 21}, +{'l', 14, 16}, +}; +static cdOperation vf_default_char_137[] = { +{'m', 0, 8}, +{'l', 12, 8}, +{'l', 12, 10}, +{'l', 11, 12}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 3, 19}, +{'l', 2, 18}, +{'l', 3, 17}, +{'l', 4, 18}, +{'l', 3, 19}, +{'m', 11, 19}, +{'l', 10, 18}, +{'l', 11, 17}, +{'l', 12, 18}, +{'l', 11, 19}, +}; +static cdOperation vf_default_char_138[] = { +{'m', 0, 8}, +{'l', 12, 8}, +{'l', 12, 10}, +{'l', 11, 12}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 2, 22}, +{'l', 7, 17}, +}; +static cdOperation vf_default_char_139[] = { +{'m', 5, 14}, +{'l', 5, 0}, +{'m', 1, 19}, +{'l', 0, 18}, +{'l', 1, 17}, +{'l', 2, 18}, +{'l', 1, 19}, +{'m', 9, 19}, +{'l', 8, 18}, +{'l', 9, 17}, +{'l', 10, 18}, +{'l', 9, 19}, +}; +static cdOperation vf_default_char_140[] = { +{'m', 8, 14}, +{'l', 8, 0}, +{'m', 3, 16}, +{'l', 8, 21}, +{'l', 13, 16}, +}; +static cdOperation vf_default_char_141[] = { +{'m', 5, 14}, +{'l', 5, 0}, +{'m', 0, 22}, +{'l', 5, 17}, +}; +static cdOperation vf_default_char_142[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 4, 26}, +{'l', 3, 25}, +{'l', 4, 24}, +{'l', 5, 25}, +{'l', 4, 26}, +{'m', 12, 26}, +{'l', 11, 25}, +{'l', 12, 24}, +{'l', 13, 25}, +{'l', 12, 26}, +}; +static cdOperation vf_default_char_143[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 7, 26}, +{'l', 6, 25}, +{'l', 7, 24}, +{'l', 9, 24}, +{'l', 10, 25}, +{'l', 9, 26}, +{'l', 7, 26}, +}; +static cdOperation vf_default_char_144[] = { +{'m', 13, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'l', 13, 0}, +{'m', 0, 11}, +{'l', 8, 11}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_145[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 17, 14}, +{'l', 20, 14}, +{'l', 22, 13}, +{'l', 23, 12}, +{'l', 24, 10}, +{'l', 24, 8}, +{'l', 12, 8}, +{'l', 13, 11}, +{'l', 15, 13}, +{'l', 17, 14}, +{'m', 12, 6}, +{'l', 13, 3}, +{'l', 15, 1}, +{'l', 17, 0}, +{'l', 20, 0}, +{'l', 22, 1}, +{'l', 24, 3}, +}; +static cdOperation vf_default_char_146[] = { +{'m', 23, 21}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 10, 21}, +{'l', 10, 0}, +{'l', 23, 0}, +{'m', 10, 11}, +{'l', 18, 11}, +{'m', 3, 7}, +{'l', 10, 7}, +}; +static cdOperation vf_default_char_147[] = { +{'m', 6, 14}, +{'l', 4, 13}, +{'l', 2, 11}, +{'l', 1, 8}, +{'l', 1, 6}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 9, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 8}, +{'l', 13, 11}, +{'l', 11, 13}, +{'l', 9, 14}, +{'l', 6, 14}, +{'m', 3, 16}, +{'l', 8, 21}, +{'l', 13, 16}, +}; +static cdOperation vf_default_char_148[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 3, 19}, +{'l', 2, 18}, +{'l', 3, 17}, +{'l', 4, 18}, +{'l', 3, 19}, +{'m', 11, 19}, +{'l', 10, 18}, +{'l', 11, 17}, +{'l', 12, 18}, +{'l', 11, 19}, +}; +static cdOperation vf_default_char_149[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 2, 22}, +{'l', 7, 17}, +}; +static cdOperation vf_default_char_150[] = { +{'m', 2, 14}, +{'l', 2, 4}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 13, 4}, +{'m', 13, 14}, +{'l', 13, 0}, +{'m', 3, 17}, +{'l', 8, 22}, +{'l', 13, 17}, +}; +static cdOperation vf_default_char_151[] = { +{'m', 0, 14}, +{'l', 0, 4}, +{'l', 1, 1}, +{'l', 3, 0}, +{'l', 6, 0}, +{'l', 8, 1}, +{'l', 11, 4}, +{'m', 11, 14}, +{'l', 11, 0}, +{'m', 1, 22}, +{'l', 6, 17}, +}; +static cdOperation vf_default_char_152[] = { +{'m', 1, 14}, +{'l', 7, 0}, +{'l', 5, -4}, +{'l', 3, -6}, +{'l', 1, -7}, +{'l', 0, -7}, +{'m', 13, 14}, +{'l', 7, 0}, +{'m', 3, 19}, +{'l', 2, 18}, +{'l', 3, 17}, +{'l', 4, 18}, +{'l', 3, 19}, +{'m', 11, 19}, +{'l', 10, 18}, +{'l', 11, 17}, +{'l', 12, 18}, +{'l', 11, 19}, +}; +static cdOperation vf_default_char_153[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 4, 26}, +{'l', 3, 25}, +{'l', 4, 24}, +{'l', 5, 25}, +{'l', 4, 26}, +{'m', 12, 26}, +{'l', 11, 25}, +{'l', 12, 24}, +{'l', 13, 25}, +{'l', 12, 26}, +}; +static cdOperation vf_default_char_154[] = { +{'m', 0, 21}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 21}, +{'m', 3, 26}, +{'l', 2, 25}, +{'l', 3, 24}, +{'l', 4, 25}, +{'l', 3, 26}, +{'m', 11, 26}, +{'l', 10, 25}, +{'l', 11, 24}, +{'l', 12, 25}, +{'l', 11, 26}, +}; +static cdOperation vf_default_char_155[] = { +{'m', 12, 15}, +{'l', 10, 17}, +{'l', 8, 18}, +{'l', 5, 18}, +{'l', 3, 17}, +{'l', 1, 15}, +{'l', 0, 12}, +{'l', 0, 10}, +{'l', 1, 7}, +{'l', 3, 5}, +{'l', 5, 4}, +{'l', 8, 4}, +{'l', 10, 5}, +{'l', 12, 7}, +{'m', 6, 0}, +{'l', 6, 22}, +}; +static cdOperation vf_default_char_156[] = { +{'m', 13, 20}, +{'l', 10, 21}, +{'l', 8, 21}, +{'l', 5, 20}, +{'l', 4, 19}, +{'l', 3, 16}, +{'l', 3, 0}, +{'l', 12, 0}, +{'l', 15, 1}, +{'l', 15, 2}, +{'m', 0, 12}, +{'l', 7, 12}, +}; +static cdOperation vf_default_char_157[] = { +{'m', 0, 21}, +{'l', 8, 11}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 11}, +{'m', 4, 11}, +{'l', 13, 11}, +{'m', 4, 8}, +{'l', 13, 8}, +}; +static cdOperation vf_default_char_158[] = { +{'m', 0, 10}, +{'l', 9, 10}, +{'l', 12, 11}, +{'l', 13, 12}, +{'l', 14, 14}, +{'l', 14, 17}, +{'l', 13, 19}, +{'l', 12, 20}, +{'l', 9, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'m', 12, 8}, +{'l', 18, 8}, +{'m', 15, 12}, +{'l', 15, 2}, +{'l', 16, 0}, +{'l', 18, 0}, +{'l', 19, 1}, +}; +static cdOperation vf_default_char_159[] = { +{'m', 0, 21}, +{'l', 8, 11}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 11}, +{'m', 4, 25}, +{'l', 3, 24}, +{'l', 4, 23}, +{'l', 5, 24}, +{'l', 4, 25}, +{'m', 12, 25}, +{'l', 11, 24}, +{'l', 12, 23}, +{'l', 13, 24}, +{'l', 12, 25}, +}; +static cdOperation vf_default_char_160[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 10, 22}, +{'l', 5, 17}, +}; +static cdOperation vf_default_char_161[] = { +{'m', 3, 14}, +{'l', 3, 0}, +{'m', 7, 22}, +{'l', 2, 17}, +}; +static cdOperation vf_default_char_162[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 11, 22}, +{'l', 6, 17}, +}; +static cdOperation vf_default_char_163[] = { +{'m', 0, 14}, +{'l', 0, 4}, +{'l', 1, 1}, +{'l', 3, 0}, +{'l', 6, 0}, +{'l', 8, 1}, +{'l', 11, 4}, +{'m', 11, 14}, +{'l', 11, 0}, +{'m', 9, 22}, +{'l', 4, 17}, +}; +static cdOperation vf_default_char_164[] = { +{'m', 0, 14}, +{'l', 0, 0}, +{'m', 0, 10}, +{'l', 3, 13}, +{'l', 5, 14}, +{'l', 8, 14}, +{'l', 10, 13}, +{'l', 11, 10}, +{'l', 11, 0}, +{'m', 0, 17}, +{'l', 5, 20}, +{'l', 9, 17}, +{'l', 13, 19}, +}; +static cdOperation vf_default_char_165[] = { +{'m', 14, 21}, +{'l', 14, 0}, +{'l', 0, 21}, +{'l', 0, 0}, +{'m', 0, 24}, +{'l', 5, 27}, +{'l', 9, 24}, +{'l', 13, 26}, +}; +static cdOperation vf_default_char_166[] = { +{'m', 12, 21}, +{'l', 12, 7}, +{'m', 12, 18}, +{'l', 10, 20}, +{'l', 8, 21}, +{'l', 5, 21}, +{'l', 3, 20}, +{'l', 1, 18}, +{'l', 0, 15}, +{'l', 0, 13}, +{'l', 1, 10}, +{'l', 3, 8}, +{'l', 5, 7}, +{'l', 8, 7}, +{'l', 10, 8}, +{'l', 12, 10}, +{'m', 0, 0}, +{'l', 12, 0}, +}; +static cdOperation vf_default_char_167[] = { +{'m', 0, 15}, +{'l', 1, 12}, +{'l', 3, 10}, +{'l', 5, 9}, +{'l', 8, 9}, +{'l', 10, 10}, +{'l', 12, 12}, +{'l', 13, 15}, +{'l', 12, 18}, +{'l', 10, 20}, +{'l', 8, 21}, +{'l', 5, 21}, +{'l', 3, 20}, +{'l', 1, 18}, +{'l', 0, 15}, +{'m', 0, 0}, +{'l', 13, 0}, +}; +static cdOperation vf_default_char_168[] = { +{'m', 12, 5}, +{'l', 12, 4}, +{'l', 11, 2}, +{'l', 10, 1}, +{'l', 8, 0}, +{'l', 4, 0}, +{'l', 2, 1}, +{'l', 1, 2}, +{'l', 0, 4}, +{'l', 0, 6}, +{'l', 1, 8}, +{'l', 2, 9}, +{'l', 6, 11}, +{'l', 6, 14}, +{'m', 6, 19}, +{'l', 7, 20}, +{'l', 6, 21}, +{'l', 5, 20}, +{'l', 6, 19}, +}; +static cdOperation vf_default_char_169[] = { +{'m', 0, 0}, +{'l', 0, 8}, +{'l', 12, 8}, +{'l', 12, 5}, +{'l', 3, 5}, +{'l', 3, 0}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_170[] = { +{'m', 12, 0}, +{'l', 12, 8}, +{'l', 0, 8}, +{'l', 0, 5}, +{'l', 9, 5}, +{'l', 9, 0}, +{'l', 12, 0}, +}; +static cdOperation vf_default_char_171[] = { +{'m', 0, 18}, +{'l', 3, 21}, +{'l', 4, 21}, +{'l', 4, 12}, +{'m', 9, 6}, +{'l', 9, 7}, +{'l', 11, 9}, +{'l', 15, 9}, +{'l', 16, 7}, +{'l', 16, 5}, +{'l', 15, 4}, +{'l', 9, 0}, +{'l', 16, 0}, +{'m', 15, 21}, +{'l', 1, 0}, +}; +static cdOperation vf_default_char_172[] = { +{'m', 0, 18}, +{'l', 3, 21}, +{'l', 4, 21}, +{'l', 4, 12}, +{'m', 15, 21}, +{'l', 1, 0}, +{'m', 15, 3}, +{'l', 7, 3}, +{'l', 13, 9}, +{'l', 13, 0}, +}; +static cdOperation vf_default_char_173[] = { +{'m', 1, 0}, +{'l', 1, 14}, +{'m', 1, 19}, +{'l', 0, 20}, +{'l', 1, 21}, +{'l', 2, 20}, +{'l', 1, 19}, +}; +static cdOperation vf_default_char_174[] = { +{'m', 7, 17}, +{'l', 0, 11}, +{'l', 7, 5}, +{'m', 15, 17}, +{'l', 8, 11}, +{'l', 15, 5}, +}; +static cdOperation vf_default_char_175[] = { +{'m', 8, 17}, +{'l', 15, 11}, +{'l', 8, 5}, +{'m', 0, 17}, +{'l', 7, 11}, +{'l', 0, 5}, +}; +static cdOperation vf_default_char_176[] = { +{'m', 4, 21}, +{'l', 6, 21}, +{'l', 6, 19}, +{'l', 4, 19}, +{'l', 4, 21}, +{'m', 5, 21}, +{'l', 5, 19}, +{'m', 4, 15}, +{'l', 6, 15}, +{'l', 6, 13}, +{'l', 4, 13}, +{'l', 4, 15}, +{'m', 5, 15}, +{'l', 5, 13}, +{'m', 4, 9}, +{'l', 6, 9}, +{'l', 6, 7}, +{'l', 4, 7}, +{'l', 4, 9}, +{'m', 5, 9}, +{'l', 5, 7}, +{'m', 4, 3}, +{'l', 6, 3}, +{'l', 6, 1}, +{'l', 4, 1}, +{'l', 4, 3}, +{'m', 5, 3}, +{'l', 5, 1}, +{'m', 0, 18}, +{'l', 2, 18}, +{'l', 2, 16}, +{'l', 0, 16}, +{'l', 0, 18}, +{'m', 1, 18}, +{'l', 1, 16}, +{'m', 0, 12}, +{'l', 2, 12}, +{'l', 2, 10}, +{'l', 0, 10}, +{'l', 0, 12}, +{'m', 1, 12}, +{'l', 1, 10}, +{'m', 0, 6}, +{'l', 2, 6}, +{'l', 2, 4}, +{'l', 0, 4}, +{'l', 0, 6}, +{'m', 1, 6}, +{'l', 1, 4}, +{'m', 0, 0}, +{'l', 2, 0}, +{'l', 2, -2}, +{'l', 0, -2}, +{'l', 0, 0}, +{'m', 1, 0}, +{'l', 1, -2}, +{'m', 8, 18}, +{'l', 10, 18}, +{'l', 10, 16}, +{'l', 8, 16}, +{'l', 8, 18}, +{'m', 9, 18}, +{'l', 9, 16}, +{'m', 8, 12}, +{'l', 10, 12}, +{'l', 10, 10}, +{'l', 8, 10}, +{'l', 8, 12}, +{'m', 9, 12}, +{'l', 9, 10}, +{'m', 8, 6}, +{'l', 10, 6}, +{'l', 10, 4}, +{'l', 8, 4}, +{'l', 8, 6}, +{'m', 9, 6}, +{'l', 9, 4}, +{'m', 8, 0}, +{'l', 10, 0}, +{'l', 10, -2}, +{'l', 8, -2}, +{'l', 8, 0}, +{'m', 9, 0}, +{'l', 9, -2}, +{'m', 12, 21}, +{'l', 14, 21}, +{'l', 14, 19}, +{'l', 12, 19}, +{'l', 12, 21}, +{'m', 13, 21}, +{'l', 13, 19}, +{'m', 12, 15}, +{'l', 14, 15}, +{'l', 14, 13}, +{'l', 12, 13}, +{'l', 12, 15}, +{'m', 13, 15}, +{'l', 13, 13}, +{'m', 12, 9}, +{'l', 14, 9}, +{'l', 14, 7}, +{'l', 12, 7}, +{'l', 12, 9}, +{'m', 13, 9}, +{'l', 13, 7}, +{'m', 12, 3}, +{'l', 14, 3}, +{'l', 14, 1}, +{'l', 12, 1}, +{'l', 12, 3}, +{'m', 13, 3}, +{'l', 13, 1}, +{'m', 3, -3}, +{'l', 3, -5}, +{'l', 5, -5}, +{'l', 5, -3}, +{'l', 3, -3}, +{'m', 4, -3}, +{'l', 4, -5}, +{'m', 12, -3}, +{'l', 12, -5}, +{'l', 14, -5}, +{'l', 14, -3}, +{'l', 12, -3}, +{'m', 13, -3}, +{'l', 13, -5}, +}; +static cdOperation vf_default_char_177[] = { +{'m', 0, 18}, +{'l', 2, 18}, +{'l', 2, 16}, +{'l', 0, 16}, +{'l', 0, 18}, +{'m', 1, 18}, +{'l', 1, 16}, +{'m', 0, 12}, +{'l', 2, 12}, +{'l', 2, 10}, +{'l', 0, 10}, +{'l', 0, 12}, +{'m', 1, 12}, +{'l', 1, 10}, +{'m', 0, 6}, +{'l', 2, 6}, +{'l', 2, 4}, +{'l', 0, 4}, +{'l', 0, 6}, +{'m', 1, 6}, +{'l', 1, 4}, +{'m', 0, 0}, +{'l', 2, 0}, +{'l', 2, -2}, +{'l', 0, -2}, +{'l', 0, 0}, +{'m', 1, 0}, +{'l', 1, -2}, +{'m', 2, 21}, +{'l', 4, 21}, +{'l', 4, 19}, +{'l', 2, 19}, +{'l', 2, 21}, +{'m', 3, 21}, +{'l', 3, 19}, +{'m', 2, 15}, +{'l', 4, 15}, +{'l', 4, 13}, +{'l', 2, 13}, +{'l', 2, 15}, +{'m', 3, 15}, +{'l', 3, 13}, +{'m', 2, 9}, +{'l', 4, 9}, +{'l', 4, 7}, +{'l', 2, 7}, +{'l', 2, 9}, +{'m', 3, 9}, +{'l', 3, 7}, +{'m', 2, 3}, +{'l', 4, 3}, +{'l', 4, 1}, +{'l', 2, 1}, +{'l', 2, 3}, +{'m', 3, 3}, +{'l', 3, 1}, +{'m', 4, 18}, +{'l', 6, 18}, +{'l', 6, 16}, +{'l', 4, 16}, +{'l', 4, 18}, +{'m', 5, 18}, +{'l', 5, 16}, +{'m', 4, 12}, +{'l', 6, 12}, +{'l', 6, 10}, +{'l', 4, 10}, +{'l', 4, 12}, +{'m', 5, 12}, +{'l', 5, 10}, +{'m', 4, 6}, +{'l', 6, 6}, +{'l', 6, 4}, +{'l', 4, 4}, +{'l', 4, 6}, +{'m', 5, 6}, +{'l', 5, 4}, +{'m', 4, 0}, +{'l', 6, 0}, +{'l', 6, -2}, +{'l', 4, -2}, +{'l', 4, 0}, +{'m', 5, 0}, +{'l', 5, -2}, +{'m', 6, 21}, +{'l', 8, 21}, +{'l', 8, 19}, +{'l', 6, 19}, +{'l', 6, 21}, +{'m', 7, 21}, +{'l', 7, 19}, +{'m', 6, 15}, +{'l', 8, 15}, +{'l', 8, 13}, +{'l', 6, 13}, +{'l', 6, 15}, +{'m', 7, 15}, +{'l', 7, 13}, +{'m', 6, 9}, +{'l', 8, 9}, +{'l', 8, 7}, +{'l', 6, 7}, +{'l', 6, 9}, +{'m', 7, 9}, +{'l', 7, 7}, +{'m', 6, 3}, +{'l', 8, 3}, +{'l', 8, 1}, +{'l', 6, 1}, +{'l', 6, 3}, +{'m', 7, 3}, +{'l', 7, 1}, +{'m', 8, 18}, +{'l', 10, 18}, +{'l', 10, 16}, +{'l', 8, 16}, +{'l', 8, 18}, +{'m', 9, 18}, +{'l', 9, 16}, +{'m', 8, 12}, +{'l', 10, 12}, +{'l', 10, 10}, +{'l', 8, 10}, +{'l', 8, 12}, +{'m', 9, 12}, +{'l', 9, 10}, +{'m', 8, 6}, +{'l', 10, 6}, +{'l', 10, 4}, +{'l', 8, 4}, +{'l', 8, 6}, +{'m', 9, 6}, +{'l', 9, 4}, +{'m', 8, 0}, +{'l', 10, 0}, +{'l', 10, -2}, +{'l', 8, -2}, +{'l', 8, 0}, +{'m', 9, 0}, +{'l', 9, -2}, +{'m', 10, 21}, +{'l', 12, 21}, +{'l', 12, 19}, +{'l', 10, 19}, +{'l', 10, 21}, +{'m', 11, 21}, +{'l', 11, 19}, +{'m', 10, 15}, +{'l', 12, 15}, +{'l', 12, 13}, +{'l', 10, 13}, +{'l', 10, 15}, +{'m', 11, 15}, +{'l', 11, 13}, +{'m', 10, 9}, +{'l', 12, 9}, +{'l', 12, 7}, +{'l', 10, 7}, +{'l', 10, 9}, +{'m', 11, 9}, +{'l', 11, 7}, +{'m', 10, 3}, +{'l', 12, 3}, +{'l', 12, 1}, +{'l', 10, 1}, +{'l', 10, 3}, +{'m', 11, 3}, +{'l', 11, 1}, +{'m', 12, 18}, +{'l', 14, 18}, +{'l', 14, 16}, +{'l', 12, 16}, +{'l', 12, 18}, +{'m', 13, 18}, +{'l', 13, 16}, +{'m', 12, 12}, +{'l', 14, 12}, +{'l', 14, 10}, +{'l', 12, 10}, +{'l', 12, 12}, +{'m', 13, 12}, +{'l', 13, 10}, +{'m', 12, 6}, +{'l', 14, 6}, +{'l', 14, 4}, +{'l', 12, 4}, +{'l', 12, 6}, +{'m', 13, 6}, +{'l', 13, 4}, +{'m', 12, 0}, +{'l', 14, 0}, +{'l', 14, -2}, +{'l', 12, -2}, +{'l', 12, 0}, +{'m', 13, 0}, +{'l', 13, -2}, +{'m', 14, 21}, +{'l', 16, 21}, +{'l', 16, 19}, +{'l', 14, 19}, +{'l', 14, 21}, +{'m', 15, 21}, +{'l', 15, 19}, +{'m', 14, 15}, +{'l', 16, 15}, +{'l', 16, 13}, +{'l', 14, 13}, +{'l', 14, 15}, +{'m', 15, 15}, +{'l', 15, 13}, +{'m', 14, 9}, +{'l', 16, 9}, +{'l', 16, 7}, +{'l', 14, 7}, +{'l', 14, 9}, +{'m', 15, 9}, +{'l', 15, 7}, +{'m', 14, 3}, +{'l', 16, 3}, +{'l', 16, 1}, +{'l', 14, 1}, +{'l', 14, 3}, +{'m', 15, 3}, +{'l', 15, 1}, +{'m', 2, -3}, +{'l', 2, -5}, +{'l', 4, -5}, +{'l', 4, -3}, +{'l', 2, -3}, +{'m', 3, -3}, +{'l', 3, -5}, +{'m', 6, -3}, +{'l', 6, -5}, +{'l', 8, -5}, +{'l', 8, -3}, +{'l', 6, -3}, +{'m', 7, -3}, +{'l', 7, -5}, +{'m', 10, -3}, +{'l', 10, -5}, +{'l', 12, -5}, +{'l', 12, -3}, +{'l', 10, -3}, +{'m', 11, -3}, +{'l', 11, -5}, +{'m', 14, -3}, +{'l', 14, -5}, +{'l', 16, -5}, +{'l', 16, -3}, +{'l', 14, -3}, +{'m', 15, -3}, +{'l', 15, -5}, +}; +static cdOperation vf_default_char_178[] = { +{'m', 0, 21}, +{'l', 2, 21}, +{'l', 2, 19}, +{'l', 0, 19}, +{'l', 0, 21}, +{'m', 1, 21}, +{'l', 1, 19}, +{'m', 2, 21}, +{'l', 4, 21}, +{'l', 4, 19}, +{'l', 2, 19}, +{'l', 2, 21}, +{'m', 3, 21}, +{'l', 3, 19}, +{'m', 10, 21}, +{'l', 12, 21}, +{'l', 12, 19}, +{'l', 10, 19}, +{'l', 10, 21}, +{'m', 11, 21}, +{'l', 11, 19}, +{'m', 12, 21}, +{'l', 14, 21}, +{'l', 14, 19}, +{'l', 12, 19}, +{'l', 12, 21}, +{'m', 13, 21}, +{'l', 13, 19}, +{'m', 20, 21}, +{'l', 22, 21}, +{'l', 22, 19}, +{'l', 20, 19}, +{'l', 20, 21}, +{'m', 21, 21}, +{'l', 21, 19}, +{'m', 22, 21}, +{'l', 24, 21}, +{'l', 24, 19}, +{'l', 22, 19}, +{'l', 22, 21}, +{'m', 23, 21}, +{'l', 23, 19}, +{'m', 4, 17}, +{'l', 6, 17}, +{'l', 6, 15}, +{'l', 4, 15}, +{'l', 4, 17}, +{'m', 5, 17}, +{'l', 5, 15}, +{'m', 6, 17}, +{'l', 8, 17}, +{'l', 8, 15}, +{'l', 6, 15}, +{'l', 6, 17}, +{'m', 7, 17}, +{'l', 7, 15}, +{'m', 8, 17}, +{'l', 10, 17}, +{'l', 10, 15}, +{'l', 8, 15}, +{'l', 8, 17}, +{'m', 9, 17}, +{'l', 9, 15}, +{'m', 0, 13}, +{'l', 2, 13}, +{'l', 2, 11}, +{'l', 0, 11}, +{'l', 0, 13}, +{'m', 1, 13}, +{'l', 1, 11}, +{'m', 2, 13}, +{'l', 4, 13}, +{'l', 4, 11}, +{'l', 2, 11}, +{'l', 2, 13}, +{'m', 3, 13}, +{'l', 3, 11}, +{'m', 10, 13}, +{'l', 12, 13}, +{'l', 12, 11}, +{'l', 10, 11}, +{'l', 10, 13}, +{'m', 11, 13}, +{'l', 11, 11}, +{'m', 12, 13}, +{'l', 14, 13}, +{'l', 14, 11}, +{'l', 12, 11}, +{'l', 12, 13}, +{'m', 13, 13}, +{'l', 13, 11}, +{'m', 20, 13}, +{'l', 22, 13}, +{'l', 22, 11}, +{'l', 20, 11}, +{'l', 20, 13}, +{'m', 21, 13}, +{'l', 21, 11}, +{'m', 22, 13}, +{'l', 24, 13}, +{'l', 24, 11}, +{'l', 22, 11}, +{'l', 22, 13}, +{'m', 23, 13}, +{'l', 23, 11}, +{'m', 14, 9}, +{'l', 16, 9}, +{'l', 16, 7}, +{'l', 14, 7}, +{'l', 14, 9}, +{'m', 15, 9}, +{'l', 15, 7}, +{'m', 16, 9}, +{'l', 18, 9}, +{'l', 18, 7}, +{'l', 16, 7}, +{'l', 16, 9}, +{'m', 17, 9}, +{'l', 17, 7}, +{'m', 18, 9}, +{'l', 20, 9}, +{'l', 20, 7}, +{'l', 18, 7}, +{'l', 18, 9}, +{'m', 19, 9}, +{'l', 19, 7}, +{'m', 0, 5}, +{'l', 2, 5}, +{'l', 2, 3}, +{'l', 0, 3}, +{'l', 0, 5}, +{'m', 1, 5}, +{'l', 1, 3}, +{'m', 2, 5}, +{'l', 4, 5}, +{'l', 4, 3}, +{'l', 2, 3}, +{'l', 2, 5}, +{'m', 3, 5}, +{'l', 3, 3}, +{'m', 10, 5}, +{'l', 12, 5}, +{'l', 12, 3}, +{'l', 10, 3}, +{'l', 10, 5}, +{'m', 11, 5}, +{'l', 11, 3}, +{'m', 12, 5}, +{'l', 14, 5}, +{'l', 14, 3}, +{'l', 12, 3}, +{'l', 12, 5}, +{'m', 13, 5}, +{'l', 13, 3}, +{'m', 20, 5}, +{'l', 22, 5}, +{'l', 22, 3}, +{'l', 20, 3}, +{'l', 20, 5}, +{'m', 21, 5}, +{'l', 21, 3}, +{'m', 22, 5}, +{'l', 24, 5}, +{'l', 24, 3}, +{'l', 22, 3}, +{'l', 22, 5}, +{'m', 23, 5}, +{'l', 23, 3}, +{'m', 4, 1}, +{'l', 10, 1}, +{'l', 10, -1}, +{'l', 4, -1}, +{'l', 4, 1}, +{'m', 5, 1}, +{'l', 5, -1}, +{'m', 7, 1}, +{'l', 7, -1}, +{'m', 9, 1}, +{'l', 9, -1}, +{'m', 0, -3}, +{'l', 2, -3}, +{'l', 2, -5}, +{'l', 0, -5}, +{'l', 0, -3}, +{'m', 1, -3}, +{'l', 1, -5}, +{'m', 2, -3}, +{'l', 4, -3}, +{'l', 4, -5}, +{'l', 2, -5}, +{'l', 2, -3}, +{'m', 3, -3}, +{'l', 3, -5}, +{'m', 10, -3}, +{'l', 14, -3}, +{'l', 14, -5}, +{'l', 10, -5}, +{'l', 10, -3}, +{'m', 11, -3}, +{'l', 11, -5}, +{'m', 13, -3}, +{'l', 13, -5}, +{'m', 20, -3}, +{'l', 24, -3}, +{'l', 24, -5}, +{'l', 20, -5}, +{'l', 20, -3}, +{'m', 21, -3}, +{'l', 21, -5}, +{'m', 23, -3}, +{'l', 23, -5}, +{'m', 8, 1}, +{'l', 8, -1}, +{'m', 6, 1}, +{'l', 6, -1}, +{'m', 12, -3}, +{'l', 12, -5}, +{'m', 22, -3}, +{'l', 22, -5}, +{'m', 18, 17}, +{'l', 20, 17}, +{'l', 20, 15}, +{'l', 18, 15}, +{'l', 18, 17}, +{'m', 19, 17}, +{'l', 19, 15}, +{'m', 20, 17}, +{'l', 22, 17}, +{'l', 22, 15}, +{'l', 20, 15}, +{'l', 20, 17}, +{'m', 21, 17}, +{'l', 21, 15}, +{'m', 22, 17}, +{'l', 24, 17}, +{'l', 24, 15}, +{'l', 22, 15}, +{'l', 22, 17}, +{'m', 23, 17}, +{'l', 23, 15}, +{'m', 0, 9}, +{'l', 2, 9}, +{'l', 2, 7}, +{'l', 0, 7}, +{'l', 0, 9}, +{'m', 1, 9}, +{'l', 1, 7}, +{'m', 2, 9}, +{'l', 4, 9}, +{'l', 4, 7}, +{'l', 2, 7}, +{'l', 2, 9}, +{'m', 3, 9}, +{'l', 3, 7}, +{'m', 4, 9}, +{'l', 6, 9}, +{'l', 6, 7}, +{'l', 4, 7}, +{'l', 4, 9}, +{'m', 5, 9}, +{'l', 5, 7}, +{'m', 18, 1}, +{'l', 24, 1}, +{'l', 24, -1}, +{'l', 18, -1}, +{'l', 18, 1}, +{'m', 19, 1}, +{'l', 19, -1}, +{'m', 21, 1}, +{'l', 21, -1}, +{'m', 23, 1}, +{'l', 23, -1}, +{'m', 20, 1}, +{'l', 20, -1}, +{'m', 22, 1}, +{'l', 22, -1}, +}; +static cdOperation vf_default_char_179[] = { +{'m', 0, 21}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_180[] = { +{'m', 8, 21}, +{'l', 8, -7}, +{'m', 0, 5}, +{'l', 8, 5}, +}; +static cdOperation vf_default_char_181[] = { +{'m', 8, -7}, +{'l', 8, 21}, +{'m', 0, 9}, +{'l', 8, 9}, +{'m', 0, 5}, +{'l', 8, 5}, +}; +static cdOperation vf_default_char_182[] = { +{'m', 8, 21}, +{'l', 8, -7}, +{'m', 0, 5}, +{'l', 8, 5}, +{'m', 16, 21}, +{'l', 16, -7}, +}; +static cdOperation vf_default_char_183[] = { +{'m', 0, 5}, +{'l', 16, 5}, +{'l', 16, -7}, +{'m', 8, 5}, +{'l', 8, -7}, +}; +static cdOperation vf_default_char_184[] = { +{'m', 0, 9}, +{'l', 8, 9}, +{'l', 8, -7}, +{'m', 0, 5}, +{'l', 8, 5}, +}; +static cdOperation vf_default_char_185[] = { +{'m', 0, 5}, +{'l', 8, 5}, +{'l', 8, -7}, +{'m', 16, 21}, +{'l', 16, -7}, +{'m', 0, 9}, +{'l', 8, 9}, +{'l', 8, 21}, +{'m', 0, 1}, +{'l', 0, 1}, +}; +static cdOperation vf_default_char_186[] = { +{'m', 8, 21}, +{'l', 8, -7}, +{'m', 16, 21}, +{'l', 16, -7}, +}; +static cdOperation vf_default_char_187[] = { +{'m', 0, 9}, +{'l', 16, 9}, +{'l', 16, -7}, +{'m', 0, 5}, +{'l', 8, 5}, +{'l', 8, -7}, +}; +static cdOperation vf_default_char_188[] = { +{'m', 0, 5}, +{'l', 16, 5}, +{'l', 16, 21}, +{'m', 0, 9}, +{'l', 8, 9}, +{'l', 8, 21}, +}; +static cdOperation vf_default_char_189[] = { +{'m', 0, 9}, +{'l', 16, 9}, +{'l', 16, 21}, +{'m', 8, 9}, +{'l', 8, 21}, +}; +static cdOperation vf_default_char_190[] = { +{'m', 0, 5}, +{'l', 8, 5}, +{'l', 8, 21}, +{'m', 0, 9}, +{'l', 8, 9}, +}; +static cdOperation vf_default_char_191[] = { +{'m', 0, 5}, +{'l', 8, 5}, +{'l', 8, -7}, +}; +static cdOperation vf_default_char_192[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 4, 28}, +{'l', 9, 23}, +}; +static cdOperation vf_default_char_193[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_194[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 3, 23}, +{'l', 8, 28}, +{'l', 13, 23}, +}; +static cdOperation vf_default_char_195[] = { +{'m', 16, 0}, +{'l', 8, 21}, +{'l', 0, 0}, +{'m', 3, 7}, +{'l', 13, 7}, +{'m', 2, 24}, +{'l', 7, 27}, +{'l', 11, 24}, +{'l', 15, 26}, +}; +static cdOperation vf_default_char_196[] = { +{'m', 0, 5}, +{'l', 16, 5}, +}; +static cdOperation vf_default_char_197[] = { +{'m', 8, 21}, +{'l', 8, -7}, +{'m', 0, 5}, +{'l', 16, 5}, +}; +static cdOperation vf_default_char_198[] = { +{'m', 0, -7}, +{'l', 0, 21}, +{'m', 8, 9}, +{'l', 0, 9}, +{'m', 8, 5}, +{'l', 0, 5}, +}; +static cdOperation vf_default_char_199[] = { +{'m', 8, 21}, +{'l', 8, -7}, +{'m', 16, 5}, +{'l', 8, 5}, +{'m', 0, 21}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_200[] = { +{'m', 13, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'l', 13, 0}, +{'m', 0, 11}, +{'l', 8, 11}, +{'m', 4, 28}, +{'l', 9, 23}, +}; +static cdOperation vf_default_char_201[] = { +{'m', 16, 9}, +{'l', 0, 9}, +{'l', 0, -7}, +{'m', 16, 5}, +{'l', 8, 5}, +{'l', 8, -7}, +}; +static cdOperation vf_default_char_202[] = { +{'m', 13, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'l', 13, 0}, +{'m', 0, 11}, +{'l', 8, 11}, +{'m', 2, 24}, +{'l', 7, 29}, +{'l', 12, 24}, +{'l', 7, 29}, +{'l', 2, 24}, +}; +static cdOperation vf_default_char_203[] = { +{'m', 13, 21}, +{'l', 0, 21}, +{'l', 0, 0}, +{'l', 13, 0}, +{'m', 0, 11}, +{'l', 8, 11}, +{'m', 4, 26}, +{'l', 3, 25}, +{'l', 4, 24}, +{'l', 5, 25}, +{'l', 4, 26}, +{'m', 12, 26}, +{'l', 11, 25}, +{'l', 12, 24}, +{'l', 13, 25}, +{'l', 12, 26}, +}; +static cdOperation vf_default_char_204[] = { +{'m', 5, 21}, +{'l', 5, 0}, +{'m', 0, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_205[] = { +{'m', 5, 21}, +{'l', 5, 0}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_206[] = { +{'m', 6, 21}, +{'l', 6, 0}, +{'m', 2, 26}, +{'l', 7, 31}, +{'l', 12, 26}, +}; +static cdOperation vf_default_char_207[] = { +{'m', 8, 21}, +{'l', 8, 0}, +{'m', 4, 26}, +{'l', 3, 25}, +{'l', 4, 24}, +{'l', 5, 25}, +{'l', 4, 26}, +{'m', 12, 26}, +{'l', 11, 25}, +{'l', 12, 24}, +{'l', 13, 25}, +{'l', 12, 26}, +}; +static cdOperation vf_default_char_208[] = { +{'m', 6, 21}, +{'l', 6, 0}, +{'m', 6, 21}, +{'l', 13, 21}, +{'l', 16, 20}, +{'l', 18, 18}, +{'l', 19, 16}, +{'l', 20, 13}, +{'l', 20, 8}, +{'l', 19, 5}, +{'l', 18, 3}, +{'l', 16, 1}, +{'l', 13, 0}, +{'l', 6, 0}, +{'m', 0, 10}, +{'l', 12, 10}, +}; +static cdOperation vf_default_char_209[] = { +{'m', 0, 5}, +{'l', 8, 5}, +{'l', 8, -7}, +{'m', 16, 5}, +{'l', 8, 5}, +{'m', 0, 9}, +{'l', 16, 9}, +}; +static cdOperation vf_default_char_210[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 4, 28}, +{'l', 9, 23}, +}; +static cdOperation vf_default_char_211[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_212[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 3, 23}, +{'l', 8, 28}, +{'l', 13, 23}, +}; +static cdOperation vf_default_char_213[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 2, 24}, +{'l', 7, 27}, +{'l', 11, 24}, +{'l', 15, 26}, +}; +static cdOperation vf_default_char_214[] = { +{'m', 16, 5}, +{'l', 0, 5}, +{'l', 0, -7}, +{'m', 8, 5}, +{'l', 8, -7}, +}; +static cdOperation vf_default_char_215[] = { +{'m', 0, 0}, +{'l', 14, 14}, +{'m', 0, 13}, +{'l', 14, -1}, +}; +static cdOperation vf_default_char_216[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 1, -3}, +{'l', 2, -1}, +{'l', 16, 23}, +}; +static cdOperation vf_default_char_217[] = { +{'m', 0, 21}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 21}, +{'m', 4, 28}, +{'l', 9, 23}, +}; +static cdOperation vf_default_char_218[] = { +{'m', 0, 21}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 21}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_219[] = { +{'m', 0, 21}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 6, 0}, +{'l', 8, 0}, +{'l', 11, 1}, +{'l', 13, 3}, +{'l', 14, 6}, +{'l', 14, 21}, +{'m', 2, 24}, +{'l', 7, 29}, +{'l', 12, 24}, +{'l', 7, 29}, +{'l', 2, 24}, +}; +static cdOperation vf_default_char_220[] = { +{'m', 16, 0}, +{'l', 0, 0}, +{'l', 0, 11}, +{'l', 16, 11}, +{'l', 16, 0}, +{'l', 15, 0}, +{'l', 15, 11}, +{'m', 1, 11}, +{'l', 1, 0}, +{'m', 2, 11}, +{'l', 2, 0}, +{'m', 3, 11}, +{'l', 3, 0}, +{'m', 4, 11}, +{'l', 4, 0}, +{'m', 5, 11}, +{'l', 5, 0}, +{'m', 6, 11}, +{'l', 6, 0}, +{'m', 7, 11}, +{'l', 7, 0}, +{'m', 8, 11}, +{'l', 8, 0}, +{'m', 9, 11}, +{'l', 9, 0}, +{'m', 10, 11}, +{'l', 10, 0}, +{'m', 11, 11}, +{'l', 11, 0}, +{'m', 12, 11}, +{'l', 12, 0}, +{'m', 13, 11}, +{'l', 13, 0}, +{'m', 14, 11}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_221[] = { +{'m', 0, 21}, +{'l', 8, 11}, +{'l', 8, 0}, +{'m', 16, 21}, +{'l', 8, 11}, +{'m', 10, 28}, +{'l', 5, 23}, +}; +static cdOperation vf_default_char_222[] = { +{'m', 9, 0}, +{'l', 9, 21}, +{'m', 10, 21}, +{'l', 10, 0}, +{'m', 11, 21}, +{'l', 11, 0}, +{'m', 12, 21}, +{'l', 12, 0}, +{'m', 13, 21}, +{'l', 13, 0}, +{'m', 14, 21}, +{'l', 14, 0}, +{'m', 15, 21}, +{'l', 15, 0}, +{'m', 16, 21}, +{'l', 16, 0}, +{'m', 17, 21}, +{'l', 17, 0}, +}; +static cdOperation vf_default_char_223[] = { +{'m', 0, 1}, +{'l', 10, 1}, +{'l', 13, 3}, +{'l', 13, 7}, +{'l', 9, 9}, +{'l', 13, 11}, +{'l', 13, 14}, +{'l', 10, 16}, +{'l', 3, 16}, +{'l', 0, 14}, +{'l', 0, -3}, +{'m', 9, 9}, +{'l', 0, 9}, +}; +static cdOperation vf_default_char_224[] = { +{'m', 18, 0}, +{'l', 12, 9}, +{'l', 10, 11}, +{'l', 8, 12}, +{'l', 5, 12}, +{'l', 3, 11}, +{'l', 1, 9}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 18, 12}, +}; +static cdOperation vf_default_char_225[] = { +{'m', 0, 1}, +{'l', 10, 1}, +{'l', 13, 3}, +{'l', 13, 7}, +{'l', 9, 9}, +{'l', 13, 11}, +{'l', 13, 14}, +{'l', 10, 16}, +{'l', 3, 16}, +{'l', 0, 14}, +{'l', 0, -3}, +{'m', 9, 9}, +{'l', 0, 9}, +}; +static cdOperation vf_default_char_226[] = { +{'m', 0, 0}, +{'l', 0, 14}, +{'l', 9, 14}, +{'l', 9, 11}, +}; +static cdOperation vf_default_char_227[] = { +{'m', 12, 14}, +{'l', 12, 0}, +{'m', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'m', 0, 17}, +{'l', 5, 20}, +{'l', 9, 17}, +{'l', 13, 19}, +}; +static cdOperation vf_default_char_228[] = { +{'m', 13, 2}, +{'l', 13, 0}, +{'l', 0, 0}, +{'l', 8, 11}, +{'l', 0, 21}, +{'l', 13, 21}, +{'l', 13, 19}, +}; +static cdOperation vf_default_char_229[] = { +{'m', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 12, 9}, +{'l', 10, 11}, +{'l', 8, 12}, +{'l', 5, 12}, +{'l', 3, 11}, +{'l', 1, 9}, +{'l', 0, 6}, +{'m', 5, 12}, +{'l', 9, 14}, +{'l', 20, 14}, +}; +static cdOperation vf_default_char_230[] = { +{'m', 2, 14}, +{'l', 2, 4}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 13, 4}, +{'m', 13, 14}, +{'l', 13, 0}, +{'m', 3, 1}, +{'l', 3, -3}, +{'l', 0, -6}, +}; +static cdOperation vf_default_char_231[] = { +{'m', 0, 9}, +{'l', 0, 11}, +{'l', 1, 13}, +{'l', 3, 14}, +{'l', 6, 14}, +{'l', 8, 12}, +{'l', 8, -2}, +{'m', 8, 9}, +{'l', 11, 11}, +{'l', 14, 14}, +}; +static cdOperation vf_default_char_232[] = { +{'m', 0, 9}, +{'l', 1, 6}, +{'l', 3, 4}, +{'l', 5, 3}, +{'l', 8, 3}, +{'l', 10, 4}, +{'l', 12, 6}, +{'l', 13, 9}, +{'l', 12, 12}, +{'l', 10, 14}, +{'l', 8, 15}, +{'l', 5, 15}, +{'l', 3, 14}, +{'l', 1, 12}, +{'l', 0, 9}, +{'m', 6, 21}, +{'l', 6, 15}, +{'m', 7, 21}, +{'l', 7, 15}, +{'m', 0, 21}, +{'l', 13, 21}, +{'m', 6, -3}, +{'l', 6, 3}, +{'m', 7, -3}, +{'l', 7, 3}, +{'m', 0, -3}, +{'l', 13, -3}, +}; +static cdOperation vf_default_char_233[] = { +{'m', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 8}, +{'l', 1, 5}, +{'l', 2, 3}, +{'l', 4, 1}, +{'l', 6, 0}, +{'l', 10, 0}, +{'l', 12, 1}, +{'l', 14, 3}, +{'l', 15, 5}, +{'l', 16, 8}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'m', 0, 10}, +{'l', 16, 10}, +}; +static cdOperation vf_default_char_234[] = { +{'m', 16, 0}, +{'l', 11, 0}, +{'l', 11, 6}, +{'l', 14, 7}, +{'l', 16, 9}, +{'l', 16, 13}, +{'l', 15, 16}, +{'l', 14, 18}, +{'l', 12, 20}, +{'l', 10, 21}, +{'l', 6, 21}, +{'l', 4, 20}, +{'l', 2, 18}, +{'l', 1, 16}, +{'l', 0, 13}, +{'l', 0, 9}, +{'l', 2, 7}, +{'l', 5, 6}, +{'l', 5, 0}, +{'l', 0, 0}, +}; +static cdOperation vf_default_char_235[] = { +{'m', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 12, 9}, +{'l', 10, 11}, +{'l', 8, 12}, +{'l', 5, 12}, +{'l', 3, 11}, +{'l', 1, 9}, +{'l', 0, 6}, +{'m', 10, 11}, +{'l', 0, 21}, +{'l', 13, 21}, +{'l', 13, 18}, +}; +static cdOperation vf_default_char_236[] = { +{'m', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 12, 9}, +{'l', 10, 11}, +{'l', 8, 12}, +{'l', 5, 12}, +{'l', 3, 11}, +{'l', 1, 9}, +{'l', 0, 6}, +{'m', 12, 6}, +{'l', 13, 3}, +{'l', 15, 1}, +{'l', 17, 0}, +{'l', 20, 0}, +{'l', 22, 1}, +{'l', 24, 3}, +{'l', 25, 6}, +{'l', 24, 9}, +{'l', 22, 11}, +{'l', 20, 12}, +{'l', 17, 12}, +{'l', 15, 11}, +{'l', 13, 9}, +{'l', 12, 6}, +}; +static cdOperation vf_default_char_237[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 0, -3}, +{'l', 13, 17}, +}; +static cdOperation vf_default_char_238[] = { +{'m', 13, 21}, +{'l', 3, 21}, +{'l', 0, 19}, +{'l', 0, 11}, +{'l', 8, 11}, +{'m', 0, 11}, +{'l', 0, 2}, +{'l', 3, 0}, +{'l', 13, 0}, +}; +static cdOperation vf_default_char_239[] = { +{'m', 0, 0}, +{'l', 0, 15}, +{'l', 1, 18}, +{'l', 3, 20}, +{'l', 6, 21}, +{'l', 8, 21}, +{'l', 11, 20}, +{'l', 13, 18}, +{'l', 14, 15}, +{'l', 14, 0}, +}; +static cdOperation vf_default_char_240[] = { +{'m', 0, 9}, +{'l', 18, 9}, +{'m', 0, 5}, +{'l', 18, 5}, +{'m', 0, 13}, +{'l', 18, 13}, +}; +static cdOperation vf_default_char_241[] = { +{'m', 0, 0}, +{'l', 18, 0}, +{'m', 9, 21}, +{'l', 9, 3}, +{'m', 0, 12}, +{'l', 18, 12}, +}; +static cdOperation vf_default_char_242[] = { +{'m', 0, 0}, +{'l', 18, 0}, +{'m', 0, 21}, +{'l', 18, 12}, +{'l', 0, 3}, +}; +static cdOperation vf_default_char_243[] = { +{'m', 18, 0}, +{'l', 0, 0}, +{'m', 18, 21}, +{'l', 0, 12}, +{'l', 18, 3}, +}; +static cdOperation vf_default_char_244[] = { +{'m', 10, 20}, +{'l', 7, 21}, +{'l', 5, 21}, +{'l', 2, 20}, +{'l', 1, 19}, +{'l', 0, 16}, +{'l', 0, -7}, +}; +static cdOperation vf_default_char_245[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 0, 17}, +{'l', 5, 20}, +{'l', 9, 17}, +{'l', 13, 19}, +}; +static cdOperation vf_default_char_246[] = { +{'m', 9, 20}, +{'l', 8, 19}, +{'l', 9, 18}, +{'l', 10, 19}, +{'l', 9, 20}, +{'m', 9, 3}, +{'l', 8, 2}, +{'l', 9, 1}, +{'l', 10, 2}, +{'l', 9, 3}, +{'m', 0, 10}, +{'l', 18, 10}, +}; +static cdOperation vf_default_char_247[] = { +{'m', 9, 20}, +{'l', 8, 19}, +{'l', 9, 18}, +{'l', 10, 19}, +{'l', 9, 20}, +{'m', 9, 3}, +{'l', 8, 2}, +{'l', 9, 1}, +{'l', 10, 2}, +{'l', 9, 3}, +{'m', 0, 10}, +{'l', 18, 10}, +}; +static cdOperation vf_default_char_248[] = { +{'m', 5, 14}, +{'l', 3, 13}, +{'l', 1, 11}, +{'l', 0, 8}, +{'l', 0, 6}, +{'l', 1, 3}, +{'l', 3, 1}, +{'l', 5, 0}, +{'l', 8, 0}, +{'l', 10, 1}, +{'l', 12, 3}, +{'l', 13, 6}, +{'l', 13, 8}, +{'l', 12, 11}, +{'l', 10, 13}, +{'l', 8, 14}, +{'l', 5, 14}, +{'m', 0, -3}, +{'l', 13, 17}, +}; +static cdOperation vf_default_char_249[] = { +{'m', 0, 4}, +{'l', 3, 4}, +{'l', 3, 0}, +{'l', 0, 0}, +{'l', 0, 4}, +{'m', 1, 4}, +{'l', 1, 0}, +{'m', 2, 4}, +{'l', 2, 0}, +}; +static cdOperation vf_default_char_250[] = { +{'m', 0, 2}, +{'l', 3, 2}, +{'l', 3, 0}, +{'l', 0, 0}, +{'l', 0, 2}, +{'l', 3, 1}, +{'m', 1, 2}, +{'l', 1, 0}, +{'m', 2, 2}, +{'l', 2, 0}, +}; +static cdOperation vf_default_char_251[] = { +{'m', 16, 18}, +{'l', 16, 21}, +{'l', 8, 21}, +{'l', 8, 0}, +{'l', 0, 10}, +}; +static cdOperation vf_default_char_252[] = { +{'m', 0, 21}, +{'l', 0, 10}, +{'m', 0, 17}, +{'l', 3, 20}, +{'l', 5, 21}, +{'l', 8, 21}, +{'l', 10, 20}, +{'l', 11, 17}, +{'l', 11, 10}, +}; +static cdOperation vf_default_char_253[] = { +{'m', 1, 14}, +{'l', 7, 0}, +{'m', 13, 14}, +{'l', 7, 0}, +{'l', 5, -4}, +{'l', 3, -6}, +{'l', 1, -7}, +{'l', 0, -7}, +{'m', 10, 22}, +{'l', 5, 17}, +}; +static cdOperation vf_default_char_254[] = { +{'m', 0, 0}, +{'l', 0, 11}, +{'l', 8, 11}, +{'l', 8, 0}, +{'l', 0, 0}, +{'m', 1, 11}, +{'l', 1, 0}, +{'m', 2, 11}, +{'l', 2, 0}, +{'m', 3, 11}, +{'l', 3, 0}, +{'m', 4, 11}, +{'l', 4, 0}, +{'m', 5, 11}, +{'l', 5, 0}, +{'m', 6, 11}, +{'l', 6, 0}, +{'m', 7, 11}, +{'l', 7, 0}, +}; +static cdCaracter vf_default_chars[256] = { +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{ 0, 0, 0, 0}, +{12, 6, 0, 0}, +{6, 3, 7, vf_default_char_33}, +{14, 7, 16, vf_default_char_34}, +{18, 9, 8, vf_default_char_35}, +{17, 8, 38, vf_default_char_36}, +{21, 10, 29, vf_default_char_37}, +{22, 11, 46, vf_default_char_38}, +{6, 3, 7, vf_default_char_39}, +{10, 5, 18, vf_default_char_40}, +{11, 5, 18, vf_default_char_41}, +{13, 6, 6, vf_default_char_42}, +{22, 11, 4, vf_default_char_43}, +{6, 3, 8, vf_default_char_44}, +{22, 11, 2, vf_default_char_45}, +{6, 3, 5, vf_default_char_46}, +{14, 7, 2, vf_default_char_47}, +{17, 8, 17, vf_default_char_48}, +{14, 7, 4, vf_default_char_49}, +{17, 8, 14, vf_default_char_50}, +{17, 8, 15, vf_default_char_51}, +{17, 8, 5, vf_default_char_52}, +{17, 8, 17, vf_default_char_53}, +{16, 8, 23, vf_default_char_54}, +{17, 8, 4, vf_default_char_55}, +{17, 8, 29, vf_default_char_56}, +{17, 8, 23, vf_default_char_57}, +{6, 3, 10, vf_default_char_58}, +{6, 3, 13, vf_default_char_59}, +{20, 10, 3, vf_default_char_60}, +{22, 11, 4, vf_default_char_61}, +{20, 10, 3, vf_default_char_62}, +{15, 7, 19, vf_default_char_63}, +{24, 12, 52, vf_default_char_64}, +{19, 9, 5, vf_default_char_65}, +{17, 8, 21, vf_default_char_66}, +{19, 9, 18, vf_default_char_67}, +{17, 8, 14, vf_default_char_68}, +{15, 7, 6, vf_default_char_69}, +{14, 7, 6, vf_default_char_70}, +{18, 9, 21, vf_default_char_71}, +{18, 9, 6, vf_default_char_72}, +{4, 2, 2, vf_default_char_73}, +{14, 7, 10, vf_default_char_74}, +{17, 8, 6, vf_default_char_75}, +{13, 6, 4, vf_default_char_76}, +{20, 10, 8, vf_default_char_77}, +{18, 9, 6, vf_default_char_78}, +{19, 9, 21, vf_default_char_79}, +{17, 8, 11, vf_default_char_80}, +{19, 9, 23, vf_default_char_81}, +{17, 8, 14, vf_default_char_82}, +{17, 8, 20, vf_default_char_83}, +{15, 7, 4, vf_default_char_84}, +{18, 9, 10, vf_default_char_85}, +{17, 8, 4, vf_default_char_86}, +{22, 11, 8, vf_default_char_87}, +{17, 8, 4, vf_default_char_88}, +{17, 8, 5, vf_default_char_89}, +{17, 8, 6, vf_default_char_90}, +{7, 3, 8, vf_default_char_91}, +{14, 7, 2, vf_default_char_92}, +{8, 4, 8, vf_default_char_93}, +{19, 9, 6, vf_default_char_94}, +{17, 8, 2, vf_default_char_95}, +{6, 3, 7, vf_default_char_96}, +{16, 8, 16, vf_default_char_97}, +{15, 7, 16, vf_default_char_98}, +{15, 7, 14, vf_default_char_99}, +{16, 8, 16, vf_default_char_100}, +{15, 7, 17, vf_default_char_101}, +{10, 5, 7, vf_default_char_102}, +{16, 8, 21, vf_default_char_103}, +{15, 7, 9, vf_default_char_104}, +{7, 3, 7, vf_default_char_105}, +{9, 4, 10, vf_default_char_106}, +{13, 6, 6, vf_default_char_107}, +{4, 2, 2, vf_default_char_108}, +{26, 13, 16, vf_default_char_109}, +{15, 7, 9, vf_default_char_110}, +{16, 8, 17, vf_default_char_111}, +{15, 7, 16, vf_default_char_112}, +{16, 8, 16, vf_default_char_113}, +{9, 4, 7, vf_default_char_114}, +{14, 7, 17, vf_default_char_115}, +{10, 5, 7, vf_default_char_116}, +{15, 7, 9, vf_default_char_117}, +{14, 7, 4, vf_default_char_118}, +{19, 9, 8, vf_default_char_119}, +{14, 7, 4, vf_default_char_120}, +{15, 7, 8, vf_default_char_121}, +{14, 7, 6, vf_default_char_122}, +{10, 5, 37, vf_default_char_123}, +{4, 2, 2, vf_default_char_124}, +{9, 4, 37, vf_default_char_125}, +{14, 7, 4, vf_default_char_126}, +{16, 8, 8, vf_default_char_127}, +{18, 9, 30, vf_default_char_128}, +{15, 7, 19, vf_default_char_129}, +{15, 7, 19, vf_default_char_130}, +{18, 9, 19, vf_default_char_131}, +{16, 8, 26, vf_default_char_132}, +{16, 8, 18, vf_default_char_133}, +{16, 8, 23, vf_default_char_134}, +{15, 7, 21, vf_default_char_135}, +{18, 9, 20, vf_default_char_136}, +{15, 7, 27, vf_default_char_137}, +{15, 7, 19, vf_default_char_138}, +{12, 6, 12, vf_default_char_139}, +{16, 8, 5, vf_default_char_140}, +{7, 3, 4, vf_default_char_141}, +{17, 8, 15, vf_default_char_142}, +{17, 8, 12, vf_default_char_143}, +{15, 7, 8, vf_default_char_144}, +{28, 14, 33, vf_default_char_145}, +{26, 13, 10, vf_default_char_146}, +{16, 8, 20, vf_default_char_147}, +{16, 8, 27, vf_default_char_148}, +{16, 8, 19, vf_default_char_149}, +{17, 8, 12, vf_default_char_150}, +{15, 7, 11, vf_default_char_151}, +{15, 7, 18, vf_default_char_152}, +{19, 9, 31, vf_default_char_153}, +{18, 9, 20, vf_default_char_154}, +{15, 7, 16, vf_default_char_155}, +{21, 10, 12, vf_default_char_156}, +{17, 8, 9, vf_default_char_157}, +{21, 10, 18, vf_default_char_158}, +{17, 8, 15, vf_default_char_159}, +{16, 8, 18, vf_default_char_160}, +{7, 3, 4, vf_default_char_161}, +{16, 8, 19, vf_default_char_162}, +{15, 7, 11, vf_default_char_163}, +{17, 8, 13, vf_default_char_164}, +{18, 9, 8, vf_default_char_165}, +{16, 8, 18, vf_default_char_166}, +{16, 8, 17, vf_default_char_167}, +{15, 7, 19, vf_default_char_168}, +{16, 8, 7, vf_default_char_169}, +{16, 8, 7, vf_default_char_170}, +{19, 9, 15, vf_default_char_171}, +{19, 9, 10, vf_default_char_172}, +{6, 3, 7, vf_default_char_173}, +{19, 9, 6, vf_default_char_174}, +{19, 9, 6, vf_default_char_175}, +{14, 7, 126, vf_default_char_176}, +{16, 8, 252, vf_default_char_177}, +{24, 12, 276, vf_default_char_178}, +{5, 2, 2, vf_default_char_179}, +{13, 6, 4, vf_default_char_180}, +{13, 6, 6, vf_default_char_181}, +{21, 10, 6, vf_default_char_182}, +{21, 10, 5, vf_default_char_183}, +{13, 6, 5, vf_default_char_184}, +{21, 10, 10, vf_default_char_185}, +{20, 10, 4, vf_default_char_186}, +{21, 10, 6, vf_default_char_187}, +{21, 10, 6, vf_default_char_188}, +{21, 10, 5, vf_default_char_189}, +{13, 6, 5, vf_default_char_190}, +{0, 0, 3, vf_default_char_191}, +{19, 9, 7, vf_default_char_192}, +{19, 9, 7, vf_default_char_193}, +{19, 9, 8, vf_default_char_194}, +{19, 9, 9, vf_default_char_195}, +{16, 8, 2, vf_default_char_196}, +{16, 8, 4, vf_default_char_197}, +{8, 4, 6, vf_default_char_198}, +{16, 8, 6, vf_default_char_199}, +{15, 7, 8, vf_default_char_200}, +{16, 8, 6, vf_default_char_201}, +{15, 7, 11, vf_default_char_202}, +{15, 7, 16, vf_default_char_203}, +{9, 2, 4, vf_default_char_204}, +{9, 2, 4, vf_default_char_205}, +{12, 2, 5, vf_default_char_206}, +{12, 2, 12, vf_default_char_207}, +{23, 8, 16, vf_default_char_208}, +{16, 8, 7, vf_default_char_209}, +{19, 9, 23, vf_default_char_210}, +{19, 9, 23, vf_default_char_211}, +{19, 9, 24, vf_default_char_212}, +{19, 9, 25, vf_default_char_213}, +{16, 8, 5, vf_default_char_214}, +{18, 11, 4, vf_default_char_215}, +{19, 9, 24, vf_default_char_216}, +{18, 9, 12, vf_default_char_217}, +{18, 9, 12, vf_default_char_218}, +{18, 9, 15, vf_default_char_219}, +{16, 8, 35, vf_default_char_220}, +{17, 8, 7, vf_default_char_221}, +{17, 8, 18, vf_default_char_222}, +{18, 9, 13, vf_default_char_223}, +{22, 11, 15, vf_default_char_224}, +{18, 9, 13, vf_default_char_225}, +{14, 7, 4, vf_default_char_226}, +{16, 8, 20, vf_default_char_227}, +{18, 9, 7, vf_default_char_228}, +{24, 12, 18, vf_default_char_229}, +{18, 9, 12, vf_default_char_230}, +{18, 9, 10, vf_default_char_231}, +{18, 9, 27, vf_default_char_232}, +{21, 10, 23, vf_default_char_233}, +{21, 10, 20, vf_default_char_234}, +{18, 9, 19, vf_default_char_235}, +{29, 14, 30, vf_default_char_236}, +{16, 8, 19, vf_default_char_237}, +{17, 8, 9, vf_default_char_238}, +{19, 9, 10, vf_default_char_239}, +{23, 11, 6, vf_default_char_240}, +{23, 11, 6, vf_default_char_241}, +{23, 11, 5, vf_default_char_242}, +{24, 12, 5, vf_default_char_243}, +{13, 6, 7, vf_default_char_244}, +{16, 8, 21, vf_default_char_245}, +{23, 11, 12, vf_default_char_246}, +{23, 11, 12, vf_default_char_247}, +{16, 8, 19, vf_default_char_248}, +{7, 3, 9, vf_default_char_249}, +{7, 3, 10, vf_default_char_250}, +{18, 9, 5, vf_default_char_251}, +{15, 7, 9, vf_default_char_252}, +{15, 7, 10, vf_default_char_253}, +{13, 6, 19, vf_default_char_254}, +{ 0, 0, 0, 0} +}; + +/******************************************************/ +/* inicializacao & controle */ +/******************************************************/ + +static void vf_releasefontchars(cdVectorFont *vector_font) +{ + int c; + + for (c=0; c<256; c++) + { + if (vector_font->chars[c].op) + free(vector_font->chars[c].op); + } + + free(vector_font->chars); +} + +static void vf_setdefaultfont(cdVectorFont *vector_font) +{ + if (vector_font->chars && vector_font->chars != vf_default_chars) + vf_releasefontchars(vector_font); + + strcpy(vector_font->name, "Simplex II"); + vector_font->file_name[0] = 0; + vector_font->chars = vf_default_chars; + vector_font->top = vf_default_top; + vector_font->cap = vf_default_cap; + vector_font->half = vf_default_half; + vector_font->bottom = vf_default_bottom; + vector_font->point_size_x = 1.0; + vector_font->point_size_y = 1.0; + vector_font->current_cos = 1.0; + vector_font->current_sin = 0.0; + vector_font->space = 1; + vector_font->line_space = 1; +} + +static int vf_readfontfile(FILE *file, cdVectorFont *vector_font) +{ + int c, right, center, operations; + + if (vector_font->chars && vector_font->chars != vf_default_chars) + vf_releasefontchars(vector_font); + + vector_font->chars = (cdCaracter *)calloc(256, sizeof(cdCaracter)); + if (!vector_font->chars) + return 0; + + if (fscanf(file,"%d%d%d%d",&vector_font->top,&vector_font->cap,&vector_font->half,&vector_font->bottom) != 4) + { + if (fscanf(file, "%[^\n]", vector_font->name) != 1) + return 0; + if (fscanf(file,"%d%d%d%d",&vector_font->top,&vector_font->cap,&vector_font->half,&vector_font->bottom)!=4) + return 0; + } + else + sprintf(vector_font->name, "Unknown"); + + while (fscanf(file, "%d%d%d%d", &c, &right, ¢er, &operations) == 4) + { + vector_font->chars[c].right = right; + vector_font->chars[c].center = center; + vector_font->chars[c].operations = operations; + if (operations) + { + int i; + vector_font->chars[c].op = (cdOperation *)calloc(operations, sizeof(cdOperation)); + if (!vector_font->chars[c].op) return 0; + for (i=0; ichars[c].op[i].operation = operation; + vector_font->chars[c].op[i].x = (signed char)x; + vector_font->chars[c].op[i].y = (signed char)y; + } + } + } + + return 1; +} + +static int vf_readfontstring(const char* file, cdVectorFont *vector_font) +{ + int c, right, center, operations; + + if (vector_font->chars && vector_font->chars != vf_default_chars) + vf_releasefontchars(vector_font); + + vector_font->chars = (cdCaracter *)calloc(256, sizeof(cdCaracter)); + if (!vector_font->chars) + return 0; + + /* try to read without a name */ + if (sscanf(file,"%d%d%d%d",&vector_font->top,&vector_font->cap,&vector_font->half,&vector_font->bottom) != 4) + { + if (sscanf(file, "%[^\n]", vector_font->name) != 1) + return 0; + file = strstr(file, "\n")+1; /* goto next line */ + if (file == (void*)1) return 0; + + if (sscanf(file,"%d%d%d%d",&vector_font->top,&vector_font->cap,&vector_font->half,&vector_font->bottom)!=4) + return 0; + file = strstr(file, "\n"); /* goto next line */ + if (file == (void*)1) return 0; + } + else + { + file = strstr(file, "\n")+1; /* goto next line */ + sprintf(vector_font->name, "Unknown"); + } + + /* skip 2 blank vf_lines */ + file = strstr(file, "\n")+1; /* goto next line */ + file = strstr(file, "\n")+1; /* goto next line */ + + /* for each font character */ + while (sscanf(file, "%d%d%d%d", &c, &right, ¢er, &operations) == 4) + { + file = strstr(file, "\n")+1; /* goto next line */ + if (file == (void*)1) return 0; + + vector_font->chars[c].right = right; + vector_font->chars[c].center = center; + vector_font->chars[c].operations = operations; + if (operations) + { + int i; + vector_font->chars[c].op = (cdOperation *)calloc(operations, sizeof(cdOperation)); + if (!vector_font->chars[c].op) return 0; + for (i=0; ichars[c].op[i].operation = operation; + vector_font->chars[c].op[i].x = (signed char)x; + vector_font->chars[c].op[i].y = (signed char)y; + } + } + + /* skip 1 blank line */ + file = strstr(file, "\n")+1; /* goto next line */ + if (file == (void*)1) return 1; + } + + return 1; +} + +static int vf_primlen(cdVectorFont *vector_font, const char* s) +{ + int len = 0; + while (*s) + len += vector_font->chars[(unsigned char)(*(s++))].right + vector_font->space; + return len; +} + +static void vf_move_dir(cdVectorFont *vector_font, int *px, int *py, double dx, double dy) +{ + *px += cdRound(vector_font->current_cos*dx - vector_font->current_sin*dy); + *py += cdRound(vector_font->current_sin*dx + vector_font->current_cos*dy); +} + +static void vf_wmove_dir(cdVectorFont *vector_font, double *px, double *py, double dx, double dy) +{ + *px += vector_font->current_cos*dx - vector_font->current_sin*dy; + *py += vector_font->current_sin*dx + vector_font->current_cos*dy; +} + +static void vf_writechar(cdVectorFont *vector_font, char c, int *px, int *py) +{ + unsigned char ac = vf_ansi2ascii[(unsigned char)c]; + cdOperation *current = vector_font->chars[ac].op; + int m, op = vector_font->chars[ac].operations; + + for(m = 0; m < op; m++) + { + int ponto_x = *px; + int ponto_y = *py; + + if (current->operation == 'm') + { + if (m) cdCanvasEnd(vector_font->canvas); + cdCanvasBegin(vector_font->canvas, CD_OPEN_LINES); + } + + vf_move_dir(vector_font, &ponto_x, &ponto_y, current->x*vector_font->point_size_x, current->y*vector_font->point_size_y); + + if (vector_font->text_transf) + { + double aux = ponto_x*vector_font->text_matrix[3] + ponto_y*vector_font->text_matrix[4] + vector_font->text_matrix[5]; + ponto_y = cdRound(ponto_x*vector_font->text_matrix[0] + ponto_y*vector_font->text_matrix[1] + vector_font->text_matrix[2]); + ponto_x = _cdRound(aux); + } + + cdCanvasVertex(vector_font->canvas, ponto_x, ponto_y); + current++; + } + + if (m) cdCanvasEnd(vector_font->canvas); +} + +static void vf_wwritechar(cdVectorFont *vector_font, char c, double *px, double *py) +{ + unsigned char ac = vf_ansi2ascii[(unsigned char)c]; + cdOperation *current = vector_font->chars[ac].op; + int m, op = vector_font->chars[ac].operations; + + for(m = 0; m < op; m++) + { + double ponto_x = *px; + double ponto_y = *py; + + if (current->operation == 'm') + { + if (m) cdCanvasEnd(vector_font->canvas); + cdCanvasBegin(vector_font->canvas, CD_OPEN_LINES); + } + + vf_wmove_dir(vector_font, &ponto_x, &ponto_y, current->x*vector_font->point_size_x, current->y*vector_font->point_size_y); + + if (vector_font->text_transf) + { + double aux = ponto_x*vector_font->text_matrix[3] + ponto_y*vector_font->text_matrix[4] + vector_font->text_matrix[5]; + ponto_y = ponto_x*vector_font->text_matrix[0] + ponto_y*vector_font->text_matrix[1] + vector_font->text_matrix[2]; + ponto_x = aux; + } + + wdCanvasVertex(vector_font->canvas, ponto_x, ponto_y); + current++; + } + + if (m) cdCanvasEnd(vector_font->canvas); +} + +static int vf_lines(char * s) +{ + int n = 1; + while (*s != 0) + { + if (*s == '\n') + { + n++; + *s = 0; + } + s++; + } + return n; +} + +static void vf_basic_write(cdVectorFont *vector_font, const char* s, int px, int py) +{ + while (*s) + { + vf_writechar(vector_font, *s, &px, &py); + vf_move_dir(vector_font, &px, &py, (vector_font->chars[(unsigned char)*s].right + vector_font->space)*vector_font->point_size_x, 0); + s++; + } +} + +static void vf_wbasic_write(cdVectorFont *vector_font, const char* s, double px, double py) +{ + while (*s) + { + vf_wwritechar(vector_font, *s, &px, &py); + vf_wmove_dir(vector_font, &px, &py, (vector_font->chars[(unsigned char)*s].right + vector_font->space)*vector_font->point_size_x, 0); + s++; + } +} + +static void vf_calc_pos(cdVectorFont *vector_font, int *px, int *py, int prim_len) +{ + int align = cdCanvasTextAlignment(vector_font->canvas, CD_QUERY); + + if (align == CD_NORTH || align == CD_NORTH_EAST || align == CD_NORTH_WEST) + { + vf_move_dir(vector_font, px, py, 0, -vector_font->top*vector_font->point_size_y); + } + else if (align == CD_SOUTH || align == CD_SOUTH_EAST || align == CD_SOUTH_WEST) + { + vf_move_dir(vector_font, px, py, 0, -vector_font->bottom*vector_font->point_size_y); /* bottom is < 0 */ + } + else if (align == CD_BASE_CENTER || align == CD_BASE_LEFT || align == CD_BASE_RIGHT) + { + /* py = py; */ + } + else /* center em y */ + vf_move_dir(vector_font, px, py, 0, -(double)(vector_font->cap+vector_font->bottom)/2*vector_font->point_size_y); + + if (align == CD_EAST || align == CD_NORTH_EAST || align == CD_SOUTH_EAST || align == CD_BASE_RIGHT) + { + vf_move_dir(vector_font, px, py, -prim_len*vector_font->point_size_x, 0); + } + else if (align == CD_WEST || align == CD_NORTH_WEST || align == CD_SOUTH_WEST || align == CD_BASE_LEFT) + { + ; /* px = px; */ + } + else /* center em x */ + vf_move_dir(vector_font, px, py, -(prim_len*vector_font->point_size_x)/2, 0); +} + +static void vf_wcalc_pos(cdVectorFont *vector_font, double *px, double *py, int prim_len) +{ + int align = cdCanvasTextAlignment(vector_font->canvas, CD_QUERY); + + if (align == CD_NORTH || align == CD_NORTH_EAST || align == CD_NORTH_WEST) + { + vf_wmove_dir(vector_font, px, py, 0, -vector_font->top*vector_font->point_size_y); + } + else if (align == CD_SOUTH || align == CD_SOUTH_EAST || align == CD_SOUTH_WEST) + { + vf_wmove_dir(vector_font, px, py, 0, -vector_font->bottom*vector_font->point_size_y); /* bottom is < 0 */ + } + else if (align == CD_BASE_CENTER || align == CD_BASE_LEFT || align == CD_BASE_RIGHT) + { + /* py = py; */ + } + else /* center em y */ + vf_wmove_dir(vector_font, px, py, 0, -(double)(vector_font->cap+vector_font->bottom)/2*vector_font->point_size_y); + + if (align == CD_EAST || align == CD_NORTH_EAST || align == CD_SOUTH_EAST || align == CD_BASE_RIGHT) + { + vf_wmove_dir(vector_font, px, py, -prim_len*vector_font->point_size_x, 0); + } + else if (align == CD_WEST || align == CD_NORTH_WEST || align == CD_SOUTH_WEST || align == CD_BASE_LEFT) + { + ; /* px = px; */ + } + else /* center em x */ + vf_wmove_dir(vector_font, px, py, -(prim_len*vector_font->point_size_x)/2, 0); +} + +static void vf_calc_point(cdVectorFont *vector_font, int startx, int starty, int *px, int *py, int dx, int dy) +{ + *px = startx; + *py = starty; + vf_move_dir(vector_font, px, py, dx, dy); + + if (vector_font->text_transf) + { + double aux = *px * vector_font->text_matrix[3] + *py * vector_font->text_matrix[4] + vector_font->text_matrix[5]; + *py = cdRound(*px * vector_font->text_matrix[0] + *py * vector_font->text_matrix[1] + vector_font->text_matrix[2]); + *px = _cdRound(aux); + } +} + +static void vf_wcalc_point(cdVectorFont *vector_font, double startx, double starty, double *px, double *py, double dx, double dy) +{ + *px = startx; + *py = starty; + + vf_wmove_dir(vector_font, px, py, dx, dy); + + if (vector_font->text_transf) + { + double aux = *px * vector_font->text_matrix[3] + *py * vector_font->text_matrix[4] + vector_font->text_matrix[5]; + *py = *px * vector_font->text_matrix[0] + *py * vector_font->text_matrix[1] + vector_font->text_matrix[2]; + *px = aux; + } +} + +static char *cd_getCDDIR(void) +{ + static char *env = NULL; + if (env) return env; + env = getenv("CDDIR"); + if (!env) env = "."; + return env; +} + +/******************************************************/ +/* vector text */ +/******************************************************/ + +cdVectorFont* cdCreateVectorFont(cdCanvas* canvas) +{ + cdVectorFont* vector_font = calloc(1, sizeof(cdVectorFont)); + vector_font->canvas = canvas; + vf_setdefaultfont(vector_font); + return vector_font; +} + +void cdKillVectorFont(cdVectorFont* vector_font) +{ + if (vector_font->chars && vector_font->chars != vf_default_chars) + vf_releasefontchars(vector_font); /* not the default font */ + + free(vector_font); +} + +void cdCanvasVectorTextDirection(cdCanvas* canvas, int x1, int y1, int x2, int y2) +{ + int dx=x2-x1; + int dy=y2-y1; + double len = sqrt(dx*dx +dy*dy); + cdVectorFont* vector_font = canvas->vector_font; + vector_font->current_sin = dy/len; + vector_font->current_cos = dx/len; +} + +int cdCanvasVectorCharSize(cdCanvas* canvas, int size) +{ + cdVectorFont* vector_font = canvas->vector_font; + int old_size = cdRound(vector_font->point_size_y*vector_font->top); + if (size == CD_QUERY) + return old_size; + + vector_font->point_size_y = size/(double)vector_font->top; + vector_font->point_size_x = size/(double)vector_font->top; + + return old_size; +} + +double* cdCanvasVectorTextTransform(cdCanvas* canvas, const double* matrix) +{ + cdVectorFont* vector_font = canvas->vector_font; + int i; + static double old_matrix[6]; + + if (vector_font->text_transf) + { + for (i=0; i<6; i++) + old_matrix[i] = vector_font->text_matrix[i]; + } + else + { + old_matrix[0] = 1; old_matrix[1] = 0; old_matrix[2] = 0; + old_matrix[3] = 0; old_matrix[4] = 1; old_matrix[5] = 0; + } + + if (matrix) + { + for (i=0; i<6; i++) + vector_font->text_matrix[i] = matrix[i]; + + vector_font->text_transf = 1; + } + else + vector_font->text_transf = 0; + + return old_matrix; +} + +void cdCanvasGetVectorTextSize(cdCanvas* canvas, const char *s, int *px, int *py) +{ + cdVectorFont* vector_font = canvas->vector_font; + if (px) *px = cdRound(vf_primlen(vector_font, s)*vector_font->point_size_x); + if (py) *py = cdRound(vector_font->top*vector_font->point_size_y); +} + +void cdCanvasGetVectorTextBounds(cdCanvas* canvas, const char *s, int px, int py, int *rect) +{ + cdVectorFont* vector_font = canvas->vector_font; + int prim_len = vf_primlen(vector_font, s); + int sx = cdRound(prim_len*vector_font->point_size_x); + int sy = cdRound(vector_font->top*vector_font->point_size_y); + + vf_calc_pos(vector_font, &px, &py, prim_len); + + vf_move_dir(vector_font, &px, &py, 0, vector_font->bottom*vector_font->point_size_y); + + vf_calc_point(vector_font, px, py, &rect[0], &rect[1], 0, 0); + vf_calc_point(vector_font, px, py, &rect[2], &rect[3], sx, 0); + vf_calc_point(vector_font, px, py, &rect[4], &rect[5], sx, sy); + vf_calc_point(vector_font, px, py, &rect[6], &rect[7], 0, sy); +} + +void cdCanvasVectorTextSize(cdCanvas* canvas, int size_x, int size_y, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + vector_font->point_size_x = size_x/(double)vf_primlen(vector_font, s); + vector_font->point_size_y = size_y/(double)vector_font->top; +} + +void cdCanvasVectorText(cdCanvas* canvas, int px, int py, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + int prim_len = vf_primlen(vector_font, s); + vf_calc_pos(vector_font, &px, &py, prim_len); + vf_basic_write(vector_font, s, px, py); +} + +void cdCanvasMultiLineVectorText(cdCanvas* canvas, int px, int py, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + double line_height = (vector_font->top - vector_font->bottom + vector_font->line_space) * vector_font->point_size_y; + char buff[MULTILINE_MAXLEN]; + char *str = buff; + int n; + + int align = cdCanvasTextAlignment(vector_font->canvas, CD_QUERY); /* procura o alinhamento do CD */ + + if (strlen(s) >= MULTILINE_MAXLEN) + return; + + strcpy(str, s); + n = vf_lines(str); + if (align == CD_NORTH || align == CD_NORTH_EAST || align == CD_NORTH_WEST) + { + ; /* Already at position */ + } + else if (align == CD_SOUTH || align == CD_SOUTH_EAST || align == CD_SOUTH_WEST) + { + vf_move_dir(vector_font, &px, &py, 0, (n-1)*line_height); + } + else + vf_move_dir(vector_font, &px, &py, 0, ((double)(n-1)/2)*line_height); + + while (n--) + { + cdCanvasVectorText(canvas, px, py, str); + str += strlen(str)+1; + vf_move_dir(vector_font, &px, &py, 0, -line_height); + } +} + +char *cdCanvasVectorFont(cdCanvas* canvas, const char *file) +{ + cdVectorFont* vector_font = canvas->vector_font; + if (!file) + { + vf_setdefaultfont(vector_font); + vector_font->file_name[0] = 0; + } + else + { + FILE *font = NULL; + int read_ok; + + /* se arquivo foi o mesmo que o arq. corrente, entao retorna */ + if (strcmp (file, vector_font->file_name) == 0) + return vector_font->name; + + /* abre arq. no dir. corrente */ + font = fopen(file, "r"); + + /* se nao conseguiu, abre arq. no dir. do cd, */ + if (!font && (strlen(file) < 10240 - strlen(cd_getCDDIR()))) + { + char filename[10240]; + sprintf(filename, "%s/%s", cd_getCDDIR(), file); + font = fopen(filename, "r"); + } + + if (font) + read_ok = vf_readfontfile(font, vector_font); + else + read_ok = vf_readfontstring(file, vector_font); + + if (!read_ok) + { + if (font) fclose(font); + vf_setdefaultfont(vector_font); + vector_font->file_name[0] = 0; + return NULL; + } + + /* guarda nome do arquivo que esta' carregado */ + if (font) + { + strcpy(vector_font->file_name, file); + fclose(font); + } + else + strcpy(vector_font->file_name, vector_font->name); + } + + return vector_font->name; +} + +/******************************************************/ +/* vector text em WC */ +/******************************************************/ + +void wdCanvasVectorTextDirection(cdCanvas* canvas, double x1, double y1, double x2, double y2) +{ + cdVectorFont* vector_font = canvas->vector_font; + double dx=x2-x1; + double dy=y2-y1; + double len = sqrt(dx*dx +dy*dy); + vector_font->current_sin = dy/len; + vector_font->current_cos = dx/len; +} + +double wdCanvasVectorCharSize(cdCanvas* canvas, double size) +{ + cdVectorFont* vector_font = canvas->vector_font; + double old_size = vector_font->point_size_y*vector_font->top; + if (size == CD_QUERY) + return old_size; + + vector_font->point_size_y = size/(double)vector_font->top; + vector_font->point_size_x = size/(double)vector_font->top; + + return old_size; +} + +void wdCanvasVectorTextSize(cdCanvas* canvas, double size_x, double size_y, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + vector_font->point_size_x = size_x/(double)vf_primlen(vector_font, s); + vector_font->point_size_y = size_y/(double)vector_font->top; +} + +void wdCanvasGetVectorTextSize(cdCanvas* canvas, const char *s, double *px, double *py) +{ + cdVectorFont* vector_font = canvas->vector_font; + if (px) *px = vf_primlen(vector_font, s)*vector_font->point_size_x; + if (py) *py = vector_font->top*vector_font->point_size_y; +} + +void wdCanvasGetVectorTextBounds(cdCanvas* canvas, const char *s, double px, double py, double *rect) +{ + cdVectorFont* vector_font = canvas->vector_font; + int prim_len = vf_primlen(vector_font, s); + double sx = prim_len*vector_font->point_size_x; + double sy = vector_font->top*vector_font->point_size_y; + + vf_wcalc_pos(vector_font, &px, &py, prim_len); + + vf_wmove_dir(vector_font, &px, &py, 0, vector_font->bottom*vector_font->point_size_y); + + vf_wcalc_point(vector_font, px, py, &rect[0], &rect[1], 0, 0); + vf_wcalc_point(vector_font, px, py, &rect[2], &rect[3], sx, 0); + vf_wcalc_point(vector_font, px, py, &rect[4], &rect[5], sx, sy); + vf_wcalc_point(vector_font, px, py, &rect[6], &rect[7], 0, sy); +} + +void wdCanvasVectorText(cdCanvas* canvas, double px, double py, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + int prim_len = vf_primlen(vector_font, s); + vf_wcalc_pos(vector_font, &px, &py, prim_len); + vf_wbasic_write(vector_font, s, px, py); +} + +void wdCanvasMultiLineVectorText(cdCanvas* canvas, double px, double py, const char* s) +{ + cdVectorFont* vector_font = canvas->vector_font; + double line_height = (vector_font->top - vector_font->bottom + vector_font->line_space)*vector_font->point_size_y; + char buff[MULTILINE_MAXLEN]; + char *str = buff; + int n; + + int align = cdCanvasTextAlignment(vector_font->canvas, CD_QUERY); /* procura o alinhamento do CD */ + + if (strlen(s) >= MULTILINE_MAXLEN) + return; + + strcpy(str, s); + n = vf_lines(str); + if (align == CD_NORTH || align == CD_NORTH_EAST || align == CD_NORTH_WEST) + ; /* Already at position */ + else if (align == CD_SOUTH || align == CD_SOUTH_EAST || align == CD_SOUTH_WEST) + vf_wmove_dir(vector_font, &px, &py, 0, (n-1)*line_height); + else + vf_wmove_dir(vector_font, &px, &py, 0, ((double)(n-1)/2)*line_height); + + while (n--) + { + wdCanvasVectorText(canvas, px, py, str); + str += strlen(str)+1; + vf_wmove_dir(vector_font, &px, &py, 0, -line_height); + } +} diff --git a/src/cdcontextplus.mak b/src/cdcontextplus.mak new file mode 100644 index 0000000..9cce04e --- /dev/null +++ b/src/cdcontextplus.mak @@ -0,0 +1,25 @@ +PROJNAME = cd +LIBNAME = cdcontextplus +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE + + +ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + SRCDIR = gdiplus + SRC = cdwemfp.cpp cdwimgp.cpp cdwinp.cpp cdwnativep.cpp cdwprnp.cpp cdwdbufp.cpp cdwclpp.cpp cdwgdiplus.c + + INCLUDES = . gdiplus drv + LIBS = gdiplus +else + SRC = xrender/cdxrender.c xrender/cdxrplus.c + + LIBS = Xrender Xft + USE_X11 = Yes + + INCLUDES = . sim drv freetype2 x11 +endif + + +USE_CD = YES +CD = .. diff --git a/src/cdlua3.mak b/src/cdlua3.mak new file mode 100644 index 0000000..cb809de --- /dev/null +++ b/src/cdlua3.mak @@ -0,0 +1,12 @@ +PROJNAME = cd +LIBNAME = cdlua3 + +OPT = YES + +DEF_FILE = cdlua.def +SRCDIR = lua3 +SRC = cdlua.c toluacd.c toluawd.c cdvoid.c cdluactx.c + +USE_LUA = YES +USE_CD = YES +CD = .. diff --git a/src/cdlua5.mak b/src/cdlua5.mak new file mode 100644 index 0000000..6083b86 --- /dev/null +++ b/src/cdlua5.mak @@ -0,0 +1,13 @@ +PROJNAME = cd +LIBNAME = cdlua51 + +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE +SRCDIR = lua5 +SRC = cdlua5.c cdvoid5.c cdlua5ctx.c cdlua5_active.c cdlua5_canvas.c +DEF_FILE = cdlua5.def + +USE_LUA51 = Yes +USE_CD = YES +CD = .. diff --git a/src/cdluacontextplus5.mak b/src/cdluacontextplus5.mak new file mode 100644 index 0000000..43c4211 --- /dev/null +++ b/src/cdluacontextplus5.mak @@ -0,0 +1,16 @@ +PROJNAME = cd +LIBNAME = cdluacontextplus51 + +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE +SRCDIR = lua5 +SRC = cdluacontextplus5.c +DEF_FILE = cdluacontextplus5.def + +LIBS = cdcontextplus + +USE_LUA51 = Yes +USE_CD = YES +USE_CDLUA = YES +CD = .. diff --git a/src/cdluaim5.mak b/src/cdluaim5.mak new file mode 100644 index 0000000..241104c --- /dev/null +++ b/src/cdluaim5.mak @@ -0,0 +1,15 @@ +PROJNAME = cd +LIBNAME = cdluaim51 + +OPT = YES + +DEF_FILE = cdluaim5.def +SRCDIR = lua5 +SRC = cdluaim5.c + +USE_CD = YES +USE_CDLUA = YES +USE_IM = YES +USE_IMLUA = YES +USE_LUA51 = YES +CD = .. diff --git a/src/cdluapdf3.mak b/src/cdluapdf3.mak new file mode 100644 index 0000000..e26b583 --- /dev/null +++ b/src/cdluapdf3.mak @@ -0,0 +1,15 @@ +PROJNAME = cd +LIBNAME = cdluapdf3 + +OPT = YES + +DEF_FILE = cdluapdf.def +SRCDIR = lua +SRC = cdluapdf.c +DEF_FILE = cdluapdf.def + +INCLUDES = ../include +LIBS = cdlua3 cdpdf +LDIR = ../lib/$(TEC_UNAME) + +USE_LUA = YES diff --git a/src/cdluapdf5.mak b/src/cdluapdf5.mak new file mode 100644 index 0000000..8f381a3 --- /dev/null +++ b/src/cdluapdf5.mak @@ -0,0 +1,16 @@ +PROJNAME = cd +LIBNAME = cdluapdf51 + +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE +SRCDIR = lua5 +SRC = cdluapdf5.c +DEF_FILE = cdluapdf5.def + +LIBS = cdpdf + +USE_LUA51 = Yes +USE_CD = YES +USE_CDLUA = YES +CD = .. diff --git a/src/cdpdf.def b/src/cdpdf.def new file mode 100644 index 0000000..eb139fe --- /dev/null +++ b/src/cdpdf.def @@ -0,0 +1,2 @@ +EXPORTS + cdContextPDF diff --git a/src/cdpdf.mak b/src/cdpdf.mak new file mode 100644 index 0000000..f4e5b40 --- /dev/null +++ b/src/cdpdf.mak @@ -0,0 +1,12 @@ +PROJNAME = cd +LIBNAME = cdpdf +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE +SRC = drv/cdpdf.c + +INCLUDES = . sim pdflib/pdflib +LIBS = pdflib + +USE_CD = YES +CD = .. diff --git a/src/config.mak b/src/config.mak new file mode 100644 index 0000000..5465a06 --- /dev/null +++ b/src/config.mak @@ -0,0 +1,47 @@ +PROJNAME = cd +LIBNAME = cd +OPT = YES + +DEFINES = CD_NO_OLD_INTERFACE + +SRCINTCGM = circle.c ellipse.c intcgm1.c \ + intcgm2.c intcgm4.c intcgm6.c list.c \ + sism.c tparse.c bparse.c +SRCINTCGM := $(addprefix intcgm/, $(SRCINTCGM)) + +SRCWIN32 = cdwclp.c cdwemf.c cdwimg.c cdwin.c cdwnative.c cdwprn.c cdwwmf.c wmf_emf.c cdwdbuf.c cdwdib.c +SRCWIN32 := $(addprefix win32/, $(SRCWIN32)) + +SRCSIM := cdfontex.c sim.c cd_truetype.c sim_other.c sim_primitives.c sim_text.c sim_linepolyfill.c +SRCSIM := $(addprefix sim/, $(SRCSIM)) + +SRCX11 = cdx11.c cdxclp.c cdximg.c cdxnative.c cdxdbuf.c xvertex.c +SRCX11 := $(addprefix x11/, $(SRCX11)) + +SRCDRV = cddgn.c cdcgm.c cgm.c cddxf.c cdirgb.c cdmf.c cdps.c cdpicture.c cddebug.c +SRCDRV := $(addprefix drv/, $(SRCDRV)) + +SRCNULL = cd0prn.c cd0emf.c cd0wmf.c +SRCNULL := $(addprefix drv/, $(SRCNULL)) + +SRCCOMM = cd.c wd.c wdhdcpy.c rgb2map.c cd_vectortext.c cd_active.c \ + cd_attributes.c cd_bitmap.c cd_image.c cd_primitives.c cd_text.c cd_util.c + +SRC = $(SRCCOMM) $(SRCINTCGM) $(SRCDRV) $(SRCSIM) + +ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + SRC += $(SRCWIN32) + LIBS = freetype6 +else + SRC += $(SRCNULL) $(SRCX11) + USE_X11 = Yes + LIBS = freetype +endif + +ifneq ($(findstring dll, $(TEC_UNAME)), ) + SRC += cd.rc +endif + +LDIR = ../lib/$(TEC_UNAME) + +INCLUDES = . drv x11 win32 intcgm freetype2 sim ../include diff --git a/src/drv/cd0emf.c b/src/drv/cd0emf.c new file mode 100644 index 0000000..13beb4c --- /dev/null +++ b/src/drv/cd0emf.c @@ -0,0 +1,17 @@ +/** \file + * \brief Dummy EMF + * + * See Copyright Notice in cd.h + */ + +#include +#include "cd.h" +#include "cdemf.h" + + +cdContext* cdContextEMF(void) +{ + return NULL; +} + + diff --git a/src/drv/cd0prn.c b/src/drv/cd0prn.c new file mode 100644 index 0000000..429a392 --- /dev/null +++ b/src/drv/cd0prn.c @@ -0,0 +1,17 @@ +/** \file + * \brief Dummy Printer + * + * See Copyright Notice in cd.h + */ + +#include +#include "cd.h" +#include "cdprint.h" + + + +cdContext* cdContextPrinter(void) +{ + return NULL; +} + diff --git a/src/drv/cd0wmf.c b/src/drv/cd0wmf.c new file mode 100644 index 0000000..a96761a --- /dev/null +++ b/src/drv/cd0wmf.c @@ -0,0 +1,16 @@ +/** \file + * \brief Dummy WMF + * + * See Copyright Notice in cd.h + */ + +#include +#include "cd.h" +#include "cdwmf.h" + + +cdContext* cdContextWMF(void) +{ + return NULL; +} + diff --git a/src/drv/cdcgm.c b/src/drv/cdcgm.c new file mode 100644 index 0000000..4ba0065 --- /dev/null +++ b/src/drv/cdcgm.c @@ -0,0 +1,1135 @@ +/** \file + * \brief CGM driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cdcgm.h" +#include "cgm.h" + +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + CGM *cgm; + + char filename[256]; /* Arquivo CGM */ + + int codificacao; /* Codificacao */ + int vdc_int_prec; + int first; /* Primeira primitiva a ser desenhada */ + long point; + int hassize; + int patindex; + + struct + { + cdfRect bbox; + int first; + } clip; + + cdfRect b_box; +}; + +static double cve_black[] = { 0.0, 0.0, 0.0 }; +static double cve_white[] = { 1.0, 1.0, 1.0 }; + +/* From INTCGM */ +int cdplayCGM(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data); +int cdRegisterCallbackCGM(int cb, cdCallback func); + + +/* +%F Atualiza os valores do bounding box +*/ +static void setbbox (cdCtxCanvas *ctxcanvas, double x, double y ) +{ + if ( ctxcanvas->first ) + { + ctxcanvas->b_box.xmin = x; + ctxcanvas->b_box.xmax = x; + ctxcanvas->b_box.ymin = y; + ctxcanvas->b_box.ymax = y; + ctxcanvas->first = 0; + } + + if ( xb_box.xmin ) ctxcanvas->b_box.xmin = x; + if ( x>ctxcanvas->b_box.xmax ) ctxcanvas->b_box.xmax = x; + if ( yb_box.ymin ) ctxcanvas->b_box.ymin = y; + if ( y>ctxcanvas->b_box.ymax ) ctxcanvas->b_box.ymax = y; +} + + +/* +%F metafile descriptor elements +*/ +static void metafile_descriptor (cdCtxCanvas *ctxcanvas) +{ + const char *font_list[] = { "SYSTEM", "COURIER", "TIMES_ROMAN", "HELVETICA", + "SYSTEM_BOLD", "COURIER_BOLD", "TIMES_ROMAN_BOLD", "HELVETICA_BOLD", + "SYSTEM_ITALIC", "COURIER_ITALIC", "TIMES_ROMAN_ITALIC", + "HELVETICA_ITALIC", "SYSTEM_BOLDITALIC", "COURIER_BOLDITALIC", + "TIMES_ROMAN_BOLDITALIC", "HELVETICA_BOLDITALIC", NULL }; + + cgm_metafile_version ( ctxcanvas->cgm, 1); + cgm_metafile_description ( ctxcanvas->cgm, "CD generated" ); + cgm_vdc_type ( ctxcanvas->cgm, 0 /* integer */ ); + cgm_integer_precision ( ctxcanvas->cgm, 16 ); + cgm_real_precision ( ctxcanvas->cgm, 3 /* fixed 32 */ ); + cgm_index_precision ( ctxcanvas->cgm, 16 ); + cgm_colour_precision ( ctxcanvas->cgm, 8 ); + cgm_colour_index_precision ( ctxcanvas->cgm, 8 ); + cgm_maximum_colour_index ( ctxcanvas->cgm, 255ul ); + cgm_colour_value_extent ( ctxcanvas->cgm, cve_black, cve_white ); + + { + static int classes[] = { -1 /* drawing set */ }; + static int ids [] = { 1 /* plus control set */ }; + cgm_metafile_element_list ( ctxcanvas->cgm, 1, classes, ids ); + } + + cgm_begin_metafile_defaults ( ctxcanvas->cgm ); + + cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec ); + cgm_interior_style ( ctxcanvas->cgm, 1 ); /* SOLID */ + cgm_edge_visibility ( ctxcanvas->cgm, 0 ); /* OFF */ + + cgm_end_metafile_defaults ( ctxcanvas->cgm ); + + cgm_font_list ( ctxcanvas->cgm, font_list ); +} + +/* +%F Pictire descriptor elements +*/ +static void picture_descriptor (cdCtxCanvas *ctxcanvas) +{ + cgm_scaling_mode ( ctxcanvas->cgm, 1 /* metric */, 1.0f ); + cgm_colour_selection_mode ( ctxcanvas->cgm, 1 /* direct */ ); + cgm_line_width_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ ); + cgm_marker_size_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ ); + + ctxcanvas->point = ftell ( ctxcanvas->cgm->file ); + if ( ctxcanvas->codificacao == CD_CLEAR_TEXT ) + { + fprintf ( ctxcanvas->cgm->file, "%80s\n", "" ); + fprintf ( ctxcanvas->cgm->file, "%80s\n", "" ); + } + else + { + cgm_vdc_extent( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + } +} + +/* +%F Control descriptor elements +*/ +static void control_elements (cdCtxCanvas *ctxcanvas) +{ + double c[3] = {1.0,1.0,1.0}; + + cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec ); + cgm_vdc_real_precision ( ctxcanvas->cgm, 2 /* fixed 32 */ ); + cgm_auxiliary_colour ( ctxcanvas->cgm, c ); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + long pt; + + pt = ftell ( ctxcanvas->cgm->file ); + fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET ); + + if (ctxcanvas->hassize) + cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + else + { + if ( ctxcanvas->clip.first ) + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin, ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax ); + else + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin, ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax ); + } + + fseek ( ctxcanvas->cgm->file, pt, SEEK_SET ); + + cgm_end_picture ( ctxcanvas->cgm ); + cgm_end_metafile ( ctxcanvas->cgm ); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->cgm->file); +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + long pt; + + pt = ftell ( ctxcanvas->cgm->file ); + fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET ); + + if (ctxcanvas->hassize) + cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + else + { + if ( ctxcanvas->clip.first ) + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin, + ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax ); + else + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin, + ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax ); + } + + fseek ( ctxcanvas->cgm->file, pt, SEEK_SET ); + + cgm_end_picture ( ctxcanvas->cgm ); + + cgm_begin_picture ( ctxcanvas->cgm, "Picture x" ); + picture_descriptor ( ctxcanvas); + cgm_begin_picture_body ( ctxcanvas->cgm ); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (mode == CD_CLIPPOLYGON) + return ctxcanvas->canvas->clip_mode; + + cgm_clip_indicator ( ctxcanvas->cgm, mode ); + + if (mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, (double) ctxcanvas->canvas->clip_rect.xmin, (double) ctxcanvas->canvas->clip_rect.ymin, + (double) ctxcanvas->canvas->clip_rect.xmax, (double) ctxcanvas->canvas->clip_rect.ymax ); + + return mode; +} + +static void clip_bbox (cdCtxCanvas *ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + if ( ctxcanvas->clip.first ) + { + ctxcanvas->clip.bbox.xmin = xmin; + ctxcanvas->clip.bbox.xmax = xmax; + ctxcanvas->clip.bbox.ymin = ymin; + ctxcanvas->clip.bbox.ymax = ymax; + ctxcanvas->clip.first = 0; + } + + if ( xmin < ctxcanvas->clip.bbox.xmin ) ctxcanvas->clip.bbox.xmin = xmin; + if ( ymin < ctxcanvas->clip.bbox.ymin ) ctxcanvas->clip.bbox.ymin = ymin; + if ( xmax > ctxcanvas->clip.bbox.xmax ) ctxcanvas->clip.bbox.xmax = xmax; + if ( ymax > ctxcanvas->clip.bbox.ymax ) ctxcanvas->clip.bbox.ymax = ymax; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, (double) xmin, (double) ymin, + (double) xmax, (double) ymax ); + + clip_bbox (ctxcanvas, (double)xmin, (double)ymin, (double)xmax, (double)ymax ); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, xmin, ymin, xmax, ymax ); + + clip_bbox (ctxcanvas, xmin, ymin, xmax, ymax ); +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style); + +static void cdline(cdCtxCanvas *ctxcanvas, int px1, int py1, int px2, int py2) +{ + double points[4]; + + points[0] = (double)px1; + points[1] = (double)py1; + points[2] = (double)px2; + points[3] = (double)py2; + + cgm_polyline( ctxcanvas->cgm, 2, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double px1, double py1, double px2, double py2) +{ + double points[4]; + + points[0] = px1; + points[1] = py1; + points[2] = px2; + points[3] = py2; + + cgm_polyline( ctxcanvas->cgm, 2, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + double points[4]; + + points[0] = (double)xmin; + points[1] = (double)ymin; + points[2] = (double)xmax; + points[3] = (double)ymax; + + cgm_interior_style ( ctxcanvas->cgm, HOLLOW); + cgm_rectangle( ctxcanvas->cgm, points); + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + double points[4]; + + points[0] = xmin; + points[1] = ymin; + points[2] = xmax; + points[3] = ymax; + + cgm_interior_style ( ctxcanvas->cgm, HOLLOW); + cgm_rectangle( ctxcanvas->cgm, points); + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + double points[4]; + + points[0] = (double)xmin; + points[1] = (double)ymin; + points[2] = (double)xmax; + points[3] = (double)ymax; + + cgm_rectangle( ctxcanvas->cgm, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + double points[4]; + + points[0] = xmin; + points[1] = ymin; + points[2] = xmax; + points[3] = ymax; + + cgm_rectangle( ctxcanvas->cgm, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void arc (cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2, + double *center, double *first_end_point, + double *second_end_point, double *dx_start, double *dy_start, + double *dx_end, double *dy_end ) +{ + double width, height; + + center[0] = xc; + center[1] = yc; + + width = w/2; + height = h/2; + + first_end_point[0] = center[0] + width; + first_end_point[1] = center[1]; + + second_end_point[0] = center[0]; + second_end_point[1] = center[1] + height; + + *dx_start = width*cos(a1*CD_DEG2RAD); + *dy_start = height*sin(a1*CD_DEG2RAD); + + *dx_end = width*cos(a2*CD_DEG2RAD); + *dy_end = height*sin(a2*CD_DEG2RAD); + + setbbox (ctxcanvas, center[0]-width, center[1]-height ); + setbbox (ctxcanvas, center[0]+width, center[1]-height ); + setbbox (ctxcanvas, center[0]+width, center[1]+height ); + setbbox (ctxcanvas, center[0]-width, center[1]+height ); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end ); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end ); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + + cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point, + dx_start, dy_start, dx_end, dy_end, 0 ); + + setbbox (ctxcanvas, (double)xc-w/2., (double)yc-h/2. ); + setbbox (ctxcanvas, (double)xc+w/2., (double)yc-h/2. ); + setbbox (ctxcanvas, (double)xc+w/2., (double)yc+h/2. ); + setbbox (ctxcanvas, (double)xc-w/2., (double)yc+h/2. ); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + + cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point, + dx_start, dy_start, dx_end, dy_end, 0 ); + + setbbox (ctxcanvas, xc-w/2., yc-h/2. ); + setbbox (ctxcanvas, xc+w/2., yc-h/2. ); + setbbox (ctxcanvas, xc+w/2., yc+h/2. ); + setbbox (ctxcanvas, xc-w/2., yc+h/2. ); +} + +static void settextbbox (cdCtxCanvas *ctxcanvas, double x, double y, int width, int height ) +{ + switch ( ctxcanvas->canvas->text_alignment ) + { + case CD_NORTH: + setbbox (ctxcanvas, x-(width/2.), y-height ); + setbbox (ctxcanvas, x+(width/2.), y ); + break; + case CD_SOUTH: + setbbox (ctxcanvas, x-(width/2.), y+height ); + setbbox (ctxcanvas, x+(width/2.), y ); + break; + case CD_EAST: + setbbox (ctxcanvas, x-width, y-(height/2.) ); + setbbox (ctxcanvas, x, y+(height/2.) ); + break; + case CD_WEST: + setbbox (ctxcanvas, x, y-(height/2.) ); + setbbox (ctxcanvas, x+width, y+(height/2.) ); + break; + case CD_NORTH_EAST: + setbbox (ctxcanvas, x-width, y-height ); + setbbox (ctxcanvas, x, y ); + break; + case CD_NORTH_WEST: + setbbox (ctxcanvas, x, y-height ); + setbbox (ctxcanvas, x+width, y ); + break; + case CD_SOUTH_EAST: + setbbox (ctxcanvas, x-width, y ); + setbbox (ctxcanvas, x, y+height ); + break; + case CD_SOUTH_WEST: + setbbox (ctxcanvas, x, y ); + setbbox (ctxcanvas, x+width, y+height ); + break; + case CD_CENTER: + setbbox (ctxcanvas, x-(width/2.), y-(height/2.) ); + setbbox (ctxcanvas, x+(width/2.), y+(height/2.) ); + break; + case CD_BASE_LEFT: + setbbox (ctxcanvas, x, y ); + setbbox (ctxcanvas, x+width, y+height ); + break; + case CD_BASE_CENTER: + setbbox (ctxcanvas, x-(width/2.), y ); + setbbox (ctxcanvas, x+(width/2.), y+height ); + break; + case CD_BASE_RIGHT: + setbbox (ctxcanvas, x-width, y ); + setbbox (ctxcanvas, x, y+height ); + break; + } +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + int width, height; + + cgm_text( ctxcanvas->cgm, 1 /* final */ , (double)x, (double)y, s ); + + cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height); + + settextbbox (ctxcanvas, (double) x, (double) y, width, height ); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s) +{ + int width, height; + + cgm_text( ctxcanvas->cgm, 1 /* final */ , x, y, s ); + + cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height); + + settextbbox (ctxcanvas, x, y, width, height ); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + double *fpoly; + + fpoly = (double *)malloc(2 * (n+1) * sizeof(double)); + + for (i = 0; i < n; i++) + { + fpoly[2*i] = (double) poly[i].x; + fpoly[2*i+1] = (double) poly[i].y; + + setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] ); + } + + switch ( mode ) + { + case CD_OPEN_LINES: + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_CLOSED_LINES: + fpoly[2*n] = fpoly[0]; + fpoly[2*n+1] = fpoly[1]; + n++; + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_FILL: + cgm_polygon( ctxcanvas->cgm, n, fpoly); + break; + } + + free(fpoly); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + double *fpoly = (double*)poly; + + for (i = 0; i < n; i++) + { + setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] ); + } + + switch ( mode ) + { + case CD_OPEN_LINES: + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_CLOSED_LINES: + fpoly[2*n] = fpoly[0]; + fpoly[2*n+1] = fpoly[1]; + n++; + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_FILL: + cgm_polygon( ctxcanvas->cgm, n, fpoly); + break; + } +} + + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + cgm_line_type( ctxcanvas->cgm, (long)(style + 1)); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + cgm_line_width( ctxcanvas->cgm, (double)width ); + return width; +} + +static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style ) +{ + switch ( style ) + { + case CD_SOLID: + style = 1; + break; + case CD_STIPPLE: + case CD_PATTERN: + style = 2; + break; + case CD_HATCH: + style = 3; + break; + } + + cgm_interior_style ( ctxcanvas->cgm, style ); + + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + int cgm_style = style; + + if ( cgm_style==2 ) + cgm_style = 3; + else if ( cgm_style==3 ) + cgm_style = 2; + + cgm_hatch_index ( ctxcanvas->cgm, (long)cgm_style+1 ); + + cgm_interior_style ( ctxcanvas->cgm, 3 ); + + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + double *pattab; + int i, j=0; + + pattab = (double *) malloc ( n*m*3*sizeof(double)); + + for ( i=0; icanvas->foreground) : get_red(ctxcanvas->canvas->background); + pattab[j+1] = ( stipple[i] ) ? get_green(ctxcanvas->canvas->foreground) : get_green(ctxcanvas->canvas->background); + pattab[j+2] = ( stipple[i] ) ? get_blue(ctxcanvas->canvas->foreground) : get_blue(ctxcanvas->canvas->background); + j+=3; + } + + cgm_pattern_table ( ctxcanvas->cgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab ); + cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ ); + free(pattab); + + cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */ +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + double *pattab; + int i, j=0; + + pattab = (double *) malloc ( n*m*3*sizeof(double) ); + + for ( i=0; icgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab ); + cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ ); + free(pattab); + + cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */ +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + long index = 0; + + if (cdStrEqualNoCase(type_face, "System")) + switch (style&3) + { + case CD_PLAIN: + index = 1; + break; + case CD_BOLD: + index = 5; + break; + case CD_ITALIC: + index = 9; + break; + case CD_BOLD_ITALIC: + index = 13; + break; + } + else if (cdStrEqualNoCase(type_face, "Courier")) + switch (style&3) + { + case CD_PLAIN: + index = 2; + break; + case CD_BOLD: + index = 6; + break; + case CD_ITALIC: + index = 10; + break; + case CD_BOLD_ITALIC: + index = 14; + break; + } + else if (cdStrEqualNoCase(type_face, "Times")) + switch (style&3) + { + case CD_PLAIN: + index = 3; + break; + case CD_BOLD: + index = 7; + break; + case CD_ITALIC: + index = 11; + break; + case CD_BOLD_ITALIC: + index = 15; + break; + } + else if (cdStrEqualNoCase(type_face, "Helvetica")) + switch (style&3) + { + case CD_PLAIN: + index = 4; + break; + case CD_BOLD: + index = 8; + break; + case CD_ITALIC: + index = 12; + break; + case CD_BOLD_ITALIC: + index = 16; + break; + } + + if (index == 0) return 0; + + cgm_char_height ( ctxcanvas->cgm, cdGetFontSizePixels(ctxcanvas->canvas, size)); + cgm_text_font_index( ctxcanvas->cgm, index ); + + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + int hor = 0, ver = 0; + enum { NORMHORIZ, LEFT, CTR, RIGHT }; + enum { NORMVERT, TOP, CAP, HALF, BASE, BOTTOM }; + + switch ( alignment ) + { + case CD_NORTH: + hor = CTR; + ver = TOP; + break; + case CD_SOUTH: + hor = CTR; + ver = BOTTOM; + break; + case CD_EAST: + hor = RIGHT; + ver = HALF; + break; + case CD_WEST: + hor = LEFT; + ver = HALF; + break; + case CD_NORTH_EAST: + hor = RIGHT; + ver = TOP; + break; + case CD_NORTH_WEST: + hor = LEFT; + ver = TOP; + break; + case CD_SOUTH_EAST: + hor = RIGHT; + ver = BOTTOM; + break; + case CD_SOUTH_WEST: + hor = LEFT; + ver = BOTTOM; + break; + case CD_CENTER: + hor = CTR; + ver = HALF; + break; + case CD_BASE_LEFT: + hor = LEFT; + ver = BASE; + break; + case CD_BASE_CENTER: + hor = CTR; + ver = BASE; + break; + case CD_BASE_RIGHT: + hor = RIGHT; + ver = BASE; + break; + } + + cgm_text_alignment ( ctxcanvas->cgm, hor, ver , (double)0.0, (double)0.0 ); + + return alignment; +} + +/******************************************************/ +/* color */ +/******************************************************/ + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + double cor[3]; + + cor[0] = get_red(color); + cor[1] = get_green(color); + cor[2] = get_blue(color); + + cgm_text_colour( ctxcanvas->cgm, cor ); + cgm_fill_colour( ctxcanvas->cgm, cor ); + cgm_line_colour( ctxcanvas->cgm, cor ); + + return color; +} + +static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + double bc[3]; + + bc[0] = get_red(color); + bc[1] = get_green(color); + bc[2] = get_blue(color); + + ctxcanvas->canvas->background = color; + cgm_backgound_colour ( ctxcanvas->cgm, bc ); + + return color; +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque) +{ + if (opaque == CD_TRANSPARENT) + cgm_transparency(ctxcanvas->cgm, 1); + else + cgm_transparency(ctxcanvas->cgm, 0); + return opaque; +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + double p[6]; + double *color_array; + int i,j,index,c; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + color_array = (double *) malloc ( rw*rh*3*sizeof(double) ); + if (!color_array) + return; + + p[0] = (double) x; p[1] = (double) (y+h); + p[2] = (double) (x+w); p[3] = (double) y; + p[4] = (double) (x+w); p[5] = (double) (y+h); + + for ( i=0; icgm, p, (long)rw, (long)rh, 8, color_array ); + + free(color_array); + + setbbox (ctxcanvas, p[0], p[1] ); + setbbox (ctxcanvas, p[2], p[3] ); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + double p[6]; + double *color_array; + int i,j,c; + unsigned char r, g, b; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + color_array = (double *) malloc ( rw*rh*3*sizeof(double) ); + if (!color_array) + return; + + p[0] = (double) x; p[1] = (double) y; + p[2] = (double) (x+w); p[3] = (double) (y+h); + p[4] = (double) (x+w); p[5] = (double) y; + + for ( i=0; icgm, p, (long)rw, (long)rh, 8, color_array ); + + free(color_array); + + setbbox (ctxcanvas, p[0], p[1] ); + setbbox (ctxcanvas, p[2], p[3] ); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + double cor[3]; + double pts[2]; + + pts[0] = (double) x; + pts[1] = (double) y; + + cor[0] = get_red(color); + cor[1] = get_green(color); + cor[2] = get_blue(color); + + cgm_marker_colour( ctxcanvas->cgm, cor); + cgm_polymarker ( ctxcanvas->cgm, 1, pts ); +} + +/* +%F Cria um canvas CGM. +Parametros passados em data: +[nome] nome do arquivo de saida <= 255 caracteres +[size] tamanho do papel +-t codificacao clear text se nao binaria +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas *ctxcanvas; + char *line = (char *)data; + char c; + char words[4][256]; + char filename[10240] = ""; + double w=0, h=0, r=0; + int p=0; + int i, n; + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + n = sscanf(line, "%s %s %s %s", words[0], words[1], words[2], words[3]); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + + canvas->ctxcanvas = ctxcanvas; + ctxcanvas->canvas = canvas; + + strcpy(ctxcanvas->filename, filename); + + canvas->w_mm = (double)INT_MAX*3.78; + canvas->h_mm = (double)INT_MAX*3.78; + canvas->xres = 3.78; + canvas->yres = 3.78; + canvas->bpp = 24; + + ctxcanvas->vdc_int_prec = 16; + ctxcanvas->codificacao = CD_BIN; + ctxcanvas->first = 1; + ctxcanvas->clip.first = 1; + ctxcanvas->patindex = 1; + + ctxcanvas->hassize = 0; /* Indica se foi passado um tamanho para o canvas */ + + for (i = 0; i < n; i++) + { + if (sscanf ( words[i], "%lgx%lg", &w, &h )== 2) + { + canvas->w_mm = w; + canvas->h_mm = h; + ctxcanvas->hassize = 1; + } + else if (sscanf ( words[i], "%lg", &r ) == 1) + canvas->yres = canvas->xres = r; + else if (sscanf ( words[i], "-%c%d", &c, &p )>0) + { + if ( c=='t' ) + ctxcanvas->codificacao = CD_CLEAR_TEXT; + else if ( c=='p' ) + ctxcanvas->vdc_int_prec = p; + } + } + + if ( ctxcanvas->vdc_int_prec != 16 && w == 0.0 && h == 0.0 ) + { + canvas->w_mm = (double) (pow(2,p)/2)-1; + canvas->h_mm = (double) (pow(2,p)/2)-1; + } + + /* update canvas context */ + canvas->w = (int)(canvas->w_mm * canvas->xres); + canvas->h = (int)(canvas->h_mm * canvas->yres); + + ctxcanvas->cgm = cgm_begin_metafile ( ctxcanvas->filename, ctxcanvas->codificacao, "CD - CanvasDraw, Tecgraf/PUC-RIO" ); + + metafile_descriptor(ctxcanvas); + + cgm_begin_picture ( ctxcanvas->cgm, "Picture x" ); + + picture_descriptor (ctxcanvas); + + cgm_clip_rectangle ( ctxcanvas->cgm, 0, 0, (double)canvas->w, (double)canvas->h); + cgm_clip_indicator (ctxcanvas->cgm, 0); + + cgm_begin_picture_body ( ctxcanvas->cgm ); + + control_elements (ctxcanvas); + + cgm_marker_type( ctxcanvas->cgm, MARKER_DOT); + cgm_marker_size( ctxcanvas->cgm, 1.0); +} + +static void cdinittable(cdCanvas* canvas) +{ + /* initialize function table*/ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFText = cdftext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxBackOpacity = cdbackopacity; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdCGMContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PALETTE | + CD_CAP_CLIPPOLY | CD_CAP_WRITEMODE | CD_CAP_IMAGESRV | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_FONTDIM | CD_CAP_TEXTSIZE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + cdplayCGM, + cdRegisterCallbackCGM, +}; + +cdContext* cdContextCGM(void) +{ + return &cdCGMContext; +} + diff --git a/src/drv/cddebug.c b/src/drv/cddebug.c new file mode 100644 index 0000000..5532568 --- /dev/null +++ b/src/drv/cddebug.c @@ -0,0 +1,729 @@ +/** \file + * \brief CD DEBUG driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" +#include "cddebug.h" + + +#define CDDBG_FLUSH "Flush" +#define CDDBG_CLEAR "Clear" +#define CDDBG_CLIP "Clip" +#define CDDBG_CLIPAREA "Cliparea" +#define CDDBG_LINE "Line" +#define CDDBG_BOX "Box" +#define CDDBG_ARC "Arc" +#define CDDBG_SECTOR "Sector" +#define CDDBG_TEXT "Text" +#define CDDBG_BEGIN "Begin" +#define CDDBG_VERTEX "Vertex" +#define CDDBG_END "End" +#define CDDBG_MARK "Mark" +#define CDDBG_BACKOPACITY "BackOpacity" +#define CDDBG_WRITEMODE "WriteMode" +#define CDDBG_LINESTYLE "LineStyle" +#define CDDBG_LINEWIDTH "LineWidth" +#define CDDBG_INTERIORSTYLE "InteriorStyle" +#define CDDBG_HATCH "Hatch" +#define CDDBG_STIPPLE "Stipple" +#define CDDBG_PATTERN "Pattern" +#define CDDBG_NATIVEFONT "NativeFont" +#define CDDBG_TEXTALIGNMENT "TextAlignment" +#define CDDBG_PALETTE "Palette" +#define CDDBG_BACKGROUND "Background" +#define CDDBG_FOREGROUND "Foreground" +#define CDDBG_PIXEL "Pixel" +#define CDDBG_SCROLLAREA "ScrollArea" +#define CDDBG_TEXTORIENTATION "TextOrientation" +#define CDDBG_RECT "Rect" +#define CDDBG_FILLMODE "FillMode" +#define CDDBG_LINESTYLEDASHES "LineStyleDashes" +#define CDDBG_LINECAP "LineCap" +#define CDDBG_LINEJOIN "LineJoin" +#define CDDBG_CHORD "Chord" +#define CDDBG_FLINE "fLine" +#define CDDBG_FRECT "fRect" +#define CDDBG_FBOX "fBox" +#define CDDBG_FARC "fArc" +#define CDDBG_FSECTOR "fSector" +#define CDDBG_FTEXT "fText" +#define CDDBG_FVERTEX "fVertex" +#define CDDBG_MATRIX "Matrix" +#define CDDBG_FCHORD "fChord" +#define CDDBG_FCLIPAREA "fClipArea" +#define CDDBG_FONT "Font" +#define CDDBG_PUTIMAGERGB "PutImageRGB" +#define CDDBG_PUTIMAGERGBA "PutImageRGBA" +#define CDDBG_PUTIMAGEMAP "PutImageMap" + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + char* filename; + FILE* file; + int last_line_style; + int last_fill_mode; +}; + +struct _cdCtxImage { + cdCtxCanvas *ctxcanvas; +}; + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); + fprintf(ctxcanvas->file, "%s()\n", CDDBG_FLUSH); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "%s()\n", CDDBG_CLEAR); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + const char* enum2str[] = { + "CD_CLIPOFF", + "CD_CLIPAREA", + "CD_CLIPPOLYGON", + "CD_CLIPREGION" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_CLIP, enum2str[mode]); + return mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_CLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FCLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + else + fprintf(ctxcanvas->file, "%s(NULL)\n", CDDBG_MATRIX); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_LINE, x1, y1, x2, y2); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FLINE, x1, y1, x2, y2); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_RECT, xmin, xmax, ymin, ymax); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FRECT, xmin, xmax, ymin, ymax); +} + +static const char* get_region_mode(int combine_mode) +{ + const char* enum2str[] = { + "CD_UNION", + "CD_INTERSECT", + "CD_DIFFERENCE", + "CD_NOTINTERSECT" + }; + return enum2str[combine_mode]; +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %s)\n", CDDBG_BOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_BOX, xmin, xmax, ymin, ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %s)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_ARC, xc, yc, w, h, a1, a2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FARC, xc, yc, w, h, a1, a2); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, \"%s\", %s)\n", CDDBG_TEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, \"%s\")\n", CDDBG_TEXT, x, y, text); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, \"%s\", %s)\n", CDDBG_FTEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, \"%s\")\n", CDDBG_FTEXT, x, y, text); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + const char* enum2str[] = { + "CD_FILL", + "CD_OPEN_LINES", + "CD_CLOSED_LINES", + "CD_CLIP", + "CD_BEZIER", + "CD_REGION" + }; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + const char* enum2str[] = { + "CD_EVENODD", + "CD_WINDING" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%s, %s)\n", CDDBG_BEGIN, enum2str[mode], get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]); + + for(i = 0; ifile, "%s(%d, %d)\n", CDDBG_VERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%s()\n", CDDBG_END); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + const char* enum2str[] = { + "CD_FILL", + "CD_OPEN_LINES", + "CD_CLOSED_LINES", + "CD_CLIP", + "CD_BEZIER", + "CD_REGION" + }; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + const char* enum2str[] = { + "CD_EVENODD", + "CD_WINDING" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]); + + for(i = 0; ifile, "%s(%g, %g)\n", CDDBG_FVERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%s()\n", CDDBG_END); +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity) +{ + const char* enum2str[] = { + "CD_OPAQUE", + "CD_TRANSPARENT" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BACKOPACITY, enum2str[opacity]); + return opacity; +} + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode) +{ + const char* enum2str[] = { + "CD_REPLACE", + "CD_XOR", + "CD_NOT_XOR" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_WRITEMODE, enum2str[mode]); + return mode; +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_CONTINUOUS", + "CD_DASHED", + "CD_DOTTED", + "CD_DASH_DOT", + "CD_DASH_DOT_DOT", + "CD_CUSTOM" + }; + + if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style) + { + int i; + + fprintf(ctxcanvas->file, "%s(%d", CDDBG_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, ", %d", ctxcanvas->canvas->line_dashes[i]); + fprintf(ctxcanvas->file, ")\n"); + + ctxcanvas->last_line_style = ctxcanvas->canvas->line_style; + } + + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINESTYLE, enum2str[style]); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%s(%d)\n", CDDBG_LINEWIDTH, width); + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + const char* enum2str[] = { + "CD_CAPFLAT", + "CD_CAPSQUARE", + "CD_CAPROUND" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINECAP, enum2str[cap]); + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + const char* enum2str[] = { + "CD_MITER", + "CD_BEVEL", + "CD_ROUND" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINEJOIN, enum2str[join]); + return join; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_SOLID", + "CD_HATCH", + "CD_STIPPLE", + "CD_PATTERN", + "CD_HOLLOW" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_INTERIORSTYLE, enum2str[style]); + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_HORIZONTAL", + "CD_VERTICAL", + "CD_FDIAGONAL", + "CD_BDIAGONAL", + "CD_CROSS", + "CD_DIAGCROSS" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_HATCH, enum2str[style]); + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_STIPPLE, w, h, stipple); +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_PATTERN, w, h, pattern); +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size) +{ + char style_str[50] = ""; + if (style & CD_BOLD) + strcat(style_str, "CD_BOLD"); + if (style & CD_ITALIC) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_ITALIC"); + } + if (style & CD_UNDERLINE) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_UNDERLINE"); + } + if (style & CD_STRIKEOUT) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_STRIKEOUT"); + } + if (style_str[0]==0) strcat(style_str, "CD_PLAIN"); + fprintf(ctxcanvas->file, "%s(\"%s\", %s, %d)\n", CDDBG_FONT, type_face, style_str, size); + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font) +{ + fprintf(ctxcanvas->file, "%s(\"%s\")\n", CDDBG_NATIVEFONT, font); + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + const char* enum2str[] = { + "CD_NORTH", + "CD_SOUTH", + "CD_EAST", + "CD_WEST", + "CD_NORTH_EAST", + "CD_NORTH_WEST", + "CD_SOUTH_EAST", + "CD_SOUTH_WEST", + "CD_CENTER", + "CD_BASE_LEFT", + "CD_BASE_CENTER", + "CD_BASE_RIGHT" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_TEXTALIGNMENT, enum2str[alignment]); + return alignment; +} + +static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle) +{ + fprintf(ctxcanvas->file, "%s(%g)\n", CDDBG_TEXTORIENTATION, angle); + return angle; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + const char* enum2str[] = { + "CD_POLITE", + "CD_FORCE" + }; + fprintf(ctxcanvas->file, "%s(%d, %p, %s)\n", CDDBG_PALETTE, n, palette, enum2str[mode]); +} + +static long cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_BACKGROUND, (int)r, (int)g, (int)b); + return color; +} + +static long cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_FOREGROUND, (int)r, (int)g, (int)b); + return color; +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGB, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGBA, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGEMAP, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %d)\n", CDDBG_PIXEL, x, y, (int)r, (int)g, (int)b); +} + +static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %d, %d)\n", CDDBG_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + fprintf(ctxcanvas->file, "%p, %p, %p = GetImageRGB(%d, %d, %d, %d)\n", r, g, b, x, y, w, h); +} + +static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h) +{ + cdCtxImage* ctximage = malloc(sizeof(cdCtxImage)); + ctximage->ctxcanvas = ctxcanvas; + fprintf(ctxcanvas->file, "%p = GetImage(%d, %d)\n", ctximage, w, h); + return ctximage; +} + +static void cdkillimage(cdCtxImage* ctximage) +{ + fprintf(ctximage->ctxcanvas->file, "KillImage(%p)\n", ctximage); + free(ctximage); +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y) +{ + fprintf(ctxcanvas->file, "GetImage(%p, %d, %d)\n", ctximage, x, y); +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "PutImage(%p, %d, %d, %d, %d, %d, %d)\n", ctximage, x, y, xmin, xmax, ymin, ymax); +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "NewRegion()\n"); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + fprintf(ctxcanvas->file, "IsPointInRegion(%d, %d)\n", x, y); + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + fprintf(ctxcanvas->file, "OffsetRegion(%d, %d)\n", x, y); +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + (void)xmin; + (void)ymin; + (void)xmax; + (void)ymax; + fprintf(ctxcanvas->file, "GetRegionBox()\n"); +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "Activate()\n"); + return CD_OK; +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "Deactivate()\n"); +} + +static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + int tmp_max_width, tmp_height, tmp_ascent, tmp_descent; + if (!max_width) max_width = &tmp_max_width; + if (!height) height = &tmp_height; + if (!ascent) ascent = &tmp_ascent; + if (!descent) descent = &tmp_descent; + cdgetfontdimEX(ctxcanvas, max_width, height, ascent, descent); + fprintf(ctxcanvas->file, "%d, %d, %d, %d = GetFontDim()\n", *max_width, *height, *ascent, *descent); +} + +static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + int tmp_width, tmp_height; + if (!width) width = &tmp_width; + if (!height) height = &tmp_height; + cdgettextsizeEX(ctxcanvas, s, width, height); + fprintf(ctxcanvas->file, "%d, %d = GetTextSize(\"%s\")\n", *width, *height, s); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "KillCanvas()\n"); + free(ctxcanvas->filename); + fclose(ctxcanvas->file); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; + cdCtxCanvas* ctxcanvas; + int size; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->file = fopen(filename, "w"); + if (!ctxcanvas->file) + { + free(ctxcanvas); + return; + } + + size = strlen(filename); + ctxcanvas->filename = malloc(size+1); + memcpy(ctxcanvas->filename, filename, size+1); + + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->w = (int)(w_mm * res); + canvas->h = (int)(h_mm * res); + canvas->w_mm = w_mm; + canvas->h_mm = h_mm; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->last_line_style = -1; + ctxcanvas->last_fill_mode = -1; + + fprintf(ctxcanvas->file, "CreateCanvas(CD_DEBUG, \"%s\")\n", (char*)data); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxScrollArea = cdscrollarea; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxTextOrientation = cdtextorientation; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxFClipArea = cdfcliparea; + canvas->cxTransform = cdtransform; + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxScrollArea = cdscrollarea; + canvas->cxCreateImage = cdcreateimage; + canvas->cxKillImage = cdkillimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; +} + +static cdContext cdDebugContext = +{ + CD_CAP_ALL, + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDebug(void) +{ + return &cdDebugContext; +} + diff --git a/src/drv/cddgn.c b/src/drv/cddgn.c new file mode 100644 index 0000000..32435b9 --- /dev/null +++ b/src/drv/cddgn.c @@ -0,0 +1,1696 @@ +/** \file + * \brief DGN driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cddgn.h" + +/* defines */ + +#define MAX_NUM_VERTEX 101 +#define MAX_NUM_VERTEX_PER_POLYLINE 15000 + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#define END_OF_DGN_FILE 0xffff +#define DGN_FILE_BLOCK 512 + +#define NOFILL 0 /* tipos de fill que o driver faz */ +#define CONVEX 1 +#define NORMAL 2 + +/* macros */ + +#define SIZE_LINE_STRING(x) (19+4*(x)) +#define SIZE_FILLED_SHAPE(x) (27+4*(x)) +#define SIZE_ARC 40 +#define SIZE_LINE 26 + +#define IGNORE(x) ((void) x) + + +/* estruturas similares as que o MicroStation usa */ + +typedef struct +{ + union + { + struct + { + unsigned level:6; + unsigned :1; + unsigned complex:1; + unsigned type:7; + unsigned :1; + } flags; + short type_as_word; + } type; + + unsigned short words; + unsigned long xmin; + unsigned long ymin; + unsigned long xmax; + unsigned long ymax; +} Elm_hdr; + +typedef struct +{ + short attindx; + union + { + short s; + struct + { + unsigned /*class*/ :4; + unsigned /*res*/ :4; + unsigned /*l*/ :1; + unsigned /*n*/ :1; + unsigned /*m*/ :1; + unsigned attributes:1; + unsigned /*r*/ :1; + unsigned /*p*/ :1; + unsigned /*s*/ :1; + unsigned /*hole*/ :1; + } flags; + } props; + + union + { + short s; + struct + { + unsigned style:3; + unsigned weight:5; + unsigned color:8; + } b; + } symb; + +} Disp_hdr; + +/* tipo de poligono/setor */ +enum +{ + FILLED, + OPEN +}; + +/* grupos de tamanhos de caracter + (usado por gettextwidth e cdgetfontdim) */ + +static long fontsizes[4][8]= +{ + {1,2,4,5,6,7,0}, + {5,3,2,1,0}, + {8,6,4,3,2,1,0}, + {5,3,2,1,0} +}; + + +/********************** + * contexto do driver * + **********************/ + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* arquivo dgn */ + long int bytes; /* tamanho do arquivo */ + char level; + + short color, style; + + short alignment; + short typeface_index; + short symbology; + long tl; + short is_base; /* setado se texto e' do tipo CD_BASE_... */ + + short fill_type; /* como o driver faz fill: + NOFILL -> nao faz fill + CONVEX -> so faz fill de poligonos convexos + NORMAL -> faz fill normalmente */ + + long colortable[256]; /* palette */ + short num_colors; + + short is_complex; +}; + +/* prototipos de funcao */ +static void startComplexShape(cdCtxCanvas*, unsigned short,short,unsigned short, + unsigned long,unsigned long, + unsigned long,unsigned long); +static void endComplexElement(cdCtxCanvas*); + +/****************************** + * * + * funcoes internas do driver * + * * + ******************************/ + +/********************************************************* + * Obtem o descent do texto (para letras como q,p,g etc) * + *********************************************************/ + +static long get_descent(const char *text, int size_pixel) +{ + char *descent="jgyqp"; + long a=0; + long length = strlen(text); + + while(a < length) + { + if(strchr(descent, text[a])) + return size_pixel/2; + + a++; + } + return 0; +} + +/*********************************************** + * Calcula a largura da string no MicroStation * + ***********************************************/ + +static long gettextwidth(cdCtxCanvas* ctxcanvas, const char *s, int size_pixel) +{ + long a=0, + width=0, + length = strlen(s); + + short default_size=0; + + static char *fontchars[4][8] = + { + { /* CD_SYSTEM */ + "Ww", + "jshyut#*-=<>", + "iIl[]", + ";:.,'|!()`{}", + "","","","" + }, + + { /* CD_COURIER */ + "Iflrit!();.'", + "1|[]\"/`", + "BCDEKPRSUVXYbdgkpq&-_", + "w#%", + "Wm^+=<>~", + "@","","" + }, + + { /* CD_TIMES_ROMAN */ + "m", + "HMUWw", + "CSTZLbhknpuvxy23567890e", + "fstz1#$-=<>", + "Iijl*[]", + ";:.,'|!()`{}", + "","" + }, + + { /* CD_HELVETICA */ + "Ww", + "jshyut#*-=<>", + "iIl[]", + ";:.,'|!()`{}", + "","","","" + } + }; + + if (ctxcanvas->typeface_index == 1) + default_size=2; + else if (ctxcanvas->typeface_index == 2) + default_size=5; + else if (ctxcanvas->typeface_index == 3) + default_size=4; + else + default_size=4; + + for(a=0,width=0;a < length; a++) + { + static short size_number; + static char letter; + + if(s[a] == ' ') + letter = s[a-1]; + else + letter = s[a]; + + for(size_number=0;size_number < 8;size_number++) + { + if(strchr(fontchars[ctxcanvas->typeface_index][size_number], letter)) + { + width+=(ctxcanvas->tl*fontsizes[ctxcanvas->typeface_index][size_number])/6; + break; + } + } + + if(size_number == 8) + width+=(ctxcanvas->tl*default_size)/6; + + width+=ctxcanvas->tl/3; + } + + width-=ctxcanvas->tl/3; + + if (ctxcanvas->canvas->font_style & CD_ITALIC) + width+= (long) ((double)size_pixel*tan(4*atan(1)/8)); /* angulo de 15 graus */ + + return width; +} + +/**************************** + * Salva um byte no arquivo * + ****************************/ + +static void put_byte(cdCtxCanvas* ctxcanvas, unsigned char byte) +{ + fputc(byte, ctxcanvas->file); +} + +/************************************ + * Salva um sequencia de caracteres * + ************************************/ + +static void writec (cdCtxCanvas* ctxcanvas, const char *t, short tam ) +{ + short i; + + ctxcanvas->bytes += tam; + for ( i = 0; i < tam; i++ ) + fputc ( t[i], ctxcanvas->file ); +} + +/****************** + * Salva uma word * + ******************/ + +static void put_word(cdCtxCanvas* ctxcanvas, unsigned short w) +{ + char c; + + c = (char) (w & 0xff); + fputc (c, ctxcanvas->file); + c = (char) ((w >> 8) & 0xff); + fputc (c, ctxcanvas->file); + ctxcanvas->bytes += 2; +} + +/**************************** + * Salva um long no arquivo * + ****************************/ + +static void put_long (cdCtxCanvas* ctxcanvas, unsigned long i) +{ + put_word(ctxcanvas, (short) (i >> 16)); + put_word(ctxcanvas, (short) i); +} + +/******************* + * Salva um double * + *******************/ + +static void put_as_double(cdCtxCanvas* ctxcanvas, long i) +{ + float dfloat=(float) 4*i; + + put_long(ctxcanvas, *((long *) &dfloat)); + put_long(ctxcanvas, 0); + + ctxcanvas->bytes+=sizeof(float); +} + +/**************************** + * Salva uma UOR no arquivo * + ****************************/ + +static void put_uor(cdCtxCanvas* ctxcanvas, long i) +{ + put_word(ctxcanvas, (unsigned short)((i >> 16) ^ (1 << 15))); /* troca o bit 31 + para transformar em uor */ + put_word(ctxcanvas, (unsigned short)i); +} + +/*************************************** + * Salva a bounding box de um elemento * + ***************************************/ + +static void put_bound(cdCtxCanvas* ctxcanvas, long xmin, long xmax, long ymin, long ymax) +{ + put_uor(ctxcanvas, xmin); + put_uor(ctxcanvas, ymin); + put_uor(ctxcanvas, 0L); + put_uor(ctxcanvas, xmax); + put_uor(ctxcanvas, ymax); + put_uor(ctxcanvas, 0L); +} + +/****************************************** + * Calcula a bounding box de uma polyline * + ******************************************/ + +static void line_string_bound(cdPoint *buffer, short num_vertex, + unsigned long *xmin, unsigned long *ymin, + unsigned long *xmax, unsigned long *ymax) +{ + short i; + unsigned long v; + + *xmin = *xmax = buffer[0].x; + *ymin = *ymax = buffer[0].y; + + for (i = 1; i < num_vertex; i++) + { + v = buffer[i].x; + if (v < *xmin) + *xmin = v; + else if (v > *xmax) + *xmax = v; + + v = (long) buffer[i].y; + if (v < *ymin) + *ymin = v; + else if (v > *ymax) + *ymax = v; + } +} + +/************************************ + * Retorna symbology de um elemento * + ************************************/ + +static short symbology(cdCtxCanvas* ctxcanvas) +{ + return (short)((ctxcanvas->color << 8) | (ctxcanvas->canvas->line_width << 3) | ctxcanvas->style); +} + +/***************************************** + * Salva um Element Header no arquivo * + *****************************************/ + +static void putElementHeader(cdCtxCanvas* ctxcanvas, Elm_hdr *ehdr) +{ + ehdr->type.flags.complex = ctxcanvas->is_complex; + + put_word(ctxcanvas, (short)(ehdr->type.flags.type << 8 | + ehdr->type.flags.complex << 7 | ehdr->type.flags.level)); + + + put_word(ctxcanvas, ehdr->words); + put_bound(ctxcanvas, ehdr->xmin, ehdr->xmax, ehdr->ymin, ehdr->ymax); +} + +/************************************** + * Salva um display header no arquivo * + **************************************/ + +static void putDisplayHeader(cdCtxCanvas* ctxcanvas, Disp_hdr *dhdr) +{ + put_word(ctxcanvas, 0); /* graphics group */ + put_word(ctxcanvas, dhdr->attindx); /* index to attributes */ + put_word(ctxcanvas, dhdr->props.flags.attributes << 11); /* properties */ + put_word(ctxcanvas, dhdr->symb.s); /* display symbology */ +} + + +/*************************************** + * completa o arquivo com zeros para * + * que o numero de bytes seja multiplo * + * de 512 * + ***************************************/ + +static void complete_file(cdCtxCanvas* ctxcanvas) +{ + long resto, i; + + put_word(ctxcanvas, END_OF_DGN_FILE); + + resto = DGN_FILE_BLOCK - ctxcanvas->bytes % DGN_FILE_BLOCK; + + /* checa validade do tamanho do arquivo */ + if (resto%2 != 0) return; + + for (i = 0; i < resto; i+=2) + put_word(ctxcanvas, 0); +} + +/************************************* + * Salva um elemento arco no arquivo * + *************************************/ + +static void arc (cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, double a1, double a2) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=16; + ehdr.words=SIZE_ARC-2; + ehdr.xmin=xc - w/2; + ehdr.xmax=xc + w/2; + ehdr.ymin=yc - h/2; + ehdr.ymax=yc + h/2; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx = ehdr.words - 14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s = symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_long(ctxcanvas, (long) a1*360000); /* start angle */ + put_long(ctxcanvas, (long) (a2-a1)*360000); /* sweep angle */ + put_as_double(ctxcanvas, w/2); /* primary axis */ + put_as_double(ctxcanvas, h/2); /* secondary axis */ + put_long(ctxcanvas, 0); /* rotation angle (sempre 0) */ + put_as_double(ctxcanvas, xc); /* x origin */ + put_as_double(ctxcanvas, yc); /* y origin */ +} + +/*************************************** + * Salva um elemento elipse no arquivo * + ***************************************/ + +static void ellipse(cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, short type) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=15; + ehdr.words=34+((type==FILLED) ? 8 : 0); + ehdr.xmin=xc - w/2; + ehdr.xmax=xc + w/2; + ehdr.ymin=yc - h/2; + ehdr.ymax=yc + h/2; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=20; + dhdr.props.flags.attributes=(type == FILLED) ? 1 : 0; + dhdr.symb.s=symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_as_double(ctxcanvas, w/2); /* primary axis */ + put_as_double(ctxcanvas, h/2); /* secondary axis */ + put_long(ctxcanvas, 50); /* rotation angle (sempre 0) */ + put_as_double(ctxcanvas, xc); /* x origin */ + put_as_double(ctxcanvas, yc); /* y origin */ + + /* salva atributo de fill */ + if(type == FILLED) + { + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + } +} + +static short getclosestColor(cdCtxCanvas* ctxcanvas, long color) +{ + short count=0, closest=0; + long diff=0; + unsigned char r = cdRed(color), + g = cdGreen(color), + b = cdBlue(color); + short rd, gd, bd; + long newdiff; + + /* procura a cor mais proxima */ + + diff = 3*65536; /* inicializa com maior diferenca possivel */ + + for(count=0; count < ctxcanvas->num_colors; count++) + { + rd = r - cdRed(ctxcanvas->colortable[count]); + gd = g - cdGreen(ctxcanvas->colortable[count]); + bd = b - cdBlue(ctxcanvas->colortable[count]); + + newdiff = rd*rd + gd*gd + bd*bd; + + if(newdiff <= diff) + { + /* verifica se encontrou a cor */ + if(newdiff == 0) + return count-1; + + diff = newdiff; + closest=count-1; + } + } + + /* nao encontrou a cor, tenta adicionar na palette, ou retorna a mais proxima */ + if(ctxcanvas->num_colors < 254) + { + ctxcanvas->colortable[ctxcanvas->num_colors+1] = color; + return ctxcanvas->num_colors++; + } + else + return closest; +} + +static void saveColorTable(cdCtxCanvas* ctxcanvas) +{ + unsigned char r,g,b; + short i; + + put_word(ctxcanvas, (0x05 << 8) | 1); /* colortable */ + put_word(ctxcanvas, 434); + + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0xffffffff); + put_long(ctxcanvas, 0xffffffff); + put_long(ctxcanvas, 0xffffffff); + + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 420); + put_word(ctxcanvas, 0x0400); + put_word(ctxcanvas, 0x100); + put_word(ctxcanvas, 0); + + for(i=0;i<256;i++) + { + cdDecodeColor(ctxcanvas->colortable[i], &r, &g, &b); + put_byte(ctxcanvas, r); + put_byte(ctxcanvas, g); + put_byte(ctxcanvas, b); + } + + put_word(ctxcanvas, 25); + for(i=0;i<32;i++) + put_word(ctxcanvas, 0x2020); +} + + +/***************************** + * Le uma word de um arquivo * + *****************************/ + +static short file_get_word(FILE *fp) +{ + short word=0; + + word = (short)fgetc(fp); + word |= ((short)fgetc(fp) << 8) & 0xff00; + + return word; +} + +/******************************** + * Salva uma word em um arquivo * + ********************************/ + +static void file_put_word (short word, FILE *fp) +{ + fputc ((char) (word & 0xff), fp); + fputc ((char) ((word >> 8) & 0xff), fp); +} + +/******************************************* + * Le elementos de um arquivo DGN e os * + * coloca no inicio do arquivo aberto pelo * + * driver * + *******************************************/ + +static void dgn_copy (FILE *file, cdCtxCanvas *ctxcanvas) +{ + short word=0; + + while ((word = file_get_word(file)) != END_OF_DGN_FILE) + { + file_put_word(word, ctxcanvas->file); /* type e level do elemento */ + ctxcanvas->bytes+=2; + + word = file_get_word(file); /* words to follow */ + file_put_word(word, ctxcanvas->file); + ctxcanvas->bytes+=2; + + while (word) /* copia resto do elemento */ + { + file_put_word(file_get_word(file), ctxcanvas->file); + word--; + ctxcanvas->bytes+=2; + } + } +} + + +/* + * Funcoes do driver + */ + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + saveColorTable(ctxcanvas); + complete_file(ctxcanvas); + fclose (ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate (cdCtxCanvas* ctxcanvas) +{ + fflush(ctxcanvas->file); +} + +static void cdflush (cdCtxCanvas* ctxcanvas) +{ + fflush(ctxcanvas->file); +} + + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdline (cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + cdPoint buffer[2]; + + buffer[0].x=x1; + buffer[0].y=y1; + buffer[1].x=x2; + buffer[1].y=y2; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=3; + + ehdr.words=SIZE_LINE-2; + + line_string_bound(buffer, 2, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx = ehdr.words - 14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + /* pontos inicial e final da linha */ + + put_long(ctxcanvas, (long) x1); + put_long(ctxcanvas, (long) y1); + put_long(ctxcanvas, (long) x2); + put_long(ctxcanvas, (long) y2); +} + +static void cdbox (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=6; + ehdr.words=17+4*5+8; + ehdr.xmin=xmin; + ehdr.xmax=xmax; + ehdr.ymin=ymin; + ehdr.ymax=ymax; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=3+4*5; + dhdr.props.flags.attributes=1; + dhdr.symb.s=symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, 5); /* numero de vertices */ + + /* vertices */ + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymin); + + put_long(ctxcanvas, (long) xmax); + put_long(ctxcanvas, (long) ymin); + + put_long(ctxcanvas, (long) xmax); + put_long(ctxcanvas, (long) ymax); + + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymax); + + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymin); + + /* atributos de fill */ + + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); +} + +static void cdarc (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (a2 == a1 + 360) + ellipse(ctxcanvas, xc,yc,w,h,OPEN); + else + arc(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdsector (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (a2 == a1 + 360) + { + ellipse(ctxcanvas, xc,yc,w,h,FILLED); + return; + } + + startComplexShape(ctxcanvas, 3, 1, SIZE_ARC+SIZE_LINE*2, + (unsigned long) xc-w/2, (unsigned long) yc-h/2, + (unsigned long) xc+h/2, (unsigned long) yc+h/2); + + arc(ctxcanvas, xc, yc, w, h, a1, a2); + + cdline(ctxcanvas, xc, yc, (int) + (((double)w*cos(a1*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a1*CD_DEG2RAD))/2.+.5)); + cdline(ctxcanvas, xc, yc, (int) + (((double)w*cos(a2*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a2*CD_DEG2RAD))/2.+.5)); + + endComplexElement(ctxcanvas); +} + +static void cdtext (cdCtxCanvas* ctxcanvas, int x, int y, const char *s) +{ + long n=0; + long descent=0; + short w=0; + long hc=0,wc=0; + int size_pixel; + short italic = (ctxcanvas->canvas->font_style&CD_ITALIC); + + Elm_hdr ehdr; + Disp_hdr dhdr; + + n = strlen(s); + + if(n > 255) + n=255; + + w = (short)((n/2)+(n%2)); + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + descent=get_descent(s, size_pixel); + hc = size_pixel+descent; + wc = gettextwidth(ctxcanvas, s, size_pixel); + + y+=descent; + + switch (ctxcanvas->alignment) + { + case 12: x = x; y = y; break; + case 13: x = x; y = y - (int) (hc/2.0); break; + case 14: x = x; y = y - (int) hc; break; + case 6: x = x - (int) (wc/2.0); y = y; break; + case 7: x = x - (int) (wc/2.0); y = y - (int) (hc/2.0); break; + case 8: x = x - (int) (wc/2.0); y = y - (int) hc; break; + case 0: x = x - (int) wc; y = y; break; + case 1: x = x - (int) wc; y = y - (int) (hc/2.0); break; + case 2: x = x - (int) wc; y = y - (int) hc; break; + } + + if(ctxcanvas->is_base) + y -= (int) (hc/4.0); + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=17; + ehdr.words=28+w+((italic) ? 8 : 0); + ehdr.xmin=x; + ehdr.xmax=x+wc; + ehdr.ymin=y-descent; + ehdr.ymax=y+hc; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=14+w; + dhdr.props.flags.attributes=(italic) ? 1 : 0; + + if (ctxcanvas->canvas->font_style&CD_BOLD) + dhdr.symb.s=ctxcanvas->color << 8 | (3 << 3); + else + dhdr.symb.s=ctxcanvas->color << 8; + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, (ctxcanvas->alignment << 8) | ctxcanvas->typeface_index); + + put_long(ctxcanvas, (long)((1000 * ctxcanvas->tl) / 6) | (1 << 7)); + put_long(ctxcanvas, (long)((1000 * size_pixel) / 6) | (1 << 7)); + + put_long(ctxcanvas, 0); + put_long(ctxcanvas, x); + put_long(ctxcanvas, y); + put_word(ctxcanvas, (unsigned short) n); + writec(ctxcanvas, s, (short)(n+(n%2))); /* deve escrever sempre um numero par de caracteres */ + + if(italic) + { + put_word(ctxcanvas, 0x1007); /* atributos e words to follow */ + put_word(ctxcanvas, 0x80d4); /* tipo de atributo */ + put_long(ctxcanvas, 0x000865c0); + put_long(ctxcanvas, 0x00520000); + put_long(ctxcanvas, 0x00000000); + } +} + +static void startComplexShape(cdCtxCanvas* ctxcanvas, + unsigned short num_elements, + short is_fill, + unsigned short size, + unsigned long xmin, + unsigned long ymin, + unsigned long xmax, + unsigned long ymax) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=14; + ehdr.words=22 + ((is_fill) ? 8 : 0); + ehdr.xmax = xmax; + ehdr.xmin = xmin; + ehdr.ymax = ymax; + ehdr.ymin = ymin; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=4; + dhdr.props.flags.attributes = (is_fill) ? 1 : 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, size + 5 + ((is_fill) ? 8 : 0)); + put_word(ctxcanvas, num_elements); + + put_long(ctxcanvas, 0); /* atributo nulo */ + put_long(ctxcanvas, 0); + + /* salva atributo de fill */ + if(is_fill) + { + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + } + + /* marca inicio de elemento complexo */ + + ctxcanvas->is_complex = 1; +} + + +static void startComplexChain(cdCtxCanvas* ctxcanvas, + unsigned short num_elements, + unsigned short size, + unsigned long xmin, + unsigned long ymin, + unsigned long xmax, + unsigned long ymax) + +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=12; + + ehdr.words=22; + ehdr.xmax = xmax; + ehdr.xmin = xmin; + ehdr.ymax = ymax; + ehdr.ymin = ymin; + + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=4; + dhdr.props.flags.attributes = 1; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, size+5); + put_word(ctxcanvas, num_elements); + + put_long(ctxcanvas, 0); /* atributo nulo */ + put_long(ctxcanvas, 0); + + + /* marca inicio de elemento complexo */ + + ctxcanvas->is_complex = 1; +} + +static void endComplexElement(cdCtxCanvas* ctxcanvas) +{ + ctxcanvas->is_complex = 0; +} + +static void putLineString(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + short i=0; + + ehdr.type.flags.level=ctxcanvas->level; + + ehdr.type.flags.type=4; + + ehdr.words=SIZE_LINE_STRING(num_vertex)-2; + + line_string_bound(buffer, num_vertex, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=ehdr.words-14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, num_vertex); + + for (i = 0; i < num_vertex; i++) + { + put_long(ctxcanvas, (long) buffer[i].x); + put_long(ctxcanvas, (long) buffer[i].y); + } +} + +static void putShape(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + short i=0; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=6; + + ehdr.words=SIZE_FILLED_SHAPE(num_vertex)-2; + + line_string_bound(buffer, num_vertex, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=ehdr.words - 14 - 8; /* 8 -> size of attributes */ + dhdr.props.flags.attributes = 1; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, num_vertex); + + for (i = 0; i < num_vertex; i++) + { + put_long(ctxcanvas, (long) buffer[i].x); + put_long(ctxcanvas, (long) buffer[i].y); + } + + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + short is_fill=0; + + if(mode == CD_FILL && ctxcanvas->fill_type == NOFILL) + mode = CD_CLOSED_LINES; + + if(n > MAX_NUM_VERTEX_PER_POLYLINE) + n = MAX_NUM_VERTEX_PER_POLYLINE; + + /* acerta buffer de pontos */ + if(mode == CD_FILL || mode == CD_CLOSED_LINES) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + /* se fill_type for CONVEX, testa se poligono e' convexo ou concavo */ + if((ctxcanvas->fill_type == CONVEX) && (n > 3) && (mode == CD_FILL)) + { + short signal=0; + short count=0; + long vect=0; + + /* calcula sinal do vetorial entre o primeiro lado e o segundo */ + vect = (poly[1].x - poly[0].x) * + (poly[2].y - poly[1].y) - + (poly[1].y - poly[0].y) * + (poly[2].x - poly[1].x); + + if(vect == 0) + mode = CD_CLOSED_LINES; /* ver se precisa mudar */ + else + { + signal = (short)(vect/abs(vect)); + + for(count=1 ; count< (n-2); count++) + { + vect = (poly[count+1].x - poly[count].x) * + (poly[count+2].y - poly[count+1].y) - + (poly[count+1].y - poly[count].y) * + (poly[count+2].x - poly[count+1].x); + + if(vect == 0) + { + mode=CD_CLOSED_LINES; + break; + } + + if((vect/abs(vect)) != signal) + { + mode=CD_CLOSED_LINES; + break; + } + } + } + } + + /* se tiver fill */ + + if(mode == CD_FILL) + is_fill=1; + + if(n > MAX_NUM_VERTEX) /* tem que usar complex shape ou chain */ + { + short count=0; + short num_whole_elements = n / MAX_NUM_VERTEX; + short num_whole_vertex = num_whole_elements * MAX_NUM_VERTEX; + short rest = n % MAX_NUM_VERTEX; + short is_there_rest = (rest > 0) ? 1 : 0; + unsigned long xmax, xmin, ymax, ymin; + unsigned short size = + SIZE_LINE_STRING(MAX_NUM_VERTEX)*num_whole_elements+ + SIZE_LINE_STRING(rest)*is_there_rest; + + line_string_bound(poly, n, &xmin, &ymin, &xmax, &ymax); + + if(mode == CD_OPEN_LINES) + startComplexChain(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)), + size, xmin, ymin, xmax, ymax); + else + startComplexShape(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)), + is_fill, size, xmin, ymin, xmax, ymax); + + for(count=0;count < num_whole_vertex; count+=MAX_NUM_VERTEX, n-=MAX_NUM_VERTEX) + putLineString(ctxcanvas, &poly[count], MAX_NUM_VERTEX); + + if(rest) + putLineString(ctxcanvas, &poly[num_whole_vertex],n); + + endComplexElement(ctxcanvas); + } + else + { + if(is_fill) + putShape(ctxcanvas, poly, n); + else + putLineString(ctxcanvas, poly, n); + } +} + +/************** + * attributes * + **************/ + +static int cdlinestyle (cdCtxCanvas* ctxcanvas, int style) +{ + switch(style) + { + case CD_CONTINUOUS: + ctxcanvas->style = 0; + break; + + case CD_DASHED: + ctxcanvas->style = 3; + break; + + case CD_DOTTED: + ctxcanvas->style = 1; + break; + + case CD_DASH_DOT: + ctxcanvas->style = 4; + break; + + case CD_DASH_DOT_DOT: + ctxcanvas->style = 6; + break; + } + + return style; +} + +static int cdlinewidth (cdCtxCanvas* ctxcanvas, int width) +{ + (void)ctxcanvas; + width = width & 31; + return width; +} + +static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + (void)style; + ctxcanvas->tl = (long)(cdGetFontSizePoints(ctxcanvas->canvas, size)/4)*3; + + if (cdStrEqualNoCase(type_face, "Courier")) + ctxcanvas->typeface_index=1; + else if (cdStrEqualNoCase(type_face, "Times")) + ctxcanvas->typeface_index=2; + else if (cdStrEqualNoCase(type_face, "Helvetica")) + ctxcanvas->typeface_index=3; + else if (cdStrEqualNoCase(type_face, "System")) + ctxcanvas->typeface_index=0; + else + return 0; + + return 1; +} + +static void cdgetfontdim (cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + int size_pixel; + + if(max_width) + { + int a=0; + *max_width=0; + + while(fontsizes[ctxcanvas->typeface_index][a]) + { + if(fontsizes[ctxcanvas->typeface_index][a] > *max_width) + *max_width = fontsizes[ctxcanvas->typeface_index][a]; + a++; + } + } + + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + + if(height) *height = (size_pixel*3)/2; + if(ascent) *ascent = size_pixel; + if(descent) *descent = size_pixel/2; +} + +static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + if(height) *height = size_pixel + get_descent(s, size_pixel); + if(width) *width = gettextwidth(ctxcanvas, s, size_pixel); +} + +static int cdtextalignment (cdCtxCanvas* ctxcanvas, int alignment) +{ + ctxcanvas->is_base = 0; + + /* DGN guarda posicao do texto em relacao ao ponto */ + + switch(alignment) + { + case CD_NORTH: + ctxcanvas->alignment = 8; /* center-bottom */ + break; + + case CD_SOUTH: + ctxcanvas->alignment = 6; /* center-top */ + break; + + case CD_EAST: + ctxcanvas->alignment = 1; /* left-center */ + break; + + case CD_WEST: + ctxcanvas->alignment = 13; /* right-center */ + break; + + case CD_NORTH_EAST: + ctxcanvas->alignment = 2; /* left-bottom */ + break; + + case CD_NORTH_WEST: + ctxcanvas->alignment = 14; /* right-bottom */ + break; + + case CD_SOUTH_EAST: + ctxcanvas->alignment = 0; /* left-top */ + break; + + case CD_SOUTH_WEST: + ctxcanvas->alignment = 12; /* right-top */ + break; + + case CD_CENTER: + ctxcanvas->alignment = 7; /* center-center */ + break; + + case CD_BASE_LEFT: + ctxcanvas->alignment = 13; /* right-center */ + ctxcanvas->is_base=1; + break; + + case CD_BASE_CENTER: + ctxcanvas->alignment = 7; /* center-center */ + ctxcanvas->is_base=1; + break; + + case CD_BASE_RIGHT: + ctxcanvas->alignment = 1; /* left-center */ + ctxcanvas->is_base=1; + break; + } + + return alignment; +} + +/******************************************************/ +/* color */ +/******************************************************/ + +static void cdpalette (cdCtxCanvas* ctxcanvas, int n, const long int *palette, int mode) +{ + int c=0; + + IGNORE(mode); + + for(c=0; c < n; c++) + ctxcanvas->colortable[c] = *palette++; + + ctxcanvas->num_colors = n; +} + +static long int cdforeground (cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->color = getclosestColor(ctxcanvas, color); + return color; +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, + const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i=0,j=0, remainder=iw%2, total_colors; + int *ix=NULL,*iy=NULL; + Elm_hdr ehdr; + Disp_hdr dhdr; + unsigned char map_colors[256]; + + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=87; + ehdr.words=39; + ehdr.xmin=x; + ehdr.xmax=x+w; + ehdr.ymin=y; + ehdr.ymax=y+h; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=25; + dhdr.symb.s=0; + + putDisplayHeader(ctxcanvas, &dhdr); + + /* description of the element */ + put_long(ctxcanvas, 21+(23+w/2+w%2)*h); /* total length of cell */ + put_word(ctxcanvas, 0x0714); /* raster flags */ + put_word(ctxcanvas, 0x0100); /* background e foreground colors + (nao usados) */ + put_word(ctxcanvas, w); /* largura da imagem em pixels */ + put_word(ctxcanvas, h); /* altura da imagem em pixel */ + put_long(ctxcanvas, 0); /* resevado */ + put_as_double(ctxcanvas, 0); /* resolution (nao usado) */ + + put_word(ctxcanvas, 0x4080); /* scale */ + put_long(ctxcanvas, 0); + put_word(ctxcanvas, 0); + + put_long(ctxcanvas, x); /* origem */ + put_long(ctxcanvas, y+h); + put_long(ctxcanvas, 0); + + put_word(ctxcanvas, 0); /* no de vertices */ + + ctxcanvas->is_complex = 1; /* elemento complexo */ + + /* obtem o maior indice usado na imagem */ + + total_colors = 0; + for (i = 0; i < iw*ih; i++) + { + if (index[i] > total_colors) + total_colors = index[i]; + } + total_colors++; + + /* cria tabela para acelerar match de cor na palette */ + + for (i = 0; i < total_colors; i++) + { + map_colors[i] = (unsigned char)getclosestColor(ctxcanvas, colors[i]); + } + + /** salva dados da imagem **/ + + /* calcula stretch */ + + ix = cdGetZoomTable(w, xmax-xmin+1, xmin); + iy = cdGetZoomTable(h, ymax-ymin+1, ymin); + + for(i=h-1; i >= 0; i--) + { + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=88; + ehdr.words=21+w/2+remainder; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=7+w/2+remainder; + dhdr.symb.s=0; + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, 0x0714); /* raster flags */ + put_word(ctxcanvas, 0x0100); /* background e foreground + colors (nao usados) */ + + put_word(ctxcanvas, 0); /* x offset da origem */ + put_word(ctxcanvas, i); /* y offset */ + put_word(ctxcanvas, w); /* numero de pixels neste elemento */ + + for(j=0; j < w; j++) + put_byte(ctxcanvas, map_colors[index[(iy[i])*iw + ix[j]]]); + + if(remainder) put_byte(ctxcanvas, 0); + } + + ctxcanvas->is_complex = 0; + + free(ix); /* libera memoria alocada */ + free(iy); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel (cdCtxCanvas* ctxcanvas, int x, int y, long int color) +{ + long old_color = cdforeground(ctxcanvas, color); + int old_linestyle = cdlinestyle(ctxcanvas, CD_CONTINUOUS); + int old_linewidth = cdlinewidth(ctxcanvas, 1); + + cdline(ctxcanvas, x,y,x,y); + + cdforeground(ctxcanvas, old_color); + cdlinestyle(ctxcanvas, old_linestyle); + cdlinewidth(ctxcanvas, old_linewidth); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas *ctxcanvas; + char* strdata = (char*)data; + char words[4][256]; + char filename[10240] = ""; + char seedfile[10240] = ""; + int count = 0; + double res = 0; + + if (!data) return; + + /* separa palavras da expressao, que e' na forma + "filename [mm_wxmm_h] [res] [-f] [-sseedfile]" */ + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%s %s %s %s", words[0], words[1], words[2], words[3]); + + if(!strlen(filename)) /* se nao pegou filename */ + return; + + ctxcanvas = (cdCtxCanvas *) malloc(sizeof(cdCtxCanvas)); + + /* tenta criar arquivo DGN */ + + if((ctxcanvas->file = fopen (filename, "wb"))==NULL) + { + free(ctxcanvas); + return; + } + + /* verifica se foi passado tamanho do canvas em mm. Se foi, + extrai-o da string */ + + if(sscanf(words[0], "%lgx%lg", + &canvas->w_mm, &canvas->h_mm) == 2) + { + count++; /* incrementa contador de palavras */ + + if(canvas->w_mm == 0 || canvas->h_mm == 0) + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + else + canvas->w_mm = canvas->h_mm = 0; + + /* Verifica se foi passada resolucao */ + + if(sscanf(words[count], "%lg", &res) == 1) + { + count++; /* incrementa contador de palavras */ + + if(res <= 0) /* verifica validade da resolucao */ + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + else + res = 3.78; + + /* se tamanho em milimetros nao tiver sido inicializado, + usa como default o tamanho maximo em pixels para fazer as + contas + */ + + if (canvas->w_mm == 0 || canvas->h_mm == 0) + { + canvas->w = INT_MAX; + canvas->h = INT_MAX; + + canvas->w_mm = canvas->w / res; + canvas->h_mm = canvas->h / res; + } + else + { + canvas->w = (long) (canvas->w_mm * res); + canvas->h = (long) (canvas->h_mm * res); + } + + canvas->xres = res; + canvas->yres = res; + canvas->bpp = 8; + + /* verifica se usuario que alterar metodo de fill */ + + if (strcmp(words[count], "-f")==0) + { + ctxcanvas->fill_type = CONVEX; + count++; + } + else + ctxcanvas->fill_type = NORMAL; + + /* se tiver passado seedfile como argumento */ + if(sscanf(words[count], "-s%s", seedfile) == 1) + { + FILE *seed=NULL; + char *cd_dir = getenv("CDDIR"); + static char newfilename[512]; + + if(cd_dir == NULL) + cd_dir = "."; + + sprintf(newfilename, "%s/%s", cd_dir, seedfile); + + count++; + + /* testa concatenando com variavel de ambiente */ + + if((seed = fopen (newfilename, "rb"))==NULL) + { + /* tenta abrir usando string passada pelo usuario + diretamente */ + + if((seed = fopen (seedfile, "rb"))==NULL) + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + + /* concatena seed */ + + fseek(seed, 0, SEEK_SET); + fseek(ctxcanvas->file, 0, SEEK_SET); + + ctxcanvas->bytes=0; + dgn_copy(seed, ctxcanvas); + fclose(seed); + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + /* config */ + + ctxcanvas->level = 1; + + /** valores default do contexto sao setados **/ + + /* texto */ + + ctxcanvas->alignment = 12; + ctxcanvas->is_base = 1; + ctxcanvas->typeface_index = 0; + ctxcanvas->tl=12; + + /* cores */ + + memset(ctxcanvas->colortable, 0, 1024); + ctxcanvas->colortable[0] = CD_BLACK; + ctxcanvas->num_colors = 1; + + /* atributos */ + + ctxcanvas->color = 1; + ctxcanvas->style = 0; + + /* DGN */ + + ctxcanvas->is_complex=0; +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectMap = cdputimagerectmap; + + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxPalette = cdpalette; + canvas->cxForeground = cdforeground; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdDGNContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | CD_CAP_RECT | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_IMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_FPRIMTIVES | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDGN(void) +{ + return &cdDGNContext; +} + + diff --git a/src/drv/cddxf.c b/src/drv/cddxf.c new file mode 100644 index 0000000..b5c8854 --- /dev/null +++ b/src/drv/cddxf.c @@ -0,0 +1,1184 @@ +/** \file + * \brief DXF driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include "cd.h" +#include "cd_private.h" +#include "cddxf.h" + + +#ifndef ignore +#define ignore(x) (void)x +#endif + +#ifndef max +#define max(x, y) ((x > y)? x : y) +#endif + +#ifndef min +#define min(x, y) ((x < y)? x : y) +#endif + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* pointer to file */ + int layer; /* layer */ + + int tf; /* text font */ + double th; /* text height (in points) */ + int toa; /* text oblique angle (for italics) */ + int tha, tva; /* text horizontal and vertical alignment */ + + int fgcolor; /* foreground AutoCAD palette color */ + + int lt; /* line type */ + double lw; /* line width (in milimeters) */ +}; + + +static void wnamline (cdCtxCanvas* ctxcanvas, int t) /* write name of a line */ +{ + + static char *line[] = + {"CONTINUOUS", + "DASHED", + "HIDDEN", + "CENTER", + "PHANTOM", + "DOT", + "DASHDOT", + "BORDER", + "DIVIDE"}; + +/* + AutoCAD line styles ( see acad.lin ): + + 0 CONTINUOUS ____________________________________________ + 1 DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + 2 HIDDEN _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 3 CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____ _ __ + 4 PHANTOM _____ _ _ _____ _ _ _____ _ _ _____ _ _ ____ + 5 DOT ............................................ + 6 DASHDOT __ . __ . __ . __ . __ . __ . __ . __ . __ . + 7 BORDER __ __ . __ __ . __ __ . __ __ . __ __ . __ _ + 8 DIVIDE __ . . __ . . __ . . __ . . __ . . __ . . __ + +*/ + + fprintf (ctxcanvas->file, "%s\n", line[t]); +} + + +static void wnamfont (cdCtxCanvas *ctxcanvas, int t) /* write name of a font */ +{ + static char *font[] = + { + "STANDARD", + "ROMAN", + "ROMAN_BOLD", + "ROMANTIC", + "ROMANTIC_BOLD", + "SANSSERIF", + "SANSSERIF_BOLD", + }; +/* + CD Fonts / Style AutoCAD Fonts + ------------------------------------------------------------------- + CD_SYSTEM 0 STANDARD + CD_COURIER / CD_PLAIN 1 ROMAN + CD_COURIER / CD_BOLD 2 ROMAN_BOLD + CD_COURIER / CD_ITALIC 1 ROMAN (ctxcanvas->toa = 15) + CD_COURIER / CD_BOLD_ITALIC 2 ROMAN_BOLD (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_PLAIN 3 ROMANTIC + CD_TIMES_ROMAN / CD_BOLD 4 ROMANTIC_BOLD + CD_TIMES_ROMAN / CD_ITALIC 3 ROMANTIC (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_BOLD_ITALIC 4 ROMANTIC_BOLD (ctxcanvas->toa = 15) + CD_HELVETICA / CD_PLAIN 5 SANSSERIF + CD_HELVETICA / CD_BOLD 6 SANSSERIF_BOLD + CD_HELVETICA / CD_ITALIC 5 SANSSERIF (ctxcanvas->toa = 15) + CD_HELVETICA / CD_BOLD_ITALIC 6 SANSSERIF_BOLD(ctxcanvas->toa = 15) +*/ + + fprintf (ctxcanvas->file, "%s\n", font[t]); +} + + +static void writepoly (cdCtxCanvas *ctxcanvas, cdPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; ifile, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void writepolyf (cdCtxCanvas *ctxcanvas, cdfPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; ifile, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void deflines (cdCtxCanvas *ctxcanvas) /* define lines */ +{ + int i, j; + static char *line[] = + {"Solid line", + "Dashed line", + "Hidden line", + "Center line", + "Phantom line", + "Dot line", + "Dashdot line", + "Border line", + "Divide Line"}; + +#define TABSIZE (sizeof(tab)/sizeof(tab[0])) + + static int tab[][8] = + { + { 0, 0, 0 , 0, 0, 0, 0, 0 }, + { 2, 15, 10, -5, 0, 0, 0, 0 }, + { 2, 10, 5 , -5, 0, 0, 0, 0 }, + { 4, 35, 20, -5, 5, -5, 0, 0 }, + { 6, 50, 25, -5, 5, -5, 5, -5 }, + { 2, 5, 0 , -5, 0, 0, 0, 0 }, + { 4, 20, 10, -5, 0, -5, 0, 0 }, + { 6, 35, 10, -5, 10, -5, 0, -5 }, + { 6, 25, 10, -5, 0, -5, 0, -5 } + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (j = 0; j < TABSIZE; j++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamline (ctxcanvas, j); /* line style */ + + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", line[j]); /* line style */ + fprintf (ctxcanvas->file, "72\n"); + fprintf (ctxcanvas->file, "65\n"); + fprintf (ctxcanvas->file, "73\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][0]); /* number of parameters */ + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][1]); + for (i = 2; i < 2 + tab[j][0]; i++) + { + fprintf (ctxcanvas->file, "49\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][i]); /* parameters */ + } + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + + +static void deffonts (cdCtxCanvas *ctxcanvas) /* define fonts */ +{ + int i; + static char *font[] = + { + "romanc.shx" , + "romant.shx" , + "rom_____.pfb", + "romb____.pfb", + "sas_____.pfb", + "sasb____.pfb" + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (i = 1; i < 7; i++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamfont (ctxcanvas, i); /* font style name */ + + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", font[i-1]); /* font style file */ + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "71\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "41\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "42\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "50\n"); + fprintf (ctxcanvas->file, "0\n"); + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + +static void cddeactivate (cdCtxCanvas *ctxcanvas) +{ + fflush (ctxcanvas->file); /* flush file */ +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "EOF\n"); /* fputs eof */ + fprintf (ctxcanvas->file, " \n"); + + fflush (ctxcanvas->file); /* flush file */ + fclose (ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free (ctxcanvas); +} + +static void cdflush (cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->layer++; +} + +/*==========================================================================*/ +/* Primitives */ +/*==========================================================================*/ +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepoly (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdline (cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepoly (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdboxrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepoly (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepolyf (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdfline (cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + cdfPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepolyf (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdfboxrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + cdfPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepolyf (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +/*--------------------------------------------------------------------------*/ +/* gives radius of the circle most resembling elliptic arc at angle t */ +/*--------------------------------------------------------------------------*/ +static double calc_radius (double a, double b, double t) +{ + return (pow ((a*a*sin(t)*sin(t) + b*b*cos(t)*cos(t)), 1.5))/(a*b); +} + +/*--------------------------------------------------------------------------*/ +/* calculates bulge for a given circular arc segment (between points p1 and */ +/* p2, with radius r). Bulge is the tangent of 1/4 the angle theta of the */ +/* arc segment(a bulge of 1 is a semicircle, which has an angle of 180 deg) */ +/*--------------------------------------------------------------------------*/ +static double calc_bulge (double a, double b, double t1, double t2) +{ + cdfPoint p1, p2; /* initial and ending arc points */ + double r; /* radius most resembling arc at angle (t1+t2)/2 */ + double theta; /* angle of circular arc segment */ + double sin_theta; /* sine of theta */ + double dist_x; /* distance between two points along the x axis */ + double dist_y; /* distance between two points along the y axis */ + double halfdist; /* half distance between two points */ + + p1.x = a*cos(t1); + p1.y = b*sin(t1); + p2.x = a*cos(t2); + p2.y = b*sin(t2); + r = calc_radius (a, b, (t1+t2)/2); + + dist_x = p2.x - p1.x; + dist_y = p2.y - p1.y; + halfdist = (sqrt (dist_x*dist_x + dist_y*dist_y))/2; + sin_theta = halfdist/r; + if (sin_theta > 1) sin_theta = 1; + theta = 2*asin(sin_theta); + + return tan(theta/4); +} + +static void writevertex (cdCtxCanvas *ctxcanvas, int xc, int yc, double a, double b, double t, double bulge) +{ + cdfPoint p; + p.x = (xc + a*cos(t))/ctxcanvas->canvas->xres; + p.y = (yc + b*sin(t))/ctxcanvas->canvas->xres; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", p.x ); + fprintf ( ctxcanvas->file, "20\n" ); /* vertex coordinates */ + fprintf ( ctxcanvas->file, "%f\n", p.y ); + fprintf ( ctxcanvas->file, "42\n" ); /* bulge from this vertex */ + fprintf ( ctxcanvas->file, "%f\n", bulge ); /* to the next one */ +} + +static void cdarc (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + for (i=0, t=t1; ifile, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdsector (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + if ((a2-a1) != 360) + writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */ + for (i=0, t=t1; ifile, " 0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdtext (cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "TEXT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "7\n" ); + wnamfont( ctxcanvas, ctxcanvas->tf ); /* current font */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* current position */ + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "11\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* alignment point */ + fprintf ( ctxcanvas->file, "21\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->th ); /* text height */ + fprintf ( ctxcanvas->file, "50\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->canvas->text_orientation ); /* text orientation angle */ + fprintf ( ctxcanvas->file, "51\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->toa ); /* text oblique angle */ + fprintf ( ctxcanvas->file, "72\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tha ); /* text horizontal alignment */ + fprintf ( ctxcanvas->file, "73\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tva ); /* text vertical alignment */ + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "%s\n", s ); /* text */ +} + + +/*==========================================================================*/ +/* Attributes */ +/*==========================================================================*/ + +static int cdlinestyle (cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + ctxcanvas->lt = 0; + break; + case CD_DASHED: + ctxcanvas->lt = 1; + break; + case CD_DOTTED: + ctxcanvas->lt = 5; + break; + case CD_DASH_DOT: + ctxcanvas->lt = 6; + break; + case CD_DASH_DOT_DOT: + ctxcanvas->lt = 8; + break; + } + + return style; +} + +static int cdlinewidth (cdCtxCanvas *ctxcanvas, int width) +{ + ctxcanvas->lw = width/ctxcanvas->canvas->xres; + return width; +} + +static int cdfont (cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + /* obs: DXF's text height (ctxcanvas->th) corresponds to CD ascent */ + + if (cdStrEqualNoCase(type_face, "System")) + { + ctxcanvas->tf = 0; + ctxcanvas->toa = 0; + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Courier")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 1; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 2; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 1; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 2; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Times")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 3; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 4; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 3; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 4; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.125; + } + else if (cdStrEqualNoCase(type_face, "Helvetica")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 5; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 6; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 5; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 6; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.; + } + else + return 0; + + ctxcanvas->th = ctxcanvas->th * cdGetFontSizePoints(ctxcanvas->canvas, size); + + return 1; +} + +static void cdgetfontdim (cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + double tangent_ta; + double pixel_th; + + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + switch (ctxcanvas->tf) + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = _cdRound(pixel_th); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = cdRound((pixel_th*21/20) + tangent_ta*(*ascent)); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*14/15) + tangent_ta*(*ascent)); + break; + + case 4: + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*29/30) + tangent_ta*(*ascent)); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (ascent) *ascent = cdRound(pixel_th*3/4); + if (descent) *descent = cdRound(pixel_th/4); + if (max_width) *max_width = cdRound((pixel_th*15/16) + tangent_ta*(*ascent)); + break; + } +} + +static void cdgettextsize (cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + int i; + double tangent_ta; + double pixel_th; + + i = (int)strlen(s); + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + + switch (ctxcanvas->tf) /* width return value based on maximum character width */ + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound(pixel_th*i + (pixel_th/3)*(i-1)); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound((pixel_th*21/20)*i + (pixel_th/10)*(i-1) + tangent_ta*pixel_th); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*14/15)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 4: + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*29/30)*i + (pixel_th*2/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (width) *width = cdRound((pixel_th*15/16)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*3/4); + break; + } +} + +static int cdtextalignment (cdCtxCanvas *ctxcanvas, int alignment) +{ + switch (alignment) /* convert alignment to DXF format */ + { + case CD_BASE_LEFT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 0; + break; + + case CD_BASE_CENTER: + ctxcanvas->tva = 0; + ctxcanvas->tha = 1; + break; + + case CD_BASE_RIGHT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 2; + break; + + case CD_SOUTH_WEST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 0; + break; + + case CD_SOUTH: + ctxcanvas->tva = 1; + ctxcanvas->tha = 1; + break; + + case CD_SOUTH_EAST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 2; + break; + + case CD_WEST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 0; + break; + + case CD_CENTER: + ctxcanvas->tva = 2; + ctxcanvas->tha = 1; + break; + + case CD_EAST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 2; + break; + + case CD_NORTH_WEST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 0; + break; + + case CD_NORTH: + ctxcanvas->tva = 3; + ctxcanvas->tha = 1; + break; + + case CD_NORTH_EAST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 2; + break; + } + + return alignment; +} + +/*==========================================================================*/ +/* Color */ +/*==========================================================================*/ + +static void RGB_to_HSB (unsigned char r, unsigned char g, unsigned char b, + double *hue, double *sat, double *bright) +{ + double maximum; + double minimum; + double delta; + double red = r/255.; /* red, green and blue range from 0 to 1 */ + double green = g/255.; + double blue = b/255.; + + maximum = max(max(red, green), blue); /* stores higher index */ + minimum = min(min(red, green), blue); /* stores lower index */ + delta = maximum - minimum; + + *bright = maximum*100; + *sat = 0; + + if (maximum != 0) /* sat from 0 to 100 */ + *sat = (delta*100)/maximum; + + if (*sat != 0) /* hue from 0 to 359 */ + { + if (red == maximum) *hue = (green - blue)/delta; + if (green == maximum) *hue = 2 + (blue - red)/delta; + if (blue == maximum) *hue = 4 + (red - green)/delta; + *hue *= 60; + if (*hue < 0) *hue += 360; + } + else + *hue = 0; /* color is greyscale (hue is meaningless) */ +} + +static int HSB_to_AutoCAD_Palette (double hue, double sat, double bright) +{ + int index; + int h, s, b; + + if (bright < 17) /* 5 levels of brightness in AutoCAD palette, 6 with */ + { /* black. If bright < 17, index is black (7). */ + index = 7; /* 17 is 100/6 (rounded up) */ + } + else if (sat < 10) /* low saturation makes color tend to */ + { /* grey/white. 6 levels of grey/white in */ + b = (int)floor(bright/14.3)-1;/* palette WITHOUT black. 14.3 is 100/7 */ + index = 250 + b; /* index is grey to white(255 in palette) */ + } + else + { + h = cdRound(hue/15.) + 1; + if (h > 24) h -= 24; /* 15 is 360/24 */ + h *= 10; /* h ranges from 10 to 240 in palette */ + s = (sat < 55) ? 1 : 0; /* s is 'high'(0) or 'low'(1) in palette */ + b = (int)floor(bright/16.7)-1;/* b is 0, 2, 4, 6 or 8 in palette */ + b = 2*(4 - b); /* (from brightest to dimmest) */ + index = h + s + b; /* index is simple sum of h, s and b */ + } + return index; +} + +static int get_palette_index (long int color) /* gives closest palette */ +{ /* index to RGB color */ + unsigned char red, green, blue; + double hue, sat, bright; + + cdDecodeColor (color, &red, &green, &blue); /* AutoCAD palette is */ + RGB_to_HSB (red, green, blue, &hue, &sat, &bright); /* based on HSB model */ + + return HSB_to_AutoCAD_Palette (hue, sat, bright); +} + +static long int cdforeground (cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->fgcolor = get_palette_index (color); + return color; +} + + +/*==========================================================================*/ +/* Server Images */ +/*==========================================================================*/ + +static void cdpixel (cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + int oldcolor = ctxcanvas->fgcolor; /* put 'color' as current */ + cdforeground (ctxcanvas, color); /* foreground color */ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POINT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* position */ + fprintf ( ctxcanvas->file, " 20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + ctxcanvas->fgcolor = oldcolor; /* retrieve old fgcolor */ +} + +/******************************************************/ + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + cdCtxCanvas *ctxcanvas; + double param1, param2, param3; + + ctxcanvas = (cdCtxCanvas *) malloc (sizeof (cdCtxCanvas)); + + param1 = 0; + param2 = 0; + param3 = 0; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lfx%lf %lf", ¶m1, ¶m2, ¶m3); + + ctxcanvas->file = fopen (filename, "w"); + if (ctxcanvas->file == NULL) + { + free(ctxcanvas); + return; + } + + if (!param1) + { + canvas->w_mm = INT_MAX*3.78; + canvas->h_mm = INT_MAX*3.78; + canvas->xres = 3.78; + } + else if (!param2) + { + canvas->w_mm = INT_MAX*param1; + canvas->h_mm = INT_MAX*param1; + canvas->xres = param1; + } + else if (!param3) + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = 3.78; + } + else + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = param3; + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + canvas->bpp = 8; + + canvas->yres = canvas->xres; + + canvas->w = (int)(canvas->w_mm * canvas->xres); + canvas->h = (int)(canvas->h_mm * canvas->yres); + + ctxcanvas->layer = 0; /* reset layer */ + + ctxcanvas->tf = 0; /* text font (0 is STANDARD) */ + ctxcanvas->th = 9; /* text height */ + ctxcanvas->toa = 0; /* text oblique angle */ + ctxcanvas->tva = 0; /* text vertical alignment (0 is baseline) */ + ctxcanvas->tha = 0; /* text horizontal alignment (0 is left) */ + ctxcanvas->fgcolor = 7; /* foreground AutoCAD palette color */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); /* header maker */ + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "HEADER\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMCHECK\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$CLAYER\n"); + fprintf (ctxcanvas->file, "8\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); /* precision (resolution dependant) */ + fprintf (ctxcanvas->file, "%d\n", (int)ceil(log10(ctxcanvas->canvas->xres))); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$TEXTSTYLE\n"); + fprintf (ctxcanvas->file, "7\n"); + fprintf (ctxcanvas->file, "STANDARD\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "TABLES\n"); + + deflines (ctxcanvas); /* define lines */ + deffonts (ctxcanvas); /* define fonts */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "ENTITIES\n"); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdboxrect; + canvas->cxBox = cdboxrect; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfboxrect; + canvas->cxFBox = cdfboxrect; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxForeground = cdforeground; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdDXFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_IMAGERGB | CD_CAP_IMAGEMAP | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDXF(void) +{ + return &cdDXFContext; +} + diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c new file mode 100644 index 0000000..9fbb540 --- /dev/null +++ b/src/drv/cdirgb.c @@ -0,0 +1,2135 @@ +/** \file + * \brief Image RGB Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" +#include "cdirgb.h" + + +struct _cdCtxImage +{ + int w, h; + unsigned char* red; /* red color buffer */ + unsigned char* green; /* green color buffer */ + unsigned char* blue; /* blue color buffer */ + unsigned char* alpha; /* alpha color buffer */ +}; + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + int user_image; /* can not free an user image */ + + unsigned char* red; /* red color buffer */ + unsigned char* green; /* green color buffer */ + unsigned char* blue; /* blue color buffer */ + unsigned char* alpha; /* alpha color buffer */ + unsigned char* clip; /* clipping buffer */ + + unsigned char* clip_region; /* clipping region used during NewRegion */ + + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + cdCanvas* canvas_dbuffer; /* used by the CD_DBUFFERRGB driver */ +}; + +/*******************/ +/* Local functions */ +/*******************/ + +#define _sNormX(_ctxcanvas, _x) (_x < 0? 0: _x < _ctxcanvas->canvas->w? _x: _ctxcanvas->canvas->w-1) +#define _sNormY(_ctxcanvas, _y) (_y < 0? 0: _y < _ctxcanvas->canvas->h? _y: _ctxcanvas->canvas->h-1) + +#define RGBA_COMPOSE(_SRC, _SRC_ALPHA, _DST, _TMP_MULTI, _TMP_ALPHA) (unsigned char)(((_SRC_ALPHA)*(_SRC) + (_TMP_MULTI)*(_DST)) / (_TMP_ALPHA)) + +#define RGBA_COLOR_COMBINE(_ctxcanvas, _pdst_red, _pdst_green, _pdst_blue, _pdst_alpha, _src_red, _src_green, _src_blue, _src_alpha) \ +{ \ + unsigned char _tmp_red = 0, _tmp_green = 0, _tmp_blue = 0; \ + \ + if (_pdst_alpha) /* (_pdst_alpha != NULL) */ \ + { \ + if (_src_alpha != 255) /* some transparency */ \ + { \ + if (_src_alpha != 0) /* source not full transparent */ \ + { \ + if (*_pdst_alpha == 0) /* destiny full transparent */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + *_pdst_alpha = _src_alpha; \ + } \ + else if (*_pdst_alpha == 255) /* destiny opaque */ \ + { \ + _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \ + _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \ + _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \ + /* *_pdst_alpha is not changed */ \ + } \ + else /* (0<*_pdst_alpha<255 && 0<_src_alpha<255) destiny and source are semi-transparent */ \ + { \ + /* Closed Compositing Formulas for SRC over DST, Colors Not Premultiplied by Alpha: */ \ + int _tmp_multi = *_pdst_alpha * (255 - _src_alpha); \ + int _tmp_alpha = _src_alpha + _tmp_multi; \ + _tmp_red = RGBA_COMPOSE(_src_red, _src_alpha, *_pdst_red, _tmp_multi, _tmp_alpha); \ + _tmp_green = RGBA_COMPOSE(_src_green, _src_alpha, *_pdst_green, _tmp_multi, _tmp_alpha); \ + _tmp_blue = RGBA_COMPOSE(_src_blue, _src_alpha, *_pdst_blue, _tmp_multi, _tmp_alpha); \ + *_pdst_alpha = (unsigned char)(_tmp_alpha / 255); \ + } \ + } \ + else /* (_src_alpha == 0) source full transparent */ \ + { \ + _tmp_red = *_pdst_red; \ + _tmp_green = *_pdst_green; \ + _tmp_blue = *_pdst_blue; \ + /* *_pdst_alpha is not changed */ \ + } \ + } \ + else /* (_src_alpha == 255) source has no alpha = opaque */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + *_pdst_alpha = (unsigned char)255; /* set destiny as opaque */ \ + } \ + } \ + else /* (_pdst_alpha == NULL) */ \ + { \ + if (_src_alpha != 255) /* source has some transparency */ \ + { \ + if (_src_alpha != 0) /* source semi-transparent */ \ + { \ + _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \ + _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \ + _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \ + } \ + else /* (_src_alpha == 0) source full transparent */ \ + { \ + _tmp_red = *_pdst_red; \ + _tmp_green = *_pdst_green; \ + _tmp_blue = *_pdst_blue; \ + } \ + } \ + else /* (_src_alpha == 255) source has no alpha = opaque */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + } \ + } \ + \ + switch (_ctxcanvas->canvas->write_mode) \ + { \ + case CD_REPLACE: \ + *_pdst_red = _tmp_red; \ + *_pdst_green = _tmp_green; \ + *_pdst_blue = _tmp_blue; \ + break; \ + case CD_XOR: \ + *_pdst_red ^= _tmp_red; \ + *_pdst_green ^= _tmp_green; \ + *_pdst_blue ^= _tmp_blue; \ + break; \ + case CD_NOT_XOR: \ + *_pdst_red = (unsigned char)~(_tmp_red ^ *_pdst_red); \ + *_pdst_green = (unsigned char)~(_tmp_green ^ *_pdst_green); \ + *_pdst_blue = (unsigned char)~(_tmp_blue ^ *_pdst_blue); \ + break; \ + } \ +} + +static void sCombineRGBColor(cdCtxCanvas* ctxcanvas, int offset, long color) +{ + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + unsigned char sr = cdRed(color); + unsigned char sg = cdGreen(color); + unsigned char sb = cdBlue(color); + unsigned char sa = cdAlpha(color); + + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa); +} + +static void sCombineRGB(cdCtxCanvas* ctxcanvas, int offset, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa) +{ + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa); +} + +static void sCombineRGBLine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, int size) +{ + int c; + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + unsigned char src_a = 255; + + if (size > 0) + { + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a); + dr++; dg++; db++; clip++; + sr++; sg++; sb++; + if (da) da++; + } + } + else + { + size *= -1; + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a); + dr--; dg--; db--; clip--; + sr--; sg--; sb--; + if (da) da--; + } + } +} + +static void sCombineRGBALine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, const unsigned char *sa, int size) +{ + int c; + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + if (size > 0) + { + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa); + dr++; dg++; db++; clip++; + sr++; sg++; sb++; sa++; + if (da) da++; + } + } + else + { + size *= -1; + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa); + dr--; dg--; db--; clip--; + sr--; sg--; sb--; sa--; + if (da) da--; + } + } +} + +static void irgbSolidLine(cdCanvas* canvas, int xmin, int y, int xmax) +{ + int x; + unsigned long offset = y * canvas->w; + + if (y < 0) + return; + + if (y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + for (x = xmin; x <= xmax; x++) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); +} + +static void irgbPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern) +{ + int x, i; + unsigned long offset = y * canvas->w; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + i = xmin % pw; + + for (x = xmin; x <= xmax; x++,i++) + { + if (i == pw) + i = 0; + + sCombineRGBColor(canvas->ctxcanvas, offset + x, pattern[i]); + } +} + +static void irgbStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple) +{ + int x,i; + unsigned long offset = y * canvas->w; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + i = xmin % pw; + + for (x = xmin; x <= xmax; x++,i++) + { + if (i == pw) + i = 0; + if(stipple[i]) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); + else if (canvas->back_opacity == CD_OPAQUE) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background); + } +} + +static void irgbHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch) +{ + int x; + unsigned long offset = y * canvas->w; + unsigned char n; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + n = (unsigned char)(xmin&7); + simRotateHatchN(hatch, n); + + for (x = xmin; x <= xmax; x++) + { + if (hatch & 0x80) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); + else if (canvas->back_opacity == CD_OPAQUE) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background); + + _cdRotateHatch(hatch); + } +} + +/********************/ +/* driver functions */ +/********************/ + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->user_image) + free(ctxcanvas->red); + + if (ctxcanvas->clip_region) + free(ctxcanvas->clip_region); + + free(ctxcanvas->clip); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +unsigned char* cdAlphaImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->alpha; +} + +unsigned char* cdRedImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->red; +} + +unsigned char* cdGreenImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->green; +} + +unsigned char* cdBlueImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->blue; +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + int size = ctxcanvas->canvas->w * ctxcanvas->canvas->h; + memset(ctxcanvas->red, cdRed(ctxcanvas->canvas->background), size); + memset(ctxcanvas->green, cdGreen(ctxcanvas->canvas->background), size); + memset(ctxcanvas->blue, cdBlue(ctxcanvas->canvas->background), size); + if (ctxcanvas->alpha) memset(ctxcanvas->alpha, cdAlpha(ctxcanvas->canvas->background), size); +} + +static void irgPostProcessIntersect(unsigned char* clip, int size) +{ + int i; + for(i = 0; i < size; i++) + { + if (*clip == 2) + *clip = 1; + else + *clip = 0; + + clip++; + } +} + +#define _irgSetClipPixel(_clip, _combine_mode) \ +{ \ + switch (_combine_mode) \ + { \ + case CD_INTERSECT: \ + if (_clip) \ + _clip = 2; /* fills the intersection \ + with a value to be post-processed */ \ + break; \ + case CD_DIFFERENCE: \ + if (_clip) \ + _clip = 0; /* clears the intersection */ \ + break; \ + case CD_NOTINTERSECT: /* XOR */ \ + if (_clip) \ + _clip = 0; /* clears the intersection */ \ + else \ + _clip = 1; /* fills the region */ \ + break; \ + default: /* CD_UNION */ \ + _clip = 1; /* fills the region */ \ + break; \ + } \ +} + +static void irgbClipTextBitmap(FT_Bitmap* bitmap, int x, int y, int w, unsigned char* clip, int combine_mode) +{ + unsigned char *bitmap_data; + int width = bitmap->width; + int height = bitmap->rows; + int i, j; + + /* avoid spaces */ + if (width == 0 || height == 0) + return; + + bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */ + + clip += y * w + x; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + if (bitmap_data[j] == 255) + _irgSetClipPixel(clip[j], combine_mode); + } + clip += w; + bitmap_data -= width; + } +} + +static void irgbClipText(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + cdCanvas* canvas = ctxcanvas->canvas; + cdSimulation* simulation = canvas->simulation; + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix matrix; /* transformation matrix */ + FT_Vector pen; /* untransformed origin */ + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* move the reference point to the baseline-left */ + simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen); + + while(*s) + { + /* set transformation */ + FT_Set_Transform(face, &matrix, &pen); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER); + if (error) {s++; continue;} /* ignore errors */ + + x = slot->bitmap_left; + y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */ + + /* now, draw to our target surface (convert position) */ + irgbClipTextBitmap(&slot->bitmap, x, y, canvas->w, ctxcanvas->clip_region, canvas->combine_mode); + + /* increment pen position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + s++; + } + + if (canvas->combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipFillLine(unsigned char* clip_line, int combine_mode, int x1, int x2, int width) +{ + int x; + if (x1 < 0) x1 = 0; + if (x2 > width-1) x2 = width-1; + for (x = x1; x <= x2; x++) + { + _irgSetClipPixel(clip_line[x], combine_mode); + } +} + +static int compare_int(const int* xx1, const int* xx2) +{ + return *xx1 - *xx2; +} + +static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdPoint* poly, int n, int combine_mode) +{ + cdCanvas* canvas = ctxcanvas->canvas; + unsigned char* clip_line; + simLineSegment *seg_i; + cdPoint* t_poly = NULL; + int y_max, y_min, i, y, i1, fill_mode, num_lines, + inter_count, width, height; + + int *xx = (int*)malloc((n+1)*sizeof(int)); + simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment)); + + if (canvas->use_matrix) + { + t_poly = malloc(sizeof(cdPoint)*n); + memcpy(t_poly, poly, sizeof(cdPoint)*n); + poly = t_poly; + + for(i = 0; i < n; i++) + cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); + } + + width = canvas->w; + height = canvas->h; + fill_mode = canvas->fill_mode; + + y_max = poly[0].y; + y_min = poly[0].y; + for(i = 0; i < n; i++) + { + i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */ + simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min); + } + + if (y_min < 0) + y_min = 0; + + if (y_max > height-1) + num_lines = height-y_min; + else + num_lines = y_max-y_min+1; + + /* for all horizontal lines between y_max and y_min */ + for(y = y_max; y >= y_min; y--) + { + inter_count = 0; + + /* for all segments, calculates the intervals to be filled. */ + for(i = 0; i < n; i++) + { + seg_i = segment + i; + + /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */ + /* if it is an horizontal line, then ignore the segment. */ + if (seg_i->y1 > y || + seg_i->y1 == seg_i->y2) + continue; + + if (y == seg_i->y1) /* intersection at the start point (x1,y1) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* always save at least one intersection point for (y1) */ + + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + + /* check for missing bottom-corner points (|_|), must duplicate the intersection */ + if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */ + { + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + } + } + else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */ + { + xx[inter_count++] = simSegmentInc(seg_i, canvas, y); /* save the intersection point */ + } + else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* only save the intersection point for (y2) if not handled by (y1) of another segment */ + + /* check for missing top-corner points (^) or (|¯¯|) */ + if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */ + (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) || + (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1)) + { + xx[inter_count++] = seg_i->x2; /* save the intersection point */ + } + } + } + + /* if outside the canvas, ignore the intervals and */ + /* continue since the segments where updated. */ + if (y > height-1 || inter_count == 0) + continue; + + /* sort the intervals */ + qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int); + + clip_line = clip_region + y*width; + + /* for all intervals, fill the interval */ + for(i = 0; i < inter_count; i += 2) + { + if (fill_mode == CD_EVENODD) + { + /* since it fills only pairs of intervals, */ + /* it is the EVENODD fill rule. */ + irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width); + } + else + { + irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width); + if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */ + if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */ + irgbClipFillLine(clip_line, combine_mode, xx[i+1], xx[i+2], width); + } + } + } + + if (t_poly) free(t_poly); + free(xx); + free(segment); + + if (combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) +{ + float c, s, sx, sy, x, y, prev_x, prev_y; + double da; + int i, p; + cdPoint* poly; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(ctxcanvas->canvas, xc, yc, width, height); + + /* number of segments for the arc */ + n = cdRound((fabs(angle2-angle1)*n)/360); + if (n < 1) n = 1; + + poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */ + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = (float)cos(da); + s = (float)sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = xc + (width/2.0f)*(float)cos(angle1); + y = yc + (height/2.0f)*(float)sin(angle1); + poly[0].x = _cdRound(x); + poly[0].y = _cdRound(y); + prev_x = x; + prev_y = y; + p = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = xc + c*(prev_x-xc) + sx*(prev_y-yc); + y = yc + sy*(prev_x-xc) + c*(prev_y-yc); + + poly[p].x = _cdRound(x); + poly[p].y = _cdRound(y); + + if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) + p++; + + prev_x = x; + prev_y = y; + } + + if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) + { + if (sector) /* cdSector */ + { + /* add center */ + poly[p].x = xc; + poly[p].y = yc; + } + else /* cdChord */ + { + /* add initial point */ + poly[p].x = poly[0].x; + poly[p].y = poly[0].y; + } + p++; + } + + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, p, ctxcanvas->canvas->combine_mode); + + free(poly); +} + +static void irgbClipBox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + int combine_mode = ctxcanvas->canvas->combine_mode; + unsigned char* clip_line; + int x, y, width; + + if (ctxcanvas->canvas->use_matrix) + { + cdPoint poly[4]; + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, 4, ctxcanvas->canvas->combine_mode); + return; + } + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + width = ctxcanvas->canvas->w; + + for(y = ymin; y <= ymax; y++) + { + clip_line = ctxcanvas->clip_region + y*width; + for(x = xmin; x <= xmax; x++) + { + _irgSetClipPixel(clip_line[x], combine_mode); + } + } + + if (combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipArea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + unsigned char* clip_line = ctxcanvas->clip; /* set directly to clip */ + int y, xsize, ysize, height, width, xrigth; + + if (ctxcanvas->canvas->use_matrix) + { + cdPoint poly[4]; + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, 4, CD_UNION); + return; + } + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + xsize = xmax-xmin+1; + ysize = ymax-ymin+1; + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + xrigth = width-(xmax+1); + + for(y = 0; y < ymin; y++) + { + memset(clip_line, 0, width); + clip_line += width; + } + + for(y = ymin; y <= ymax; y++) + { + if (xmin) + memset(clip_line, 0, xmin); + + memset(clip_line+xmin, 1, xsize); + + if (xrigth) + memset(clip_line+xmax+1, 0, xrigth); + + clip_line += width; + } + + for(y = ymax+1; y < height; y++) + { + memset(clip_line, 0, width); + clip_line += width; + } +} + +static int cdclip(cdCtxCanvas* ctxcanvas, int mode) +{ + switch(mode) + { + case CD_CLIPAREA: + irgbClipArea(ctxcanvas, ctxcanvas->canvas->clip_rect.xmin, + ctxcanvas->canvas->clip_rect.xmax, + ctxcanvas->canvas->clip_rect.ymin, + ctxcanvas->canvas->clip_rect.ymax); + break; + case CD_CLIPPOLYGON: + memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + irgbClipPoly(ctxcanvas, ctxcanvas->clip, ctxcanvas->canvas->clip_poly, ctxcanvas->canvas->clip_poly_n, CD_UNION); + break; + case CD_CLIPREGION: + if (ctxcanvas->clip_region) + memcpy(ctxcanvas->clip, ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + break; + default: + memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */ + break; + } + + return mode; +} + +static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + irgbClipArea(ctxcanvas, xmin, xmax, ymin, ymax); +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + free(ctxcanvas->clip_region); + ctxcanvas->clip_region = malloc(ctxcanvas->canvas->w * ctxcanvas->canvas->h); + memset(ctxcanvas->clip_region, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->clip_region) + return 0; + + if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h) + { + if (ctxcanvas->clip_region[y*ctxcanvas->canvas->w + x]) + return 1; + } + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int dx, int dy) +{ + unsigned char* clip_region = ctxcanvas->clip_region; + int x, y, X, Y, old_X, old_Y, width, height; + + if (!ctxcanvas->clip_region) + return; + + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + + for (y = 0; y < height; y++) + { + if (dy > 0) + Y = height-1 - y; + else + Y = y; + old_Y = Y - dy; + for(x = 0; x < width; x++) + { + if (dx > 0) + X = width-1 - x; + else + X = x; + old_X = X - dx; + + if (old_X >= 0 && old_Y >= 0 && old_Y < height && old_X < width) + clip_region[Y*width + X] = clip_region[old_Y*width + old_X]; + else + clip_region[Y*width + X] = 0; + } + } +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + unsigned char* clip_line = ctxcanvas->clip_region; + int x, y, width, height; + + if (!ctxcanvas->clip_region) + return; + + *xmin = ctxcanvas->canvas->w-1; + *xmax = 0; + *ymin = ctxcanvas->canvas->h-1; + *ymax = 0; + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + + for (y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + if (*clip_line) + { + if (x < *xmin) + *xmin = x; + if (y < *ymin) + *ymin = y; + if (x > *xmax) + *xmax = x; + if (y > *ymax) + *ymax = y; + } + + clip_line++; + } + } +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipBox(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1); + return; + } + + cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0); + return; + } + + cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipText(ctxcanvas, x, y, s); + return; + } + + cdtextSIM(ctxcanvas, x, y, s); +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, n, ctxcanvas->canvas->combine_mode); + return; + } + + if (mode == CD_CLIP) + { + /* set directly to clip */ + memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */ + irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, n, CD_UNION); + } + else + cdpolySIM(ctxcanvas, mode, poly, n); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + int dst_offset, src_offset, l, xsize, ysize, xpos, ypos; + unsigned char *src_red, *src_green, *src_blue; + + if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h || + x + w < 0 || y + h < 0) + return; + + /* ajusta parametros de entrada */ + xpos = _sNormX(ctxcanvas, x); + ypos = _sNormY(ctxcanvas, y); + + xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos; + ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos; + + /* ajusta posicao inicial em source */ + src_offset = xpos + ypos * ctxcanvas->canvas->w; + src_red = ctxcanvas->red + src_offset; + src_green = ctxcanvas->green + src_offset; + src_blue = ctxcanvas->blue + src_offset; + + /* offset para source */ + src_offset = ctxcanvas->canvas->w; + + /* ajusta posicao inicial em destine */ + dst_offset = (xpos - x) + (ypos - y) * w; + r += dst_offset; + g += dst_offset; + b += dst_offset; + + for (l = 0; l < ysize; l++) + { + memcpy(r, src_red, xsize); + memcpy(g, src_green, xsize); + memcpy(b, src_blue, xsize); + + src_red += src_offset; + src_green += src_offset; + src_blue += src_offset; + + r += w; + g += w; + b += w; + } +} + +static void cdputimagerectrgba_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, + t_x, t_y, img_topdown = 0, dst_offset; + float i_x, i_y, xfactor, yfactor; + unsigned char sr, sg, sb, sa = 255; + double inv_matrix[6]; + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL); + + /* Setup inverse transform */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = t_y * ctxcanvas->canvas->w; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + if (img_topdown) /* image is top-bottom */ + i_y = ih-1 - i_y; + + if (t_x == 350 && t_y == 383) + t_x = 350; + + sr = cdBilinearInterpolation(iw, ih, r, i_x, i_y); + sg = cdBilinearInterpolation(iw, ih, g, i_x, i_y); + sb = cdBilinearInterpolation(iw, ih, b, i_x, i_y); + if (a) sa = cdBilinearInterpolation(iw, ih, a, i_x, i_y); + + if (sr > 210 && sg > 210 && sb > 210) + sr = sr; + + sCombineRGB(ctxcanvas, t_x + dst_offset, sr, sg, sb, sa); + } + } + } +} + +static void cdputimagerectmap_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, + t_x, t_y, img_topdown = 0, dst_offset; + float i_x, i_y, xfactor, yfactor; + unsigned char si; + double inv_matrix[6]; + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left (undocumented feature) */ + } + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL); + + /* Setup inverse transform */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = t_y * ctxcanvas->canvas->w; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + if (img_topdown) /* image is top-bottom */ + i_y = ih-1 - i_y; + + si = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y); + sCombineRGBColor(ctxcanvas, t_x + dst_offset, colors[si]); + } + } + } +} + +static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rh, rw, img_topdown = 0; + const unsigned char *src_red, *src_green, *src_blue; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_red = r + src_offset; + src_green = g + src_offset; + src_blue = b + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], 255); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + r += src_offset; + g += src_offset; + b += src_offset; + + for (l = 0; l < ysize; l++) + { + sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize); + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + { + r -= iw; + g -= iw; + b -= iw; + } + else + { + r += iw; + g += iw; + b += iw; + } + } + } +} + +static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, img_topdown = 0; + const unsigned char *src_red, *src_green, *src_blue, *src_alpha; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_red = r + src_offset; + src_green = g + src_offset; + src_blue = b + src_offset; + src_alpha = a + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], src_alpha[src_offset]); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + r += src_offset; + g += src_offset; + b += src_offset; + a += src_offset; + + for (l = 0; l < ysize; l++) + { + sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize); + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + { + r -= iw; + g -= iw; + b -= iw; + a -= iw; + } + else + { + r += iw; + g += iw; + b += iw; + a += iw; + } + } + } +} + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, pal_size, idx, img_topdown = 0; + const unsigned char *src_index; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = 0; + + for (l=0; l pal_size) + pal_size = idx; + } + } + + pal_size++; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_index = index + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + idx = src_index[src_offset]; + sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + index += src_offset; + + for (l = 0; l < ysize; l++) + { + for(c = 0; c < xsize; c++) + { + idx = index[c]; + sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]); + } + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + index -= iw; + else + index += iw; + } + } +} + +static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int color) +{ + int offset; + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->canvas->matrix, x, y, &x, &y); + + offset = ctxcanvas->canvas->w * y + x; + + /* verifica se esta dentro da area de desenho */ + if (x < 0 || + x > (ctxcanvas->canvas->w-1) || + y < 0 || + y > (ctxcanvas->canvas->h-1)) + return; + + sCombineRGBColor(ctxcanvas, offset, color); +} + +static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h) +{ + cdCtxImage* ctximage; + int size = w * h; + int num_c = ctxcanvas->alpha? 4: 3; + + ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage)); + memset(ctximage, 0, sizeof(cdCtxImage)); + + ctximage->w = w; + ctximage->h = h; + + ctximage->red = (unsigned char*) malloc(num_c*size); + if (!ctximage->red) + { + free(ctximage); + return NULL; + } + + ctximage->green = ctximage->red + size; + ctximage->blue = ctximage->red + 2*size; + if (ctxcanvas->alpha) + ctximage->alpha = ctximage->red + 3*size; + + memset(ctximage->red, 0xFF, 3*size); + if (ctximage->alpha) memset(ctximage->alpha, 0, size); /* transparent */ + + return ctximage; +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y) +{ + unsigned char *r, *g, *b, *a = NULL; + int w, h, dst_offset, src_offset, l, xsize, ysize, xpos, ypos, do_alpha = 0; + unsigned char *src_red, *src_green, *src_blue, *src_alpha = NULL; + + w = ctximage->w; + h = ctximage->h; + + if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h || + x + w < 0 || y + h < 0) + return; + + if (ctximage->alpha && ctxcanvas->alpha) + do_alpha = 1; + + r = ctximage->red; + g = ctximage->green; + b = ctximage->blue; + if (do_alpha) a = ctximage->alpha; + + /* ajusta parametros de entrada */ + xpos = _sNormX(ctxcanvas, x); + ypos = _sNormY(ctxcanvas, y); + + xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos; + ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos; + + /* ajusta posicao inicial em source */ + src_offset = xpos + ypos * ctxcanvas->canvas->w; + src_red = ctxcanvas->red + src_offset; + src_green = ctxcanvas->green + src_offset; + src_blue = ctxcanvas->blue + src_offset; + if (do_alpha) src_alpha = ctxcanvas->alpha + src_offset; + + /* offset para source */ + src_offset = ctxcanvas->canvas->w; + + /* ajusta posicao inicial em destine */ + dst_offset = (xpos - x) + (ypos - y) * w; + r += dst_offset; + g += dst_offset; + b += dst_offset; + if (do_alpha) a += dst_offset; + + for (l = 0; l < ysize; l++) + { + memcpy(r, src_red, xsize); + memcpy(g, src_green, xsize); + memcpy(b, src_blue, xsize); + if (do_alpha) memcpy(a, src_alpha, xsize); + + src_red += src_offset; + src_green += src_offset; + src_blue += src_offset; + if (do_alpha) src_alpha += src_offset; + + r += w; + g += w; + b += w; + if (do_alpha) a += w; + } +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + int iw, ih, w, h; + unsigned char *r, *g, *b, *a; + int l, xsize, ysize, xpos, ypos, src_offset, dst_offset; + + iw = ctximage->w; + ih = ctximage->h; + + r = ctximage->red; + g = ctximage->green; + b = ctximage->blue; + a = ctximage->alpha; + + w = xmax-xmin+1; + h = ymax-ymin+1; + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + x + w < 0 || y + h < 0) + return; + + xpos = x; + ypos = y; + + if (ypos < 0) ypos = 0; + if (xpos < 0) xpos = 0; + + xsize = w < ((ctxcanvas->canvas->w-1)+1 - xpos)? w: ((ctxcanvas->canvas->w-1)+1 - xpos); + ysize = h < ((ctxcanvas->canvas->h-1)+1 - ypos)? h: ((ctxcanvas->canvas->h-1)+1 - ypos); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + src_offset = ((xpos - x) + xmin) + ((ypos - y) + ymin) * iw; + r += src_offset; + g += src_offset; + b += src_offset; + if (a) a += src_offset; + + for (l = 0; l < ysize; l++) + { + if (a) + sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize); + else + sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize); + + dst_offset += ctxcanvas->canvas->w; + + r += iw; + g += iw; + b += iw; + if (a) a += iw; + } +} + +static void cdkillimage(cdCtxImage* ctximage) +{ + free(ctximage->red); + memset(ctximage, 0, sizeof(cdCtxImage)); + free(ctximage); +} + +static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + int l; + long src_offset, dst_offset; + int incx,incy, xsize, ysize; + int dst_xmin, dst_xmax, dst_ymin, dst_ymax; + + /* corrige valores de entrada */ + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + + dst_xmin = xmin + dx; + dst_ymin = ymin + dy; + dst_xmax = xmax + dx; + dst_ymax = ymax + dy; + + /* verifica se esta dentro da area de desenho */ + if (dst_xmin > (ctxcanvas->canvas->w-1) || dst_ymin > (ctxcanvas->canvas->h-1) || + dst_xmax < 0 || dst_ymax < 0) + return; + + if (dst_ymin < 0) dst_ymin = 0; + if (dst_xmin < 0) dst_xmin = 0; + + if (dst_ymax > (ctxcanvas->canvas->h-1)) dst_ymax = (ctxcanvas->canvas->h-1); + if (dst_xmax > (ctxcanvas->canvas->w-1)) dst_xmax = (ctxcanvas->canvas->w-1); + + if (dst_xmin > dst_xmax || dst_ymin > dst_ymax) + return; + + /* Decide de onde vai comecar a copiar, isto e' necessario pois pode haver + uma intersecao entre a imagem original e a nova imagem, assim devo + garantir que nao estou colocando um ponto, em cima de um ponto ainda nao + lido da imagem antiga. */ + + xsize = dst_xmax - dst_xmin + 1; + ysize = dst_ymax - dst_ymin + 1; + + /* sentido de copia da direita para a esquerda ou ao contrario. */ + if (dx < 0) + { + incx = 1; + dst_offset = dst_xmin; + src_offset = xmin; + } + else + { + incx = -1; + dst_offset = dst_xmax; + src_offset = xmax; + } + + /* sentido de copia de cima para baixo ou ao contrario. */ + if (dy < 0) + { + incy = ctxcanvas->canvas->w; + dst_offset += dst_ymin * ctxcanvas->canvas->w; + src_offset += ymin * ctxcanvas->canvas->w; + } + else + { + incy = -(ctxcanvas->canvas->w); + dst_offset += dst_ymax * ctxcanvas->canvas->w; + src_offset += ymax * ctxcanvas->canvas->w; + } + + xsize *= incx; + + for (l = 0; l < ysize; l++) + { + sCombineRGBLine(ctxcanvas, dst_offset, ctxcanvas->red + src_offset, ctxcanvas->green + src_offset, ctxcanvas->blue + src_offset, xsize); + dst_offset += incy; + src_offset += incy; + } +} + +static char* get_green_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->green; +} + +static cdAttribute green_attrib = +{ + "GREENIMAGE", + NULL, + get_green_attrib +}; + +static char* get_blue_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->blue; +} + +static cdAttribute blue_attrib = +{ + "BLUEIMAGE", + NULL, + get_blue_attrib +}; + +static char* get_red_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->red; +} + +static cdAttribute red_attrib = +{ + "REDIMAGE", + NULL, + get_red_attrib +}; + +static char* get_alpha_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->alpha; +} + +static cdAttribute alpha_attrib = +{ + "ALPHAIMAGE", + NULL, + get_alpha_attrib +}; + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data || data[0] == '0') + ctxcanvas->canvas->simulation->antialias = 0; + else + ctxcanvas->canvas->simulation->antialias = 1; +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->canvas->simulation->antialias) + return "0"; + else + return "1"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + + cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle); + cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + + cdCanvasTransform(ctxcanvas->canvas, NULL); + } +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + int w = 0, h = 0, use_alpha = 0; + float res = (float)3.78; + unsigned char *r = NULL, *g = NULL, *b = NULL, *a = NULL; + char* str_data = (char*)data; + char* res_ptr = NULL; + + if (strstr(str_data, "-a")) + use_alpha = 1; + + res_ptr = strstr(str_data, "-r"); + if (res_ptr) + sscanf(res_ptr+2, "%g", &res); + + /* size and rgb */ +#ifdef SunOS_OLD + if (use_alpha) + sscanf(str_data, "%dx%d %d %d %d %d", &w, &h, &r, &g, &b, &a); + else + sscanf(str_data, "%dx%d %d %d %d", &w, &h, &r, &g, &b); +#else + if (use_alpha) + sscanf(str_data, "%dx%d %p %p %p %p", &w, &h, &r, &g, &b, &a); + else + sscanf(str_data, "%dx%d %p %p %p", &w, &h, &r, &g, &b); +#endif + + if (w == 0 || h == 0) + return; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + canvas->w = w; + canvas->h = h; + canvas->yres = res; + canvas->xres = res; + canvas->w_mm = ((double)w) / res; + canvas->h_mm = ((double)h) / res; + if (use_alpha) + canvas->bpp = 32; + else + canvas->bpp = 24; + + if (r && g && b) + { + ctxcanvas->user_image = 1; + + ctxcanvas->red = r; + ctxcanvas->green = g; + ctxcanvas->blue = b; + ctxcanvas->alpha = a; + } + else + { + int size = w * h; + int num_c = use_alpha? 4: 3; + + ctxcanvas->user_image = 0; + + ctxcanvas->red = (unsigned char*)malloc(num_c*size); + if (!ctxcanvas->red) + { + free(ctxcanvas); + return; + } + + ctxcanvas->green = ctxcanvas->red + size; + ctxcanvas->blue = ctxcanvas->red + 2*size; + if (use_alpha) + ctxcanvas->alpha = ctxcanvas->red + 3*size; + + memset(ctxcanvas->red, 0xFF, 3*size); /* white */ + if (ctxcanvas->alpha) memset(ctxcanvas->alpha, 0, size); /* transparent */ + } + + ctxcanvas->clip = (unsigned char*)malloc(w*h); + memset(ctxcanvas->clip, 1, w*h); /* CD_CLIPOFF */ + + canvas->ctxcanvas = ctxcanvas; + ctxcanvas->canvas = canvas; + + cdSimInitText(canvas->simulation); + /* nao preciso inicializar a fonte, + pois isso sera' feito na inicializacao dos atributos default do driver */ + + canvas->simulation->antialias = 1; + + cdRegisterAttribute(canvas, &red_attrib); + cdRegisterAttribute(canvas, &green_attrib); + cdRegisterAttribute(canvas, &blue_attrib); + cdRegisterAttribute(canvas, &alpha_attrib); + cdRegisterAttribute(canvas, &aa_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdSimulation* sim; + + /* initialize function table*/ + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxGetImageRGB = cdgetimagergb; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + canvas->cxScrollArea = cdscrollarea; + + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + + canvas->cxLine = cdlineSIM; + canvas->cxRect = cdrectSIM; + canvas->cxBox = cdbox; + canvas->cxArc = cdarcSIM; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxPoly = cdpoly; + canvas->cxText = cdtext; + + canvas->cxKillCanvas = cdkillcanvas; + + /* use simulation */ + canvas->cxFont = cdfontSIM; + canvas->cxGetFontDim = cdgetfontdimSIM; + canvas->cxGetTextSize = cdgettextsizeSIM; + + sim = canvas->simulation; + + sim->SolidLine = irgbSolidLine; + sim->PatternLine = irgbPatternLine; + sim->StippleLine = irgbStippleLine; + sim->HatchLine = irgbHatchLine; +} + +static cdContext cdImageRGBContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_FPRIMTIVES | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | + CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextImageRGB(void) +{ + return &cdImageRGBContext; +} + +static void cdflushDB(cdCtxCanvas *ctxcanvas) +{ + int old_writemode; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + + old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + cdCanvasPutImageRectRGB(canvas_dbuffer, ctxcanvas->canvas->w, ctxcanvas->canvas->h, ctxcanvas->red, ctxcanvas->green, ctxcanvas->blue, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0, 0, 0); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static void cdcreatecanvasDB(cdCanvas* canvas, cdCanvas* canvas_dbuffer) +{ + char rgbdata[100]; + sprintf(rgbdata, "%dx%d -r%g", canvas_dbuffer->w, canvas_dbuffer->h, canvas_dbuffer->xres); + cdcreatecanvas(canvas, rgbdata); + if (canvas->ctxcanvas) + canvas->ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +static int cdactivateDB(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->canvas->w || + canvas_dbuffer->h != ctxcanvas->canvas->h) + { + cdCanvas* canvas = ctxcanvas->canvas; + /* save the current, if the rebuild fail */ + cdCtxCanvas* old_ctxcanvas = ctxcanvas; + + /* if the image is rebuild, the canvas that uses the image must be also rebuild */ + + /* rebuild the image and the canvas */ + canvas->ctxcanvas = NULL; + cdcreatecanvasDB(canvas, canvas_dbuffer); + if (!canvas->ctxcanvas) + { + canvas->ctxcanvas = old_ctxcanvas; + return CD_ERROR; + } + + /* remove the old image and canvas */ + cdkillcanvas(old_ctxcanvas); + + ctxcanvas = canvas->ctxcanvas; + + /* update canvas attributes */ + if (canvas->cxBackground) canvas->cxBackground(ctxcanvas, canvas->background); + if (canvas->cxForeground) canvas->cxForeground(ctxcanvas, canvas->foreground); + if (canvas->cxBackOpacity) canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity); + if (canvas->cxWriteMode) canvas->cxWriteMode(ctxcanvas, canvas->write_mode); + if (canvas->cxLineStyle) canvas->cxLineStyle(ctxcanvas, canvas->line_style); + if (canvas->cxLineWidth) canvas->cxLineWidth(ctxcanvas, canvas->line_width); + if (canvas->cxLineCap) canvas->cxLineCap(ctxcanvas, canvas->line_cap); + if (canvas->cxLineJoin) canvas->cxLineJoin(ctxcanvas, canvas->line_join); + if (canvas->cxHatch) canvas->cxHatch(ctxcanvas, canvas->hatch_style); + if (canvas->stipple && canvas->cxStipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple); + if (canvas->pattern && canvas->cxPattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern); + if (canvas->cxInteriorStyle) canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style); + if (canvas->native_font[0] && canvas->cxNativeFont) + canvas->cxNativeFont(ctxcanvas, canvas->native_font); + else if (canvas->cxFont) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + if (canvas->cxTextAlignment) canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); + if (canvas->cxTextOrientation) canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); + if (canvas->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix); + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax); + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n); + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); + if (canvas->clip_mode != CD_CLIPOFF && canvas->cxClip) canvas->cxClip(ctxcanvas, canvas->clip_mode); + } + + return CD_OK; +} + +static void cddeactivateDB(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdinittableDB(cdCanvas* canvas) +{ + cdinittable(canvas); + + canvas->cxActivate = cdactivateDB; + canvas->cxDeactivate = cddeactivateDB; + + canvas->cxFlush = cdflushDB; +} + +static cdContext cdDBufferRGBContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_FPRIMTIVES | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | + CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvasDB, + cdinittableDB, + NULL, + NULL, +}; + +cdContext* cdContextDBufferRGB(void) +{ + return &cdDBufferRGBContext; +} diff --git a/src/drv/cdmf.c b/src/drv/cdmf.c new file mode 100644 index 0000000..6c2e711 --- /dev/null +++ b/src/drv/cdmf.c @@ -0,0 +1,1188 @@ +/** \file + * \brief CD Metafile driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" +#include "cdmf.h" +#include "cdmf_private.h" + + +/* codes for the primitives and attributes in the metafile + Can NOT be changed, only added for backward compatibility. +*/ +enum +{ + CDMF_FLUSH, /* 0 */ + CDMF_CLEAR, /* 1 */ + CDMF_CLIP, /* 2 */ + CDMF_CLIPAREA, /* 3 */ + CDMF_LINE, /* 4 */ + CDMF_BOX, /* 5 */ + CDMF_ARC, /* 6 */ + CDMF_SECTOR, /* 7 */ + CDMF_TEXT, /* 8 */ + CDMF_BEGIN, /* 9 */ + CDMF_VERTEX, /* 10 */ + CDMF_END, /* 11 */ + CDMF_MARK, /* 12 */ + CDMF_BACKOPACITY, /* 13 */ + CDMF_WRITEMODE, /* 14 */ + CDMF_LINESTYLE, /* 15 */ + CDMF_LINEWIDTH, /* 16 */ + CDMF_INTERIORSTYLE, /* 17 */ + CDMF_HATCH, /* 18 */ + CDMF_STIPPLE, /* 19 */ + CDMF_PATTERN, /* 20 */ + CDMF_OLDFONT, /* 21 */ + CDMF_NATIVEFONT, /* 22 */ + CDMF_TEXTALIGNMENT, /* 23 */ + CDMF_MARKTYPE, /* 24 */ + CDMF_MARKSIZE, /* 25 */ + CDMF_PALETTE, /* 26 */ + CDMF_BACKGROUND, /* 27 */ + CDMF_FOREGROUND, /* 28 */ + CDMF_PUTIMAGERGB, /* 29 */ + CDMF_PUTIMAGEMAP, /* 30 */ + CDMF_PIXEL, /* 31 */ + CDMF_SCROLLAREA, /* 32 */ + CDMF_TEXTORIENTATION, /* 33 */ + CDMF_RECT, /* 34 */ + CDMF_PUTIMAGERGBA, /* 35 */ + CDMF_WLINE, /* 36 */ + CDMF_WRECT, /* 37 */ + CDMF_WBOX, /* 38 */ + CDMF_WARC, /* 39 */ + CDMF_WSECTOR, /* 40 */ + CDMF_WTEXT, /* 41 */ + CDMF_WVERTEX, /* 42 */ + CDMF_WMARK, /* 43 */ + CDMF_VECTORTEXT, /* 44 */ + CDMF_MULTILINEVECTORTEXT, /* 45 */ + CDMF_WVECTORTEXT, /* 46 */ + CDMF_WMULTILINEVECTORTEXT, /* 47 */ + CDMF_WINDOW, /* 48 */ + CDMF_WCLIPAREA, /* 49 */ + CDMF_VECTORFONT, /* 50 */ + CDMF_VECTORTEXTDIRECTION, /* 51 */ + CDMF_VECTORTEXTTRANSFORM, /* 52 */ + CDMF_VECTORTEXTSIZE, /* 53 */ + CDMF_VECTORCHARSIZE, /* 54 */ + CDMF_WVECTORTEXTDIRECTION, /* 55 */ + CDMF_WVECTORTEXTSIZE, /* 56 */ + CDMF_WVECTORCHARSIZE, /* 57 */ + CDMF_FILLMODE, /* 58 */ + CDMF_LINESTYLEDASHES, /* 59 */ + CDMF_LINECAP, /* 60 */ + CDMF_LINEJOIN, /* 61 */ + CDMF_CHORD, /* 62 */ + CDMF_WCHORD, /* 63 */ + CDMF_FLINE, /* 64 */ + CDMF_FRECT, /* 65 */ + CDMF_FBOX, /* 66 */ + CDMF_FARC, /* 67 */ + CDMF_FSECTOR, /* 68 */ + CDMF_FTEXT, /* 69 */ + CDMF_FVERTEX, /* 70 */ + CDMF_MATRIX, /* 71 */ + CDMF_FCHORD, /* 72 */ + CDMF_FCLIPAREA, /* 73 */ + CDMF_FONT, /* 74 */ + CDMF_RESETMATRIX /* 75 */ +}; + +struct _cdCtxCanvas +{ + /* public */ + cdCanvas* canvas; + char* filename; + void* data; /* used by other drivers */ + + /* private */ + int last_line_style; + int last_fill_mode; + FILE* file; +}; + +void cdkillcanvasMF(cdCanvasMF *mfcanvas) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas*)mfcanvas; + free(ctxcanvas->filename); + fclose(ctxcanvas->file); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); + fprintf(ctxcanvas->file, "%d\n", CDMF_FLUSH); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "%d\n", CDMF_CLEAR); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_CLIP, mode); + return mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_CLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FCLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + else + fprintf(ctxcanvas->file, "%d\n", CDMF_RESETMATRIX); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_LINE, x1, y1, x2, y2); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FLINE, x1, y1, x2, y2); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_RECT, xmin, xmax, ymin, ymax); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FRECT, xmin, xmax, ymin, ymax); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_BOX, xmin, xmax, ymin, ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FBOX, xmin, xmax, ymin, ymax); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_ARC, xc, yc, w, h, a1, a2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FARC, xc, yc, w, h, a1, a2); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_SECTOR, xc, yc, w, h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FSECTOR, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_CHORD, xc, yc, w, h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FCHORD, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_TEXT, x, y, text); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + fprintf(ctxcanvas->file, "%d %g %g %s\n", CDMF_FTEXT, x, y, text); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode); + + for(i = 0; ifile, "%d %d %d\n", CDMF_VERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%d\n", CDMF_END); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode); + + for(i = 0; ifile, "%d %g %g\n", CDMF_FVERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%d\n", CDMF_END); +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BACKOPACITY, opacity); + return opacity; +} + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_WRITEMODE, mode); + return mode; +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style) + { + int i; + fprintf(ctxcanvas->file, "%d %d", CDMF_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, " %d", ctxcanvas->canvas->line_dashes[i]); + fprintf(ctxcanvas->file, "\n"); + ctxcanvas->last_line_style = ctxcanvas->canvas->line_style; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINESTYLE, style); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEWIDTH, width); + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINECAP, cap); + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEJOIN, join); + return join; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_INTERIORSTYLE, style); + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_HATCH, style); + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple) +{ + int c, t; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_STIPPLE, w, h); + + t = w * h; + + for (c = 0; c < t; c++) + { + fprintf(ctxcanvas->file, "%d ", (int)*stipple++); + if ((c + 1) % w == 0) + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern) +{ + int c, t; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PATTERN, w, h); + + t = w * h; + + /* stores the pattern with separeted RGB values */ + for (c = 0; c < t; c++) + { + cdDecodeColor(*pattern++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d ", (int)r, (int)g, (int)b); + if (c % w == 0) + fprintf(ctxcanvas->file, "\n"); + } +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size) +{ + fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_FONT, style, size, type_face); + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font) +{ + fprintf(ctxcanvas->file, "%d %s\n", CDMF_NATIVEFONT, font); + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_TEXTALIGNMENT, alignment); + return alignment; +} + +static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle) +{ + fprintf(ctxcanvas->file, "%d %g\n", CDMF_TEXTORIENTATION, angle); + return angle; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + int c; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PALETTE, n, mode); + + for (c = 0; c < n; c++) + { + cdDecodeColor(*palette++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b); + } +} + +static long cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_BACKGROUND, (int)r, (int)g, (int)b); + return color; +} + +static long cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_FOREGROUND, (int)r, (int)g, (int)b); + return color; +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, offset; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGB, iw, ih, x, y, w, h); + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + fprintf(ctxcanvas->file, "%d %d %d ", (int)*r++, (int)*g++, (int)*b++); + } + + r += offset; + g += offset; + b += offset; + + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, offset; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGBA, iw, ih, x, y, w, h); + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + a += offset; + + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + fprintf(ctxcanvas->file, "%d %d %d %d ", (int)*r++, (int)*g++, (int)*b++, (int)*a++); + } + + r += offset; + g += offset; + b += offset; + a += offset; + + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, n = 0, offset; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGEMAP, iw, ih, x, y, w, h); + + index += ymin*iw + xmin; + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + if (*index > n) + n = *index; + + fprintf(ctxcanvas->file, "%d ", (int)*index++); + } + + index += offset; + + fprintf(ctxcanvas->file, "\n"); + } + + n++; + + for (c = 0; c < n; c++) + { + cdDecodeColor(*colors++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b); + } +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d %d %d\n", CDMF_PIXEL, x, y, (int)r, (int)g, (int)b); +} + +static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy); +} + + +/**********/ +/* cdPlay */ +/**********/ + + +static double factorX = 1; +static double factorY = 1; +static int offsetX = 0; +static int offsetY = 0; +static double factorS = 1; + +static int sScaleX(int x) +{ + return cdRound(x * factorX + offsetX); +} + +static int sScaleY(int y) +{ + return cdRound(y * factorY + offsetY); +} + +static double sfScaleX(double x) +{ + return x * factorX + offsetX; +} + +static double sfScaleY(double y) +{ + return y * factorY + offsetY; +} + +static int sScaleW(int w) +{ + w = (int)(w * factorX + 0.5); /* always positive */ + return w == 0? 1: w; +} + +static double sfScaleH(double h) +{ + h = h * factorY; + return h == 0? 1: h; +} + +static double sfScaleW(double w) +{ + w = w * factorX; /* always positive */ + return w == 0? 1: w; +} + +static int sScaleH(int h) +{ + h = (int)(h * factorY + 0.5); + return h == 0? 1: h; +} + +static int sScaleS(int s) +{ + s = (int)(s * factorS + 0.5); + return s == 0? 1: s; +} + +typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm); +static _cdsizecb cdsizecb = NULL; + +static int cdregistercallback(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecb = (_cdsizecb)func; + return CD_OK; + } + + return CD_ERROR; +} + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + FILE* file; + char TextBuffer[512]; + int iparam1, iparam2, iparam3, iparam4, iparam5, iparam6, iparam7, iparam8, iparam9, iparam10; + int c, t, n, w, h, func; + double dparam1, dparam2, dparam3, dparam4, dparam5, dparam6; + unsigned char* stipple, * _stipple, *red, *green, *blue, *_red, *_green, *_blue, *index, *_index, *_alpha, *alpha; + long int *pattern, *palette, *_pattern, *_palette, *colors, *_colors; + int* dashes; + double matrix[6]; + const char * font_family[] = + { + "System", /* CD_SYSTEM */ + "Courier", /* CD_COURIER */ + "Times", /* CD_TIMES_ROMAN */ + "Helvetica" /* CD_HELVETICA */ + }; + + file = fopen(filename, "r"); + if (!file) + return CD_ERROR; + + func = -1; + w = 0; + h = 0; + + factorX = 1; + factorY = 1; + offsetX = 0; + offsetY = 0; + factorS = 1; + + fscanf(file, "%s %d %d", TextBuffer, &w, &h); + + if (strcmp(TextBuffer, "CDMF") != 0) + { + fclose(file); + return CD_ERROR; + } + + if (w>1 && h>1 && xmax!=0 && ymax!=0) + { + offsetX = xmin; + offsetY = ymin; + factorX = ((double)(xmax-xmin)) / (w-1); + factorY = ((double)(ymax-ymin)) / (h-1); + + if (factorX < factorY) + factorS = factorX; + else + factorS = factorY; + } + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, w, h, w, h); + if (err) + return CD_ERROR; + } + + while (!feof(file)) + { + fscanf(file, "%d", &func); + if (feof(file)) + break; + + switch (func) + { + case CDMF_FLUSH: + cdCanvasFlush(canvas); + break; + case CDMF_CLEAR: + cdCanvasClear(canvas); + break; + case CDMF_CLIP: + fscanf(file, "%d", &iparam1); + cdCanvasClip(canvas, iparam1); + break; + case CDMF_CLIPAREA: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasClipArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_FCLIPAREA: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasClipArea(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_MATRIX: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]); + cdCanvasTransform(canvas, matrix); + break; + case CDMF_RESETMATRIX: + cdCanvasTransform(canvas, NULL); + break; + case CDMF_WCLIPAREA: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasClipArea(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_LINE: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasLine(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleX(iparam3), sScaleY(iparam4)); + break; + case CDMF_FLINE: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasLine(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleX(dparam3), sfScaleY(dparam4)); + break; + case CDMF_WLINE: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasLine(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_RECT: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasRect(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_FRECT: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasRect(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_WRECT: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasRect(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_BOX: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasBox(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_WBOX: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasBox(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_FBOX: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasBox(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_ARC: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasArc(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FARC: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasArc(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WARC: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasArc(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_SECTOR: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasSector(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FSECTOR: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasSector(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WSECTOR: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasSector(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_CHORD: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasChord(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FCHORD: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasChord(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WCHORD: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasChord(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_TEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasText(canvas, sScaleX(iparam1), sScaleY(iparam2), TextBuffer); + break; + case CDMF_FTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + cdfCanvasText(canvas, sfScaleX(dparam1), sfScaleY(dparam2), TextBuffer); + break; + case CDMF_WTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_BEGIN: + fscanf(file, "%d", &iparam1); + cdCanvasBegin(canvas, iparam1); + break; + case CDMF_VERTEX: + fscanf(file, "%d %d", &iparam1, &iparam2); + cdCanvasVertex(canvas, sScaleX(iparam1), sScaleY(iparam2)); + break; + case CDMF_FVERTEX: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + cdfCanvasVertex(canvas, sfScaleX(dparam1), sfScaleY(dparam2)); + break; + case CDMF_WVERTEX: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + wdCanvasVertex(canvas, dparam1, dparam2); + break; + case CDMF_END: + cdCanvasEnd(canvas); + break; + case CDMF_MARK: + fscanf(file, "%d %d", &iparam1, &iparam2); + cdCanvasMark(canvas, sScaleX(iparam1), sScaleY(iparam2)); + break; + case CDMF_WMARK: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + wdCanvasMark(canvas, dparam1, dparam2); + break; + case CDMF_BACKOPACITY: + fscanf(file, "%d", &iparam1); + cdCanvasBackOpacity(canvas, iparam1); + break; + case CDMF_WRITEMODE: + fscanf(file, "%d", &iparam1); + cdCanvasWriteMode(canvas, iparam1); + break; + case CDMF_LINESTYLE: + fscanf(file, "%d", &iparam1); + cdCanvasLineStyle(canvas, iparam1); + break; + case CDMF_LINEWIDTH: + fscanf(file, "%d", &iparam1); + cdCanvasLineWidth(canvas, sScaleS(iparam1)); + break; + case CDMF_LINECAP: + fscanf(file, "%d", &iparam1); + cdCanvasLineCap(canvas, iparam1); + break; + case CDMF_LINEJOIN: + fscanf(file, "%d", &iparam1); + cdCanvasLineJoin(canvas, iparam1); + break; + case CDMF_LINESTYLEDASHES: + fscanf(file, "%d", &iparam1); + dashes = (int*)malloc(iparam1*sizeof(int)); + for (c = 0; c < iparam1; c++) + fscanf(file, "%d", &dashes[c]); + cdCanvasLineStyleDashes(canvas, dashes, iparam1); + free(dashes); + break; + case CDMF_FILLMODE: + fscanf(file, "%d", &iparam1); + cdCanvasFillMode(canvas, iparam1); + break; + case CDMF_INTERIORSTYLE: + fscanf(file, "%d", &iparam1); + cdCanvasInteriorStyle(canvas, iparam1); + break; + case CDMF_HATCH: + fscanf(file, "%d", &iparam1); + cdCanvasHatch(canvas, iparam1); + break; + case CDMF_STIPPLE: + fscanf(file, "%d %d", &iparam1, &iparam2); + t = iparam1 * iparam2; + stipple = (unsigned char*)malloc(t); + _stipple = stipple; + for (c = 0; c < t; c++) + { + fscanf(file, "%d", &iparam3); + *_stipple++ = (unsigned char)iparam3; + } + cdCanvasStipple(canvas, iparam1, iparam2, stipple); + free(stipple); + break; + case CDMF_PATTERN: + fscanf(file, "%d %d", &iparam1, &iparam2); + t = iparam1 * iparam2; + pattern = (long int*)malloc(t * sizeof(long)); + _pattern = pattern; + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5); + *_pattern++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5); + } + cdCanvasPattern(canvas, iparam1, iparam2, pattern); + free(pattern); + break; + case CDMF_OLDFONT: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + if (iparam1 < 0 || iparam1 > 3) break; + if (iparam3 < 0) + { + iparam3 = -sScaleH(abs(iparam3)); + if (iparam3 > -5) iparam3 = -5; + } + else + { + iparam3 = sScaleH(abs(iparam3)); + if (iparam3 < 5) iparam3 = 5; + } + cdCanvasFont(canvas, font_family[iparam1], iparam2, iparam3); + break; + case CDMF_FONT: + fscanf(file, "%d %d %[^\n]", &iparam2, &iparam3, TextBuffer); + if (iparam3 < 0) + { + iparam3 = -sScaleH(abs(iparam3)); + if (iparam3 > -5) iparam3 = -5; + } + else + { + iparam3 = sScaleH(abs(iparam3)); + if (iparam3 < 5) iparam3 = 5; + } + cdCanvasFont(canvas, TextBuffer, iparam2, iparam3); + break; + case CDMF_NATIVEFONT: + fscanf(file, "%[^\n]", TextBuffer); + cdCanvasNativeFont(canvas, TextBuffer); + break; + case CDMF_TEXTALIGNMENT: + fscanf(file, "%d", &iparam1); + cdCanvasTextAlignment(canvas, iparam1); + break; + case CDMF_TEXTORIENTATION: + fscanf(file, "%lg", &dparam1); + cdCanvasTextOrientation(canvas, dparam1); + break; + case CDMF_MARKTYPE: + fscanf(file, "%d", &iparam1); + cdCanvasMarkType(canvas, iparam1); + break; + case CDMF_MARKSIZE: + fscanf(file, "%d", &iparam1); + cdCanvasMarkSize(canvas, sScaleS(iparam1)); + break; + case CDMF_PALETTE: + fscanf(file, "%d %d", &iparam1, &iparam2); + _palette = palette = (long int*)malloc(iparam1); + for (c = 0; c < iparam1; c++) + { + fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5); + *_palette++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5); + } + cdCanvasPalette(canvas, iparam1, palette, iparam2); + free(palette); + break; + case CDMF_BACKGROUND: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + cdCanvasSetBackground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3)); + break; + case CDMF_FOREGROUND: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + cdCanvasSetForeground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3)); + break; + case CDMF_PUTIMAGERGB: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + _red = red = (unsigned char*) malloc(t); + _green = green = (unsigned char*) malloc(t); + _blue = blue = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9); + *_red++ = (unsigned char)iparam7; + *_green++ = (unsigned char)iparam8; + *_blue++ = (unsigned char)iparam9; + } + cdCanvasPutImageRectRGB(canvas, iparam1, iparam2, red, green, blue, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(red); + free(green); + free(blue); + break; + case CDMF_PUTIMAGERGBA: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + _red = red = (unsigned char*) malloc(t); + _green = green = (unsigned char*) malloc(t); + _blue = blue = (unsigned char*) malloc(t); + _alpha = alpha = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d %d", &iparam7, &iparam8, &iparam9, &iparam10); + *_red++ = (unsigned char)iparam7; + *_green++ = (unsigned char)iparam8; + *_blue++ = (unsigned char)iparam9; + *_alpha++ = (unsigned char)iparam10; + } + cdCanvasPutImageRectRGBA(canvas, iparam1, iparam2, red, green, blue, alpha, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(red); + free(green); + free(blue); + free(alpha); + break; + case CDMF_PUTIMAGEMAP: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + n = 0; + _index = index = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d", &iparam7); + *_index++ = (unsigned char)iparam7; + if (iparam7 > n) + n = iparam7; + } + _colors = colors = (long int*)malloc(n); + for (c = 0; c < n; c++) + { + fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9); + *_colors++ = cdEncodeColor((unsigned char)iparam7, (unsigned char)iparam8, (unsigned char)iparam9); + } + cdCanvasPutImageRectMap(canvas, iparam1, iparam2, index, colors, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(index); + free(colors); + break; + case CDMF_PIXEL: + fscanf(file, "%d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5); + cdCanvasPixel(canvas, sScaleX(iparam1), sScaleY(iparam2), cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5)); + break; + case CDMF_SCROLLAREA: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + cdCanvasScrollArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4), sScaleX(iparam5), sScaleY(iparam6)); + break; + case CDMF_WVECTORTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_WMULTILINEVECTORTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_VECTORTEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_MULTILINEVECTORTEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_WVECTORCHARSIZE: + fscanf(file, "%lg", &dparam1); + wdCanvasVectorCharSize(canvas, dparam1); + break; + case CDMF_WVECTORTEXTSIZE: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorTextSize(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_WVECTORTEXTDIRECTION: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasVectorTextDirection(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_VECTORCHARSIZE: + fscanf(file, "%d", &iparam1); + cdCanvasVectorCharSize(canvas, iparam1); + break; + case CDMF_VECTORTEXTSIZE: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorTextSize(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_VECTORTEXTDIRECTION: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasVectorTextDirection(canvas, iparam1, iparam2, iparam3, iparam4); + break; + case CDMF_VECTORFONT: + fscanf(file, "%[^\n]", TextBuffer); + cdCanvasVectorFont(canvas, TextBuffer); + break; + case CDMF_VECTORTEXTTRANSFORM: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]); + cdCanvasVectorTextTransform(canvas, matrix); + break; + case CDMF_WINDOW: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasWindow(canvas, dparam1, dparam2, dparam3, dparam4); + break; + default: + fclose(file); + return CD_ERROR; + } + } + + fclose(file); + + return CD_OK; +} + +/*******************/ +/* Canvas Creation */ +/*******************/ + +void cdcreatecanvasMF(cdCanvas *canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; + cdCtxCanvas* ctxcanvas; + int size; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->file = fopen(filename, "w"); + if (!ctxcanvas->file) + { + free(ctxcanvas); + return; + } + + size = strlen(filename); + ctxcanvas->filename = malloc(size+1); + memcpy(ctxcanvas->filename, filename, size+1); + + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->w = (int)(w_mm * res); + canvas->h = (int)(h_mm * res); + canvas->w_mm = w_mm; + canvas->h_mm = h_mm; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->last_line_style = -1; + ctxcanvas->last_fill_mode = -1; + + fprintf(ctxcanvas->file, "CDMF %d %d\n", canvas->w, canvas->h); +} + +void cdinittableMF(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxScrollArea = cdscrollarea; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxTextOrientation = cdtextorientation; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxFClipArea = cdfcliparea; + canvas->cxTransform = cdtransform; + + canvas->cxKillCanvas = (void (*)(cdCtxCanvas*))cdkillcanvasMF; +} + +static cdContext cdMetafileContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvasMF, + cdinittableMF, + cdplay, + cdregistercallback, +}; + +cdContext* cdContextMetafile(void) +{ + return &cdMetafileContext; +} diff --git a/src/drv/cdpdf.c b/src/drv/cdpdf.c new file mode 100644 index 0000000..24509f6 --- /dev/null +++ b/src/drv/cdpdf.c @@ -0,0 +1,1491 @@ +/** \file + * \brief PDF Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cdpdf.h" + +#include "pdflib.h" + + +/* +** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1. +*/ +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + PDF *pdf; /* Arquivo PDF */ + int res; /* Resolucao - DPI */ + int pages; /* Numero total de paginas */ + double width_pt; /* Largura do papel (points) */ + double height_pt; /* Altura do papel (points) */ + double width_mm; /* Largura do papel (mm) */ + double height_mm; /* Altura do papel (mm) */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int landscape; /* page orientation */ + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + int font; + int underline; + int strikeover; + + int hatchboxsize; + int pattern; + int opacity; + int opacity_states[256]; + + int poly_holes[500]; + int holes; +}; + + +/* +%F Ajusta o tamanho do papel em points. +*/ +static void setpdfpapersize(cdCtxCanvas* ctxcanvas, int size) +{ + static struct + { + int width; + int height; + } paper[] = + { + { 2393, 3391 }, /* A0 */ + { 1689, 2393 }, /* A1 */ + { 1192, 1689 }, /* A2 */ + { 842, 1192 }, /* A3 */ + { 595, 842 }, /* A4 */ + { 420, 595 }, /* A5 */ + { 612, 792 }, /* LETTER */ + { 612, 1008 } /* LEGAL */ + }; + + if (sizeCD_LEGAL) + return; + + ctxcanvas->width_pt = paper[size].width; + ctxcanvas->height_pt = paper[size].height; + ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT; + ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT; +} + +/* +%F Registra os valores default para impressao. +*/ +static void setpdfdefaultvalues(cdCtxCanvas* ctxcanvas) +{ + int i; + + /* all the other values are set to 0 */ + setpdfpapersize(ctxcanvas, CD_A4); + ctxcanvas->res = 300; + ctxcanvas->hatchboxsize = 8; + ctxcanvas->opacity = 255; /* full opaque */ + + for (i=0; i<256; i++) + ctxcanvas->opacity_states[i] = -1; +} + +static void update_state(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas = ctxcanvas->canvas; + + if (!canvas->cxFont) /* just check if the first time */ + return; + + /* must set the current transform and line style if different from the default */ + + if (canvas->line_style != CD_CONTINUOUS) + canvas->cxLineStyle(ctxcanvas, canvas->line_style); + if (canvas->line_width != 1) + canvas->cxLineWidth(ctxcanvas, canvas->line_width); + if (canvas->line_cap != CD_CAPFLAT) + canvas->cxLineCap(ctxcanvas, canvas->line_cap); + if (canvas->line_join != CD_MITER) + canvas->cxLineJoin(ctxcanvas, canvas->line_join); + if (canvas->use_matrix) + canvas->cxTransform(ctxcanvas, canvas->matrix); + canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); +} + +static void begin_page(cdCtxCanvas *ctxcanvas) +{ + PDF_begin_page_ext(ctxcanvas->pdf, ctxcanvas->width_pt, ctxcanvas->height_pt, ""); + + /* default coordinate system is in points, change it to pixels. */ + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + PDF_save(ctxcanvas->pdf); /* save the initial configuration, to be used when clipping is reset. */ + + update_state(ctxcanvas); +} + +static void init_pdf(cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->scale = 72.0/ctxcanvas->res; + + /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->w = (int)(ctxcanvas->width_pt/ctxcanvas->scale + 0.5); + ctxcanvas->canvas->h = (int)(ctxcanvas->height_pt/ctxcanvas->scale + 0.5); + + /* Passa o valor em milimetros para o canvas CD */ + ctxcanvas->canvas->w_mm = ctxcanvas->width_mm; + ctxcanvas->canvas->h_mm = ctxcanvas->height_mm; + + ctxcanvas->canvas->bpp = 24; + ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm; + ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm; + + begin_page(ctxcanvas); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration. */ + PDF_end_page_ext(ctxcanvas->pdf, ""); + PDF_end_document(ctxcanvas->pdf, ""); + PDF_delete(ctxcanvas->pdf); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void update_fill(cdCtxCanvas *ctxcanvas, int fill) +{ + if (fill == 0) + { + /* called before a NON filled primitive */ + PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + + } + else + { + /* called before a filled primitive */ + if (ctxcanvas->canvas->interior_style == CD_SOLID) + { + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + } + else + PDF_setcolor(ctxcanvas->pdf, "fill", "pattern", (float)ctxcanvas->pattern, 0, 0, 0); + } +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration */ + + PDF_end_page_ext(ctxcanvas->pdf, ""); + + begin_page(ctxcanvas); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static void resetcliprect(cdCtxCanvas* ctxcanvas) +{ + /* clipping is reset, by restoring the initial state */ + /* this will also reset the current transformation and line style */ + PDF_restore(ctxcanvas->pdf); + PDF_save(ctxcanvas->pdf); + + update_state(ctxcanvas); +} + +static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + resetcliprect(ctxcanvas); + + PDF_moveto(ctxcanvas->pdf, xmin, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymax); + PDF_lineto(ctxcanvas->pdf, xmin, ymax); + + PDF_clip(ctxcanvas->pdf); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA) + return; + + setcliprect(ctxcanvas, xmin, ymin, xmax, ymax); +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfcliparea(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_mode = CD_CLIPAREA; + + setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin, + (double)ctxcanvas->canvas->clip_rect.ymin, + (double)ctxcanvas->canvas->clip_rect.xmax, + (double)ctxcanvas->canvas->clip_rect.ymax); + } + else if (mode == CD_CLIPPOLYGON) + { + int hole_index = 0; + int i; + + resetcliprect(ctxcanvas); + + if (ctxcanvas->canvas->clip_poly) + { + cdPoint *poly = ctxcanvas->canvas->clip_poly; + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + for (i=1; icanvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + else if (ctxcanvas->canvas->clip_fpoly) + { + cdfPoint *poly = ctxcanvas->canvas->clip_fpoly; + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + for (i=1; icanvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + PDF_clip(ctxcanvas->pdf); + } + else if (mode == CD_CLIPOFF) + { + resetcliprect(ctxcanvas); + } + + return mode; +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + update_fill(ctxcanvas, 0); + + PDF_moveto(ctxcanvas->pdf, x1, y1); + PDF_lineto(ctxcanvas->pdf, x2, y2); + PDF_stroke(ctxcanvas->pdf); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 0); + + PDF_rect(ctxcanvas->pdf, xmin, ymin, xmax-xmin, ymax-ymin); + PDF_stroke(ctxcanvas->pdf); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfrect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 1); + + PDF_moveto(ctxcanvas->pdf, xmin, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymax); + PDF_lineto(ctxcanvas->pdf, xmin, ymax); + PDF_fill(ctxcanvas->pdf); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) + { + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_stroke(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, w/h, 1); + PDF_translate(ctxcanvas->pdf, -xc, -yc); + + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + PDF_stroke(ctxcanvas->pdf); + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfarc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) + { + PDF_moveto(ctxcanvas->pdf, xc, yc); + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, w/h, 1); + PDF_translate(ctxcanvas->pdf, -xc, -yc); + + PDF_moveto(ctxcanvas->pdf, xc, yc); + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + + if (ctxcanvas->canvas->interior_style == CD_SOLID || + ctxcanvas->canvas->interior_style == CD_PATTERN) + PDF_fill(ctxcanvas->pdf); + else + { + PDF_lineto(ctxcanvas->pdf, xc, yc); + PDF_stroke(ctxcanvas->pdf); + } + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfsector(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) + { + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill_stroke(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + /* local transform */ + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, 1, w/h); + + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill_stroke(ctxcanvas->pdf); + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfchord(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + double fontsize, a, d, linegap; + + if (ctxcanvas->font<0) + return; + + fontsize = PDF_get_value(ctxcanvas->pdf, "fontsize", 0); + a = PDF_get_value(ctxcanvas->pdf, "ascender", 0); + d = PDF_get_value(ctxcanvas->pdf, "descender", 0); + + /* linegap = PDF_info_font(ctxcanvas->pdf, 1, "linegap", ""); - not supported call */ + linegap = 0.23 * a; /* use default value for linegap */ + a += linegap; + d += linegap; /* since d<0, it is a subtraction */ + + a *= fontsize; + d *= fontsize; + + if (ascent) *ascent = (int)a; + if (descent) *descent = (int)(-d); + if (height) *height = (int)(a - d); + if (max_width) *max_width = (int)(PDF_info_textline(ctxcanvas->pdf, "W", 0, "width", "")/ctxcanvas->scale); +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + if (ctxcanvas->font<0) + return; + if (height) cdgetfontdim(ctxcanvas, NULL, height, NULL, NULL); + if (width) *width = (int)(PDF_info_textline(ctxcanvas->pdf, s, 0, "width", "")/ctxcanvas->scale); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s) +{ + char temp[200], options[200]; + + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + + strcpy(options, ""); + + sprintf(temp, "rotate=%g ", ctxcanvas->canvas->text_orientation); + strcat(options, temp); + + if (ctxcanvas->underline != 0) + strcat(options, "underline=true "); + else + strcat(options, "underline=false "); + + if (ctxcanvas->strikeover != 0) + strcat(options, "strikeout=true "); + else + strcat(options, "strikeout=false "); + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_NORTH: + sprintf(temp, "position={50 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_NORTH_EAST: + sprintf(temp, "position={100 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_NORTH_WEST: + sprintf(temp, "position={0 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_EAST: + sprintf(temp, "position={100 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_WEST: + sprintf(temp, "position={0 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_CENTER: + sprintf(temp, "position={50 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH_EAST: + sprintf(temp, "position={100 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH: + sprintf(temp, "position={50 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH_WEST: + sprintf(temp, "position={0 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_BASE_RIGHT: + sprintf(temp, "position={100 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + case CD_BASE_CENTER: + sprintf(temp, "position={50 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + case CD_BASE_LEFT: + sprintf(temp, "position={0 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + } + + PDF_fit_textline(ctxcanvas->pdf, s, 0, x, y, options); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + cdftext(ctxcanvas, (double)x, (double)y, s); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (mode==CD_FILL) + { + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd"); + else + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding"); + } + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; ipdf, poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + PDF_closepath_stroke(ctxcanvas->pdf); + break; + case CD_OPEN_LINES : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_BEZIER : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_FILL : + PDF_fill(ctxcanvas->pdf); + break; + } +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (mode==CD_FILL) + { + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd"); + else + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding"); + } + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; ipdf, poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + PDF_closepath_stroke(ctxcanvas->pdf); + break; + case CD_OPEN_LINES : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_BEZIER : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_FILL : + PDF_fill(ctxcanvas->pdf); + break; + } +} + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + double mm = (72.0/25.4) / ctxcanvas->scale; + char options[80]; + + switch (style) + { + case CD_CONTINUOUS : /* empty dash */ + PDF_setdash(ctxcanvas->pdf, 0, 0); + break; + case CD_DASHED : + PDF_setdash(ctxcanvas->pdf, 3*mm, mm); + break; + case CD_DOTTED : + PDF_setdash(ctxcanvas->pdf, mm, mm); + break; + case CD_DASH_DOT : + sprintf(options, "dasharray={%g %g %g %g}", 3*mm, mm, mm, mm); + PDF_setdashpattern(ctxcanvas->pdf, options); + break; + case CD_DASH_DOT_DOT : + sprintf(options, "dasharray={%g %g %g %g %g %g}", 3*mm, mm, mm, mm, mm, mm); + PDF_setdashpattern(ctxcanvas->pdf, options); + break; + case CD_CUSTOM : + { + int i; + + strcpy(options, "dasharray={"); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + { + char tmp[80]; + sprintf(tmp, "%g ", ctxcanvas->canvas->line_dashes[i]*mm); + strcat(options, tmp); + } + strcat(options, "}"); + PDF_setdashpattern(ctxcanvas->pdf, options); + } + break; + } + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + if (width==0) width = 1; + + PDF_setlinewidth(ctxcanvas->pdf, width); + + return width; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2ps_join[] = {0, 2, 1}; + PDF_setlinejoin(ctxcanvas->pdf, cd2ps_join[join]); + return join; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2pdf_cap[] = {0, 2, 1}; + PDF_setlinecap(ctxcanvas->pdf, cd2pdf_cap[cap]); + return cap; +} + +static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)) +{ + int i, j; + unsigned char r, g, b; + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m, + ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1); + + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + for (j=0; jpdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + PDF_rect(ctxcanvas->pdf, i, j, 1, 1); + PDF_fill(ctxcanvas->pdf); + } + } + + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); +} + +static int long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + long* long_data = (long*)data; + (void)ctxcanvas; + cdDecodeColor(long_data[j*n+i], r, g, b); + return 1; +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); +} + +static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + int ret = 1; + unsigned char* uchar_data = (unsigned char*)data; + if (uchar_data[j*n+i]) + { + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + ret = 1; + } + else + { + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); + if (ctxcanvas->canvas->back_opacity==CD_TRANSPARENT) + ret = -1; + } + + return ret; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); +} + +static void make_hatch(cdCtxCanvas *ctxcanvas, int style) +{ + unsigned char r, g, b; + int hsize = ctxcanvas->hatchboxsize - 1; + int hhalf = hsize / 2; + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, hsize + 1, hsize + 1, + ((double)hsize)*ctxcanvas->scale, ((double)hsize)*ctxcanvas->scale, 1); + + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + if (ctxcanvas->canvas->back_opacity==CD_OPAQUE) + { + cdDecodeColor(ctxcanvas->canvas->background, &r, &g, &b); + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + PDF_rect(ctxcanvas->pdf, 0, 0, hsize, hsize); + PDF_fill(ctxcanvas->pdf); + } + + cdDecodeColor(ctxcanvas->canvas->foreground, &r, &g, &b); + PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + + switch(style) + { + case CD_HORIZONTAL: + PDF_moveto(ctxcanvas->pdf, 0, hhalf); + PDF_lineto(ctxcanvas->pdf, hsize, hhalf); + break; + case CD_VERTICAL: + PDF_moveto(ctxcanvas->pdf, hhalf, 0); + PDF_lineto(ctxcanvas->pdf, hhalf, hsize); + break; + case CD_BDIAGONAL: + PDF_moveto(ctxcanvas->pdf, 0, hsize); + PDF_lineto(ctxcanvas->pdf, hsize, 0); + break; + case CD_FDIAGONAL: + PDF_moveto(ctxcanvas->pdf, 0, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + break; + case CD_CROSS: + PDF_moveto(ctxcanvas->pdf, hsize, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + PDF_moveto(ctxcanvas->pdf, 0, hhalf); + PDF_lineto(ctxcanvas->pdf, hsize, hhalf); + break; + case CD_DIAGCROSS: + PDF_moveto(ctxcanvas->pdf, 0, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + PDF_moveto(ctxcanvas->pdf, hsize, 0); + PDF_lineto(ctxcanvas->pdf, 0, hsize); + break; + } + + PDF_stroke(ctxcanvas->pdf); + + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + make_hatch(ctxcanvas, style); + return style; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + int newfont, sizepixel; + char nativefontname[1024]; + const char* options = ""; + + if (cdStrEqualNoCase(type_face, "System")) + type_face = "Courier"; + + strcpy(nativefontname, type_face); + + if (cdStrEqualNoCase(type_face, "Courier") || + cdStrEqualNoCase(type_face, "Helvetica")) + { + if (style&CD_BOLD && style&CD_ITALIC) + strcat(nativefontname, "-BoldOblique"); + else + { + if (style&CD_BOLD) + strcat(nativefontname, "-Bold"); + + if (style&CD_ITALIC) + strcat(nativefontname, "-Oblique"); + } + } + else if (cdStrEqualNoCase(type_face, "Times")) + { + if ((style&3) == CD_PLAIN) + strcat(nativefontname, "-Roman"); + if (style&CD_BOLD && style&CD_ITALIC) + strcat(nativefontname, "-BoldItalic"); + else + { + if (style&CD_BOLD) + strcat(nativefontname, "-Bold"); + + if (style&CD_ITALIC) + strcat(nativefontname, "-Italic"); + } + } + else + { + switch(style&3) + { + case CD_PLAIN: + options = "fontstyle=normal"; + break; + case CD_BOLD: + options = "fontstyle=bold"; + break; + case CD_ITALIC: + options = "fontstyle=italic"; + break; + case CD_BOLD_ITALIC: + options = "fontstyle=bolditalic"; + break; + } + } + + newfont = PDF_load_font(ctxcanvas->pdf, nativefontname, 0, "auto", options); + if (newfont<0) + { + /* must reload the previous one */ + return 0; + } + ctxcanvas->font = newfont; + + sizepixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + PDF_setfont(ctxcanvas->pdf, ctxcanvas->font, sizepixel); + + if (style&CD_UNDERLINE) + ctxcanvas->underline = 1; + else + ctxcanvas->underline = 0; + + if (style&CD_STRIKEOUT) + ctxcanvas->strikeover = 1; + else + ctxcanvas->strikeover = 0; + + return 1; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); + + /* default coordinate system is in points, change it to pixels. */ + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + if (matrix) + { + PDF_concat(ctxcanvas->pdf, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + else if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle); + PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, image, rw, rh, rgb_size; + char options[80]; + unsigned char* rgb_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + rgb_data[d] = r[i*iw+j]; d++; + rgb_data[d] = g[i*iw+j]; d++; + rgb_data[d] = b[i*iw+j]; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + + sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, image, image_mask, rw, rh, alpha_size, rgb_size; + char options[80]; + unsigned char *rgb_data, *alpha_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + rgb_data[d] = r[i*iw+j]; d++; + rgb_data[d] = g[i*iw+j]; d++; + rgb_data[d] = b[i*iw+j]; d++; + } + + alpha_size = rw*rh; + alpha_data = (unsigned char*)malloc(alpha_size); + if (!alpha_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + alpha_data[d] = a[i*iw+j]; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0, alpha_data, alpha_size, ""); + + sprintf(options, "width=%d height=%d components=1 bpc=8 imagewarning=true", rw, rh); + image_mask = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_alpha", 0, options); + + sprintf(options, "width=%d height=%d components=3 bpc=8 masked=%d", rw, rh, image_mask); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0); + free(alpha_data); + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, rw, rh, image, rgb_size; + char options[80]; + unsigned char* rgb_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + unsigned char r, g, b; + cdDecodeColor(colors[index[i*iw+j]], &r, &g, &b); + rgb_data[d] = r; d++; + rgb_data[d] = g; d++; + rgb_data[d] = b; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + + sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(color), get_green(color), get_blue(color), 0); + + PDF_moveto(ctxcanvas->pdf, x, y); + PDF_circle(ctxcanvas->pdf, x, y, .5); + + PDF_fill(ctxcanvas->pdf); +} + +/******************************************************/ +/* custom attributes */ +/******************************************************/ + +static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hole; + + if (data == NULL) + { + ctxcanvas->holes = 0; + return; + } + + sscanf(data, "%d", &hole); + ctxcanvas->poly_holes[ctxcanvas->holes] = hole; + ctxcanvas->holes++; +} + +static char* get_poly_attrib(cdCtxCanvas *ctxcanvas) +{ + static char holes[10]; + sprintf(holes, "%d", ctxcanvas->holes); + return holes; +} + +static cdAttribute poly_attrib = +{ + "POLYHOLE", + set_poly_attrib, + get_poly_attrib +}; + +static void set_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hatchboxsize; + + if (data == NULL) + { + ctxcanvas->hatchboxsize = 8; + return; + } + + sscanf(data, "%d", &hatchboxsize); + ctxcanvas->hatchboxsize = hatchboxsize; +} + +static char* get_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas) +{ + static char size[10]; + sprintf(size, "%d", ctxcanvas->hatchboxsize); + return size; +} + +static cdAttribute hatchboxsize_attrib = +{ + "HATCHBOXSIZE", + set_hatchboxsize_attrib, + get_hatchboxsize_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); + + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle); + PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_pattern_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + if (data) + { + int n, m; + sscanf(data, "%dx%d", &n, &m); + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m, + ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1); + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + } + else + { + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); + ctxcanvas->canvas->interior_style = CD_PATTERN; + } +} + +static cdAttribute pattern_attrib = +{ + "PATTERN", + set_pattern_attrib, + NULL +}; + +static void set_opacity_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int state; + + if (data) + { + sscanf(data, "%d", &ctxcanvas->opacity); + if (ctxcanvas->opacity < 0) ctxcanvas->opacity = 0; + if (ctxcanvas->opacity > 255) ctxcanvas->opacity = 255; + } + else + ctxcanvas->opacity = 255; + + /* reuse the extended graphics state if the opacity is the same */ + if (ctxcanvas->opacity_states[ctxcanvas->opacity] == -1) + { + char options[50]; + sprintf(options, "opacityfill=%g opacitystroke=%g", ctxcanvas->opacity/255.0, ctxcanvas->opacity/255.0); + state = PDF_create_gstate(ctxcanvas->pdf, options); + ctxcanvas->opacity_states[ctxcanvas->opacity] = state; + } + else + state = ctxcanvas->opacity_states[ctxcanvas->opacity]; + + PDF_set_gstate(ctxcanvas->pdf, state); +} + +static char* get_opacity_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[50]; + sprintf(data, "%d", ctxcanvas->opacity); + return data; +} + +static cdAttribute opacity_attrib = +{ + "OPACITY", + set_opacity_attrib, + get_opacity_attrib +}; + +static char* get_pdf_attrib(cdCtxCanvas *ctxcanvas) +{ + return (char*)ctxcanvas->pdf; +} + +static cdAttribute pdf_attrib = +{ + "PDF", + NULL, + get_pdf_attrib +}; + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *line = (char *)data; + cdCtxCanvas *ctxcanvas; + char filename[10240] = ""; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + ctxcanvas->pdf = PDF_new(); + if (!ctxcanvas->pdf) + { + free(ctxcanvas); + return; + } + + if (PDF_begin_document(ctxcanvas->pdf, filename, 0, "") == -1) + { + PDF_delete(ctxcanvas->pdf); + free(ctxcanvas); + return; + } + + PDF_set_parameter(ctxcanvas->pdf, "fontwarning", "false"); + PDF_set_parameter(ctxcanvas->pdf, "errorpolicy", "return"); + + cdRegisterAttribute(canvas, &poly_attrib); + cdRegisterAttribute(canvas, &hatchboxsize_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &opacity_attrib); + cdRegisterAttribute(canvas, &pattern_attrib); + cdRegisterAttribute(canvas, &pdf_attrib); + + setpdfdefaultvalues(ctxcanvas); + + while (*line != '\0') + { + while (*line != '\0' && *line != '-') + line++; + + if (*line != '\0') + { + float num; + line++; + switch (*line++) + { + case 'p': + { + int paper; + sscanf(line, "%d", &paper); + setpdfpapersize(ctxcanvas, paper); + break; + } + case 'w': + sscanf(line, "%g", &num); + ctxcanvas->width_mm = num; + ctxcanvas->width_pt = CD_MM2PT*ctxcanvas->width_mm; + break; + case 'h': + sscanf(line, "%g", &num); + ctxcanvas->height_mm = num; + ctxcanvas->height_pt = CD_MM2PT*ctxcanvas->height_mm; + break; + case 's': + sscanf(line, "%d", &(ctxcanvas->res)); + break; + case 'o': + ctxcanvas->landscape = 1; + break; + } + } + + while (*line != '\0' && *line != ' ') + line++; + } + + /* store the base canvas */ + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->ctxcanvas = ctxcanvas; + + if (ctxcanvas->landscape == 1) + { + _cdSwapDouble(ctxcanvas->width_pt, ctxcanvas->height_pt); + _cdSwapDouble(ctxcanvas->width_mm, ctxcanvas->height_mm); + } + + init_pdf(ctxcanvas); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxPattern = cdpattern; + canvas->cxStipple = cdstipple; + canvas->cxHatch = cdhatch; + canvas->cxFont = cdfont; + canvas->cxTransform = cdtransform; + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdPDFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_REGION | CD_CAP_IMAGESRV | CD_CAP_TEXTSIZE | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextPDF(void) +{ + return &cdPDFContext; +} + +/* +p.set_info("Creator", "PDFlib Cookbook") +*/ diff --git a/src/drv/cdpicture.c b/src/drv/cdpicture.c new file mode 100644 index 0000000..9bc5104 --- /dev/null +++ b/src/drv/cdpicture.c @@ -0,0 +1,1133 @@ +/** \file + * \brief CD Picture driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cdpicture.h" + + +/* codes for the primitives. +*/ +typedef enum _tPrim +{ + CDPIC_LINE, + CDPIC_RECT, + CDPIC_BOX, + CDPIC_ARC, + CDPIC_SECTOR, + CDPIC_CHORD, + CDPIC_TEXT, + CDPIC_POLY, + CDPIC_FLINE, + CDPIC_FRECT, + CDPIC_FBOX, + CDPIC_FARC, + CDPIC_FSECTOR, + CDPIC_FCHORD, + CDPIC_FTEXT, + CDPIC_FPOLY, + CDPIC_PIXEL, + CDPIC_IMAGEMAP, + CDPIC_IMAGERGB, + CDPIC_IMAGERGBA, +} tPrim; + +typedef struct _tFillAttrib +{ + long foreground, background; + int back_opacity; + int interior_style, hatch_style; + int fill_mode; + int pattern_w, pattern_h; + long* pattern; + int stipple_w, stipple_h; + unsigned char* stipple; +} tFillAttrib; + +typedef struct _tLineAttrib +{ + long foreground, background; + int back_opacity; + int line_style, line_width; + int line_cap, line_join; + int* line_dashes; + int line_dashes_count; +} tLineAttrib; + +typedef struct _tTextAttrib +{ + long foreground; + char* font_type_face; + int font_style, font_size; + int text_alignment; + double text_orientation; + char* native_font; +} tTextAttrib; + +typedef struct _tLBR +{ + int x1, y1, x2, y2; +} tLBR; /* Line or Box or Rect */ + +typedef struct _tfLBR +{ + double x1, y1, x2, y2; +} tfLBR; /* Line or Box or Rect */ + +typedef struct _tASC +{ + int xc, yc, w, h; + double angle1, angle2; +} tASC; /* Arc or Sector or Chord */ + +typedef struct _tfASC +{ + double xc, yc, w, h; + double angle1, angle2; +} tfASC; /* Arc or Sector or Chord */ + +typedef struct _tPoly +{ + int mode; + int n; + cdPoint* points; +} tPoly; /* Begin, Vertex and End */ + +typedef struct _tfPoly +{ + int mode; + int n; + cdfPoint* points; +} tfPoly; /* Begin, Vertex and End */ + +typedef struct _tText +{ + int x, y; + char *s; +} tText; /* Text */ + +typedef struct _tfText +{ + double x, y; + char *s; +} tfText; /* Text */ + +typedef struct _tPixel +{ + int x, y; + long color; +} tPixel; /* Pixel */ + +typedef struct _tImageMap +{ + int iw, ih; + unsigned char *index; + long int *colors; + int x, y, w, h; +} tImageMap; + +typedef struct _tImageRGBA +{ + int iw, ih; + unsigned char *r; + unsigned char *g; + unsigned char *b; + unsigned char *a; + int x, y, w, h; +} tImageRGBA; + +typedef struct _tPrimNode +{ + tPrim type; + void* param_buffer; /* dinamically allocated memory for the parameter */ + union { + tLBR lineboxrect; + tfLBR lineboxrectf; + tASC arcsectorchord; + tfASC arcsectorchordf; + tPoly poly; + tfPoly polyf; + tText text; + tfText textf; + tPixel pixel; + tImageMap imagemap; + tImageRGBA imagergba; + } param; + void* attrib_buffer; /* dinamically allocated memory for the attributes */ + union { + tLineAttrib line; + tFillAttrib fill; + tTextAttrib text; + } attrib; + struct _tPrimNode *next; +} tPrimNode; + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + /* primitives list */ + tPrimNode *prim_first, + *prim_last; + int prim_n; + + /* bounding box */ + int xmin, xmax, + ymin, ymax; +}; + +static void picUpdateSize(cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->canvas->w = ctxcanvas->xmax-ctxcanvas->xmin+1; + ctxcanvas->canvas->h = ctxcanvas->ymax-ctxcanvas->ymin+1; + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; +} + +static void picUpdateBBox(cdCtxCanvas *ctxcanvas, int x, int y, int ew) +{ + if (x+ew > ctxcanvas->xmax) + ctxcanvas->xmax = x+ew; + if (y+ew > ctxcanvas->ymax) + ctxcanvas->ymax = y+ew; + if (x-ew < ctxcanvas->xmin) + ctxcanvas->xmin = x-ew; + if (y-ew < ctxcanvas->ymin) + ctxcanvas->ymin = y-ew; + + picUpdateSize(ctxcanvas); +} + +static void picUpdateBBoxF(cdCtxCanvas *ctxcanvas, double x, double y, int ew) +{ + if ((int)ceil(x+ew) > ctxcanvas->xmax) + ctxcanvas->xmax = (int)ceil(x+ew); + if ((int)ceil(y+ew) > ctxcanvas->ymax) + ctxcanvas->ymax = (int)ceil(y+ew); + if ((int)floor(x-ew) < ctxcanvas->xmin) + ctxcanvas->xmin = (int)floor(x-ew); + if ((int)floor(y-ew) < ctxcanvas->ymin) + ctxcanvas->ymin = (int)floor(y-ew); + + picUpdateSize(ctxcanvas); +} + +static void picAddPrim(cdCtxCanvas *ctxcanvas, tPrimNode *prim) +{ + if (ctxcanvas->prim_n == 0) + ctxcanvas->prim_first = prim; + else + ctxcanvas->prim_last->next = prim; + + ctxcanvas->prim_last = prim; + ctxcanvas->prim_n++; +} + +static tPrimNode* primCreate(tPrim type) +{ + tPrimNode *prim = malloc(sizeof(tPrimNode)); + memset(prim, 0, sizeof(tPrimNode)); + prim->type = type; + return prim; +} + +static void primDestroy(tPrimNode *prim) +{ + if (prim->param_buffer) + free(prim->param_buffer); + if (prim->attrib_buffer) + free(prim->attrib_buffer); + free(prim); +} + +static void primAddAttrib_Line(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.line.foreground = canvas->foreground; + prim->attrib.line.background = canvas->background; + prim->attrib.line.back_opacity = canvas->back_opacity; + prim->attrib.line.line_style = canvas->line_style; + prim->attrib.line.line_width = canvas->line_width; + prim->attrib.line.line_cap = canvas->line_cap; + prim->attrib.line.line_join = canvas->line_join; + + if (canvas->line_style==CD_CUSTOM && canvas->line_dashes) + { + prim->attrib.line.line_dashes_count = canvas->line_dashes_count; + prim->attrib_buffer = malloc(canvas->line_dashes_count*sizeof(int)); + prim->attrib.line.line_dashes = prim->attrib_buffer; + memcpy(prim->attrib.line.line_dashes, canvas->line_dashes, canvas->line_dashes_count*sizeof(int)); + } +} + +static void primAddAttrib_Fill(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.fill.foreground = canvas->foreground; + prim->attrib.fill.background = canvas->background; + prim->attrib.fill.back_opacity = canvas->back_opacity; + prim->attrib.fill.interior_style = canvas->interior_style; + prim->attrib.fill.hatch_style = canvas->hatch_style; + prim->attrib.fill.fill_mode = canvas->fill_mode; + prim->attrib.fill.pattern_w = canvas->pattern_w; + prim->attrib.fill.pattern_h = canvas->pattern_h; + prim->attrib.fill.stipple_w = canvas->stipple_w; + prim->attrib.fill.stipple_h = canvas->stipple_h; + + if (canvas->interior_style==CD_PATTERN && canvas->pattern) + { + prim->attrib_buffer = malloc(canvas->pattern_size*sizeof(long)); + prim->attrib.fill.pattern = prim->attrib_buffer; + memcpy(prim->attrib.fill.pattern, canvas->pattern, canvas->pattern_size*sizeof(long)); + } + + if (canvas->interior_style==CD_STIPPLE && canvas->stipple) + { + prim->attrib_buffer = malloc(canvas->stipple_size*sizeof(long)); + prim->attrib.fill.stipple = prim->attrib_buffer; + memcpy(prim->attrib.fill.stipple, canvas->stipple, canvas->stipple_size*sizeof(long)); + } +} + +static void primAddAttrib_Text(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.text.foreground = canvas->foreground; + + prim->attrib.text.font_style = canvas->font_style; + prim->attrib.text.font_size = canvas->font_size; + prim->attrib.text.text_alignment = canvas->text_alignment; + prim->attrib.text.text_orientation = canvas->text_orientation; + + if (canvas->native_font[0]) + { + prim->attrib_buffer = strdup(canvas->native_font); + prim->attrib.text.native_font = prim->attrib_buffer; + } + else + { + prim->attrib_buffer = strdup(canvas->font_type_face); + prim->attrib.text.font_type_face = prim->attrib_buffer; + } +} + +static void primUpdateAttrib_Line(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetBackground(canvas, prim->attrib.line.background); + cdCanvasSetForeground(canvas, prim->attrib.line.foreground); + cdCanvasBackOpacity(canvas, prim->attrib.line.back_opacity); + cdCanvasLineStyle(canvas, prim->attrib.line.line_style); + cdCanvasLineWidth(canvas, prim->attrib.line.line_width); + cdCanvasLineCap(canvas, prim->attrib.line.line_cap); + cdCanvasLineJoin(canvas, prim->attrib.line.line_join); + + if (prim->attrib.line.line_style==CD_CUSTOM && prim->attrib.line.line_dashes) + cdCanvasLineStyleDashes(canvas, prim->attrib.line.line_dashes, prim->attrib.line.line_dashes_count); +} + +void primUpdateAttrib_Fill(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetBackground(canvas, prim->attrib.fill.background); + cdCanvasSetForeground(canvas, prim->attrib.fill.foreground); + cdCanvasBackOpacity(canvas, prim->attrib.fill.back_opacity); + cdCanvasFillMode(canvas, prim->attrib.fill.fill_mode); + + if (prim->attrib.fill.interior_style==CD_HATCH) + cdCanvasHatch(canvas, prim->attrib.fill.hatch_style); + else if (prim->attrib.fill.interior_style==CD_PATTERN && prim->attrib.fill.pattern) + cdCanvasPattern(canvas, prim->attrib.fill.pattern_w, prim->attrib.fill.pattern_h, prim->attrib.fill.pattern); + else if (prim->attrib.fill.interior_style==CD_STIPPLE && prim->attrib.fill.stipple) + cdCanvasStipple(canvas, prim->attrib.fill.stipple_w, prim->attrib.fill.stipple_h, prim->attrib.fill.stipple); + + cdCanvasInteriorStyle(canvas, prim->attrib.fill.interior_style); +} + +void primUpdateAttrib_Text(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetForeground(canvas, prim->attrib.text.foreground); + cdCanvasTextAlignment(canvas, prim->attrib.text.text_alignment); + cdCanvasTextOrientation(canvas, prim->attrib.text.text_orientation); + + if (canvas->native_font[0]) + cdCanvasNativeFont(canvas, prim->attrib.text.native_font); + else + cdCanvasFont(canvas, prim->attrib.text.font_type_face, prim->attrib.text.font_style, prim->attrib.text.font_size); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + tPrimNode *prim; + int i; + for (i = 0; i < ctxcanvas->prim_n; i++) + { + prim = ctxcanvas->prim_first; + ctxcanvas->prim_first = prim->next; + + primDestroy(prim); + } + + ctxcanvas->prim_n = 0; + ctxcanvas->prim_first = NULL; + ctxcanvas->prim_last = NULL; +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + tPrimNode *prim = primCreate(CDPIC_PIXEL); + prim->param.pixel.x = x; + prim->param.pixel.y = y; + prim->param.pixel.color = color; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, x, y, 0); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + tPrimNode *prim = primCreate(CDPIC_LINE); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = x1; + prim->param.lineboxrect.y1 = y1; + prim->param.lineboxrect.x2 = x2; + prim->param.lineboxrect.y2 = y2; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + tPrimNode *prim = primCreate(CDPIC_FLINE); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = x1; + prim->param.lineboxrectf.y1 = y1; + prim->param.lineboxrectf.x2 = x2; + prim->param.lineboxrectf.y2 = y2; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width); + picUpdateBBoxF(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + tPrimNode *prim = primCreate(CDPIC_RECT); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = xmin; + prim->param.lineboxrect.y1 = ymin; + prim->param.lineboxrect.x2 = xmax; + prim->param.lineboxrect.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + tPrimNode *prim = primCreate(CDPIC_FRECT); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = xmin; + prim->param.lineboxrectf.y1 = ymin; + prim->param.lineboxrectf.x2 = xmax; + prim->param.lineboxrectf.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBoxF(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + tPrimNode *prim = primCreate(CDPIC_BOX); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = xmin; + prim->param.lineboxrect.y1 = ymin; + prim->param.lineboxrect.x2 = xmax; + prim->param.lineboxrect.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + tPrimNode *prim = primCreate(CDPIC_FBOX); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = xmin; + prim->param.lineboxrectf.y1 = ymin; + prim->param.lineboxrectf.x2 = xmax; + prim->param.lineboxrectf.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, xmin, ymin, 0); + picUpdateBBoxF(ctxcanvas, xmax, ymax, 0); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_ARC); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FARC); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_SECTOR); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); + picUpdateBBox(ctxcanvas, xc, yc, 0); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FSECTOR); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); + picUpdateBBox(ctxcanvas, _cdRound(xc), _cdRound(yc), 0); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_CHORD); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FCHORD); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_TEXT); + primAddAttrib_Text(prim, ctxcanvas->canvas); + prim->param.text.x = x; + prim->param.text.y = y; + prim->param.text.s = strdup(text); + prim->param_buffer = prim->param.text.s; + picAddPrim(ctxcanvas, prim); + cdCanvasGetTextBox(ctxcanvas->canvas, x, y, text, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FTEXT); + primAddAttrib_Text(prim, ctxcanvas->canvas); + prim->param.textf.x = x; + prim->param.textf.y = y; + prim->param.textf.s = strdup(text); + prim->param_buffer = prim->param.textf.s; + picAddPrim(ctxcanvas, prim); + cdCanvasGetTextBox(ctxcanvas->canvas, _cdRound(x), _cdRound(y), text, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + tPrimNode *prim; + if (mode == CD_CLIP || mode == CD_REGION) return; + prim = primCreate(CDPIC_POLY); + if (mode == CD_FILL) + primAddAttrib_Fill(prim, ctxcanvas->canvas); + else + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.poly.n = n; + prim->param.poly.points = malloc(n * sizeof(cdPoint)); + memcpy(prim->param.poly.points, poly, n * sizeof(cdPoint)); + prim->param_buffer = prim->param.poly.points; + picAddPrim(ctxcanvas, prim); + + for (i = 0; i < n; i++) + { + if (mode == CD_FILL) + picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, 0); + else + picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, ctxcanvas->canvas->line_width); + } +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + tPrimNode *prim; + if (mode == CD_CLIP || mode == CD_REGION) return; + prim = primCreate(CDPIC_FPOLY); + if (mode == CD_FILL) + primAddAttrib_Fill(prim, ctxcanvas->canvas); + else + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.polyf.n = n; + prim->param.polyf.points = malloc(n * sizeof(cdPoint)); + memcpy(prim->param.polyf.points, poly, n * sizeof(cdPoint)); + prim->param_buffer = prim->param.polyf.points; + picAddPrim(ctxcanvas, prim); + + for (i = 0; i < n; i++) + { + if (mode == CD_FILL) + picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), 0); + else + picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), ctxcanvas->canvas->line_width); + } +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, offset, size; + unsigned char *dr, *dg, *db; + + tPrimNode *prim = primCreate(CDPIC_IMAGERGB); + prim->param.imagergba.iw = xmax-xmin+1; + prim->param.imagergba.ih = ymax-ymin+1; + prim->param.imagergba.x = x; + prim->param.imagergba.y = y; + prim->param.imagergba.w = w; + prim->param.imagergba.h = h; + + size = prim->param.imagergba.iw*prim->param.imagergba.ih; + prim->param_buffer = malloc(3*size); + prim->param.imagergba.r = prim->param_buffer; + prim->param.imagergba.g = prim->param.imagergba.r + size; + prim->param.imagergba.b = prim->param.imagergba.g + size; + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + + dr = prim->param.imagergba.r; + dg = prim->param.imagergba.g; + db = prim->param.imagergba.b; + offset = prim->param.imagergba.iw; + + for (l = ymin; l <= ymax; l++) + { + memcpy(dr, r, offset); + memcpy(dg, g, offset); + memcpy(db, b, offset); + + r += iw; + g += iw; + b += iw; + dr += offset; + dg += offset; + db += offset; + } + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, offset, size; + unsigned char *dr, *dg, *db, *da; + + tPrimNode *prim = primCreate(CDPIC_IMAGERGBA); + prim->param.imagergba.iw = xmax-xmin+1; + prim->param.imagergba.ih = ymax-ymin+1; + prim->param.imagergba.x = x; + prim->param.imagergba.y = y; + prim->param.imagergba.w = w; + prim->param.imagergba.h = h; + + size = prim->param.imagergba.iw*prim->param.imagergba.ih; + prim->param_buffer = malloc(4*size); + prim->param.imagergba.r = prim->param_buffer; + prim->param.imagergba.g = prim->param.imagergba.r + size; + prim->param.imagergba.b = prim->param.imagergba.g + size; + prim->param.imagergba.a = prim->param.imagergba.b + size; + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + a += offset; + + dr = prim->param.imagergba.r; + dg = prim->param.imagergba.g; + db = prim->param.imagergba.b; + da = prim->param.imagergba.a; + offset = prim->param.imagergba.iw; + + for (l = ymin; l <= ymax; l++) + { + memcpy(dr, r, offset); + memcpy(dg, g, offset); + memcpy(db, b, offset); + memcpy(da, a, offset); + + r += iw; + g += iw; + b += iw; + a += iw; + dr += offset; + dg += offset; + db += offset; + da += offset; + } + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, n = 0, offset, size; + unsigned char *dindex; + long *dcolors; + + tPrimNode *prim = primCreate(CDPIC_IMAGEMAP); + prim->param.imagemap.iw = xmax-xmin+1; + prim->param.imagemap.ih = ymax-ymin+1; + prim->param.imagemap.x = x; + prim->param.imagemap.y = y; + prim->param.imagemap.w = w; + prim->param.imagemap.h = h; + + size = prim->param.imagemap.iw*prim->param.imagemap.ih; + prim->param_buffer = malloc(size + 256); + prim->param.imagemap.index = prim->param_buffer; + prim->param.imagemap.colors = (long*)(prim->param.imagemap.index + size); + + offset = ymin*iw + xmin; + index += offset; + + dindex = prim->param.imagemap.index; + dcolors = prim->param.imagemap.colors; + offset = iw - prim->param.imagemap.iw; + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + if (*index > n) + n = *index; + + *dindex++ = *index++; + } + + index += offset; + } + + n++; + + for (c = 0; c < n; c++) + dcolors[c] = colors[c]; + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagemap.iw-1, y+prim->param.imagemap.ih-1, 0); +} + + +/**********/ +/* cdPlay */ +/**********/ + +typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm); +static _cdsizecb cdsizecb = NULL; + +static int cdregistercallback(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecb = (_cdsizecb)func; + return CD_OK; + } + + return CD_ERROR; +} + +#define sMin1(_v) (_v == 0? 1: _v) + +#define sScaleX(_x) cdRound((_x - pic_xmin) * factorX + xmin) +#define sScaleY(_y) cdRound((_y - pic_ymin) * factorY + ymin) +#define sScaleW(_w) sMin1(cdRound(_w * factorX)) +#define sScaleH(_h) sMin1(cdRound(_h * factorY)) + +#define sfScaleX(_x) ((_x - pic_xmin) * factorX + xmin) +#define sfScaleY(_y) ((_y - pic_ymin) * factorY + ymin) +#define sfScaleW(_w) (_w * factorX) +#define sfScaleH(_h) (_h * factorY) + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + tPrimNode *prim; + cdCanvas* pic_canvas = (cdCanvas*)data; + cdCtxCanvas* ctxcanvas = pic_canvas->ctxcanvas; + int p, i, scale = 0, + pic_xmin = ctxcanvas->xmin, + pic_ymin = ctxcanvas->ymin; + double factorX = 1, factorY = 1; + + if ((ctxcanvas->xmax-ctxcanvas->xmin)!=0 && + (ctxcanvas->ymax-ctxcanvas->ymin)!=0 && + (xmax-xmin)!=0 && + (ymax-ymin)!=0) + { + scale = 1; + factorX = ((double)(xmax-xmin)) / (ctxcanvas->xmax-ctxcanvas->xmin); + factorY = ((double)(ymax-ymin)) / (ctxcanvas->ymax-ctxcanvas->ymin); + } + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, pic_canvas->w, pic_canvas->h, pic_canvas->w_mm, pic_canvas->h_mm); + if (err) + return CD_ERROR; + } + + prim = ctxcanvas->prim_first; + for (i = 0; i < ctxcanvas->prim_n; i++) + { + if (scale) + { + switch (prim->type) + { + case CDPIC_LINE: + primUpdateAttrib_Line(prim, canvas); + cdCanvasLine(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleY(prim->param.lineboxrect.y1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FLINE: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasLine(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleY(prim->param.lineboxrectf.y1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_RECT: + primUpdateAttrib_Line(prim, canvas); + cdCanvasRect(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FRECT: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasRect(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_BOX: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasBox(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FBOX: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasBox(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_ARC: + primUpdateAttrib_Line(prim, canvas); + cdCanvasArc(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FARC: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasArc(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_SECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasSector(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FSECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasSector(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_CHORD: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasChord(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FCHORD: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasChord(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_TEXT: + primUpdateAttrib_Text(prim, canvas); + cdCanvasText(canvas, sScaleX(prim->param.text.x), sScaleY(prim->param.text.y), prim->param.text.s); + break; + case CDPIC_FTEXT: + primUpdateAttrib_Text(prim, canvas); + cdfCanvasText(canvas, sfScaleX(prim->param.textf.x), sfScaleY(prim->param.textf.y), prim->param.text.s); + break; + case CDPIC_POLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.poly.mode); + for (p = 0; p < prim->param.poly.n; p++) + cdCanvasVertex(canvas, sScaleX(prim->param.poly.points[p].x), sScaleY(prim->param.poly.points[p].y)); + cdCanvasEnd(canvas); + break; + case CDPIC_FPOLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.polyf.mode); + for (p = 0; p < prim->param.polyf.n; p++) + cdfCanvasVertex(canvas, sfScaleX(prim->param.polyf.points[p].x), sfScaleY(prim->param.polyf.points[p].y)); + cdCanvasEnd(canvas); + break; + case CDPIC_IMAGERGB: + cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0); + break; + case CDPIC_IMAGERGBA: + cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0); + break; + case CDPIC_IMAGEMAP: + cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, sScaleX(prim->param.imagemap.x), sScaleY(prim->param.imagemap.y), sScaleW(prim->param.imagemap.w), sScaleH(prim->param.imagemap.h), 0, 0, 0, 0); + break; + case CDPIC_PIXEL: + cdCanvasPixel(canvas, sScaleX(prim->param.pixel.x), sScaleY(prim->param.pixel.y), prim->param.pixel.color); + break; + } + } + else + { + switch (prim->type) + { + case CDPIC_LINE: + primUpdateAttrib_Line(prim, canvas); + cdCanvasLine(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.y1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y2); + break; + case CDPIC_FLINE: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasLine(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y2); + break; + case CDPIC_RECT: + primUpdateAttrib_Line(prim, canvas); + cdCanvasRect(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2); + break; + case CDPIC_FRECT: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasRect(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2); + break; + case CDPIC_BOX: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasBox(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2); + break; + case CDPIC_FBOX: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasBox(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2); + break; + case CDPIC_ARC: + primUpdateAttrib_Line(prim, canvas); + cdCanvasArc(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FARC: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasArc(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_SECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasSector(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FSECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasSector(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_CHORD: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasChord(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FCHORD: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasChord(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_TEXT: + primUpdateAttrib_Text(prim, canvas); + cdCanvasText(canvas, prim->param.text.x, prim->param.text.y, prim->param.text.s); + break; + case CDPIC_FTEXT: + primUpdateAttrib_Text(prim, canvas); + cdfCanvasText(canvas, prim->param.textf.x, prim->param.textf.y, prim->param.text.s); + break; + case CDPIC_POLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.poly.mode); + for (p = 0; p < prim->param.poly.n; p++) + cdCanvasVertex(canvas, prim->param.poly.points[p].x, prim->param.poly.points[p].y); + cdCanvasEnd(canvas); + break; + case CDPIC_FPOLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.polyf.mode); + for (p = 0; p < prim->param.polyf.n; p++) + cdfCanvasVertex(canvas, prim->param.polyf.points[p].x, prim->param.polyf.points[p].y); + cdCanvasEnd(canvas); + break; + case CDPIC_IMAGERGB: + cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0); + break; + case CDPIC_IMAGERGBA: + cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0); + break; + case CDPIC_IMAGEMAP: + cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, prim->param.imagemap.x, prim->param.imagemap.y, prim->param.imagemap.w, prim->param.imagemap.h, 0, 0, 0, 0); + break; + case CDPIC_PIXEL: + cdCanvasPixel(canvas, prim->param.pixel.x, prim->param.pixel.y, prim->param.pixel.color); + break; + } + } + + prim = prim->next; + } + + return CD_OK; +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdclear(ctxcanvas); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/*******************/ +/* Canvas Creation */ +/*******************/ + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + char* strdata = (char*)data; + double res = 3.78; + cdCtxCanvas* ctxcanvas; + + sscanf(strdata, "%lg", &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + /* update canvas context */ + canvas->w = 0; + canvas->h = 0; + canvas->w_mm = 0; + canvas->h_mm = 0; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxFLine = cdfline; + canvas->cxRect = cdrect; + canvas->cxFRect = cdfrect; + canvas->cxBox = cdbox; + canvas->cxFBox = cdfbox; + canvas->cxArc = cdarc; + canvas->cxFArc = cdfarc; + canvas->cxSector = cdsector; + canvas->cxFSector = cdfsector; + canvas->cxChord = cdchord; + canvas->cxFChord = cdfchord; + canvas->cxText = cdtext; + canvas->cxFText = cdftext; + canvas->cxPoly = cdpoly; + canvas->cxFPoly = cdfpoly; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdPictureContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvas, + cdinittable, + cdplay, + cdregistercallback, +}; + +cdContext* cdContextPicture(void) +{ + return &cdPictureContext; +} diff --git a/src/drv/cdps.c b/src/drv/cdps.c new file mode 100644 index 0000000..0d23608 --- /dev/null +++ b/src/drv/cdps.c @@ -0,0 +1,1836 @@ +/** \file + * \brief PS driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#include "cd.h" +#include "cd_private.h" +#include "cdps.h" + + +#define mm2pt(x) (CD_MM2PT*(x)) + +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif +#ifndef max +#define max(a, b) ((a)>(b)?(a):(b)) +#endif + +/* +** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1. +*/ +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + +/* ATENTION: currentmatrix/setmatrix + Remeber that there is a tranformation set just after file open, to define margins and pixel scale. + So use transformations carefully. +*/ + +static unsigned char HatchBits[6][8] = { /* [style][y] (8x8) */ + {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, /* CD_HORIZONTAL */ + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /* CD_VERTICAL */ + {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* CD_BDIAGONAL */ + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* CD_FDIAGONAL */ + {0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10}, /* CD_CROSS */ + {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}};/* CD_DIAGCROSS */ + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* Arquivo PS */ + int res; /* Resolucao */ + int pages; /* Numero total de paginas */ + double width; /* Largura do papel (points) */ + double height; /* Altura do papel (points) */ + double xmin, ymin; /* Definem as margens esquerda e inferior (points) */ + double xmax, ymax; /* Definem as margens direita e superior (points) */ + double bbxmin, bbymin; /* Definem a bounding box */ + double bbxmax, bbymax; /* Definem a bounding box */ + double bbmargin; /* Define a margem para a bounding box */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int eps; /* Postscrip encapsulado? */ + int level1; /* if true generates level 1 only function calls */ + int landscape; /* page orientation */ + int debug; /* print debug strings in the file */ + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + char *nativefontname[100]; /* Registra as fontes usadas */ + int num_native_font; + + int poly_holes[500]; + int holes; + +}; + + +/* +%F Ajusta o tamanho do papel em points. +*/ +static void setpspapersize(cdCtxCanvas *ctxcanvas, int size) +{ + static struct + { + int width; + int height; + } paper[] = + { + { 2393, 3391 }, /* A0 */ + { 1689, 2393 }, /* A1 */ + { 1192, 1689 }, /* A2 */ + { 842, 1192 }, /* A3 */ + { 595, 842 }, /* A4 */ + { 420, 595 }, /* A5 */ + { 612, 792 }, /* LETTER */ + { 612, 1008 } /* LEGAL */ + }; + + if (sizeCD_LEGAL) + return; + + ctxcanvas->width = (double)paper[size].width; + ctxcanvas->height = (double)paper[size].height; +} + +/* +%F Registra os valores default para impressao. +*/ +static void setpsdefaultvalues(cdCtxCanvas *ctxcanvas) +{ + /* all the other values are set to 0 */ + setpspapersize(ctxcanvas, CD_A4); + ctxcanvas->xmin = 25.4; /* ainda em mm, sera' convertido para points na init_ps */ + ctxcanvas->xmax = 25.4; + ctxcanvas->ymin = 25.4; + ctxcanvas->ymax = 25.4; + ctxcanvas->res = 300; +} + +/* +%F Insere o ponto (x, y) na BoundingBox corrente. +Nao leva em consideracao a espessura das linhas. +*/ +static void insertpoint(cdCtxCanvas *ctxcanvas, int x, int y) +{ + double xmin = x*ctxcanvas->scale + ctxcanvas->xmin - ctxcanvas->bbmargin; + double ymin = y*ctxcanvas->scale + ctxcanvas->ymin - ctxcanvas->bbmargin; + + double xmax = x*ctxcanvas->scale + ctxcanvas->xmin + ctxcanvas->bbmargin; + double ymax = y*ctxcanvas->scale + ctxcanvas->ymin + ctxcanvas->bbmargin; + + if (!ctxcanvas->bbxmin && !ctxcanvas->bbxmax && !ctxcanvas->bbymin && !ctxcanvas->bbymax) + { + ctxcanvas->bbxmin = xmin; + ctxcanvas->bbymin = ymin; + + ctxcanvas->bbxmax = xmax; + ctxcanvas->bbymax = ymax; + } + else + { + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->bbxmin = max(ctxcanvas->canvas->clip_rect.xmin*ctxcanvas->scale + ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin)); + ctxcanvas->bbymin = max(ctxcanvas->canvas->clip_rect.ymin*ctxcanvas->scale + ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin)); + + ctxcanvas->bbxmax = min(ctxcanvas->canvas->clip_rect.xmax*ctxcanvas->scale + ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax)); + ctxcanvas->bbymax = min(ctxcanvas->canvas->clip_rect.ymax*ctxcanvas->scale + ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax)); + } + else + { + ctxcanvas->bbxmin = max(ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin)); + ctxcanvas->bbymin = max(ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin)); + + ctxcanvas->bbxmax = min(ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax)); + ctxcanvas->bbymax = min(ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax)); + } + } +} + +/* +%F Ajusta a BoundingBox para conter o ponto (x,y). +Leva em consideracao a espessura das linhas. +*/ +static void bbox(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (ctxcanvas->canvas->line_width > 1) + { + insertpoint(ctxcanvas, x-ctxcanvas->canvas->line_width, y-ctxcanvas->canvas->line_width); + insertpoint(ctxcanvas, x+ctxcanvas->canvas->line_width, y+ctxcanvas->canvas->line_width); + } + else + insertpoint(ctxcanvas, x, y); +} + +static void fbbox(cdCtxCanvas *ctxcanvas, double x, double y) +{ + if (ctxcanvas->canvas->line_width > 1) + { + insertpoint(ctxcanvas, (int)(x-ctxcanvas->canvas->line_width), (int)(y-ctxcanvas->canvas->line_width)); + insertpoint(ctxcanvas, (int)(x+ctxcanvas->canvas->line_width), (int)(y+ctxcanvas->canvas->line_width)); + } + else + insertpoint(ctxcanvas, (int)x, (int)y); +} + +static char new_codes[] = {"\ +/newcodes % foreign character encodings\n\ +[\n\ +160/space 161/exclamdown 162/cent 163/sterling 164/currency\n\ +165/yen 166/brokenbar 167/section 168/dieresis 169/copyright\n\ +170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered\n\ +175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior\n\ +180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla\n\ +185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter\n\ +189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute\n\ +194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla\n\ +200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute\n\ +206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute\n\ +212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash\n\ +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn\n\ +223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde\n\ +228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute\n\ +234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex\n\ +239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex\n\ +245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute\n\ +251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis\n\ +] def\n\ +"}; + +static char change_font[] = {"\ +% change fonts using ISO Latin1 characters\n\ +/ChgFnt % size psname natname => font\n\ +{\n\ + dup FontDirectory exch known % is re-encoded name known?\n\ + { exch pop } % yes, get rid of long name\n\ + { dup 3 1 roll ReEncode } ifelse % no, re-encode it\n\ + findfont exch scalefont setfont\n\ +} def\n\ +"}; + +static char re_encode[] = {"\ +/ReEncode %\n\ +{\n\ + 12 dict begin\n\ + /newname exch def\n\ + /basename exch def\n\ + /basedict basename findfont def\n\ + /newfont basedict maxlength dict def\n\ + basedict\n\ + { exch dup /FID ne\n\ + { dup /Encoding eq\n\ + { exch dup length array copy newfont 3 1 roll put }\n\ + { exch newfont 3 1 roll put } ifelse\n\ + }\n\ + { pop pop } ifelse\n\ + } forall\n\ + newfont /FontName newname put\n\ + newcodes aload pop newcodes length 2 idiv\n\ + { newfont /Encoding get 3 1 roll put } repeat\n\ + newname newfont definefont pop\n\ + end\n\ +} def\n\ +"}; + +static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + fprintf(ctxcanvas->file, "initclip\n"); + + /* cliping geral para a margem */ + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C\n"); + fprintf(ctxcanvas->file, "clip\n"); + fprintf(ctxcanvas->file, "N\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g rectclip\n", xmin, ymin, xmax-xmin, ymax-ymin); +} + +static void set_default_matrix(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->eps) + fprintf(ctxcanvas->file, "oldmatrix setmatrix\n"); /* reset to current */ + else + { + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] defaultmatrix\n"); /* reset to default */ + fprintf(ctxcanvas->file, "setmatrix\n"); + } + + /* margin and scale */ + fprintf(ctxcanvas->file, "%g %g translate\n", ctxcanvas->xmin, ctxcanvas->ymin); + fprintf(ctxcanvas->file, "%g %g scale\n", ctxcanvas->scale, ctxcanvas->scale); +} + +/* +%F Inicializa o arquivo PS. +*/ +static void init_ps(cdCtxCanvas *ctxcanvas) +{ + double w, h; + + time_t now = time(NULL); + + ctxcanvas->scale = 72.0/ctxcanvas->res; + ctxcanvas->xmin = mm2pt(ctxcanvas->xmin); + ctxcanvas->xmax = ctxcanvas->width - mm2pt(ctxcanvas->xmax); + ctxcanvas->ymin = mm2pt(ctxcanvas->ymin); + ctxcanvas->ymax = ctxcanvas->height - mm2pt(ctxcanvas->ymax); + ctxcanvas->bbmargin = mm2pt(ctxcanvas->bbmargin); + + fprintf(ctxcanvas->file, "%%!PS-Adobe-3.0 %s\n", ctxcanvas->eps ? "EPSF-3.0":""); + fprintf(ctxcanvas->file, "%%%%Title: CanvasDraw\n"); + fprintf(ctxcanvas->file, "%%%%Creator: CanvasDraw\n"); + fprintf(ctxcanvas->file, "%%%%CreationDate: %s", asctime(localtime(&now))); + fprintf(ctxcanvas->file, "%%%%DocumentFonts: (atend)\n"); /* attend means at the end of the file, */ + fprintf(ctxcanvas->file, "%%%%Pages: (atend)\n"); /* see killcanvas */ + fprintf(ctxcanvas->file, "%%%%PageOrder: Ascend\n"); + fprintf(ctxcanvas->file, "%%%%LanguageLevel: %d\n", ctxcanvas->level1 ? 1: 2); + fprintf(ctxcanvas->file, "%%%%Orientation: %s\n", ctxcanvas->landscape ? "Landscape": "Portrait"); + + if (ctxcanvas->eps) + { + fprintf(ctxcanvas->file, "%%%%BoundingBox: (atend)\n"); + ctxcanvas->bbxmin = ctxcanvas->bbxmax = ctxcanvas->bbymin = ctxcanvas->bbymax = 0; + /* BoundingBox==Empty */ + } + + fprintf(ctxcanvas->file, "%%%%EndComments\n"); + fprintf(ctxcanvas->file, "%%%%BeginProlog\n"); + + fprintf(ctxcanvas->file, "/N {newpath} bind def\n"); + fprintf(ctxcanvas->file, "/C {closepath} bind def\n"); + fprintf(ctxcanvas->file, "/M {moveto} bind def\n"); + fprintf(ctxcanvas->file, "/L {lineto} bind def\n"); + fprintf(ctxcanvas->file, "/B {curveto} bind def\n"); + fprintf(ctxcanvas->file, "/S {stroke} bind def\n"); + fprintf(ctxcanvas->file, "/LL {moveto lineto stroke} bind def\n"); + + if (!ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "/RF {rectfill} bind def\n"); + fprintf(ctxcanvas->file, "/RS {rectstroke} bind def\n"); + } + + fprintf(ctxcanvas->file, "%%%%EndProlog\n"); + fprintf(ctxcanvas->file, "%%%%BeginSetup\n"); + + if (!ctxcanvas->eps && !ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "%%%%IncludeFeature: *Resolution %d\n", ctxcanvas->res); + fprintf(ctxcanvas->file, "%%%%BeginFeature: *PageSize\n"); + fprintf(ctxcanvas->file, "<< /PageSize [%g %g] >> setpagedevice\n", ctxcanvas->width, ctxcanvas->height); /* setpagedevice not allowed in EPS */ + fprintf(ctxcanvas->file, "%%%%EndFeature\n"); + } + + fprintf(ctxcanvas->file, "%%%%EndSetup\n"); + + fputs(new_codes, ctxcanvas->file); + fputs(change_font, ctxcanvas->file); + fputs(re_encode, ctxcanvas->file); + + w = ctxcanvas->xmax - ctxcanvas->xmin; + h = ctxcanvas->ymax - ctxcanvas->ymin; + + ctxcanvas->canvas->w = (int)(w/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->h = (int)(h/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->w_mm = w/CD_MM2PT; /* Converte p/ milimetros */ + ctxcanvas->canvas->h_mm = h/CD_MM2PT; /* Converte p/ milimetros */ + ctxcanvas->canvas->bpp = 24; + ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm; + ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm; + + fprintf(ctxcanvas->file, "%%%%Page: 1 1\n"); + ctxcanvas->pages = 1; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdCreateCanvas: Margin Begin\n"); + + if (ctxcanvas->eps) + fprintf(ctxcanvas->file, "/oldmatrix [0 0 0 0 0 0] currentmatrix def\n"); /* save current matrix */ + + set_default_matrix(ctxcanvas); + + /* cliping geral para a margem */ + setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdCreateCanvas: MarginEnd\n"); +} + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + int i; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdKillCanvas\n"); + + fprintf(ctxcanvas->file, "showpage\n"); + fprintf(ctxcanvas->file, "%%%%Trailer\n"); + fprintf(ctxcanvas->file, "%%%%Pages: %d 1\n", ctxcanvas->pages); + + if (ctxcanvas->eps) + { + int xmin = (int)ctxcanvas->bbxmin; + int xmax = (int)ctxcanvas->bbxmax; + int ymin = (int)ctxcanvas->bbymin; + int ymax = (int)ctxcanvas->bbymax; + if (xmax < ctxcanvas->bbxmax) xmax++; + if (ymax < ctxcanvas->bbymax) ymax++; + fprintf(ctxcanvas->file,"%%%%BoundingBox: %5d %5d %5d %5d\n",xmin,ymin,xmax,ymax); + } + + fprintf(ctxcanvas->file, "%%%%DocumentFonts:"); + + for (i = 0; i < ctxcanvas->num_native_font; i++) + { + fprintf(ctxcanvas->file, " %s", ctxcanvas->nativefontname[i]); + free(ctxcanvas->nativefontname[i]); + } + + putc('\n', ctxcanvas->file); + fprintf(ctxcanvas->file,"%%%%EOF"); + + fclose(ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style); +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple); +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern); + +static void update_fill(cdCtxCanvas *ctxcanvas, int fill) +{ + if (fill == 0) + { + /* called before a NON filled primitive */ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill); + + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground)); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill); + } + else + { + /* called before a filled primitive */ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill); + + if (ctxcanvas->canvas->interior_style == CD_SOLID) + { + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground)); + } + else if (!ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "cd_pattern\n"); + fprintf(ctxcanvas->file, "setpattern\n"); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill); + } +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdFlush Begin\n"); + + if (!ctxcanvas->eps) + { + fprintf(ctxcanvas->file, "gsave\n"); + + fprintf(ctxcanvas->file, "showpage\n"); + ctxcanvas->pages++; + fprintf(ctxcanvas->file, "%%%%Page: %d %d\n", ctxcanvas->pages, ctxcanvas->pages); + + fprintf(ctxcanvas->file, "grestore\n"); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdFlushEnd\n"); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfClipArea Begin\n"); + + setcliprect(ctxcanvas, xmin, ymin, xmax, ymax); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfClipAreaEnd\n"); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdClip %d Begin\n", mode); + + if (mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_mode = CD_CLIPAREA; + + setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin, + (double)ctxcanvas->canvas->clip_rect.ymin, + (double)ctxcanvas->canvas->clip_rect.xmax, + (double)ctxcanvas->canvas->clip_rect.ymax); + } + else if (mode == CD_CLIPPOLYGON) + { + fprintf(ctxcanvas->file, "clip_polygon\n"); + } + else + { + /* margin clipping only */ + setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdClip %dEnd\n", mode); + + return mode; +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + update_fill(ctxcanvas, 0); + + fprintf(ctxcanvas->file, "N %d %d %d %d LL\n", x1, y1, x2, y2); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x1, y1); + bbox(ctxcanvas, x2, y2); + } +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + update_fill(ctxcanvas, 0); + + fprintf(ctxcanvas->file, "N %g %g %g %g LL\n", x1, y1, x2, y2); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, x1, y1); + fbbox(ctxcanvas, x2, y2); + } +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + update_fill(ctxcanvas, 0); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C S\n"); + } + else + fprintf(ctxcanvas->file, "%d %d %d %d RS\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 0); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C S\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g RS\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, xmin, ymin); + fbbox(ctxcanvas, xmax, ymax); + } +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + update_fill(ctxcanvas, 1); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%d %d %d %d RF\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 1); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g RF\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, xmin, ymin); + fbbox(ctxcanvas, xmax, ymax); + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) /* Circulo: PS implementa direto */ + { + fprintf(ctxcanvas->file, "N %d %d %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdArc Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); /* fill new matrix from CTM */ + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "S\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); /* back to CTM */ + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdArc EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) /* Circulo: PS implementa direto */ + { + fprintf(ctxcanvas->file, "N %g %g %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfArc Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "S\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfArc EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xc, yc); + fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 M\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + bbox(ctxcanvas, xc, yc); + } +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xc, yc); + fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 M\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + fbbox(ctxcanvas, xc, yc); + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix); + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + int i, length; + int ascent, height, baseline; + + update_fill(ctxcanvas, 0); + + cdCanvasGetFontDim(ctxcanvas->canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdText Begin\n"); + + if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle) + set_default_matrix(ctxcanvas); + + fprintf(ctxcanvas->file, "N 0 0 M\n"); + putc('(', ctxcanvas->file); + + for (length = (int)strlen(s), i=0; ifile); + putc(s[i], ctxcanvas->file); + } + + fprintf(ctxcanvas->file, ")\n"); + fprintf(ctxcanvas->file, "dup true charpath\n"); + fprintf(ctxcanvas->file, "flattenpath\n"); + fprintf(ctxcanvas->file, "pathbbox\n"); /* bbox na pilha: llx lly urx ury */ + fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: llx lly ury urx */ + fprintf(ctxcanvas->file, "4 1 roll\n"); /* roda: urx llx lly ury */ + fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: urx llx ury lly */ + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: urx llx h */ + fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: h urx llx */ + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: h w */ + fprintf(ctxcanvas->file, "0 0\n"); /* empilha: h w 0 0 */ + fprintf(ctxcanvas->file, "4 -1 roll\n"); /* roda: w 0 0 h */ + + if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle) + cdtransform(ctxcanvas, ctxcanvas->canvas->use_matrix? ctxcanvas->canvas->matrix: NULL); + + fprintf(ctxcanvas->file, "gsave\n"); /* save to use local transform */ + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + + if (ctxcanvas->canvas->text_orientation != 0) + fprintf(ctxcanvas->file, "%g rotate\n", ctxcanvas->canvas->text_orientation); + + switch (ctxcanvas->canvas->text_alignment) /* Operacao em Y. topo da pilha: w x y h */ + { + case CD_NORTH: + case CD_NORTH_EAST: + case CD_NORTH_WEST: + fprintf(ctxcanvas->file, "%d sub sub\n", baseline); /* empilha, subtrai, subtrai: w x y-(h-baseline) */ + break; + case CD_EAST: + case CD_WEST: + case CD_CENTER: + fprintf(ctxcanvas->file, "2 div %d sub sub\n", baseline); /* empilha, divide, empilha, subtrai, subtrai: w x y-(h/2-baseline) */ + break; + case CD_SOUTH_EAST: + case CD_SOUTH: + case CD_SOUTH_WEST: + fprintf(ctxcanvas->file, "pop %d add\n", baseline); /* desempilha, empilha, adiciona: w x y+baseline */ + break; + case CD_BASE_RIGHT: + case CD_BASE_CENTER: + case CD_BASE_LEFT: + fprintf(ctxcanvas->file, "pop\n"); /* desempilha h: w x y */ + break; + } + + fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: y' w x */ + fprintf(ctxcanvas->file, "exch\n"); /* inverte: y' x w */ + + switch (ctxcanvas->canvas->text_alignment) /* Operacao em X, topo da pilha: x w */ + { + case CD_NORTH: + case CD_SOUTH: + case CD_CENTER: + case CD_BASE_CENTER: + fprintf(ctxcanvas->file, "2 div sub\n"); /* empilha, divide, subtrai: y' x-w/2 */ + break; + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + case CD_BASE_RIGHT: + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: y' x-w */ + break; + case CD_SOUTH_WEST: + case CD_WEST: + case CD_NORTH_WEST: + case CD_BASE_LEFT: + fprintf(ctxcanvas->file, "pop\n"); /* desempilha: y' x */ + break; + } + + fprintf(ctxcanvas->file, "exch\n"); /* inverte: x' y' */ + fprintf(ctxcanvas->file, "M\n"); /* moveto */ + + fprintf(ctxcanvas->file, "show\n"); + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetTextBox(ctxcanvas->canvas, x, y, s, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } + + fprintf(ctxcanvas->file, "grestore\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdTextEnd\n"); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + { + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode); + + fprintf(ctxcanvas->file, "/clip_polygon {\n"); + fprintf(ctxcanvas->file, "initclip\n"); + } + else + { + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode); + } + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", poly[0].x, poly[0].y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; ifile, "%d %d %d %d %d %d B\n", poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, poly[i].x, poly[i].y); + bbox(ctxcanvas, poly[i+2].x, poly[i+2].y); + bbox(ctxcanvas, poly[i+3].x, poly[i+3].y); + } + } + } + else + { + int hole_index = 0; + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + fprintf(ctxcanvas->file, "%d %d M\n", poly[i].x, poly[i].y); + hole_index++; + } + else + fprintf(ctxcanvas->file, "%d %d L\n", poly[i].x, poly[i].y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + fprintf(ctxcanvas->file, "C S\n"); + break; + case CD_OPEN_LINES : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_BEZIER : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_FILL : + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "eofill\n"); + else + fprintf(ctxcanvas->file, "fill\n"); + break; + case CD_CLIP : + if (ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "C eoclip\n"); + else + fprintf(ctxcanvas->file, "C clip\n"); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "} bind def\n"); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + fprintf(ctxcanvas->file, "clip_polygon\n"); + break; + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPoly %dEnd\n", mode); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i, hole_index = 0; + + if (mode == CD_CLIP) + { + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode); + + fprintf(ctxcanvas->file, "/clip_polygon {\n"); + fprintf(ctxcanvas->file, "initclip\n"); + } + else + { + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode); + } + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", poly[0].x, poly[0].y); + + if (ctxcanvas->eps) + fbbox(ctxcanvas, poly[0].x, poly[0].y); + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + fprintf(ctxcanvas->file, "%g %g M\n", poly[i].x, poly[i].y); + hole_index++; + } + else + fprintf(ctxcanvas->file, "%g %g L\n", poly[i].x, poly[i].y); + + if (ctxcanvas->eps) + fbbox(ctxcanvas, poly[i].x, poly[i].y); + } + + switch (mode) + { + case CD_CLOSED_LINES : + fprintf(ctxcanvas->file, "C S\n"); + break; + case CD_OPEN_LINES : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_FILL : + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "eofill\n"); + else + fprintf(ctxcanvas->file, "fill\n"); + break; + case CD_CLIP : + if (ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "C eoclip\n"); + else + fprintf(ctxcanvas->file, "C clip\n"); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "} bind def\n"); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + fprintf(ctxcanvas->file, "clip_polygon\n"); + break; + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfPoly %dEnd\n", mode); +} + + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + double mm = (72.0/25.4) / ctxcanvas->scale; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdLineStyle %d Begin\n", style); + + fprintf(ctxcanvas->file, "["); + + switch (style) + { + case CD_CONTINUOUS : /* empty dash */ + fprintf(ctxcanvas->file, " "); + break; + case CD_DASHED : + fprintf(ctxcanvas->file, "%g %g", 3*mm, mm); + break; + case CD_DOTTED : + fprintf(ctxcanvas->file, "%g %g", mm, mm); + break; + case CD_DASH_DOT : + fprintf(ctxcanvas->file, "%g %g %g %g", 3*mm, mm, mm, mm); + break; + case CD_DASH_DOT_DOT : + fprintf(ctxcanvas->file, "%g %g %g %g %g %g", 3*mm, mm, mm, mm, mm, mm); + break; + case CD_CUSTOM : + { + int i; + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, "%g ", ctxcanvas->canvas->line_dashes[i]*mm); + } + break; + } + + fprintf(ctxcanvas->file, "] 0 setdash\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdLineStyle %dEnd\n", style); + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%d setlinewidth\n", width); + return width; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2ps_join[] = {0, 2, 1}; + fprintf(ctxcanvas->file, "%d setlinejoin\n", cd2ps_join[join]); + return join; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2ps_cap[] = {0, 2, 1}; + fprintf(ctxcanvas->file, "%d setlinecap\n", cd2ps_cap[cap]); + return cap; +} + +static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, void (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)) +{ + int i, j; + unsigned char r, g, b; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsMakePattern Begin\n"); + + fprintf(ctxcanvas->file, "/cd_pattern\n"); + fprintf(ctxcanvas->file, "currentfile %d string readhexstring\n", n*m*3); + + for (j=0; jfile, "%02x%02x%02x", (int)r, (int)g, (int)b); + } + + fprintf(ctxcanvas->file, "\n"); + } + + fprintf(ctxcanvas->file, "pop\n"); + fprintf(ctxcanvas->file, "/Pat exch def\n"); + fprintf(ctxcanvas->file, "<<\n"); + fprintf(ctxcanvas->file, " /PatternType 1\n"); + fprintf(ctxcanvas->file, " /PaintType 1\n"); + fprintf(ctxcanvas->file, " /TilingType 1\n"); + fprintf(ctxcanvas->file, " /BBox [0 0 %d %d]\n", n, m); + fprintf(ctxcanvas->file, " /XStep %d /YStep %d\n", n, m); + fprintf(ctxcanvas->file, " /PaintProc {\n"); + fprintf(ctxcanvas->file, " pop\n"); + fprintf(ctxcanvas->file, " %d %d 8\n", n, m); + fprintf(ctxcanvas->file, " matrix\n"); + fprintf(ctxcanvas->file, " Pat\n"); + fprintf(ctxcanvas->file, " false 3\n"); + fprintf(ctxcanvas->file, " colorimage\n"); + fprintf(ctxcanvas->file, " }\n"); + fprintf(ctxcanvas->file, ">>\n"); + fprintf(ctxcanvas->file, "matrix\n"); + fprintf(ctxcanvas->file, "makepattern\n"); + fprintf(ctxcanvas->file, "def\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsMakePatternEnd\n"); +} + +static void long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + long* long_data = (long*)data; + (void)ctxcanvas; + cdDecodeColor(long_data[j*n+i], r, g, b); +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + if (ctxcanvas->level1) + return; + + make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); +} + +static void uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + unsigned char* uchar_data = (unsigned char*)data; + if (uchar_data[j*n+i]) + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + if (ctxcanvas->level1) + return; + + make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); +} + +static void ucharh2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + unsigned char* uchar_data = (unsigned char*)data; + static unsigned char hatch; + (void)n; + if (i == 0) hatch = uchar_data[j]; + if (hatch & 0x80) + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); + _cdRotateHatch(hatch); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + if (ctxcanvas->level1) + return ctxcanvas->canvas->hatch_style; + + make_pattern(ctxcanvas, 8, 8, (void*)HatchBits[style], ucharh2rgb); + + return style; +} + +static void add_font_name(cdCtxCanvas *ctxcanvas, char *nativefontname) +{ + int size, i; + for (i = 0; i < ctxcanvas->num_native_font; i++) + { + if (cdStrEqualNoCase(ctxcanvas->nativefontname[i], nativefontname)) + return; + } + + size = strlen(nativefontname)+1; + ctxcanvas->nativefontname[ctxcanvas->num_native_font] = (char*)malloc(size); + memcpy(ctxcanvas->nativefontname[ctxcanvas->num_native_font], nativefontname, size); + ctxcanvas->num_native_font++; +} + +static char *findfont(const char* type_face, int style) +{ + static char font[1024]; + + static char *type[] = + { + "", /* CD_PLAIN */ + "-Bold", /* CD_BOLD */ + "-Oblique", /* CD_ITALIC */ + "-BoldOblique", /* CD_BOLD_ITALIC */ + + "-Roman", /* Plain p/ Times */ + "-Bold", /* Bold p/ Times */ + "-Italic", /* Italic p/ Times */ + "-BoldItalic" /* BoldItalic p/ Times */ + }; + + if (cdStrEqualNoCase(type_face, "System")) + type_face = "Courier"; + + if (cdStrEqualNoCase(type_face, "Times")) + style += 4; + + sprintf(font, "%s%s", type_face, type[style]); + + return font; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + char *nativefontname = findfont(type_face, style&3); /* no underline or strikeout support */ + int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + fprintf(ctxcanvas->file, "%d /%s /%s-Latin1 ChgFnt\n", size_pixel, nativefontname, nativefontname); + add_font_name(ctxcanvas, nativefontname); + return 1; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + set_default_matrix(ctxcanvas); + + if (matrix) + { + fprintf(ctxcanvas->file, "[%g %g %g %g %g %g] concat\n", matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + else + { + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle); + fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + } +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, rw, rh; + rw = xmax-xmin+1; + rh = ymax-ymin+1; + (void)ih; + + if (ctxcanvas->level1) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGB Start\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + fprintf(ctxcanvas->file, "%d %d scale\n", w, h); + + fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh); + fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh); + fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw); + fprintf(ctxcanvas->file, "false 3\n"); + fprintf(ctxcanvas->file, "colorimage\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r[pos], (int)g[pos], (int)b[pos]); + } + + fprintf(ctxcanvas->file, "\n"); + } + + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x, y); + bbox(ctxcanvas, x+rw-1, y+rh-1); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGBEnd\n"); +} + +static int isgray(int size, const unsigned char *index, const long int *colors) +{ + int i, pal_size = 0; + unsigned char r, g, b; + + for (i = 0; i < size; i++) + { + if (index[i] > pal_size) + pal_size = index[i]; + } + + pal_size++; + + for (i = 0; i < pal_size; i++) + { + cdDecodeColor(colors[i], &r, &g, &b); + + if (i != r || r != g || g != b) + return 0; + } + + return 1; +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, rw, rh, is_gray; + rw = xmax-xmin+1; + rh = ymax-ymin+1; + (void)ih; + + is_gray = isgray(iw*ih, index, colors); + + if (!is_gray && ctxcanvas->level1) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMap Start\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + fprintf(ctxcanvas->file, "%d %d scale\n", w, h); + + fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh); + fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh); + fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw); + + if (is_gray) + { + fprintf(ctxcanvas->file, "image\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + fprintf(ctxcanvas->file, "%02x", (int)index[pos]); + } + + fprintf(ctxcanvas->file, "\n"); + } + } + else + { + fprintf(ctxcanvas->file, "false 3\n"); + fprintf(ctxcanvas->file, "colorimage\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + unsigned char r, g, b; + cdDecodeColor(colors[index[pos]], &r, &g, &b); + fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r, (int)g, (int)b); + } + + fprintf(ctxcanvas->file, "\n"); + } + } + + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x, y); + bbox(ctxcanvas, x+rw-1, y+rh-1); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMapEnd\n"); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixel Start\n"); + + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", + get_red(color), get_green(color), get_blue(color)); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d 1 0 360 arc\n", x, y); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%d %d 1 1 RF\n", x, y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, x, y); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixelEnd\n"); +} + +/******************************************************/ +/* custom attributes */ +/******************************************************/ + +static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + set_default_matrix(ctxcanvas); + + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle); + fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_cmd_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + fprintf(ctxcanvas->file, data); +} + +static cdAttribute cmd_attrib = +{ + "CMD", + set_cmd_attrib, + NULL +}; + +static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hole; + + if (data == NULL) + { + ctxcanvas->holes = 0; + return; + } + + sscanf(data, "%d", &hole); + ctxcanvas->poly_holes[ctxcanvas->holes] = hole; + ctxcanvas->holes++; +} + +static char* get_poly_attrib(cdCtxCanvas *ctxcanvas) +{ + static char holes[10]; + sprintf(holes, "%d", ctxcanvas->holes); + return holes; +} + +static cdAttribute poly_attrib = +{ + "POLYHOLE", + set_poly_attrib, + get_poly_attrib +}; + +/* +%F Cria um novo canvas PS +Parametros passados em data: +nome nome do arquivo de saida <= 255 caracteres +-p[num] tamanho do papel (A0-5, LETTER, LEGAL) +-w[num] largura do papel em milimetros +-h[num] altura do papel em milimetros +-l[num] margem esquerda em milimetros +-r[num] margem direita em milimetros +-b[num] margem inferior em milimetros +-t[num] margem superior em milimetros +-s[num] resolucao em dpi +-e encapsulated postscript +-1 level 1 operators only +-d[num] margem da bbox em milimetros para eps +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *line = (char *)data; + cdCtxCanvas *ctxcanvas; + char filename[10240] = ""; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + if ((ctxcanvas->file = fopen(filename, "w")) == NULL) + { + free(ctxcanvas); + return; + } + + ctxcanvas->holes = 0; + cdRegisterAttribute(canvas, &poly_attrib); + cdRegisterAttribute(canvas, &cmd_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + + setpsdefaultvalues(ctxcanvas); + + while (*line != '\0') + { + while (*line != '\0' && *line != '-') + line++; + + if (*line != '\0') + { + float num; + line++; + switch (*line++) + { + case 'p': + { + int paper; + sscanf(line, "%d", &paper); + setpspapersize(ctxcanvas, paper); + break; + } + case 'w': + sscanf(line, "%g", &num); + ctxcanvas->width = mm2pt(num); + break; + case 'h': + sscanf(line, "%g", &num); + ctxcanvas->height = mm2pt(num); + break; + case 'l': + sscanf(line, "%g", &num); + ctxcanvas->xmin = num; + break; + case 'r': + sscanf(line, "%g", &num); + ctxcanvas->xmax = num; /* right margin, must be converted to xmax */ + break; + case 'b': + sscanf(line, "%g", &num); + ctxcanvas->ymin = num; + break; + case 't': + sscanf(line, "%g", &num); + ctxcanvas->ymax = num; /* top margin, must be converted to ymax */ + break; + case 's': + sscanf(line, "%d", &(ctxcanvas->res)); + break; + case 'e': + ctxcanvas->eps = 1; + break; + case 'o': + ctxcanvas->landscape = 1; + break; + case '1': + ctxcanvas->level1 = 1; + break; + case 'g': + ctxcanvas->debug = 1; + break; + case 'd': + sscanf(line, "%g", &num); + ctxcanvas->bbmargin = num; + break; + } + } + + while (*line != '\0' && *line != ' ') + line++; + } + + /* store the base canvas */ + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->ctxcanvas = ctxcanvas; + + if (ctxcanvas->landscape == 1) + { + _cdSwapDouble(ctxcanvas->width, ctxcanvas->height); + _cdSwapDouble(ctxcanvas->xmin, ctxcanvas->ymin); + _cdSwapDouble(ctxcanvas->xmax, ctxcanvas->ymax); + } + + init_ps(ctxcanvas); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxClip = cdclip; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxPattern = cdpattern; + canvas->cxStipple = cdstipple; + canvas->cxHatch = cdhatch; + canvas->cxFont = cdfont; + canvas->cxTransform = cdtransform; + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +static cdContext cdPSContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_REGION | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_FONTDIM | CD_CAP_TEXTSIZE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextPS(void) +{ + return &cdPSContext; +} diff --git a/src/drv/cgm.c b/src/drv/cgm.c new file mode 100644 index 0000000..55461cb --- /dev/null +++ b/src/drv/cgm.c @@ -0,0 +1,2281 @@ +/** \file + * \brief CGM library + * Extracted from GKS/PUC + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include + +#include +#include + +#include "cgm.h" + + +struct _cgmFunc +{ + /* write command header */ + void (*wch)( CGM *, int, int, int ); + + /* put colour index at colour index precision */ + void (*ci)( CGM *, unsigned long ); + + /* put color direct at colour direct precision */ + void (*cd)( CGM *, double ); + + /* put color direct at colour direct precision */ + void (*rgb)( CGM *, double, double, double ); + + /* put index at index precision */ + void (*ix)( CGM *, long ); + + /* put enum ( int*2 ) */ + void (*e)( CGM *, int, const char *l[] ); + + /* put int ( integer precision ) */ + void (*i)( CGM *, long ); + + /* put unsigned int ( integer precision ) */ + void (*u)( CGM *, unsigned long ); + + /* put real ( real precision ) */ + void (*r)( CGM *, double ); + + /* put string */ + void (*s)( CGM *, const char * ); + + /* put VDC at VDC mode and precision */ + void (*vdc)( CGM *, double ); + + /* put point at VDC mode and precision */ + void (*p)( CGM *, double, double ); + + /* put colour at colour mode and precision */ + void (*co)( CGM *, const void * ); + + /* put separator */ + void (*sep)( CGM *, const char * ); + + /* get column position */ + int (*get_col)( CGM * ); + + /* align at column number */ + void (*align)( CGM *, int ); + + /* nova linha */ + void (*nl)( CGM * ); + + /* terminate element */ + int (*term)( CGM * ); +}; + +typedef struct _cgmCommand +{ + const char *ct; + const char *c; +} cgmCommand; + +/************************************************ +* * +* Dados para nao-binario * +* * +************************************************/ + +/* delimiter elements */ + +static const cgmCommand _cgmX_NULL = { "" , "" }; +static const cgmCommand _cgmX_BEGMF = { "BEGMF" , "\x30\x20" }; +static const cgmCommand _cgmX_ENDMF = { "ENDMF" , "\x30\x21" }; +static const cgmCommand _cgmX_BEG_PIC = { "BEG_PIC" , "\x30\x22" }; +static const cgmCommand _cgmX_BEG_PIC_BODY = { "BEG_PIC_BODY" , "\x30\x23" }; +static const cgmCommand _cgmX_END_PIC = { "END_PIC" , "\x30\x24" }; + +/* metafile descriptor elements */ + +static const cgmCommand _cgmX_MF_VERSION = { "MF_VERSION" , "\x31\x20" }; +static const cgmCommand _cgmX_MF_DESC = { "MF_DESC" , "\x31\x21" }; +static const cgmCommand _cgmX_VDC_TYPE = { "VDC_TYPE" , "\x31\x22" }; +static const cgmCommand _cgmX_INTEGER_PREC = { "INTEGER_PREC" , "\x31\x23" }; +static const cgmCommand _cgmX_REAL_PREC = { "REAL_PREC" , "\x31\x24" }; +static const cgmCommand _cgmX_INDEX_PREC = { "INDEX_PREC" , "\x31\x25" }; +static const cgmCommand _cgmX_COLR_PREC = { "COLR_PREC" , "\x31\x26" }; +static const cgmCommand _cgmX_COLR_INDEX_PREC = { "COLR_INDEX_PREC" , "\x31\x27" }; +static const cgmCommand _cgmX_MAX_COLR_INDEX = { "MAX_COLR_INDEX" , "\x31\x28" }; +static const cgmCommand _cgmX_COLR_VALUE_EXT = { "COLR_VALUE_EXT" , "\x31\x29" }; +static const cgmCommand _cgmX_MF_ELEM_LIST = { "MF_ELEM_LIST" , "\x31\x2a" }; +static const cgmCommand _cgmX_BEG_MF_DEFAULTS = { "BEG_MF_DEFAULTS" , "\x31\x2b" }; +static const cgmCommand _cgmX_END_MF_DEFAULTS = { "END_MF_DEFAULTS" , "\x31\x2c" }; +static const cgmCommand _cgmX_FONT_LIST = { "FONT_LIST" , "\x31\x2d" }; +static const cgmCommand _cgmX_CHAR_SET_LIST = { "CHAR_SET_LIST" , "\x31\x2e" }; +static const cgmCommand _cgmX_CHAR_CODING = { "CHAR_CODING" , "\x31\x2f" }; + +/* picture descriptor elements */ + +static const cgmCommand _cgmX_SCALE_MODE = { "SCALE_MODE" , "\x30\x20" }; +static const cgmCommand _cgmX_COLR_MODE = { "COLR_MODE" , "\x30\x21" }; +static const cgmCommand _cgmX_LINE_WIDTH_MODE = { "LINE_WIDTH_MODE" , "\x30\x22" }; +static const cgmCommand _cgmX_MARKER_SIZE_MODE = { "MARKER_SIZE_MODE" , "\x30\x23" }; +static const cgmCommand _cgmX_EDGE_WIDTH_MODE = { "EDGE_WIDTH_MODE" , "\x30\x24" }; +static const cgmCommand _cgmX_VDC_EXTENT = { "VDC_EXT" , "\x30\x25" }; +static const cgmCommand _cgmX_BACK_COLR = { "BACK_COLR" , "\x30\x26" }; + +/* control elements */ + +static const cgmCommand _cgmX_VDC_INTEGER_PREC = { "VDC_INTEGER_PREC" , "\x30\x20" }; +static const cgmCommand _cgmX_VDC_REAL_PREC = { "VDC_REAL_PREC" , "\x30\x21" }; +static const cgmCommand _cgmX_AUX_COLR = { "AUX_COLR" , "\x30\x22" }; +static const cgmCommand _cgmX_TRANSPARENCY = { "TRANSPARENCY" , "\x30\x23" }; +static const cgmCommand _cgmX_CLIP_RECT = { "CLIP_RECT" , "\x30\x24" }; +static const cgmCommand _cgmX_CLIP = { "CLIP" , "\x30\x25" }; + +/* primitive elements */ + +static const cgmCommand _cgmX_LINE = { "LINE" , "\x20" }; +static const cgmCommand _cgmX_DISJT_LINE = { "DISJT_LINE" , "\x21" }; +static const cgmCommand _cgmX_MARKER = { "MARKER" , "\x22" }; +static const cgmCommand _cgmX_TEXT = { "TEXT" , "\x23" }; +static const cgmCommand _cgmX_RESTR_TEXT = { "RESTR_TEXT" , "\x24" }; +static const cgmCommand _cgmX_APND_TEXT = { "APND_TEXT" , "\x25" }; +static const cgmCommand _cgmX_POLYGON = { "POLYGON" , "\x26" }; +static const cgmCommand _cgmX_POLYGON_SET = { "POLYGON_SET" , "\x27" }; +static const cgmCommand _cgmX_CELL_ARRAY = { "CELL_ARRAY" , "\x28" }; +static const cgmCommand _cgmX_GDP = { "GDP" , "\x29" }; +static const cgmCommand _cgmX_RECT = { "RECT" , "\x2a" }; +static const cgmCommand _cgmX_CIRCLE = { "CIRCLE" , "\x34\x20" }; +static const cgmCommand _cgmX_ARC_3_PT = { "ARC_3_PT" , "\x34\x21" }; +static const cgmCommand _cgmX_ARC_3_PT_CLOSE = { "ARC_3_PT_CLOSE" , "\x34\x22" }; +static const cgmCommand _cgmX_ARC_CTR = { "ARC_CTR" , "\x34\x23" }; +static const cgmCommand _cgmX_ARC_CTR_CLOSE = { "ARC_CTR_CLOSE" , "\x34\x24" }; +static const cgmCommand _cgmX_ELLIPSE = { "ELLIPSE" , "\x34\x25" }; +static const cgmCommand _cgmX_ELLIP_ARC = { "ELLIP_ARC" , "\x34\x26" }; +static const cgmCommand _cgmX_ELLIP_ARC_CLOSE = { "ELLIP_ARC_CLOSE" , "\x34\x27" }; + +/* attribute elements */ + +static const cgmCommand _cgmX_LINE_INDEX = { "LINE_INDEX" , "\x35\x20" }; +static const cgmCommand _cgmX_LINE_TYPE = { "LINE_TYPE" , "\x35\x21" }; +static const cgmCommand _cgmX_LINE_WIDTH = { "LINE_WIDTH" , "\x35\x22" }; +static const cgmCommand _cgmX_LINE_COLR = { "LINE_COLR" , "\x35\x23" }; +static const cgmCommand _cgmX_MARKER_INDEX = { "MARKER_INDEX" , "\x35\x24" }; +static const cgmCommand _cgmX_MARKER_TYPE = { "MARKER_TYPE" , "\x35\x25" }; +static const cgmCommand _cgmX_MARKER_WIDTH = { "MARKER_SIZE" , "\x35\x26" }; +static const cgmCommand _cgmX_MARKER_COLR = { "MARKER_COLR" , "\x35\x27" }; +static const cgmCommand _cgmX_TEXT_INDEX = { "TEXT_INDEX" , "\x35\x30" }; +static const cgmCommand _cgmX_TEXT_FONT_INDEX = { "TEXT_FONT_INDEX" , "\x35\x31" }; +static const cgmCommand _cgmX_TEXT_PREC = { "TEXT_PREC" , "\x35\x32" }; +static const cgmCommand _cgmX_CHAR_EXPAN = { "CHAR_EXPAN" , "\x35\x33" }; +static const cgmCommand _cgmX_CHAR_SPACE = { "CHAR_SPACE" , "\x35\x34" }; +static const cgmCommand _cgmX_TEXT_COLR = { "TEXT_COLR" , "\x35\x35" }; +static const cgmCommand _cgmX_CHAR_HEIGHT = { "CHAR_HEIGHT" , "\x35\x36" }; +static const cgmCommand _cgmX_CHAR_ORI = { "CHAR_ORI" , "\x35\x37" }; +static const cgmCommand _cgmX_TEXT_PATH = { "TEXT_PATH" , "\x35\x38" }; +static const cgmCommand _cgmX_TEXT_ALIGN = { "TEXT_ALIGN" , "\x35\x39" }; +static const cgmCommand _cgmX_CHAR_SET_INDEX = { "CHAR_SET_INDEX" , "\x35\x3a" }; +static const cgmCommand _cgmX_ALT_CHAR_SET = { "ALT_CHAR_SET_INDEX" , "\x35\x3b" }; +static const cgmCommand _cgmX_FILL_INDEX = { "FILL_INDEX" , "\x36\x20" }; +static const cgmCommand _cgmX_INT_STYLE = { "INT_STYLE" , "\x36\x21" }; +static const cgmCommand _cgmX_FILL_COLR = { "FILL_COLR" , "\x36\x22" }; +static const cgmCommand _cgmX_HATCH_INDEX = { "HATCH_INDEX" , "\x36\x23" }; +static const cgmCommand _cgmX_PAT_INDEX = { "PAT_INDEX" , "\x36\x24" }; +static const cgmCommand _cgmX_EDGE_INDEX = { "EDGE_INDEX" , "\x36\x25" }; +static const cgmCommand _cgmX_EDGE_TYPE = { "EDGE_TYPE" , "\x36\x26" }; +static const cgmCommand _cgmX_EDGE_WIDTH = { "EDGE_WIDTH" , "\x36\x27" }; +static const cgmCommand _cgmX_EDGE_COLR = { "EDGE_COLR" , "\x36\x28" }; +static const cgmCommand _cgmX_EDGE_VIS = { "EDGE_VIS" , "\x36\x29" }; +static const cgmCommand _cgmX_FILL_REF_PT = { "FILL_REF_PT" , "\x36\x2a" }; +static const cgmCommand _cgmX_PAT_TABLE = { "PAT_TABLE" , "\x36\x2b" }; +static const cgmCommand _cgmX_PAT_SIZE = { "PAT_SIZE" , "\x36\x2c" }; +static const cgmCommand _cgmX_COLR_TABLE = { "COLR_TABLE" , "\x36\x30" }; +static const cgmCommand _cgmX_ASF = { "ASF" , "\x36\x31" }; + +/* escape elements */ + +static const cgmCommand _cgmX_ESCAPE = { "ESCAPE" , "\x37\x20" }; +static const cgmCommand _cgmX_DOMAIN_RING = { "DOMAIN_RING" , "\x37\x30" }; + +/* external elements */ + +static const cgmCommand _cgmX_MESSAGE = { "MESSAGE" , "\x37\x21" }; +static const cgmCommand _cgmX_APPL_DATA = { "APPL_DATA" , "\x37\x22" }; + +/* drawing sets */ +static const cgmCommand _cgmX_DRAWING_SET = { "drawing_set" , "\x40" }; +static const cgmCommand _cgmX_DRAWING_PLUS = { "drawing_plus" , "\x41" }; + +static const cgmCommand *_elements_list_sets[] = { + & _cgmX_DRAWING_SET, + & _cgmX_DRAWING_PLUS, + NULL }; + + +static const cgmCommand *delimiter[] = { + & _cgmX_NULL, + & _cgmX_BEGMF, + & _cgmX_ENDMF, + & _cgmX_BEG_PIC, + & _cgmX_BEG_PIC_BODY, + & _cgmX_END_PIC, + NULL }; + +static const cgmCommand *metafile[] = { + & _cgmX_END_MF_DEFAULTS, + & _cgmX_MF_VERSION, + & _cgmX_MF_DESC, + & _cgmX_VDC_TYPE, + & _cgmX_INTEGER_PREC, + & _cgmX_REAL_PREC, + & _cgmX_INDEX_PREC, + & _cgmX_COLR_PREC, + & _cgmX_COLR_INDEX_PREC, + & _cgmX_MAX_COLR_INDEX, + & _cgmX_COLR_VALUE_EXT, + & _cgmX_MF_ELEM_LIST, + & _cgmX_BEG_MF_DEFAULTS, + & _cgmX_FONT_LIST, + & _cgmX_CHAR_SET_LIST, + & _cgmX_CHAR_CODING, + NULL }; + +static const cgmCommand *picture[] = { + & _cgmX_NULL, + & _cgmX_SCALE_MODE, + & _cgmX_COLR_MODE, + & _cgmX_LINE_WIDTH_MODE, + & _cgmX_MARKER_SIZE_MODE, + & _cgmX_EDGE_WIDTH_MODE, + & _cgmX_VDC_EXTENT, + & _cgmX_BACK_COLR, + NULL }; + +static const cgmCommand *control[] = { + & _cgmX_NULL, + & _cgmX_VDC_INTEGER_PREC, + & _cgmX_VDC_REAL_PREC, + & _cgmX_AUX_COLR, + & _cgmX_TRANSPARENCY, + & _cgmX_CLIP_RECT, + & _cgmX_CLIP, + NULL }; + +static const cgmCommand *primitive[] = { + & _cgmX_NULL, + & _cgmX_LINE, + & _cgmX_DISJT_LINE, + & _cgmX_MARKER, + & _cgmX_TEXT, + & _cgmX_RESTR_TEXT, + & _cgmX_APND_TEXT, + & _cgmX_POLYGON, + & _cgmX_POLYGON_SET, + & _cgmX_CELL_ARRAY, + & _cgmX_GDP, + & _cgmX_RECT, + & _cgmX_CIRCLE, + & _cgmX_ARC_3_PT, + & _cgmX_ARC_3_PT_CLOSE, + & _cgmX_ARC_CTR, + & _cgmX_ARC_CTR_CLOSE, + & _cgmX_ELLIPSE, + & _cgmX_ELLIP_ARC, + & _cgmX_ELLIP_ARC_CLOSE, + NULL }; + +static const cgmCommand *attributes[] = { + & _cgmX_NULL, + & _cgmX_LINE_INDEX, + & _cgmX_LINE_TYPE, + & _cgmX_LINE_WIDTH, + & _cgmX_LINE_COLR, + & _cgmX_MARKER_INDEX, + & _cgmX_MARKER_TYPE, + & _cgmX_MARKER_WIDTH, + & _cgmX_MARKER_COLR, + & _cgmX_TEXT_INDEX, + & _cgmX_TEXT_FONT_INDEX, + & _cgmX_TEXT_PREC, + & _cgmX_CHAR_EXPAN, + & _cgmX_CHAR_SPACE, + & _cgmX_TEXT_COLR, + & _cgmX_CHAR_HEIGHT, + & _cgmX_CHAR_ORI, + & _cgmX_TEXT_PATH, + & _cgmX_TEXT_ALIGN, + & _cgmX_CHAR_SET_INDEX, + & _cgmX_ALT_CHAR_SET, + & _cgmX_FILL_INDEX, + & _cgmX_INT_STYLE, + & _cgmX_FILL_COLR, + & _cgmX_HATCH_INDEX, + & _cgmX_PAT_INDEX, + & _cgmX_EDGE_INDEX, + & _cgmX_EDGE_TYPE, + & _cgmX_EDGE_WIDTH, + & _cgmX_EDGE_COLR, + & _cgmX_EDGE_VIS, + & _cgmX_FILL_REF_PT, + & _cgmX_PAT_TABLE, + & _cgmX_PAT_SIZE, + & _cgmX_COLR_TABLE, + & _cgmX_ASF, + NULL }; + +static const cgmCommand *escape[] = { + & _cgmX_NULL, + & _cgmX_ESCAPE, + & _cgmX_DOMAIN_RING, + NULL }; + +static const cgmCommand *external[] = { + & _cgmX_NULL, + & _cgmX_MESSAGE, + & _cgmX_APPL_DATA, + NULL }; + +static const cgmCommand **comandos[] = { + _elements_list_sets, + delimiter, + metafile, + picture, + control, + primitive, + attributes, + escape, + external, + NULL }; + +#define unit (cgm->file) + +/************************************************ +* * +* listas de funcoes necessarias * +* * +************************************************/ + + +static void cgmb_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmb_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmb_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmb_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmb_ix ( CGM *, long ); /* put index at index precision */ +static void cgmb_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmb_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmb_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmb_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmb_s ( CGM *, const char * ); /* put string */ +static void cgmb_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmb_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmb_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmb_sep ( CGM *, const char * ); /* put separator */ +static int cgmb_get_col ( CGM * ); /* get column position */ +static void cgmb_align ( CGM *, int ); /* align at column number */ +static void cgmb_nl ( CGM * ); /* new line */ +static int cgmb_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_binary = { + cgmb_wch , + cgmb_ci , + cgmb_cd , + cgmb_rgb , + cgmb_ix , + cgmb_e , + cgmb_i , + cgmb_u , + cgmb_r , + cgmb_s , + cgmb_vdc , + cgmb_p , + cgmb_co , + cgmb_sep , + cgmb_get_col, + cgmb_align , + cgmb_nl , + cgmb_term + }; + +static void cgmt_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmt_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmt_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmt_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmt_ix ( CGM *, long ); /* put index at index precision */ +static void cgmt_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmt_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmt_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmt_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmt_s ( CGM *, const char * ); /* put string */ +static void cgmt_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmt_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmt_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmt_sep ( CGM *, const char * ); /* put separator */ +static int cgmt_get_col ( CGM * ); /* get column position */ +static void cgmt_align ( CGM *, int ); /* align at column number */ +static void cgmt_nl ( CGM * ); /* new line */ +static int cgmt_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_clear_text = { + cgmt_wch , + cgmt_ci , + cgmt_cd , + cgmt_rgb , + cgmt_ix , + cgmt_e , + cgmt_i , + cgmt_u , + cgmt_r , + cgmt_s , + cgmt_vdc , + cgmt_p , + cgmt_co , + cgmt_sep , + cgmt_get_col, + cgmt_align , + cgmt_nl , + cgmt_term + }; + +static void cgmc_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmc_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmc_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmc_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmc_ix ( CGM *, long ); /* put index at index precision */ +static void cgmc_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmc_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmc_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmc_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmc_s ( CGM *, const char * ); /* put string */ +static void cgmc_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmc_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmc_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmc_sep ( CGM *, const char * ); /* put separator */ +static int cgmc_get_col ( CGM * ); /* get column position */ +static void cgmc_align ( CGM *, int ); /* align at column number */ +static void cgmc_nl ( CGM * ); /* new line */ +static int cgmc_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_character = { + cgmc_wch , + cgmc_ci , + cgmc_cd , + cgmc_rgb , + cgmc_ix , + cgmc_e , + cgmc_i , + cgmc_u , + cgmc_r , + cgmc_s , + cgmc_vdc , + cgmc_p , + cgmc_co , + cgmc_sep , + cgmc_get_col, + cgmc_align , + cgmc_nl , + cgmc_term + }; + +static const CGMFUNC *cgmf[] = { &cgmf_character, &cgmf_binary, &cgmf_clear_text }; + +/************************************************ +* * +* Funcoes para binario * +* * +************************************************/ + +#define cgmb_putw cgmb_putu16 +#define cgmb_putb(a,b) cgmb_putc((a),(int)(b)) + +static void cgmb_putw ( CGM *, unsigned ); + +static void cgmb_putc ( CGM *cgm, int b ) +{ + if ( cgm->op != -1 ) + { + register int i; + for ( i=cgm->op; i>=0; i-- ) + { + if ( cgm->bc[i] == 32766 - 2*i ) + { + long po = ftell(unit); + int op = cgm->op; + + cgm->op = -1; + fseek(unit, cgm->po[i] , SEEK_SET); + cgmb_putw ( cgm, (1 << 15) | (cgm->bc[i]) ); + + cgm->op = i - 1; + fseek(unit, po, SEEK_SET); + cgmb_putw ( cgm, 0 ); + + cgm->op = op; + cgm->bc[i] = 0; + cgm->po[i] = po; + } + cgm->bc[i] ++; + } + } + + fputc ( b, unit ); +} + + +static void cgmb_puti8 ( CGM *cgm, int b ) +{ + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti16 ( CGM *cgm, int b ) +{ + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti24 ( CGM *cgm, long b ) +{ + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti32 ( CGM *cgm, long b ) +{ + cgmb_putb ( cgm, b >> 24 ); + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu8 ( CGM *cgm, unsigned int b ) +{ + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu16 ( CGM *cgm, unsigned int b ) +{ + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu24 ( CGM *cgm, unsigned long b ) +{ + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu32 ( CGM *cgm, unsigned long b ) +{ + cgmb_putb ( cgm, b >> 24 ); + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putfl32 ( CGM *cgm, float b ) +{ + union { + float func; + long l; + } r; + r.func = b; + cgmb_putb ( cgm, r.l >> 24 ); + cgmb_putb ( cgm, r.l >> 16 ); + cgmb_putb ( cgm, r.l >> 8 ); + cgmb_putb ( cgm, r.l ); +} + +static void cgmb_putfl64 ( CGM *cgm, double b ) +{ + union { + double d; + long l[2]; + } r; + r.d = b; + cgmb_putb ( cgm, r.l[1] >> 24 ); + cgmb_putb ( cgm, r.l[1] >> 16 ); + cgmb_putb ( cgm, r.l[1] >> 8 ); + cgmb_putb ( cgm, r.l[1] ); + cgmb_putb ( cgm, r.l[0] >> 24 ); + cgmb_putb ( cgm, r.l[0] >> 16 ); + cgmb_putb ( cgm, r.l[0] >> 8 ); + cgmb_putb ( cgm, r.l[0] ); +} + +static void cgmb_putfx32 ( CGM *cgm, float b ) +{ + int si = ( int ) floor ( b ); + unsigned int ui = ( unsigned int ) ( (b - si) * 65536.0 ); + + cgmb_puti16 ( cgm, si ); + cgmb_puti16 ( cgm, ui ); +} + +static void cgmb_putfx64 ( CGM *cgm, double b ) +{ + long si = ( long ) floor ( b ); + unsigned long ui = ( unsigned long ) ( (b - si) * 65536.0 * 65536.0 ); + + cgmb_puti32 ( cgm, si ); + cgmb_puti32 ( cgm, ui ); +} + +static void cgmb_wch ( CGM* cgm, int c, int id, int len ) +{ + + /* if ( len & 1 ) len ++; */ /* word aligned */ + + if ( len > 30 ) + cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | 31 ); + else + cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | (int)(len) ); + + + cgm->op++; + + if ( len > 30 ) + { + cgm->po[cgm->op] = ftell(unit); + cgmb_putw ( cgm, 0 ); + } + else + cgm->po[cgm->op] = 0L; + + cgm->bc[cgm->op] = 0; + +} + +static void cgmb_ci ( CGM *cgm, unsigned long ci ) +{ + switch ( cgm->cix_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)ci ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)ci ); break; + case 2: cgmb_putu24 ( cgm, ci ); break; + case 3: cgmb_putu32 ( cgm, ci ); break; + } +} + +static void cgmb_cd ( CGM *cgm, double cd ) +{ + unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1)); + switch ( cgm->cd_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)cv ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)cv ); break; + case 2: cgmb_putu24 ( cgm, cv ); break; + case 3: cgmb_putu32 ( cgm, cv ); break; + } +} + +static void cgmb_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgmb_cd ( cgm, r ); + cgmb_cd ( cgm, g ); + cgmb_cd ( cgm, b ); +} + +static void cgmb_ix ( CGM *cgm, long ix ) +{ + switch ( cgm->ix_prec ) + { + case 0: cgmb_puti8 ( cgm, (int)ix ); break; + case 1: cgmb_puti16 ( cgm, (int)ix ); break; + case 2: cgmb_puti24 ( cgm, ix ); break; + case 3: cgmb_puti32 ( cgm, ix ); break; + } +} + +static void cgmb_e ( CGM *cgm, int e, const char *el[] ) +{ + cgmb_puti16 ( cgm, e ); +} + +static void cgmb_i ( CGM *cgm, long i ) +{ + switch ( cgm->int_prec ) + { + case 0: cgmb_puti8 ( cgm, (int)i ); break; + case 1: cgmb_puti16 ( cgm, (int)i ); break; + case 2: cgmb_puti24 ( cgm, i ); break; + case 3: cgmb_puti32 ( cgm, i ); break; + } +} + +static void cgmb_u ( CGM *cgm, unsigned long i ) +{ + switch ( cgm->int_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)i ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)i ); break; + case 2: cgmb_putu24 ( cgm, i ); break; + case 3: cgmb_putu32 ( cgm, i ); break; + } +} + +static void cgmb_r ( CGM *cgm, double func ) +{ + switch ( cgm->real_prec ) + { + case 0: cgmb_putfl32 ( cgm, (float )func ); break; + case 1: cgmb_putfl64 ( cgm, (double)func ); break; + case 2: cgmb_putfx32 ( cgm, (float )func ); break; + case 3: cgmb_putfx64 ( cgm, (double)func ); break; + } +} + +static void cgmb_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + unsigned l = strlen(s); + int bc = 0; + + if ( l > 254 ) + { + cgmb_putu8(cgm,255); + if ( l > 32763 ) + cgmb_putu16 ( cgm, (1<<16) | 32763 ); + else + cgmb_putu16 ( cgm, l ); + bc = 1; + } + else + cgmb_putu8(cgm,l); + + for ( i=0; s[i]; s++ ) + { + if ( (i + bc) == 32766 ) + { + l -= i; + s += i; + i = 0; + bc = 0; + if ( l > 32764 ) + cgmb_putu16 ( cgm, (1<<16) | 32764 ); + else + cgmb_putu16 ( cgm, l ); + } + cgmb_putc ( cgm, s[i] ); + } +} + +static void cgmb_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + switch ( cgm->vdc_int ) + { + case 0: cgmb_puti8 ( cgm, (int )vdc ); break; + case 1: + /* Evita overflow em ambientes de 32 bits */ + if (vdc < -32768) vdc = -32768; + else if (vdc > 32767) vdc = +32767; + cgmb_puti16 ( cgm, (int) vdc ); + break; + case 2: cgmb_puti24 ( cgm, (long)vdc ); break; + case 3: + /* Evita overflow em ambientes de 32 bits */ + if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0; + else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0; + cgmb_puti32 ( cgm, (long)vdc ); + break; + + } + else + switch ( cgm->vdc_real ) + { + case 0: cgmb_putfl32 ( cgm, (float )vdc ); break; + case 1: cgmb_putfl64 ( cgm, (double)vdc ); break; + case 2: cgmb_putfx32 ( cgm, (float )vdc ); break; + case 3: cgmb_putfx64 ( cgm, (double)vdc ); break; + } + +} + +static void cgmb_p ( CGM *cgm, double x, double y) +{ + cgmb_vdc ( cgm, x ); + cgmb_vdc ( cgm, y ); +} + +static void cgmb_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned long *)co; + cgmb_ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgmb_rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmb_sep ( CGM *cgm, const char * sep ) +{} + +static int cgmb_get_col ( CGM *cgm ) +{ + return 0; +} + +static void cgmb_align ( CGM *cgm, int n ) +{} + +static void cgmb_nl ( CGM *cgm ) +{} + +static int cgmb_term ( CGM *cgm ) +{ + if ( cgm->op != -1 ) + { + if ( cgm->bc[cgm->op] & 1 ) + { + cgmb_putb( cgm, 0 ); + cgm->bc[cgm->op] --; + } + + if ( cgm->po[cgm->op] != 0L ) + { + long po = ftell(unit); + int op = cgm->op; + + cgm->op = -1; + fseek ( unit, cgm->po[op], SEEK_SET); + cgmb_putw ( cgm, cgm->bc[op] ); + + fseek ( unit, po, SEEK_SET ); + cgm->op = op; + } + cgm->op --; + } + + return 0; +} + +/************************************************ +* * +* Funcoes para clear text * +* * +************************************************/ + +static void cgmt_wch ( CGM* cgm, int c, int id, int len ) +{ + cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct ); +} + +static void cgmt_ci ( CGM *cgm, unsigned long ci ) +{ + cgm->func->u ( cgm, ci ); +} + +static void cgmt_cd ( CGM *cgm, double cd ) +{ + unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1)); + + cgm->func->u ( cgm, cv ); +} + +static void cgmt_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgm->func->cd ( cgm, r ); + cgm->func->cd ( cgm, g ); + cgm->func->cd ( cgm, b ); +} + +static void cgmt_ix ( CGM *cgm, long ix ) +{ + cgm->func->i ( cgm, ix ); +} + +static void cgmt_e ( CGM *cgm, int e, const char *el[] ) +{ + cgm->cl += fprintf ( unit, " %s", el[e] ); +} + +static void cgmt_i ( CGM *cgm, long i ) +{ + cgm->cl += fprintf ( unit, " %ld", i ); +} + +static void cgmt_u ( CGM *cgm, unsigned long i ) +{ + cgm->cl += fprintf ( unit, " %lu", i ); +} + +static void cgmt_r ( CGM *cgm, double func ) +{ + cgm->cl += fprintf ( unit, " %g", func ); +} + +static void cgmt_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + fputc ( 34, unit ); + + for ( i=0; s[i]; i++ ) + { + if ( s[i] == 34 ) + { + fputc ( 34, unit ); + cgm->cl ++; + } + fputc ( s[i], unit ); + } + + fputc ( 34, unit ); + cgm->cl += strlen (s) + 2; +} + +static void cgmt_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + { + /* Evita overflow em ambientes de 32 bits */ + if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0; + else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0; + + cgm->func->i ( cgm, (long) vdc ); + } + else + cgm->func->r ( cgm, vdc ); +} + +static void cgmt_p ( CGM *cgm, double x, double y) +{ + cgm->func->sep ( cgm, "(" ); + cgm->func->vdc ( cgm, x ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, y ); + cgm->func->sep ( cgm, ")" ); +} + +static void cgmt_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned *)co; + cgm->func->ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmt_sep ( CGM *cgm, const char * sep ) +{ + cgm->cl += fprintf ( unit, " %s", sep ); +} + +static int cgmt_get_col ( CGM *cgm ) +{ + return cgm->cl; +} + +static void cgmt_align ( CGM *cgm, int n ) +{ + for ( ; cgm->cl < n ; cgm->cl ++ ) + fputc ( ' ', unit ); +} + +static void cgmt_nl ( CGM *cgm ) +{ + fputc ( '\n', unit ); + cgm->cl = 1; +} + +static int cgmt_term ( CGM *cgm ) +{ + fputc ( ';', unit ); + cgm->func->nl(cgm); + return 0; +} + +/************************************************ +* * +* Funcoes para character * +* * +************************************************/ + +static void cgmc_wch ( CGM* cgm, int c, int id, int len ) +{ + cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct ); +} + +static void cgmc_ci ( CGM *cgm, unsigned long ci ) +{ + cgm->func->u ( cgm, ci ); +} + +static void cgmc_cd ( CGM *cgm, double cd ) +{ + cgm->func->r ( cgm, cd ); +} + +static void cgmc_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgm->func->cd ( cgm, r ); + cgm->func->sep ( cgm, "," ); + cgm->func->cd ( cgm, g ); + cgm->func->sep ( cgm, "," ); + cgm->func->cd ( cgm, b ); +} + +static void cgmc_ix ( CGM *cgm, long ix ) +{ + cgm->func->i ( cgm, ix ); +} + +static void cgmc_e ( CGM *cgm, int e, const char *el[] ) +{ + cgm->cl += fprintf ( unit, " %s", el[e] ); +} + +static void cgmc_i ( CGM *cgm, long i ) +{ + cgm->cl += fprintf ( unit, " %ld", i ); +} + +static void cgmc_u ( CGM *cgm, unsigned long i ) +{ + cgm->cl += fprintf ( unit, " %lu", i ); +} + +static void cgmc_r ( CGM *cgm, double func ) +{ + cgm->cl += fprintf ( unit, " %g", func ); +} + +static void cgmc_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + fputc ( 34, unit ); + + for ( i=0; s[i]; i++ ) + { + if ( s[i] == 34 ) + { + fputc ( 34, unit ); + cgm->cl ++; + } + fputc ( s[i], unit ); + } + + fputc ( 34, unit ); + cgm->cl += strlen (s) + 2; +} + +static void cgmc_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + cgm->func->i ( cgm, (long) vdc ); + else + cgm->func->r ( cgm, vdc ); +} + +static void cgmc_p ( CGM *cgm, double x, double y) +{ + cgm->func->sep ( cgm, "(" ); + cgm->func->vdc ( cgm, x ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, y ); + cgm->func->sep ( cgm, ")" ); +} + +static void cgmc_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned long *)co; + cgm->func->ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmc_sep ( CGM *cgm, const char * sep ) +{ + cgm->cl += fprintf ( unit, " %s", sep ); +} + +static int cgmc_get_col ( CGM *cgm ) +{ + return cgm->cl; +} + +static void cgmc_align ( CGM *cgm, int n ) +{ + for ( ; cgm->cl < n ; cgm->cl ++ ) + fputc ( ' ', unit ); +} + +static void cgmc_nl ( CGM *cgm ) +{ + fputc ( '\n', unit ); + cgm->cl = 1; +} + +static int cgmc_term ( CGM *cgm ) +{ + fputc ( ';', unit ); + cgm->func->nl(cgm); + return 0; +} + +/************************************************ +* * +* independente de codificacao * +* * +************************************************/ + + +/* Definicoes de precisao */ + +static const long _cgm_int_precs[][2] = { + { -128, 127 }, /* 8 */ + { -32768L, 32767 }, /* 16 */ + { LONG_MIN >> 8, LONG_MAX >> 8 }, /* 24 */ + { LONG_MIN , LONG_MAX } }; /* 32 */ + +static int _cgm_ireal_precs[][4] = { + { 0, 9, 23, 0 }, /* float*32 */ + { 0, 12, 52, 0 }, /* float*64 */ + { 1, 16, 16, 5 }, /* fixed*32 */ + { 1, 32, 32, 9 } }; /* fixed*64 */ + +static double _cgm_rreal_precs[][2] = { + /* float*32 */ { 0, 0 }, /* Em Turbo C, FLT_MAX e DLB_MAX sao */ + /* float*64 */ { 0, 0 }, /* DEFINES para variaveis externas */ + /* fixed*32 */ { - (32769.0 - 1.0 / 65536.0), + 32768.0 - 1.0 / 65536.0 }, + /* fixed*64 */ { (double)(LONG_MIN) - ( 1 - 1 / ( 65536.0 * 65536.0 ) ), + (double)(LONG_MAX) + ( 1 - 1 / ( 65536.0 * 65536.0 ) ) } }; + +/* Enumeraveis genericos */ + +static const char *offon[] = { "OFF", "ON" }; + +/********************* +* Delimiter elements * +*********************/ + +CGM *cgm_begin_metafile ( char *file, int mode, char *header ) +{ + CGM *cgm; + + if ( (cgm = (CGM *)malloc ( sizeof (CGM) ) ) == NULL ) + return NULL; + +#ifdef __VAXC__ + + if ( mode == 2 ) + cgm->file = fopen ( file , "w" , "rfm=var", "rat=cr" ); + else + cgm->file = fopen ( file , "w+b", "rfm=var", "ctx=stm" ); + +#else + + if ( mode == 2 ) + cgm->file = fopen ( file , "w" ); + else + cgm->file = fopen ( file , "w+b" ); + +#endif + + if ( cgm->file == NULL ) + { + free ( cgm ); + return NULL; + } + + cgm->mode = mode; + cgm->func = cgmf[mode]; + + cgm->vdc_type = 0; + cgm->int_prec = 1; + cgm->real_prec = 2; + cgm->ix_prec = 1; + cgm->cd_prec = 0; + cgm->cix_prec = 0; + cgm->max_cix = 63; + + cgm->clrsm = 0; + cgm->lnwsm = 1; + cgm->mkssm = 1; + cgm->edwsm = 1; + cgm->vdc_int = 1; + cgm->vdc_real = 2; + + cgm->vdc_size = 2; + cgm->int_size = 2; + cgm->real_size = 4; + cgm->ix_size = 3; + cgm->cd_size = 3; + cgm->cix_size = 1; + cgm->clr_size = 1; + cgm->lnw_size = 4; + cgm->mks_size = 4; + cgm->edw_size = 4; + + cgm->cl = 1; + + cgm->op = -1; + + cgm->func->wch ( cgm, 0, 1, strlen ( header ) + 1 ); + + cgm->func->s ( cgm, header ); + + cgm->func->term ( cgm ); + + _cgm_ireal_precs[0][3] = FLT_DIG; + _cgm_ireal_precs[1][3] = DBL_DIG; + + _cgm_rreal_precs[0][0] = - FLT_MAX; + _cgm_rreal_precs[0][1] = FLT_MAX; + _cgm_rreal_precs[1][0] = - DBL_MAX; + _cgm_rreal_precs[1][1] = DBL_MAX; + + return cgm; +} + +int cgm_end_metafile ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 2, 0 ); + cgm->func->term ( cgm ); + + fclose ( cgm->file ); + cgm->file = NULL; + free ( cgm ); + + return 0; +} + +int cgm_begin_picture (CGM *cgm, const char *s ) +{ + cgm->func->wch ( cgm, 0, 3, strlen(s)+1 ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_begin_picture_body ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 4, 0 ); + return cgm->func->term(cgm); +} + +int cgm_end_picture ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 5, 0 ); + return cgm->func->term(cgm); +} + +/******************************* +* Metafile Descriptor Elements * +*******************************/ + +int cgm_metafile_version ( CGM *cgm, long version ) +{ + cgm->func->wch ( cgm, 1, 1, cgm->int_size ); + + cgm->func->i ( cgm, version ); + + return cgm->func->term(cgm); +} + +int cgm_metafile_description ( CGM *cgm, const char *s ) +{ + cgm->func->wch ( cgm, 1, 2, 1+strlen(s) ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_vdc_type ( CGM *cgm, int mode ) +{ + static const char *vdct[] = { "integer", "real" }; + cgm->func->wch ( cgm, 1, 3, 2 ); + cgm->func->e ( cgm, mode, vdct ); + + cgm->vdc_type = mode; + if ( cgm->vdc_type == 0 ) /* integer */ + cgm->vdc_size = cgm->vdc_int + 1; + else + cgm->vdc_size = ( _cgm_ireal_precs[cgm->vdc_real][1] + + _cgm_ireal_precs[cgm->vdc_real][2]) / 8; + + return cgm->func->term(cgm); +} + +int cgm_integer_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 4, cgm->int_size ); + + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->int_prec = prec/8-1; + cgm->int_size = prec/8; + + return cgm->func->term(cgm); +} + +int cgm_real_precision ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 1, 5, 2 + 2*cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) ); + break; + + case 2: /* clear text */ + cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) ); + break; + } + + cgm->real_prec = mode; + cgm->real_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8; + + /* absolute scaling modes */ + if ( cgm->lnwsm == 1 ) cgm->lnw_size = cgm->real_size; + if ( cgm->mkssm == 1 ) cgm->mks_size = cgm->real_size; + if ( cgm->edwsm == 1 ) cgm->edw_size = cgm->real_size; + + return cgm->func->term(cgm); +} + +int cgm_index_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 6, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->ix_prec = prec/8-1; + cgm->ix_size = prec/8; + return cgm->func->term(cgm); +} + +int cgm_colour_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 7, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->cd_prec = prec/8-1; + cgm->cd_size = 3*(prec/8); + + if ( cgm->clrsm == 1 ) /* direct */ + cgm->clr_size = cgm->cd_size; + + return cgm->func->term(cgm); +} + +int cgm_colour_index_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 8, cgm->int_size ); + + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->cix_prec = prec/8-1; + cgm->cix_size = prec/8; + + if ( cgm->clrsm == 0 ) /* indexed */ + cgm->clr_size = cgm->cix_size; + + return cgm->func->term(cgm); +} + +int cgm_maximum_colour_index ( CGM *cgm, unsigned long ci ) +{ + cgm->func->wch ( cgm, 1, 9, cgm->cix_size ); + cgm->func->ci ( cgm, ci ); + return cgm->func->term(cgm); +} + +int cgm_colour_value_extent ( CGM *cgm, const double *black, + const double *white) +{ + cgm->func->wch ( cgm, 1, 10, 2 * cgm->cd_size ); + cgm->func->rgb ( cgm, black[0], black[1], black[2] ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 15 ); + cgm->func->rgb ( cgm, white[0], white[1], white[2] ); + return cgm->func->term(cgm); +} + +int cgm_metafile_element_list ( CGM *cgm, int n, const int *group, const int *element ) +{ + register int i; + cgm->func->wch ( cgm, 1, 11, 31 ); + cgm->func->sep ( cgm, "\x22" ); /* aspas */ + if ( cgm->mode == 1 ) cgm->func->i ( cgm, n ); + for ( i=0; imode == 1 ) /* binario */ + { + cgm->func->ix ( cgm, group[i] ); + cgm->func->ix ( cgm, element[i] ); + cgm->func->term( cgm ); + } + else + { + cgm->func->wch ( cgm, group[i], element[i], 0 ); + cgm->func->sep ( cgm, "" ); + } + } + cgm->func->sep ( cgm, "\x22" ); /* aspas */ + return cgm->func->term(cgm); +} + +int cgm_begin_metafile_defaults ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 1, 12, 31 ); + + /* modo binario - deixa aberto */ + if ( cgm->mode == 1 ) /* binario */ + return 0; + + return cgm->func->term(cgm); +} + +int cgm_end_metafile_defaults ( CGM *cgm ) +{ + /* modo binario - ja estava aberto */ + if ( cgm->mode != 1 ) /* binario */ + cgm->func->wch ( cgm, 1, 0, 0 ); + + return cgm->func->term(cgm); +} + +int cgm_font_list ( CGM *cgm, const char *fl[] ) +{ + register int i; + + cgm->func->wch ( cgm, 1, 13, 31 ); + + for ( i=0; fl[i] != NULL; i++ ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 10 ); + cgm->func->s ( cgm, fl[i] ); + } + + return cgm->func->term(cgm); +} + +/****************************** +* Picture Descriptor Elements * +******************************/ + +int cgm_scaling_mode ( CGM *cgm, int mode, float metric ) +{ + static const char *sm[] = { "abstract", "metric" }; + cgm->func->wch ( cgm, 2, 1, 2 + 4 ); + cgm->func->e ( cgm, mode, sm ); + if ( cgm->mode == 1 ) + cgmb_putfl32 ( cgm, metric ); + else + cgm->func->r ( cgm, metric ); + return cgm->func->term(cgm); +} + +int cgm_colour_selection_mode ( CGM *cgm, int mode) +{ + static const char *csm[] = { "indexed", "direct" }; + cgm->func->wch ( cgm, 2, 2, 2 ); + cgm->func->e ( cgm, mode, csm ); + + cgm->clrsm = mode; + if ( mode == 0 ) /* indexed */ + cgm->clr_size = cgm->cix_size; + else + cgm->clr_size = cgm->cd_size; + + return cgm->func->term(cgm); +} + +static int _cgm_width_specify_mode ( CGM *cgm, int t, int mode) +{ + static const char *sm[] = { "abstract", "scaled" }; + cgm->func->wch ( cgm, 2, t, 2 ); + cgm->func->e ( cgm, mode, sm ); + return cgm->func->term(cgm); +} + +int cgm_line_width_specify_mode ( CGM *cgm, int mode) +{ + cgm->lnwsm = mode; + if ( mode == 0 ) + cgm->lnw_size = cgm->vdc_size; + else + cgm->lnw_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 3, mode ); +} + +int cgm_marker_size_specify_mode ( CGM *cgm, int mode) +{ + cgm->mkssm = mode; + if ( mode == 0 ) + cgm->mks_size = cgm->vdc_size; + else + cgm->mks_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 4, mode ); +} + +int cgm_edge_width_specify_mode ( CGM *cgm, int mode) +{ + cgm->edwsm = mode; + if ( mode == 0 ) + cgm->edw_size = cgm->vdc_size; + else + cgm->edw_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 5, mode ); +} + +int cgm_vdc_extent ( CGM *cgm, double xmin, double ymin, + double xmax, double ymax ) +{ + cgm->func->wch ( cgm, 2, 6, 2*2*cgm->vdc_size ); + cgm->func->vdc ( cgm, xmin ); + cgm->func->vdc ( cgm, ymin ); + cgm->func->vdc ( cgm, xmax ); + cgm->func->vdc ( cgm, ymax ); + return cgm->func->term(cgm); +} + +int cgm_backgound_colour ( CGM *cgm, const double *cr ) +{ + cgm->func->wch ( cgm, 2, 7, cgm->cd_size ); + cgm->func->rgb ( cgm , cr[0], cr[1], cr[2] ); + return cgm->func->term(cgm); +} + +/******************* +* Control Elements * +*******************/ + +int cgm_vdc_integer_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 3, 1, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + if ( cgm->vdc_type == 0 ) + cgm->vdc_size = prec/8; + + cgm->vdc_int = prec/8 - 1; + + if ( cgm->lnwsm == 0 && cgm->vdc_type == 0 ) cgm->lnw_size = cgm->vdc_size; + if ( cgm->mkssm == 0 && cgm->vdc_type == 0 ) cgm->mks_size = cgm->vdc_size; + if ( cgm->edwsm == 0 && cgm->vdc_type == 0 ) cgm->edw_size = cgm->vdc_size; + + return cgm->func->term(cgm); +} + +int cgm_vdc_real_precision ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 2, 2 + 2*cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) ); + break; + + case 2: /* clear text */ + cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) ); + break; + } + + if ( cgm->vdc_type == 1 ) + cgm->vdc_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8; + + cgm->vdc_real = mode; + + if ( cgm->lnwsm == 0 && cgm->vdc_type == 1 ) cgm->lnw_size = cgm->vdc_size; + if ( cgm->mkssm == 0 && cgm->vdc_type == 1 ) cgm->mks_size = cgm->vdc_size; + if ( cgm->edwsm == 0 && cgm->vdc_type == 1 ) cgm->edw_size = cgm->vdc_size; + + return cgm->func->term(cgm); +} + +int cgm_auxiliary_colour ( CGM *cgm, const void *c ) +{ + cgm->func->wch ( cgm, 3, 3, cgm->clr_size ); + + cgm->func->co ( cgm, c ) ; + + return cgm->func->term(cgm); +} + +int cgm_transparency ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 4, 2 ); + + cgm->func->e ( cgm, mode, offon ); + + return cgm->func->term(cgm); +} + +int cgm_clip_rectangle ( CGM *cgm, double xmin, double ymin, + double xmax, double ymax ) +{ + cgm->func->wch ( cgm, 3, 5, 4 * cgm->vdc_size ); + + cgm->func->vdc ( cgm, xmin ); + cgm->func->vdc ( cgm, ymin ); + cgm->func->vdc ( cgm, xmax ); + cgm->func->vdc ( cgm, ymax ); + + return cgm->func->term(cgm); +} + +int cgm_clip_indicator ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 6, 2 ); + + cgm->func->e ( cgm, mode, offon ); + + return cgm->func->term(cgm); +} + +/******************************* +* Graphical Primitive Elements * +*******************************/ + +static int _cgm_point ( CGM *cgm, double x, double y ) +{ + cgm->func->p ( cgm, x, y ); + return 0; +} + +static int _cgm_point_list ( CGM *cgm, int element, int n, const double *p) +{ + register int i; + cgm->func->wch ( cgm, 4, element, 2*n*cgm->vdc_size ); + + for ( i=0; i < 2*n; i+=2 ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + _cgm_point ( cgm, p[i], p[i+1] ); + } + return cgm->func->term(cgm); +} + +int cgm_polyline ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 1, n, p ); +} + +int cgm_polymarker ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 3, n, p ); +} + +static int _cgm_text_piece ( CGM *cgm, int t, const char *s) +{ + static const char *tt[] = { "NOT_FINAL", " FINAL" }; + cgm->func->e ( cgm, t, tt ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_text ( CGM *cgm, int tt, double x, double y, const char *s ) +{ + cgm->func->wch ( cgm, 4, 4, 2 * cgm->vdc_size + strlen(s) + 3 ); + cgm->func->p ( cgm, x, y ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 10 ); + + if ( cgm->mode == 2 ) /* clear text */ + { + while ( strlen (s) > 50 ) + { + char s1[51]; + + strncpy ( s1, s, 50 ); + s1[50] = 0; + + _cgm_text_piece ( cgm, 0, s1 ); + + s += 50; + cgm->func->wch ( cgm, 4, 6, 2 * cgm->vdc_size + strlen(s) + 1 ); + } + + } + + return _cgm_text_piece ( cgm, tt, s ); +} + +int cgm_polygon ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 7, n, p ); +} + +static int _cgm_cell_rows ( CGM *cgm, long sx, long sy, int prec, const void *c ) +{ + register long i,j, brk; + + cgm->func->nl ( cgm ); + cgm->func->sep ( cgm, "(" ); + + if ( cgm->clrsm ) + brk = 5; + else + brk = 12; + + for ( i=0; i < sy; i++ ) + { + if ( i ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 3 ); + } + + for ( j=0; j < sx; j++) + { + if ( j && ( j % brk == 0 ) ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 3 ); + } + + cgm->func->co ( cgm, c ); + c = (void*)((char*)c+ (cgm->clrsm ? (3*sizeof(double)) : sizeof(int))); + + if ( ifunc->sep ( cgm, "," ); + } + } + + cgm->func->sep ( cgm, ")" ); + + return 0; +} + +int cgm_cell_array ( CGM *cgm, const double *p, long sx, long sy, int prec, const void *c ) +{ + register int i; + static const char *repmode[] = { "run lenght", "packed" }; + + cgm->func->wch ( cgm, 4, 9, 31 ); + + for ( i=0; i<3*2; i+=2 ) + _cgm_point ( cgm, p[i], p[i+1] ); + + cgm->func->nl (cgm ); + + cgm->func->i ( cgm, sx ); + cgm->func->i ( cgm, sy ); + + if ( prec == 0 ) + cgm->func->i ( cgm, (long)(prec) ); + else + { + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) ); + break; + } + } + + if ( cgm->mode==1 ) cgm->func->e ( cgm, 1, repmode ); + + _cgm_cell_rows( cgm, sx, sy, prec, c ); + + return cgm->func->term(cgm); +} + +int cgm_rectangle ( CGM *cgm, const double *p ) +{ + return _cgm_point_list ( cgm, 11, 2, p ); +} + +static int _cgm_ellipse_CDP ( CGM *cgm, const double *c, const double *p1, + const double *p2 ) +{ + _cgm_point ( cgm, c[0], c[1] ); + _cgm_point ( cgm, p1[0], p1[1] ); + _cgm_point ( cgm, p2[0], p2[1] ); + + return 0; +} + +static int _cgm_ellipse_vectors ( CGM *cgm, double dxs, double dys, double dxe, + double dye ) +{ + cgm->func->vdc ( cgm, dxs ); + cgm->func->vdc ( cgm, dys ); + cgm->func->vdc ( cgm, dxe ); + cgm->func->vdc ( cgm, dye ); + + return 0; +} + +int cgm_elliptical_arc ( CGM *cgm, const double *c, const double *p1, + const double *p2, double dxs, double dys, double dxe, + double dye ) +{ + cgm->func->wch ( cgm, 4, 18, 10*cgm->vdc_size ); + + _cgm_ellipse_CDP ( cgm, c, p1, p2 ); + + _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye ); + + return cgm->func->term(cgm); +} + +int cgm_elliptical_arc_close ( CGM *cgm, const double *c, const double *p1, + const double *p2, double dxs, double dys, + double dxe, double dye, int type ) +{ + static const char *ct[] = { "pie", "chord" }; + + cgm->func->wch ( cgm, 4, 19, 10*cgm->vdc_size + 2 ); + + _cgm_ellipse_CDP ( cgm, c, p1, p2 ); + + _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye ); + + cgm->func->e ( cgm, type, ct ); + + return cgm->func->term(cgm); +} + +/********************* +* Attribute Elements * +*********************/ + +int cgm_line_bundle_index( CGM *cgm, long li) +{ + cgm->func->wch ( cgm, 5, 1, cgm->ix_size ); + cgm->func->ix ( cgm, li ); + return cgm->func->term(cgm); +} + +int cgm_line_type( CGM *cgm, long lt) +{ + cgm->func->wch ( cgm, 5, 2, cgm->ix_size ); + cgm->func->ix ( cgm, lt ); + return cgm->func->term(cgm); +} + +int cgm_line_width( CGM *cgm, double lw) +{ + cgm->func->wch ( cgm, 5, 3, cgm->lnw_size ); + + if ( cgm->lnwsm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, lw ); + else + cgm->func->r ( cgm, lw ); + + return cgm->func->term(cgm); +} + +int cgm_line_colour( CGM *cgm, const void *lc) +{ + cgm->func->wch ( cgm, 5, 4, cgm->clr_size ); + cgm->func->co ( cgm, lc ); + return cgm->func->term(cgm); +} + +int cgm_marker_bundle_index( CGM *cgm, long mi) +{ + cgm->func->wch ( cgm, 5, 5, cgm->ix_size ); + cgm->func->ix ( cgm, mi ); + return cgm->func->term(cgm); +} + +int cgm_marker_type( CGM *cgm, long mt) +{ + cgm->func->wch ( cgm, 5, 6, cgm->ix_size ); + cgm->func->ix ( cgm, mt ); + return cgm->func->term(cgm); +} + +int cgm_marker_size( CGM *cgm, double ms) +{ + cgm->func->wch ( cgm, 5, 7, cgm->mks_size ); + + if ( cgm->mkssm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, ms ); + else + cgm->func->r ( cgm, ms ); + + return cgm->func->term(cgm); +} + +int cgm_marker_colour( CGM *cgm, const void *mc) +{ + cgm->func->wch ( cgm, 5, 8, cgm->clr_size ); + cgm->func->co ( cgm, mc ); + return cgm->func->term(cgm); +} + +int cgm_text_bundle_index( CGM *cgm, long ti) +{ + cgm->func->wch ( cgm, 5, 9, cgm->ix_size ); + cgm->func->ix ( cgm, ti ); + return cgm->func->term(cgm); +} + +int cgm_text_font_index( CGM *cgm, long fi) +{ + cgm->func->wch ( cgm, 5, 10, cgm->ix_size ); + cgm->func->ix ( cgm, fi ); + return cgm->func->term(cgm); +} + +int cgm_text_precision( CGM *cgm, int tp) +{ + static const char *txprec[] = { "STRING", "CHAR", "STROKE" }; + cgm->func->wch ( cgm, 5, 11, 2 ); + cgm->func->e ( cgm, tp, txprec ); + return cgm->func->term(cgm); +} + +int cgm_char_expansion_factor ( CGM *cgm, double expan ) +{ + cgm->func->wch ( cgm, 5, 12, cgm->real_size ); + cgm->func->r ( cgm, expan ); + return cgm->func->term(cgm); +} + +int cgm_char_spacing ( CGM *cgm, double spacing ) +{ + cgm->func->wch ( cgm, 5, 13, cgm->real_size ); + cgm->func->r ( cgm, spacing ); + return cgm->func->term(cgm); +} + +int cgm_text_colour( CGM *cgm, const void *tc) +{ + cgm->func->wch ( cgm, 5, 14, cgm->clr_size ); + cgm->func->co ( cgm, tc ); + return cgm->func->term(cgm); +} + +int cgm_char_height ( CGM *cgm, double height ) +{ + cgm->func->wch ( cgm, 5, 15, cgm->vdc_size ); + cgm->func->vdc ( cgm, height ); + return cgm->func->term(cgm); +} + +int cgm_char_orientation ( CGM *cgm, double chupx, double chupy, + double chbsx, double chbsy ) +{ + cgm->func->wch ( cgm, 5, 16, 4*cgm->vdc_size ); + cgm->func->sep ( cgm, "% char up %" ); + cgm->func->vdc ( cgm, chupx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, chupy ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + cgm->func->sep ( cgm, "% char base %" ); + cgm->func->vdc ( cgm, chbsx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, chbsy ); + return cgm->func->term(cgm); +} + +int cgm_text_path ( CGM *cgm, int tp) +{ + static const char *txpath[] = { "RIGHT", "LEFT", "UP", "DOWN" }; + cgm->func->wch ( cgm, 5, 17, 2 ); + cgm->func->e ( cgm, tp, txpath ); + return cgm->func->term(cgm); +} + +int cgm_text_alignment ( CGM *cgm, int hor, int ver , double ch, double cv) +{ + static const char *txhor[] = { "NORMHORIZ", "LEFT", "CTR", "RIGHT", "CONTHORIZ" }; + static const char *txver[] = { "NORMVERT", "TOP", "CAP", "HALF", "BASE", + "BOTTOM", "CONTHORIZ" }; + + cgm->func->wch ( cgm, 5, 18, 2*2 + 2*cgm->real_size ); + cgm->func->e ( cgm, hor, txhor ); + cgm->func->e ( cgm, ver, txver ); + cgm->func->r ( cgm, ch ); + cgm->func->r ( cgm, cv ); + return cgm->func->term(cgm); +} + +int cgm_fill_bundle_index( CGM *cgm, long fi) +{ + cgm->func->wch ( cgm, 5, 21, cgm->ix_size ); + cgm->func->ix ( cgm, fi ); + return cgm->func->term(cgm); +} + +int cgm_interior_style( CGM *cgm, int is) +{ + static const char *style[]= { "HOLLOW", "SOLID", "PAT", "HATCH", "EMPTY" }; + cgm->func->wch ( cgm, 5, 22, 2 ); + cgm->func->e ( cgm, is, style ); + return cgm->func->term(cgm); +} + +int cgm_fill_colour( CGM *cgm, const void *fc) +{ + cgm->func->wch ( cgm, 5, 23, cgm->clr_size ); + cgm->func->co ( cgm, fc ); + return cgm->func->term(cgm); +} + +int cgm_hatch_index( CGM *cgm, long hi) +{ + cgm->func->wch ( cgm, 5, 24, cgm->ix_size ); + cgm->func->ix ( cgm, hi ); + return cgm->func->term(cgm); +} + +int cgm_pattern_index( CGM *cgm, long pi) +{ + cgm->func->wch ( cgm, 5, 25, cgm->ix_size ); + cgm->func->ix ( cgm, pi ); + return cgm->func->term(cgm); +} + +int cgm_edge_width( CGM *cgm, double ew) +{ + cgm->func->wch ( cgm, 5, 28, cgm->edw_size ); + + if ( cgm->lnwsm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, ew ); + else + cgm->func->r ( cgm, ew ); + + return cgm->func->term(cgm); +} + +int cgm_edge_colour( CGM *cgm, const void *ec) +{ + cgm->func->wch ( cgm, 5, 29, cgm->clr_size ); + cgm->func->co ( cgm, ec ); + return cgm->func->term(cgm); +} + +int cgm_edge_visibility ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 5, 30, 2 ); + cgm->func->e ( cgm, mode, offon ); + return cgm->func->term(cgm); +} + +int cgm_fill_reference_point ( CGM *cgm, double rpx, double rpy ) +{ + cgm->func->wch ( cgm, 5, 31, 2*cgm->vdc_size ); + _cgm_point ( cgm, rpx, rpy ); + return cgm->func->term(cgm); +} + +int cgm_pattern_table ( CGM *cgm, long pi, long sx, long sy, int prec, const void *c) +{ + cgm->func->wch ( cgm, 5, 32, 31 ); + cgm->func->ix ( cgm, pi ); + + cgm->func->i ( cgm, sx ); + cgm->func->i ( cgm, sy ); + + if ( prec == 0 ) + cgm->func->i ( cgm, (long)(prec) ); + else + { + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) ); + break; + } + } + + _cgm_cell_rows( cgm, sx, sy, prec, c ); + + return cgm->func->term(cgm); +} + +int cgm_pattern_size ( CGM *cgm, double hx, double hy, double wx, double wy ) +{ + cgm->func->wch ( cgm, 5, 33, 4*cgm->vdc_size ); + cgm->func->sep ( cgm, "% height %" ); + cgm->func->vdc ( cgm, hx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, hy ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + cgm->func->sep ( cgm, "% width %" ); + cgm->func->vdc ( cgm, wx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, wy ); + return cgm->func->term(cgm); +} + +int cgm_colour_table ( CGM *cgm, long ci, long n, const double *cb ) +{ + register long i=n; + + if ( n > 31 ) n = 31; + + cgm->func->wch ( cgm, 5, 34, cgm->int_size+n*cgm->cd_size ); + cgm->func->i ( cgm, ci ); + + n = i; + + for ( i=0; ifunc->nl ( cgm ); + cgm->func->align ( cgm, 18 ); + } + cgm->func->rgb ( cgm, cb[(int)i], cb[(int)i+1], cb[(int)i+2] ); + } + + return cgm->func->term(cgm); +} + +static void _cgm_asf_pair ( CGM *cgm, int asft, int asfv ) +{ + static const char *asfvl[] = { "INDIV", "BUNDLED" }; + static const char *asftl[] = { + "LINE_TYPE", "LINE_WIDTH", "LINE_COLR", + "MARKER_TYPE", "MARKER_SIZE", "MARKER_COLR", + "TEXT_FONT_INDEX", "TEXT_PREC", "CHAR_EXP", "CHAR_SPACE", "TEXT_COLR", + "INT_STYLE", "FILL_COLR", "HATCH_INDEX", "PAT_INDEX", + "EDGE_TYPE", "EDGE_WIDTH", "EDGE_COLR", + "ALL", "ALL_LINE", "ALL_MARKER", "ALL_TEXT", "ALL_FILL", "ALL_EDGE" + }; + + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 4 ); + cgm->func->e ( cgm, asft, asftl ); + cgm->func->e ( cgm, asfv, asfvl ); +} + +int cgm_asfs ( CGM *cgm, int n, const int *asfts, const int* asfvs ) +{ + register int i; + cgm->func->wch ( cgm, 5, 35, 2*n* 2 ); + + for ( i=0; ifunc->term(cgm); +} + +/***************** +* Escape Element * +*****************/ + +/******************** +* External elements * +********************/ + +int cgm_message ( CGM *cgm, int action, const char *s) +{ + static const char *ac[] = { "NOACTION", "ACTION" }; + cgm->func->wch ( cgm, 7, 2, 2 + strlen(s)+1 ); + cgm->func->e ( cgm, action, ac ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} diff --git a/src/drv/cgm.h b/src/drv/cgm.h new file mode 100644 index 0000000..0404604 --- /dev/null +++ b/src/drv/cgm.h @@ -0,0 +1,156 @@ +/** \file + * \brief CGM library + * Extracted from GKS/PUC + * + * See Copyright Notice in cd.h + */ + +#ifndef __CGM_H +#define __CGM_H + +typedef struct _cgmFunc CGMFUNC; + +typedef struct { + FILE *file; /* file pointer */ + + const CGMFUNC *func; /* functions */ + + int mode; /* character, binary, clear text */ + + int vdc_type, /* integer, real */ + int_prec, /* 8, 16, 24, 32 */ + real_prec, /* float*32, float*64, fixed*32, fixed*64 */ + ix_prec, /* 8, 16, 24, 32 */ + cd_prec, /* 8, 16, 24, 32 */ + cix_prec, /* 8, 16, 24, 32 */ + max_cix; /* maximum colour index */ + + int clrsm, /* indexed, direct */ + lnwsm, /* absolute, scaled */ + mkssm, /* absolute, scaled */ + edwsm; /* absolute, scaled */ + int vdc_int, /* X, 16, 24, 32 */ + vdc_real; /* float*32, float*64, fixed*32, fixed*64 */ + + int vdc_size, /* 2, 3, 4, 8 */ + int_size, /* 1, 2, 3, 4 */ + real_size, /* 4, 8 */ + ix_size, /* 1, 2, 3, 4 */ + cd_size, /* 1, 2, 3, 4 */ + cix_size, /* 1, 2, 3, 4 */ + clr_size, /* 3 * cd_size , cix_size */ + lnw_size, /* 2, 3, 4, 8 */ + mks_size, /* 2, 3, 4, 8 */ + edw_size; /* 2, 3, 4, 8 */ + + int cl; /* coluna para alinhamento */ + + int op; /* commands opened */ + int bc[5]; /* bytes count for command */ + long po[5]; /* position offset do arquivo */ +} CGM; + +CGM *cgm_begin_metafile ( char *, int, char * ); +int cgm_end_metafile ( CGM * ); +int cgm_begin_picture ( CGM *, const char * ); +int cgm_begin_picture_body ( CGM * ); +int cgm_end_picture ( CGM * ); +int cgm_metafile_version ( CGM *, long ); +int cgm_metafile_description ( CGM *, const char * ); +int cgm_vdc_type ( CGM *, int ); +int cgm_integer_precision ( CGM *, int ); +int cgm_real_precision ( CGM *, int ); +int cgm_index_precision ( CGM *, int ); +int cgm_colour_precision ( CGM *, int ); +int cgm_colour_index_precision ( CGM *, int ); +int cgm_maximum_colour_index ( CGM *, unsigned long ); +int cgm_colour_value_extent ( CGM *, const double *, const double * ); +int cgm_metafile_element_list ( CGM *, int, const int *, const int * ); +int cgm_begin_metafile_defaults ( CGM * ); +int cgm_end_metafile_defaults ( CGM * ); +int cgm_font_list ( CGM *, const char *l[] ); +int cgm_scaling_mode ( CGM *, int, float ); +int cgm_colour_selection_mode ( CGM *, int ); +int cgm_line_width_specify_mode ( CGM *, int ); +int cgm_marker_size_specify_mode( CGM *, int ); +int cgm_edge_width_specify_mode ( CGM *, int ); +int cgm_vdc_extent ( CGM *, double, double, double, double ); +int cgm_backgound_colour ( CGM *, const double * ); +int cgm_vdc_integer_precision ( CGM *, int ); +int cgm_vdc_real_precision ( CGM *, int ); +int cgm_auxiliary_colour ( CGM *, const void * ); +int cgm_transparency ( CGM *, int ); +int cgm_clip_rectangle ( CGM *, double, double, double, double ); +int cgm_clip_indicator ( CGM *, int ); +int cgm_polyline ( CGM *, int, const double * ); +int cgm_polymarker ( CGM *, int, const double * ); +int cgm_text ( CGM *, int, double, double, const char * ); +int cgm_polygon ( CGM *, int, const double * ); +int cgm_cell_array ( CGM *, const double *, long, long, int, const void * ); +int cgm_rectangle ( CGM *, const double * ); +int cgm_elliptical_arc ( CGM *, const double *, const double *, const double *, double, double, double, double ); +int cgm_elliptical_arc_close ( CGM *, const double *, const double *, const double *, double, double, double, double, int ); +int cgm_line_bundle_index ( CGM *, long ); +int cgm_line_type ( CGM *, long ); +int cgm_line_width ( CGM *, double ); +int cgm_line_colour ( CGM *, const void * ); +int cgm_marker_bundle_index ( CGM *, long ); +int cgm_marker_type ( CGM *, long ); +int cgm_marker_size ( CGM *, double ); +int cgm_marker_colour ( CGM *, const void * ); +int cgm_text_bundle_index ( CGM *, long ); +int cgm_text_font_index ( CGM *, long ); +int cgm_text_precision ( CGM *, int ); +int cgm_char_expansion_factor ( CGM *, double ); +int cgm_char_spacing ( CGM *, double ); +int cgm_text_colour ( CGM *, const void * ); +int cgm_char_height ( CGM *, double ); +int cgm_char_orientation ( CGM *, double, double, double, double ); +int cgm_text_path ( CGM *, int ); +int cgm_text_alignment ( CGM *, int, int, double, double ); +int cgm_fill_bundle_index ( CGM *, long ); +int cgm_interior_style ( CGM *, int ); +int cgm_fill_colour ( CGM *, const void * ); +int cgm_hatch_index ( CGM *, long ); +int cgm_pattern_index ( CGM *, long ); +int cgm_edge_width ( CGM *, double ); +int cgm_edge_colour ( CGM *, const void * ); +int cgm_edge_visibility ( CGM *, int ); +int cgm_fill_reference_point ( CGM *, double, double ); +int cgm_pattern_table ( CGM *, long, long, long, int, const void * ); +int cgm_pattern_size ( CGM *, double, double, double, double ); +int cgm_colour_table ( CGM *, long, long, const double * ); +int cgm_asfs ( CGM *, int, const int *, const int * ); +int cgm_message ( CGM *, int, const char * ); + +enum { + LINE_SOLID=1, + LINE_DASH=2, + LINE_DOT=3, + LINE_DASH_DOT=4, + LINE_DASH_DOT_DOT=5 + }; + +enum { + MARKER_DOT=1, + MARKER_PLUS=2, + MARKER_ASTERISK=3, + MARKER_CIRCLE=4, + MARKER_CROSS=5 + }; + +enum { + HOLLOW, + SOLID, + PAT, + HATCH, + EMPTY + }; + +enum { /* encoding */ + CD_CHARACTER, + CD_BIN, + CD_CLEAR_TEXT + }; + +#endif diff --git a/src/freetype2/autofit/afangles.c b/src/freetype2/autofit/afangles.c new file mode 100644 index 0000000..e2360d1 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afangles.h b/src/freetype2/autofit/afangles.h new file mode 100644 index 0000000..f33f9e1 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afcjk.c b/src/freetype2/autofit/afcjk.c new file mode 100644 index 0000000..c7ca266 --- /dev/null +++ b/src/freetype2/autofit/afcjk.c @@ -0,0 +1,1506 @@ +/***************************************************************************/ +/* */ +/* afcjk.c */ +/* */ +/* Auto-fitter hinting routines for CJK script (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. */ +/* */ +/***************************************************************************/ + + /* + * 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 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static 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; + } + } + + + static 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, 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; + } + + + static 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 + 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 ); + } + } + } + + + static 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 + { 0x0100, 0xFFFF }, /* why this? */ +#endif + { 0x2E80, 0x2EFF }, /* CJK Radicals Supplement */ + { 0x2F00, 0x2FDF }, /* Kangxi Radicals */ + { 0x3000, 0x303F }, /* CJK Symbols and Punctuation */ + { 0x3040, 0x309F }, /* Hiragana */ + { 0x30A0, 0x30FF }, /* Katakana */ + { 0x3100, 0x312F }, /* Bopomofo */ + { 0x3130, 0x318F }, /* Hangul Compatibility Jamo */ + { 0x31A0, 0x31BF }, /* Bopomofo Extended */ + { 0x31C0, 0x31EF }, /* CJK Strokes */ + { 0x31F0, 0x31FF }, /* Katakana Phonetic Extensions */ + { 0x3200, 0x32FF }, /* Enclosed CJK Letters and Months */ + { 0x3300, 0x33FF }, /* CJK Compatibility */ + { 0x3400, 0x4DBF }, /* CJK Unified Ideographs Extension A */ + { 0x4DC0, 0x4DFF }, /* Yijing Hexagram Symbols */ + { 0x4E00, 0x9FFF }, /* CJK Unified Ideographs */ + { 0xF900, 0xFAFF }, /* CJK Compatibility Ideographs */ + { 0xFE30, 0xFE4F }, /* CJK Compatibility Forms */ + { 0xFF00, 0xFFEF }, /* Halfwidth and Fullwidth Forms */ + { 0x20000, 0x2A6DF }, /* CJK Unified Ideographs Extension B */ + { 0x2F800, 0x2FA1F }, /* CJK Compatibility Ideographs Supplement */ + { 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) 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/freetype2/autofit/afcjk.h b/src/freetype2/autofit/afcjk.h new file mode 100644 index 0000000..0de4a5a --- /dev/null +++ b/src/freetype2/autofit/afcjk.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* afcjk.h */ +/* */ +/* Auto-fitter hinting routines for CJK script (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#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_END_HEADER + +#endif /* __AFCJK_H__ */ + + +/* END */ diff --git a/src/freetype2/autofit/afdummy.c b/src/freetype2/autofit/afdummy.c new file mode 100644 index 0000000..ed96e96 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afdummy.h b/src/freetype2/autofit/afdummy.h new file mode 100644 index 0000000..2a5faf8 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/aferrors.h b/src/freetype2/autofit/aferrors.h new file mode 100644 index 0000000..c2ed5fe --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afglobal.c b/src/freetype2/autofit/afglobal.c new file mode 100644 index 0000000..ad3baa1 --- /dev/null +++ b/src/freetype2/autofit/afglobal.c @@ -0,0 +1,289 @@ +/***************************************************************************/ +/* */ +/* afglobal.c */ +/* */ +/* Auto-fitter routines to compute global hinting values (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. */ +/* */ +/***************************************************************************/ + + +#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 Latin as the standard + * 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/freetype2/autofit/afglobal.h b/src/freetype2/autofit/afglobal.h new file mode 100644 index 0000000..cf52c08 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afhints.c b/src/freetype2/autofit/afhints.c new file mode 100644 index 0000000..4828706 --- /dev/null +++ b/src/freetype2/autofit/afhints.c @@ -0,0 +1,1264 @@ +/***************************************************************************/ +/* */ +/* afhints.c */ +/* */ +/* Auto-fitter hinting routines (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. */ +/* */ +/***************************************************************************/ + + +#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 + + 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 ) + { + memcpy( temp + pos, "round", 5 ); + pos += 5; + } + if ( flags & AF_EDGE_SERIF ) + { + if ( pos > 0 ) + temp[pos++] = ' '; + 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/freetype2/autofit/afhints.h b/src/freetype2/autofit/afhints.h new file mode 100644 index 0000000..1308d5c --- /dev/null +++ b/src/freetype2/autofit/afhints.h @@ -0,0 +1,333 @@ +/***************************************************************************/ +/* */ +/* afhints.h */ +/* */ +/* Auto-fitter hinting routines (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 __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_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_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_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_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/freetype2/autofit/afindic.c b/src/freetype2/autofit/afindic.c new file mode 100644 index 0000000..c6e7522 --- /dev/null +++ b/src/freetype2/autofit/afindic.c @@ -0,0 +1,134 @@ +/***************************************************************************/ +/* */ +/* afindic.c */ +/* */ +/* Auto-fitter hinting routines for Indic scripts (body). */ +/* */ +/* Copyright 2007 by */ +/* Rahul Bhalerao , . */ +/* */ +/* 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/freetype2/autofit/afindic.h b/src/freetype2/autofit/afindic.h new file mode 100644 index 0000000..b242b26 --- /dev/null +++ b/src/freetype2/autofit/afindic.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* afindic.h */ +/* */ +/* Auto-fitter hinting routines for Indic scripts (specification). */ +/* */ +/* Copyright 2007 by */ +/* Rahul Bhalerao , . */ +/* */ +/* 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/freetype2/autofit/aflatin.c b/src/freetype2/autofit/aflatin.c new file mode 100644 index 0000000..2ae9ec5 --- /dev/null +++ b/src/freetype2/autofit/aflatin.c @@ -0,0 +1,2166 @@ +/***************************************************************************/ +/* */ +/* aflatin.c */ +/* */ +/* Auto-fitter hinting routines for latin script (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. */ +/* */ +/***************************************************************************/ + + +#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; + + + 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, 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 ) + { + 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 characters) */ + { 0x00A0, 0x00FF }, /* Latin-1 Supplement (no control characters) */ + { 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 */ + { 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/freetype2/autofit/aflatin.h b/src/freetype2/autofit/aflatin.h new file mode 100644 index 0000000..3251d37 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/aflatin2.c b/src/freetype2/autofit/aflatin2.c new file mode 100644 index 0000000..0b41774 --- /dev/null +++ b/src/freetype2/autofit/aflatin2.c @@ -0,0 +1,2286 @@ +/***************************************************************************/ +/* */ +/* aflatin.c */ +/* */ +/* Auto-fitter hinting routines for latin script (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. */ +/* */ +/***************************************************************************/ + + +#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; + } + } + } + } + } + + /* 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 ) + { + 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/freetype2/autofit/aflatin2.h b/src/freetype2/autofit/aflatin2.h new file mode 100644 index 0000000..34eda05 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afloader.c b/src/freetype2/autofit/afloader.c new file mode 100644 index 0000000..4e4373a --- /dev/null +++ b/src/freetype2/autofit/afloader.c @@ -0,0 +1,530 @@ +/***************************************************************************/ +/* */ +/* afloader.c */ +/* */ +/* Auto-fitter glyph loading routines (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. */ +/* */ +/***************************************************************************/ + + +#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 */ + 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; + + 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/freetype2/autofit/afloader.h b/src/freetype2/autofit/afloader.h new file mode 100644 index 0000000..fa67c10 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afmodule.c b/src/freetype2/autofit/afmodule.c new file mode 100644 index 0000000..cd5e1cc --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afmodule.h b/src/freetype2/autofit/afmodule.h new file mode 100644 index 0000000..36268a0 --- /dev/null +++ b/src/freetype2/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 +#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/freetype2/autofit/aftypes.h b/src/freetype2/autofit/aftypes.h new file mode 100644 index 0000000..bd3fa88 --- /dev/null +++ b/src/freetype2/autofit/aftypes.h @@ -0,0 +1,349 @@ +/***************************************************************************/ +/* */ +/* aftypes.h */ +/* */ +/* Auto-fitter types (specification only). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + + /************************************************************************* + * + * 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 + +#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 +#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_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_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/freetype2/autofit/afwarp.c b/src/freetype2/autofit/afwarp.c new file mode 100644 index 0000000..f5bb9b1 --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/afwarp.h b/src/freetype2/autofit/afwarp.h new file mode 100644 index 0000000..7343fdd --- /dev/null +++ b/src/freetype2/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/freetype2/autofit/autofit.c b/src/freetype2/autofit/autofit.c new file mode 100644 index 0000000..2fe66a9 --- /dev/null +++ b/src/freetype2/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 +#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/freetype2/base/ftapi.c b/src/freetype2/base/ftapi.c new file mode 100644 index 0000000..8914d1f --- /dev/null +++ b/src/freetype2/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 +#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/freetype2/base/ftbase.c b/src/freetype2/base/ftbase.c new file mode 100644 index 0000000..d176b81 --- /dev/null +++ b/src/freetype2/base/ftbase.c @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* ftbase.c */ +/* */ +/* Single object library component (body only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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 + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#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( __APPLE__ ) && !defined ( DARWIN_NO_CARBON ) +#include +#endif + +/* END */ diff --git a/src/freetype2/base/ftbbox.c b/src/freetype2/base/ftbbox.c new file mode 100644 index 0000000..532ab13 --- /dev/null +++ b/src/freetype2/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 +#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; + + + /*************************************************************************/ + /* */ + /* */ + /* BBox_Move_To */ + /* */ + /* */ + /* 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. */ + /* */ + /* */ + /* to :: A pointer to the destination vector. */ + /* */ + /* */ + /* user :: A pointer to the current walk context. */ + /* */ + /* */ + /* 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 ) + + + /*************************************************************************/ + /* */ + /* */ + /* BBox_Conic_Check */ + /* */ + /* */ + /* 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. */ + /* */ + /* */ + /* y1 :: The start coordinate. */ + /* */ + /* y2 :: The coordinate of the control point. */ + /* */ + /* y3 :: The end coordinate. */ + /* */ + /* */ + /* 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; + } + + + /*************************************************************************/ + /* */ + /* */ + /* BBox_Conic_To */ + /* */ + /* */ + /* 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. */ + /* */ + /* */ + /* control :: A pointer to a control point. */ + /* */ + /* to :: A pointer to the destination vector. */ + /* */ + /* */ + /* user :: The address of the current walk context. */ + /* */ + /* */ + /* Always 0. Needed for the interface only. */ + /* */ + /* */ + /* 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; + } + + + /*************************************************************************/ + /* */ + /* */ + /* BBox_Cubic_Check */ + /* */ + /* */ + /* 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. */ + /* */ + /* */ + /* p1 :: The start coordinate. */ + /* */ + /* p2 :: The coordinate of the first control point. */ + /* */ + /* p3 :: The coordinate of the second control point. */ + /* */ + /* p4 :: The end coordinate. */ + /* */ + /* */ + /* 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 + + + /*************************************************************************/ + /* */ + /* */ + /* BBox_Cubic_To */ + /* */ + /* */ + /* 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. */ + /* */ + /* */ + /* control1 :: A pointer to the first control point. */ + /* */ + /* control2 :: A pointer to the second control point. */ + /* */ + /* to :: A pointer to the destination vector. */ + /* */ + /* */ + /* user :: The address of the current walk context. */ + /* */ + /* */ + /* Always 0. Needed for the interface only. */ + /* */ + /* */ + /* 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/freetype2/base/ftbdf.c b/src/freetype2/base/ftbdf.c new file mode 100644 index 0000000..d29adf0 --- /dev/null +++ b/src/freetype2/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 +#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, ®istry ); + } + + 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/freetype2/base/ftbitmap.c b/src/freetype2/base/ftbitmap.c new file mode 100644 index 0000000..4c1cdf2 --- /dev/null +++ b/src/freetype2/base/ftbitmap.c @@ -0,0 +1,630 @@ +/***************************************************************************/ +/* */ +/* ftbitmap.c */ +/* */ +/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ +/* bitmaps into 8bpp format (body). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_BITMAP_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: + { + 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: + { + 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_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/freetype2/base/ftcalc.c b/src/freetype2/base/ftcalc.c new file mode 100644 index 0000000..63aed95 --- /dev/null +++ b/src/freetype2/base/ftcalc.c @@ -0,0 +1,822 @@ +/***************************************************************************/ +/* */ +/* ftcalc.c */ +/* */ +/* Arithmetic computations (body). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* 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 +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_OBJECTS_H + + +/* 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 ) + { + 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 ; + } + + + /* 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 ) + { + /* use inline assembly to speed up things a bit */ + +#if defined( __GNUC__ ) && defined( i386 ) + + FT_Long result; + + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + "mov %%eax, %0\n" + : "=r"(result) + : "a"(a), "d"(b) + : "%ecx" + ); + return result; + +#elif 1 + + FT_Long sa, sb; + FT_ULong ua, ub; + + + if ( a == 0 || b == 0x10000L ) + return a; + + 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 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/freetype2/base/ftdbgmem.c b/src/freetype2/base/ftdbgmem.c new file mode 100644 index 0000000..52a5c20 --- /dev/null +++ b/src/freetype2/base/ftdbgmem.c @@ -0,0 +1,998 @@ +/***************************************************************************/ +/* */ +/* ftdbgmem.c */ +/* */ +/* Memory debugger (body). */ +/* */ +/* Copyright 2001, 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 +#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 +#include + + 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 = ""; + _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 = ""; + _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 = ""; + _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 */ + const FT_Byte _debug_mem_dummy = 0; + +#endif /* !FT_DEBUG_MEMORY */ + + +/* END */ diff --git a/src/freetype2/base/ftdebug.c b/src/freetype2/base/ftdebug.c new file mode 100644 index 0000000..c55d3c8 --- /dev/null +++ b/src/freetype2/base/ftdebug.c @@ -0,0 +1,246 @@ +/***************************************************************************/ +/* */ +/* ftdebug.c */ +/* */ +/* Debugging and logging component (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* 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 +#include FT_FREETYPE_H +#include FT_INTERNAL_DEBUG_H + + +#if defined( 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 ); + vprintf( 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 ); + vprintf( 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 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/freetype2/base/ftgasp.c b/src/freetype2/base/ftgasp.c new file mode 100644 index 0000000..8485d29 --- /dev/null +++ b/src/freetype2/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 +#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/freetype2/base/ftgloadr.c b/src/freetype2/base/ftgloadr.c new file mode 100644 index 0000000..ab52621 --- /dev/null +++ b/src/freetype2/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 +#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/freetype2/base/ftglyph.c b/src/freetype2/base/ftglyph.c new file mode 100644 index 0000000..969c5db --- /dev/null +++ b/src/freetype2/base/ftglyph.c @@ -0,0 +1,682 @@ +/***************************************************************************/ +/* */ +/* ftglyph.c */ +/* */ +/* FreeType convenience functions to handle glyphs (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* 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 +#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 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** Convenience functions ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* 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; + } + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** 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; + + + *target = 0; + + /* check arguments */ + if ( !target || !source || !source->clazz ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + clazz = source->clazz; + error = ft_new_glyph( source->library, clazz, © ); + 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/freetype2/base/ftgxval.c b/src/freetype2/base/ftgxval.c new file mode 100644 index 0000000..32662be --- /dev/null +++ b/src/freetype2/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 +#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_Unimplemented_Feature; + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( table ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ) + { + FT_Service_CKERNvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + + if ( ckern_table == NULL ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + ckern_table ); + else + error = FT_Err_Unimplemented_Feature; + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( table ); + } + + +/* END */ diff --git a/src/freetype2/base/ftinit.c b/src/freetype2/base/ftinit.c new file mode 100644 index 0000000..7af19c3 --- /dev/null +++ b/src/freetype2/base/ftinit.c @@ -0,0 +1,163 @@ +/***************************************************************************/ +/* */ +/* ftinit.c */ +/* */ +/* FreeType initialization layer (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* The purpose of this file is to implement the following two */ + /* functions: */ + /* */ + /* FT_Add_Default_Modules(): */ + /* This function is used to add the set of default modules to a */ + /* fresh new library object. The set is taken from the header file */ + /* `freetype/config/ftmodule.h'. See the document `FreeType 2.0 */ + /* Build System' for more information. */ + /* */ + /* FT_Init_FreeType(): */ + /* This function creates a system object for the current platform, */ + /* builds a library out of it, then calls FT_Default_Drivers(). */ + /* */ + /* Note that even if FT_Init_FreeType() uses the implementation of the */ + /* system object defined at build time, client applications are still */ + /* able to provide their own `ftsystem.c'. */ + /* */ + /*************************************************************************/ + + +#include +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_MODULE_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_init + +#undef FT_USE_MODULE +#ifdef __cplusplus +#define FT_USE_MODULE( x ) extern "C" const FT_Module_Class x; +#else +#define FT_USE_MODULE( x ) extern const FT_Module_Class x; +#endif + + +#include FT_CONFIG_MODULES_H + + +#undef FT_USE_MODULE +#define FT_USE_MODULE( x ) (const FT_Module_Class*)&(x), + + static + const FT_Module_Class* const ft_default_modules[] = + { +#include FT_CONFIG_MODULES_H + 0 + }; + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Add_Default_Modules( FT_Library library ) + { + FT_Error error; + const FT_Module_Class* const* cur; + + + /* test for valid `library' delayed to FT_Add_Module() */ + + cur = ft_default_modules; + while ( *cur ) + { + error = FT_Add_Module( library, *cur ); + /* notify errors, but don't stop */ + if ( error ) + { + FT_ERROR(( "FT_Add_Default_Module: Cannot install `%s', error = 0x%x\n", + (*cur)->module_name, error )); + } + cur++; + } + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ) + { + FT_Error error; + FT_Memory memory; + + + /* First of all, allocate a new system object -- this function is part */ + /* of the system-specific component, i.e. `ftsystem.c'. */ + + memory = FT_New_Memory(); + if ( !memory ) + { + FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); + return FT_Err_Unimplemented_Feature; + } + + /* build a library out of it, then fill it with the set of */ + /* default drivers. */ + + error = FT_New_Library( memory, alibrary ); + if ( error ) + FT_Done_Memory( memory ); + else + { + (*alibrary)->version_major = FREETYPE_MAJOR; + (*alibrary)->version_minor = FREETYPE_MINOR; + (*alibrary)->version_patch = FREETYPE_PATCH; + + FT_Add_Default_Modules( *alibrary ); + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_FreeType( FT_Library library ) + { + if ( library ) + { + FT_Memory memory = library->memory; + + + /* Discard the library object */ + FT_Done_Library( library ); + + /* discard memory manager */ + FT_Done_Memory( memory ); + } + + return FT_Err_Ok; + } + + +/* END */ diff --git a/src/freetype2/base/ftlcdfil.c b/src/freetype2/base/ftlcdfil.c new file mode 100644 index 0000000..f40bbea --- /dev/null +++ b/src/freetype2/base/ftlcdfil.c @@ -0,0 +1,351 @@ +/***************************************************************************/ +/* */ +/* ftlcdfil.c */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs (body). */ +/* */ +/* Copyright 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 +#include FT_LCD_FILTER_H +#include FT_IMAGE_H +#include FT_INTERNAL_OBJECTS_H + + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + +/* define USE_LEGACY to implement the legacy filter */ +#define USE_LEGACY + + /* FIR filter used by the default and light filters */ + static void + _ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_Library library ) + { + FT_Byte* weights = library->lcd_weights; + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + + + /* horizontal in-place FIR filter */ + if ( mode == FT_RENDER_MODE_LCD && width >= 4 ) + { + FT_Byte* line = bitmap->buffer; + + + for ( ; height > 0; height--, line += bitmap->pitch ) + { + FT_UInt fir[5]; + FT_UInt val1, xx; + + + val1 = line[0]; + fir[0] = weights[2] * val1; + fir[1] = weights[3] * val1; + fir[2] = weights[4] * val1; + fir[3] = 0; + fir[4] = 0; + + val1 = line[1]; + fir[0] += weights[1] * val1; + fir[1] += weights[2] * val1; + fir[2] += weights[3] * val1; + fir[3] += weights[4] * val1; + + for ( xx = 2; xx < width; xx++ ) + { + FT_UInt val, pix; + + + val = line[xx]; + pix = fir[0] + weights[0] * val; + fir[0] = fir[1] + weights[1] * val; + fir[1] = fir[2] + weights[2] * val; + fir[2] = fir[3] + weights[3] * val; + fir[3] = weights[4] * val; + + pix >>= 8; + pix |= -( pix >> 8 ); + line[xx - 2] = (FT_Byte)pix; + } + + { + FT_UInt pix; + + + pix = fir[0] >> 8; + pix |= -( pix >> 8 ); + line[xx - 2] = (FT_Byte)pix; + + pix = fir[1] >> 8; + pix |= -( pix >> 8 ); + line[xx - 1] = (FT_Byte)pix; + } + } + } + + /* vertical in-place FIR filter */ + else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 ) + { + FT_Byte* column = bitmap->buffer; + FT_Int pitch = bitmap->pitch; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_UInt fir[5]; + FT_UInt val1, yy; + + + val1 = col[0]; + fir[0] = weights[2] * val1; + fir[1] = weights[3] * val1; + fir[2] = weights[4] * val1; + fir[3] = 0; + fir[4] = 0; + col += pitch; + + val1 = col[0]; + fir[0] += weights[1] * val1; + fir[1] += weights[2] * val1; + fir[2] += weights[3] * val1; + fir[3] += weights[4] * val1; + col += pitch; + + for ( yy = 2; yy < height; yy++ ) + { + FT_UInt val, pix; + + + val = col[0]; + pix = fir[0] + weights[0] * val; + fir[0] = fir[1] + weights[1] * val; + fir[1] = fir[2] + weights[2] * val; + fir[2] = fir[3] + weights[3] * val; + fir[3] = weights[4] * val; + + pix >>= 8; + pix |= -( pix >> 8 ); + col[-2 * pitch] = (FT_Byte)pix; + col += pitch; + } + + { + FT_UInt pix; + + + pix = fir[0] >> 8; + pix |= -( pix >> 8 ); + col[-2 * pitch] = (FT_Byte)pix; + + pix = fir[1] >> 8; + pix |= -( pix >> 8 ); + col[-pitch] = (FT_Byte)pix; + } + } + } + } + + +#ifdef USE_LEGACY + + /* FIR filter used by the default and light filters */ + static void + _ft_lcd_filter_legacy( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_Library library ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + + static const int filters[3][3] = + { + { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 }, + { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 }, + { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 } + }; + + FT_UNUSED( library ); + + + /* horizontal in-place FIR filter */ + if ( mode == FT_RENDER_MODE_LCD && width >= 3 ) + { + FT_Byte* line = bitmap->buffer; + + + for ( ; height > 0; height--, line += pitch ) + { + FT_UInt xx; + + + for ( xx = 0; xx < width; xx += 3 ) + { + FT_UInt r = 0; + FT_UInt g = 0; + FT_UInt b = 0; + FT_UInt p; + + + p = line[xx]; + r += filters[0][0] * p; + g += filters[0][1] * p; + b += filters[0][2] * p; + + p = line[xx + 1]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = line[xx + 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + line[xx] = (FT_Byte)( r / 65536 ); + line[xx + 1] = (FT_Byte)( g / 65536 ); + line[xx + 2] = (FT_Byte)( b / 65536 ); + } + } + } + else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 ) + { + FT_Byte* column = bitmap->buffer; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_Byte* col_end = col + height * pitch; + + + for ( ; col < col_end; col += 3 * pitch ) + { + FT_UInt r = 0; + FT_UInt g = 0; + FT_UInt b = 0; + FT_UInt p; + + + p = col[0]; + r += filters[0][0] * p; + g += filters[0][1] * p; + b += filters[0][2] * p; + + p = col[pitch]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = col[pitch * 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + col[0] = (FT_Byte)( r / 65536 ); + col[pitch] = (FT_Byte)( g / 65536 ); + col[2 * pitch] = (FT_Byte)( b / 65536 ); + } + } + } + } + +#endif /* USE_LEGACY */ + + + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + static const FT_Byte light_filter[5] = + { 0, 85, 86, 85, 0 }; + /* the values here sum up to a value larger than 256, */ + /* providing a cheap gamma correction */ + static const FT_Byte default_filter[5] = + { 0x10, 0x40, 0x70, 0x40, 0x10 }; + + + if ( library == NULL ) + return FT_Err_Invalid_Argument; + + switch ( filter ) + { + case FT_LCD_FILTER_NONE: + library->lcd_filter_func = NULL; + library->lcd_extra = 0; + break; + + case FT_LCD_FILTER_DEFAULT: +#if defined( FT_FORCE_LEGACY_LCD_FILTER ) + + library->lcd_filter_func = _ft_lcd_filter_legacy; + library->lcd_extra = 0; + +#elif defined( FT_FORCE_LIGHT_LCD_FILTER ) + + memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; + +#else + + memcpy( library->lcd_weights, default_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; + +#endif + + break; + + case FT_LCD_FILTER_LIGHT: + memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; + break; + +#ifdef USE_LEGACY + + case FT_LCD_FILTER_LEGACY: + library->lcd_filter_func = _ft_lcd_filter_legacy; + library->lcd_extra = 0; + break; + +#endif + + default: + return FT_Err_Invalid_Argument; + } + + library->lcd_filter = filter; + return 0; + } + +#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + FT_UNUSED( library ); + FT_UNUSED( filter ); + + return FT_Err_Unimplemented_Feature; + } + +#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + +/* END */ diff --git a/src/freetype2/base/ftmac.c b/src/freetype2/base/ftmac.c new file mode 100644 index 0000000..fd6201a --- /dev/null +++ b/src/freetype2/base/ftmac.c @@ -0,0 +1,1096 @@ +/***************************************************************************/ +/* */ +/* ftmac.c */ +/* */ +/* Mac FOND support. Written by just@letterror.com. */ +/* Heavily modified by mpsuzuki, George Williams, and Sean McBride. */ +/* */ +/* This file is for Mac OS X only; see builds/mac/ftoldmac.c for */ +/* classic platforms built by MPW. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* Just van Rossum, 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. */ +/* */ +/***************************************************************************/ + + + /* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + + Warning: fbit and NFNT bitmap resources are not supported yet. In old + sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' + resources instead of the `bdat' table in the sfnt resource. Therefore, + face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' + resource is unavailable at present. + + The Mac FOND support works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. This + is done by checking the file type: it has to be 'FFIL' or 'tfil'. The + stream that gets passed to our init_face() routine is a stdio stream, + which isn't usable for us, since the FOND resources live in the + resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is a + TrueType font and/or(!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate `LWFN' file), read + its data into memory, massage it slightly so it becomes PFB data, wrap + it into a memory stream, load the Type 1 driver and delegate the rest + of the work to it by calling FT_Open_Face(). (XXX TODO: after this + has been done, the kerning data from the FOND resource should be + appended to the face: On the Mac there are usually no AFM files + available. However, this is tricky since we need to map Mac char + codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an `sfnt' resource), read it into memory, + wrap it into a memory stream, load the TrueType driver and delegate + the rest of the work to it, by calling FT_Open_Face(). + + - Some suitcase fonts (notably Onyx) might point the `LWFN' file to + itself, even though it doesn't contains `POST' resources. To handle + this special case without opening the file an extra time, we just + ignore errors from the `LWFN' and fallback to the `sfnt' if both are + available. + */ + + +#include +#include FT_FREETYPE_H +#include FT_INTERNAL_STREAM_H + + /* This is for Mac OS X. Without redefinition, OS_INLINE */ + /* expands to `static inline' which doesn't survive the */ + /* -ansi compilation flag of GCC. */ +#if !HAVE_ANSI_OS_INLINE +#undef OS_INLINE +#define OS_INLINE static __inline__ +#endif +#include + +#ifndef HFS_MAXPATHLEN +#define HFS_MAXPATHLEN 1024 +#endif + +#define FT_DEPRECATED_ATTRIBUTE + +#include FT_MAC_H + + /* undefine blocking-macros in ftmac.h */ +#undef FT_GetFile_From_Mac_Name( a, b, c ) +#undef FT_GetFile_From_Mac_ATS_Name( a, b, c ) +#undef FT_New_Face_From_FSSpec( a, b, c, d ) + + + /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available (this is not common, + but it *is* possible). */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif + + + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_Err_Unimplemented_Feature; + } + + + /* Private function. */ + /* The FSSpec type has been discouraged for a long time, */ + /* but for some reason, there is no FSRef version of */ + /* ATSFontGetFileSpecification(), so we made our own. */ + /* Apple will provide one eventually. */ + static OSStatus + FT_ATSFontGetFileReference( ATSFontRef ats_font_id, + FSRef* ats_font_ref ) + { +#if __LP64__ + FT_UNUSED( ats_font_id ); + FT_UNUSED( ats_font_ref ); + + return fnfErr; +#else + OSStatus err; + FSSpec spec; + + + err = ATSFontGetFileSpecification( ats_font_id, &spec ); + if ( noErr == err ) + err = FSpMakeFSRef( &spec, ats_font_ref ); + + return err; +#endif + } + + + static FT_Error + FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, + FSRef* ats_font_ref, + FT_Long* face_index ) + { + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + + + *face_index = 0; + + cf_fontName = CFStringCreateWithCString( NULL, fontName, + kCFStringEncodingMacRoman ); + ats_font_id = ATSFontFindFromName( cf_fontName, + kATSOptionFlagsUnRestrictedScope ); + CFRelease( cf_fontName ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + return FT_Err_Unknown_File_Format; + + if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) + return FT_Err_Unknown_File_Format; + + /* face_index calculation by searching preceding fontIDs */ + /* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + + + while ( id2 > 0 ) + { + if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) + break; + + id2 --; + } + *face_index = ats_font_id - ( id2 + 1 ); + } + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( FT_Err_Ok != err ) + return err; + + if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) + return FT_Err_Unknown_File_Format; + + return FT_Err_Ok; + } + + + /* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { +#if __LP64__ + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_Err_Unimplemented_Feature; +#else + FSRef ref; + FT_Error err; + + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( FT_Err_Ok != err ) + return err; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, + pathSpec, NULL ) ) + return FT_Err_Unknown_File_Format; + + return FT_Err_Ok; +#endif + } + + + static OSErr + FT_FSPathMakeRes( const UInt8* pathname, + short* res ) + { + OSErr err; + FSRef ref; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return FT_Err_Cannot_Open_Resource; + + /* at present, no support for dfont format */ + err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); + if ( noErr == err ) + return err; + + /* fallback to original resource-fork font */ + *res = FSOpenResFile( &ref, fsRdPerm ); + err = ResError(); + + return err; + } + + + /* Return the file type for given pathname */ + static OSType + get_file_type_from_path( const UInt8* pathname ) + { + FSRef ref; + FSCatalogInfo info; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return ( OSType ) 0; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, + NULL, NULL, NULL ) ) + return ( OSType ) 0; + + return ((FInfo *)(info.finderInfo))->fdType; + } + + + /* Given a PostScript font name, create the Macintosh LWFN file name. */ + static void + create_lwfn_name( char* ps_name, + Str255 lwfn_file_name ) + { + int max = 5, count = 0; + FT_Byte* p = lwfn_file_name; + FT_Byte* q = (FT_Byte*)ps_name; + + + lwfn_file_name[0] = 0; + + while ( *q ) + { + if ( ft_isupper( *q ) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + + + static short + count_faces_sfnt( char* fond_data ) + { + /* The count is 1 greater than the value in the FOND. */ + /* Isn't that cute? :-) */ + + return EndianS16_BtoN( *( (short*)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + } + + + static short + count_faces_scalable( char* fond_data ) + { + AsscEntry* assoc; + FamRec* fond; + short i, face, face_all; + + + fond = (FamRec*)fond_data; + face_all = EndianS16_BtoN( *( (short *)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + face = 0; + + for ( i = 0; i < face_all; i++ ) + { + if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) + face++; + } + return face; + } + + + /* Look inside the FOND data, answer whether there should be an SFNT + resource, and answer the name of a possible LWFN Type 1 file. + + Thanks to Paul Miller (paulm@profoundeffects.com) for the fix + to load a face OTHER than the first one in the FOND! + */ + + + static void + parse_fond( char* fond_data, + short* have_sfnt, + short* sfnt_id, + Str255 lwfn_file_name, + short face_index ) + { + AsscEntry* assoc; + AsscEntry* base_assoc; + FamRec* fond; + + + *sfnt_id = 0; + *have_sfnt = 0; + lwfn_file_name[0] = 0; + + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + base_assoc = assoc; + + /* Let's do a little range checking before we get too excited here */ + if ( face_index < count_faces_sfnt( fond_data ) ) + { + assoc += face_index; /* add on the face_index! */ + + /* if the face at this index is not scalable, + fall back to the first one (old behavior) */ + if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( assoc->fontID ); + } + else if ( base_assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); + } + } + + if ( EndianS32_BtoN( fond->ffStylOff ) ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + char ps_name[256]; + unsigned char* names[64]; + int i; + + + p += EndianS32_BtoN( fond->ffStylOff ); + style = (StyleTable*)p; + p += sizeof ( StyleTable ); + string_count = EndianS16_BtoN( *(short*)(p) ); + p += sizeof ( short ); + + for ( i = 0; i < string_count && i < 64; i++ ) + { + names[i] = p; + p += names[i][0]; + p++; + } + + { + size_t ps_name_len = (size_t)names[0][0]; + + + if ( ps_name_len != 0 ) + { + ft_memcpy(ps_name, names[0] + 1, ps_name_len); + ps_name[ps_name_len] = 0; + } + if ( style->indexes[0] > 1 ) + { + unsigned char* suffixes = names[style->indexes[0] - 1]; + + + for ( i = 1; i <= suffixes[0]; i++ ) + { + unsigned char* s; + size_t j = suffixes[i] - 1; + + + if ( j < string_count && ( s = names[j] ) != NULL ) + { + size_t s_len = (size_t)s[0]; + + + if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) + { + ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); + ps_name_len += s_len; + ps_name[ps_name_len] = 0; + } + } + } + } + } + + create_lwfn_name( ps_name, lwfn_file_name ); + } + } + + + static FT_Error + lookup_lwfn_by_fond( const UInt8* path_fond, + ConstStr255Param base_lwfn, + UInt8* path_lwfn, + size_t path_size ) + { + FSRef ref, par_ref; + int dirname_len; + + + /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ + /* We should not extract parent directory by string manipulation. */ + + if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) + return FT_Err_Invalid_Argument; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, &par_ref ) ) + return FT_Err_Invalid_Argument; + + if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) + return FT_Err_Invalid_Argument; + + if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) + return FT_Err_Invalid_Argument; + + /* now we have absolute dirname in path_lwfn */ + ft_strcat( (char *)path_lwfn, "/" ); + dirname_len = ft_strlen( (char *)path_lwfn ); + ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[dirname_len + base_lwfn[0]] = '\0'; + + if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) + return FT_Err_Cannot_Open_Resource; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, NULL ) ) + return FT_Err_Cannot_Open_Resource; + + return FT_Err_Ok; + } + + + static short + count_faces( Handle fond, + const UInt8* pathname ) + { + short sfnt_id; + short have_sfnt, have_lwfn; + Str255 lwfn_file_name; + UInt8 buff[HFS_MAXPATHLEN]; + FT_Error err; + short num_faces; + + + have_sfnt = have_lwfn = 0; + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); + + if ( lwfn_file_name[0] ) + { + err = lookup_lwfn_by_fond( pathname, lwfn_file_name, + buff, sizeof ( buff ) ); + if ( FT_Err_Ok == err ) + have_lwfn = 1; + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + num_faces = 1; + else + num_faces = count_faces_scalable( *fond ); + + return num_faces; + } + + + /* Read Type 1 data from the POST resources inside the LWFN file, + return a PFB buffer. This is somewhat convoluted because the FT2 + PFB parser wants the ASCII header as one chunk, and the LWFN + chunks are often not organized that way, so we glue chunks + of the same type together. */ + static FT_Error + read_lwfn( FT_Memory memory, + short res, + FT_Byte** pfb_data, + FT_ULong* size ) + { + FT_Error error = FT_Err_Ok; + short res_id; + unsigned char *buffer, *p, *size_p = NULL; + FT_ULong total_size = 0; + FT_ULong old_total_size = 0; + FT_ULong post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + + + UseResFile( res ); + + /* First pass: load all POST resources, and determine the size of */ + /* the output buffer. */ + res_id = 501; + last_code = -1; + + for (;;) + { + post_data = Get1Resource( 'POST', res_id++ ); + if ( post_data == NULL ) + break; /* we are done */ + + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( code == 5 ) + total_size += 2; /* just the end code */ + else + total_size += 6; /* code + 4 bytes chunk length */ + } + + total_size += GetHandleSize( post_data ) - 2; + last_code = code; + + /* detect integer overflows */ + if ( total_size < old_total_size ) + { + error = FT_Err_Array_Too_Large; + goto Error; + } + + old_total_size = total_size; + } + + if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) + goto Error; + + /* Second pass: append all POST data to the buffer, add PFB fields. */ + /* Glue all consecutive chunks of the same type together. */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + + for (;;) + { + post_data = Get1Resource( 'POST', res_id++ ); + if ( post_data == NULL ) + break; /* we are done */ + + post_size = (FT_ULong)GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( last_code != -1 ) + { + /* we are done adding a chunk, fill in the size field */ + if ( size_p != NULL ) + { + *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); + } + pfb_chunk_size = 0; + } + + *p++ = 0x80; + if ( code == 5 ) + *p++ = 0x03; /* the end */ + else if ( code == 2 ) + *p++ = 0x02; /* binary segment */ + else + *p++ = 0x01; /* ASCII segment */ + + if ( code != 5 ) + { + size_p = p; /* save for later */ + p += 4; /* make space for size field */ + } + } + + ft_memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + + *pfb_data = buffer; + *size = total_size; + + Error: + CloseResFile( res ); + return error; + } + + + /* Finalizer for a memory stream; gets called by FT_Done_Face(). + It frees the memory it uses. */ + static void + memory_stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->base = 0; + stream->close = 0; + } + + + /* Create a new memory stream from a buffer and a size. */ + static FT_Error + new_memory_stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream_CloseFunc close, + FT_Stream* astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !base ) + return FT_Err_Invalid_Argument; + + *astream = 0; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, base, size ); + + stream->close = close; + + *astream = stream; + + Exit: + return error; + } + + + /* Create a new FT_Face given a buffer and a driver name. */ + static FT_Error + open_face_from_buffer( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Long face_index, + char* driver_name, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; + FT_Stream stream; + FT_Memory memory = library->memory; + + + error = new_memory_stream( library, + base, + size, + memory_stream_close, + &stream ); + if ( error ) + { + FT_FREE( base ); + return error; + } + + args.flags = FT_OPEN_STREAM; + args.stream = stream; + if ( driver_name ) + { + args.flags = args.flags | FT_OPEN_DRIVER; + args.driver = FT_Get_Module( library, driver_name ); + } + + /* At this point, face_index has served its purpose; */ + /* whoever calls this function has already used it to */ + /* locate the correct font data. We should not propagate */ + /* this index to FT_Open_Face() (unless it is negative). */ + + if ( face_index > 0 ) + face_index = 0; + + error = FT_Open_Face( library, &args, face_index, aface ); + if ( error == FT_Err_Ok ) + (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + else + FT_Stream_Free( stream, 0 ); + + return error; + } + + + /* Create a new FT_Face from a file spec to an LWFN file. */ + static FT_Error + FT_New_Face_From_LWFN( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Byte* pfb_data; + FT_ULong pfb_size; + FT_Error error; + short res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) + return FT_Err_Cannot_Open_Resource; + + pfb_data = NULL; + pfb_size = 0; + error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); + CloseResFile( res ); /* PFB is already loaded, useless anymore */ + if ( error ) + return error; + + return open_face_from_buffer( library, + pfb_data, + pfb_size, + face_index, + "type1", + aface ); + } + + + /* Create a new FT_Face from an SFNT resource, specified by res ID. */ + static FT_Error + FT_New_Face_From_SFNT( FT_Library library, + short sfnt_id, + FT_Long face_index, + FT_Face* aface ) + { + Handle sfnt = NULL; + FT_Byte* sfnt_data; + size_t sfnt_size; + FT_Error error = FT_Err_Ok; + FT_Memory memory = library->memory; + int is_cff; + + + sfnt = GetResource( 'sfnt', sfnt_id ); + if ( ResError() ) + return FT_Err_Invalid_Handle; + + sfnt_size = (FT_ULong)GetHandleSize( sfnt ); + if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + { + ReleaseResource( sfnt ); + return error; + } + + ft_memcpy( sfnt_data, *sfnt, sfnt_size ); + ReleaseResource( sfnt ); + + is_cff = sfnt_size > 4 && sfnt_data[0] == 'O' && + sfnt_data[1] == 'T' && + sfnt_data[2] == 'T' && + sfnt_data[3] == 'O'; + + return open_face_from_buffer( library, + sfnt_data, + sfnt_size, + face_index, + is_cff ? "cff" : "truetype", + aface ); + } + + + /* Create a new FT_Face from a file spec to a suitcase file. */ + static FT_Error + FT_New_Face_From_Suitcase( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error = FT_Err_Cannot_Open_Resource; + short res_ref, res_index; + Handle fond; + short num_faces_in_res, num_faces_in_fond; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) + return FT_Err_Cannot_Open_Resource; + + UseResFile( res_ref ); + if ( ResError() ) + return FT_Err_Cannot_Open_Resource; + + num_faces_in_res = 0; + for ( res_index = 1; ; ++res_index ) + { + fond = Get1IndResource( 'FOND', res_index ); + if ( ResError() ) + break; + + num_faces_in_fond = count_faces( fond, pathname ); + num_faces_in_res += num_faces_in_fond; + + if ( 0 <= face_index && face_index < num_faces_in_fond && error ) + error = FT_New_Face_From_FOND( library, fond, face_index, aface ); + + face_index -= num_faces_in_fond; + } + + CloseResFile( res_ref ); + if ( FT_Err_Ok == error && NULL != aface ) + (*aface)->num_faces = num_faces_in_res; + return error; + } + + + /* documentation is in ftmac.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face* aface ) + { + short sfnt_id, have_sfnt, have_lwfn = 0; + short fond_id; + OSType fond_type; + Str255 fond_name; + Str255 lwfn_file_name; + UInt8 path_lwfn[HFS_MAXPATHLEN]; + OSErr err; + FT_Error error = FT_Err_Ok; + + + GetResInfo( fond, &fond_id, &fond_type, fond_name ); + if ( ResError() != noErr || fond_type != 'FOND' ) + return FT_Err_Invalid_File_Format; + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); + + if ( lwfn_file_name[0] ) + { + short res; + + + res = HomeResFile( fond ); + if ( noErr != ResError() ) + goto found_no_lwfn_file; + + { + UInt8 path_fond[HFS_MAXPATHLEN]; + FSRef ref; + + + err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, + NULL, NULL, NULL, &ref, NULL ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( FT_Err_Ok == error ) + have_lwfn = 1; + } + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + error = FT_New_Face_From_LWFN( library, + path_lwfn, + face_index, + aface ); + else + error = FT_Err_Unknown_File_Format; + + found_no_lwfn_file: + if ( have_sfnt && FT_Err_Ok != error ) + error = FT_New_Face_From_SFNT( library, + sfnt_id, + face_index, + aface ); + + return error; + } + + + /* Common function to load a new FT_Face from a resource file. */ + static FT_Error + FT_New_Face_From_Resource( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + OSType file_type; + FT_Error error; + + + /* LWFN is a (very) specific file format, check for it explicitly */ + file_type = get_file_type_from_path( pathname ); + if ( file_type == 'LWFN' ) + return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); + + /* Otherwise the file type doesn't matter (there are more than */ + /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ + /* if it works, fine. */ + + error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); + if ( error == 0 ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.); */ + /* we signal this by returning no error and no FT_Face */ + *aface = NULL; + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face */ + /* */ + /* */ + /* This is the Mac-specific implementation of FT_New_Face. In */ + /* addition to the standard FT_New_Face() functionality, it also */ + /* accepts pathnames to Mac suitcase files. For further */ + /* documentation see the original FT_New_Face() in freetype.h. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_Err_Invalid_Argument; + + error = FT_Err_Ok; + *aface = NULL; + + /* try resourcefork based font: LWFN, FFIL */ + error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, + face_index, aface ); + if ( error != 0 || *aface != NULL ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.) */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face_From_FSRef */ + /* */ + /* */ + /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */ + /* accepts an FSRef instead of a path. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef* ref, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error; + FT_Open_Args args; + OSErr err; + UInt8 pathname[HFS_MAXPATHLEN]; + + + if ( !ref ) + return FT_Err_Invalid_Argument; + + err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_Err_Cannot_Open_Resource; + + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error != 0 || *aface != NULL ) + return error; + + /* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face_From_FSSpec */ + /* */ + /* */ + /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */ + /* accepts an FSSpec instead of a path. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec* spec, + FT_Long face_index, + FT_Face* aface ) + { +#if __LP64__ + FT_UNUSED( library ); + FT_UNUSED( spec ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + + return FT_Err_Unimplemented_Feature; +#else + FSRef ref; + + + if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) + return FT_Err_Invalid_Argument; + else + return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); +#endif + } + + +/* END */ diff --git a/src/freetype2/base/ftmm.c b/src/freetype2/base/ftmm.c new file mode 100644 index 0000000..586d5e8 --- /dev/null +++ b/src/freetype2/base/ftmm.c @@ -0,0 +1,202 @@ +/***************************************************************************/ +/* */ +/* ftmm.c */ +/* */ +/* Multiple Master font support (body). */ +/* */ +/* Copyright 1996-2001, 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 +#include FT_MULTIPLE_MASTERS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_MULTIPLE_MASTERS_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_mm + + + static FT_Error + ft_face_get_mm_service( FT_Face face, + FT_Service_MultiMasters *aservice ) + { + FT_Error error; + + + *aservice = NULL; + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + error = FT_Err_Invalid_Argument; + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + MULTI_MASTERS ); + + if ( aservice ) + error = FT_Err_Ok; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->get_mm ) + error = service->get_mm( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->get_mm_var ) + error = service->get_mm_var( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_design ) + error = service->set_mm_design( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_var_design ) + error = service->set_var_design( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_blend ) + error = service->set_mm_blend( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + /* This is exactly the same as the previous function. It exists for */ + /* orthogonality. */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_blend ) + error = service->set_mm_blend( face, num_coords, coords ); + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftnames.c b/src/freetype2/base/ftnames.c new file mode 100644 index 0000000..7fde5c4 --- /dev/null +++ b/src/freetype2/base/ftnames.c @@ -0,0 +1,94 @@ +/***************************************************************************/ +/* */ +/* ftnames.c */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (body). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_SFNT_NAMES_H +#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_INTERNAL_STREAM_H + + +#ifdef TT_CONFIG_OPTION_SFNT_NAMES + + + /* documentation is in ftnames.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + return (face && FT_IS_SFNT( face )) ? ((TT_Face)face)->num_names : 0; + } + + + /* documentation is in ftnames.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + if ( aname && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( idx < (FT_UInt)ttface->num_names ) + { + TT_NameEntryRec* entry = ttface->name_table.names + idx; + + + /* load name on demand */ + if ( entry->stringLength > 0 && entry->string == NULL ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + + + if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + + aname->platform_id = entry->platformID; + aname->encoding_id = entry->encodingID; + aname->language_id = entry->languageID; + aname->name_id = entry->nameID; + aname->string = (FT_Byte*)entry->string; + aname->string_len = entry->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + +#endif /* TT_CONFIG_OPTION_SFNT_NAMES */ + + +/* END */ diff --git a/src/freetype2/base/ftobjs.c b/src/freetype2/base/ftobjs.c new file mode 100644 index 0000000..fa08094 --- /dev/null +++ b/src/freetype2/base/ftobjs.c @@ -0,0 +1,3993 @@ +/***************************************************************************/ +/* */ +/* ftobjs.c */ +/* */ +/* The FreeType private base classes (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_LIST_H +#include FT_OUTLINE_H +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_RFORK_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */ +#include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_IDS_H +#include FT_OUTLINE_H + +#include FT_SERVICE_SFNT_H +#include FT_SERVICE_POSTSCRIPT_NAME_H +#include FT_SERVICE_GLYPH_DICT_H +#include FT_SERVICE_TT_CMAP_H +#include FT_SERVICE_KERNING_H +#include FT_SERVICE_TRUETYPE_ENGINE_H + +#define GRID_FIT_METRICS + + FT_BASE_DEF( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ) + { + FT_Pointer result = NULL; + FT_ServiceDesc desc = service_descriptors; + + + if ( desc && service_id ) + { + for ( ; desc->serv_id != NULL; desc++ ) + { + if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) + { + result = (FT_Pointer)desc->serv_data; + break; + } + } + } + + return result; + } + + + FT_BASE_DEF( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ) + { + valid->base = base; + valid->limit = limit; + valid->level = level; + valid->error = FT_Err_Ok; + } + + + FT_BASE_DEF( FT_Int ) + ft_validator_run( FT_Validator valid ) + { + /* This function doesn't work! None should call it. */ + FT_UNUSED( valid ); + + return -1; + } + + + FT_BASE_DEF( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ) + { + /* since the cast below also disables the compiler's */ + /* type check, we introduce a dummy variable, which */ + /* will be optimized away */ + volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; + + + valid->error = error; + + /* throw away volatileness; use `jump_buffer' or the */ + /* compiler may warn about an unused local variable */ + ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S T R E A M ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* create a new input stream from an FT_Open_Args structure */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !args ) + return FT_Err_Invalid_Argument; + + *astream = 0; + memory = library->memory; + + if ( FT_NEW( stream ) ) + goto Exit; + + stream->memory = memory; + + if ( args->flags & FT_OPEN_MEMORY ) + { + /* create a memory-based stream */ + FT_Stream_OpenMemory( stream, + (const FT_Byte*)args->memory_base, + args->memory_size ); + } + else if ( args->flags & FT_OPEN_PATHNAME ) + { + /* create a normal system stream */ + error = FT_Stream_Open( stream, args->pathname ); + stream->pathname.pointer = args->pathname; + } + else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + { + /* use an existing, user-provided stream */ + + /* in this case, we do not need to allocate a new stream object */ + /* since the caller is responsible for closing it himself */ + FT_FREE( stream ); + stream = args->stream; + } + else + error = FT_Err_Invalid_Argument; + + if ( error ) + FT_FREE( stream ); + else + stream->memory = memory; /* just to be certain */ + + *astream = stream; + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ) + { + if ( stream ) + { + FT_Memory memory = stream->memory; + + + FT_Stream_Close( stream ); + + if ( !external ) + FT_FREE( stream ); + } + } + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ft_glyphslot_init( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + FT_Error error = FT_Err_Ok; + FT_Slot_Internal internal; + + + slot->library = driver->root.library; + + if ( FT_NEW( internal ) ) + goto Exit; + + slot->internal = internal; + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + error = FT_GlyphLoader_New( memory, &internal->loader ); + + if ( !error && clazz->init_slot ) + error = clazz->init_slot( slot ); + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) + { + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + + + FT_FREE( slot->bitmap.buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* assume that the bitmap buffer was stolen or not */ + /* allocated from the heap */ + slot->bitmap.buffer = NULL; + } + } + + + FT_BASE_DEF( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ) + { + ft_glyphslot_free_bitmap( slot ); + + slot->bitmap.buffer = buffer; + + FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); + } + + + FT_BASE_DEF( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Error error; + + + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + (void)FT_ALLOC( slot->bitmap.buffer, size ); + return error; + } + + + static void + ft_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + + slot->bitmap.width = 0; + slot->bitmap.rows = 0; + slot->bitmap.pitch = 0; + slot->bitmap.pixel_mode = 0; + /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + + + static void + ft_glyphslot_done( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + + + if ( clazz->done_slot ) + clazz->done_slot( slot ); + + /* free bitmap buffer if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* free glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + FT_GlyphLoader_Done( slot->internal->loader ); + slot->internal->loader = 0; + } + + FT_FREE( slot->internal ); + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ) + { + FT_Error error; + FT_Driver driver; + FT_Driver_Class clazz; + FT_Memory memory; + FT_GlyphSlot slot; + + + if ( !face || !face->driver ) + return FT_Err_Invalid_Argument; + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); + if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) + { + slot->face = face; + + error = ft_glyphslot_init( slot ); + if ( error ) + { + ft_glyphslot_done( slot ); + FT_FREE( slot ); + goto Exit; + } + + slot->next = face->glyph; + face->glyph = slot; + + if ( aslot ) + *aslot = slot; + } + else if ( aslot ) + *aslot = 0; + + + Exit: + FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ) + { + if ( slot ) + { + FT_Driver driver = slot->face->driver; + FT_Memory memory = driver->root.memory; + FT_GlyphSlot prev; + FT_GlyphSlot cur; + + + /* Remove slot from its parent face's list */ + prev = NULL; + cur = slot->face->glyph; + + while ( cur ) + { + if ( cur == slot ) + { + if ( !prev ) + slot->face->glyph = cur->next; + else + prev->next = cur->next; + + ft_glyphslot_done( slot ); + FT_FREE( slot ); + break; + } + prev = cur; + cur = cur->next; + } + } + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + internal->transform_flags = 0; + + if ( !matrix ) + { + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + matrix = &internal->transform_matrix; + } + else + internal->transform_matrix = *matrix; + + /* set transform_flags bit flag 0 if `matrix' isn't the identity */ + if ( ( matrix->xy | matrix->yx ) || + matrix->xx != 0x10000L || + matrix->yy != 0x10000L ) + internal->transform_flags |= 1; + + if ( !delta ) + { + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + delta = &internal->transform_delta; + } + else + internal->transform_delta = *delta; + + /* set transform_flags bit flag 1 if `delta' isn't the null vector */ + if ( delta->x | delta->y ) + internal->transform_flags |= 2; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ); + + +#ifdef GRID_FIT_METRICS + static void + ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, + FT_Bool vertical ) + { + FT_Glyph_Metrics* metrics = &slot->metrics; + FT_Pos right, bottom; + + + if ( vertical ) + { + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); + + right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width ); + bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height ); + + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + metrics->width = right - metrics->vertBearingX; + metrics->height = bottom - metrics->vertBearingY; + } + else + { + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width ); + bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height ); + + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); + + metrics->width = right - metrics->horiBearingX; + metrics->height = metrics->horiBearingY - bottom; + } + + metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance ); + metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance ); + } +#endif /* GRID_FIT_METRICS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + FT_Driver driver; + FT_GlyphSlot slot; + FT_Library library; + FT_Bool autohint = 0; + FT_Module hinter; + + + if ( !face || !face->size || !face->glyph ) + return FT_Err_Invalid_Face_Handle; + + /* The validity test for `glyph_index' is performed by the */ + /* font drivers. */ + + slot = face->glyph; + ft_glyphslot_clear( slot ); + + driver = face->driver; + library = driver->root.library; + hinter = library->auto_hinter; + + /* resolve load flags dependencies */ + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM; + + if ( load_flags & FT_LOAD_NO_SCALE ) + { + load_flags |= FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + + load_flags &= ~FT_LOAD_RENDER; + } + + /* + * Determine whether we need to auto-hint or not. + * The general rules are: + * + * - Do only auto-hinting if we have a hinter module, + * a scalable font format dealing with outlines, + * and no transforms except simple slants. + * + * - Then, autohint if FT_LOAD_FORCE_AUTOHINT is set + * or if we don't have a native font hinter. + * + * - Otherwise, auto-hint for LIGHT hinting mode. + * + * - Exception: The font requires the unpatented + * bytecode interpreter to load properly. + */ + + autohint = 0; + if ( hinter && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 && + ( load_flags & FT_LOAD_NO_AUTOHINT ) == 0 && + FT_DRIVER_IS_SCALABLE( driver ) && + FT_DRIVER_USES_OUTLINES( driver ) && + face->internal->transform_matrix.yy > 0 && + face->internal->transform_matrix.yx == 0 ) + { + if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) != 0 || + !FT_DRIVER_HAS_HINTER( driver ) ) + autohint = 1; + else + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + + + if ( mode == FT_RENDER_MODE_LIGHT || + face->internal->ignore_unpatented_hinter ) + autohint = 1; + } + } + + if ( autohint ) + { + FT_AutoHinter_Service hinting; + + + /* try to load embedded bitmaps first if available */ + /* */ + /* XXX: This is really a temporary hack that should disappear */ + /* promptly with FreeType 2.1! */ + /* */ + if ( FT_HAS_FIXED_SIZES( face ) && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SBITS_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) + goto Load_Ok; + } + + /* load auto-hinted outline */ + hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface; + + error = hinting->load_glyph( (FT_AutoHinter)hinter, + slot, face->size, + glyph_index, load_flags ); + } + else + { + error = driver->clazz->load_glyph( slot, + face->size, + glyph_index, + load_flags ); + if ( error ) + goto Exit; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* check that the loaded outline is correct */ + error = FT_Outline_Check( &slot->outline ); + if ( error ) + goto Exit; + +#ifdef GRID_FIT_METRICS + if ( !( load_flags & FT_LOAD_NO_HINTING ) ) + ft_glyphslot_grid_fit_metrics( slot, + FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); +#endif + } + } + + Load_Ok: + /* compute the advance */ + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + slot->advance.x = 0; + slot->advance.y = slot->metrics.vertAdvance; + } + else + { + slot->advance.x = slot->metrics.horiAdvance; + slot->advance.y = 0; + } + + /* compute the linear advance in 16.16 pixels */ + if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) ) + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + /* it's tricky! */ + slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, + metrics->x_scale, 64 ); + + slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, + metrics->y_scale, 64 ); + } + + if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) + { + FT_Face_Internal internal = face->internal; + + + /* now, transform the glyph image if needed */ + if ( internal->transform_flags ) + { + /* get renderer */ + FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); + + + if ( renderer ) + error = renderer->clazz->transform_glyph( + renderer, slot, + &internal->transform_matrix, + &internal->transform_delta ); + /* transform advance */ + FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); + } + } + + /* do we need to render the image now? */ + if ( !error && + slot->format != FT_GLYPH_FORMAT_BITMAP && + slot->format != FT_GLYPH_FORMAT_COMPOSITE && + load_flags & FT_LOAD_RENDER ) + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + + + if ( mode == FT_RENDER_MODE_NORMAL && + (load_flags & FT_LOAD_MONOCHROME ) ) + mode = FT_RENDER_MODE_MONO; + + error = FT_Render_Glyph( slot, mode ); + } + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ) + { + FT_UInt glyph_index; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + glyph_index = (FT_UInt)char_code; + if ( face->charmap ) + glyph_index = FT_Get_Char_Index( face, char_code ); + + return FT_Load_Glyph( face, glyph_index, load_flags ); + } + + + /* destructor for sizes list */ + static void + destroy_size( FT_Memory memory, + FT_Size size, + FT_Driver driver ) + { + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + + /* finalize format-specific stuff */ + if ( driver->clazz->done_size ) + driver->clazz->done_size( size ); + + FT_FREE( size->internal ); + FT_FREE( size ); + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ); + + + static void + destroy_charmaps( FT_Face face, + FT_Memory memory ) + { + FT_Int n; + + + if ( !face ) + return; + + for ( n = 0; n < face->num_charmaps; n++ ) + { + FT_CMap cmap = FT_CMAP( face->charmaps[n] ); + + + ft_cmap_done_internal( cmap ); + + face->charmaps[n] = NULL; + } + + FT_FREE( face->charmaps ); + face->num_charmaps = 0; + } + + + /* destructor for faces list */ + static void + destroy_face( FT_Memory memory, + FT_Face face, + FT_Driver driver ) + { + FT_Driver_Class clazz = driver->clazz; + + + /* discard auto-hinting data */ + if ( face->autohint.finalizer ) + face->autohint.finalizer( face->autohint.data ); + + /* Discard glyph slots for this face. */ + /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ + while ( face->glyph ) + FT_Done_GlyphSlot( face->glyph ); + + /* discard all sizes for this face */ + FT_List_Finalize( &face->sizes_list, + (FT_List_Destructor)destroy_size, + memory, + driver ); + face->size = 0; + + /* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + + /* discard charmaps */ + destroy_charmaps( face, memory ); + + /* finalize format-specific stuff */ + if ( clazz->done_face ) + clazz->done_face( face ); + + /* close the stream for this face if needed */ + FT_Stream_Free( + face->stream, + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->stream = 0; + + /* get rid of it */ + if ( face->internal ) + { + FT_FREE( face->internal ); + } + FT_FREE( face ); + } + + + static void + Destroy_Driver( FT_Driver driver ) + { + FT_List_Finalize( &driver->faces_list, + (FT_List_Destructor)destroy_face, + driver->root.memory, + driver ); + + /* check whether we need to drop the driver's glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* find_unicode_charmap */ + /* */ + /* */ + /* This function finds a Unicode charmap, if there is one. */ + /* And if there is more than one, it tries to favour the more */ + /* extensive one, i.e., one that supports UCS-4 against those which */ + /* are limited to the BMP (said UCS-2 encoding.) */ + /* */ + /* This function is called from open_face() (just below), and also */ + /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE). */ + /* */ + static FT_Error + find_unicode_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* cur; + FT_CharMap* unicmap = NULL; /* some UCS-2 map, if we found it */ + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return FT_Err_Invalid_CharMap_Handle; + + /* + * The original TrueType specification(s) only specified charmap + * formats that are capable of mapping 8 or 16 bit character codes to + * glyph indices. + * + * However, recent updates to the Apple and OpenType specifications + * introduced new formats that are capable of mapping 32-bit character + * codes as well. And these are already used on some fonts, mainly to + * map non-BMP Asian ideographs as defined in Unicode. + * + * For compatibility purposes, these fonts generally come with + * *several* Unicode charmaps: + * + * - One of them in the "old" 16-bit format, that cannot access + * all glyphs in the font. + * + * - Another one in the "new" 32-bit format, that can access all + * the glyphs. + * + * This function has been written to always favor a 32-bit charmap + * when found. Otherwise, a 16-bit one is returned when found. + */ + + /* Since the `interesting' table, with IDs (3,10), is normally the */ + /* last one, we loop backwards. This loses with type1 fonts with */ + /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ + /* chars (.01% ?), and this is the same about 99.99% of the time! */ + + cur = first + face->num_charmaps; /* points after the last one */ + + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { + unicmap = cur; /* record we found a Unicode charmap */ + + /* XXX If some new encodings to represent UCS-4 are added, */ + /* they should be added here. */ + if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && + cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || + ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) + + /* Hurray! We found a UCS-4 charmap. We can stop the scan! */ + { + face->charmap = cur[0]; + return 0; + } + } + } + + /* We do not have any UCS-4 charmap. Sigh. */ + /* Let's see if we have some other kind of Unicode charmap, though. */ + if ( unicmap != NULL ) + { + face->charmap = unicmap[0]; + return 0; + } + + /* Chou blanc! */ + return FT_Err_Invalid_CharMap_Handle; + } + + + /*************************************************************************/ + /* */ + /* */ + /* open_face */ + /* */ + /* */ + /* This function does some work for FT_Open_Face(). */ + /* */ + static FT_Error + open_face( FT_Driver driver, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter* params, + FT_Face *aface ) + { + FT_Memory memory; + FT_Driver_Class clazz; + FT_Face face = 0; + FT_Error error, error2; + FT_Face_Internal internal = NULL; + + + clazz = driver->clazz; + memory = driver->root.memory; + + /* allocate the face object and perform basic initialization */ + if ( FT_ALLOC( face, clazz->face_object_size ) ) + goto Fail; + + if ( FT_NEW( internal ) ) + goto Fail; + + face->internal = internal; + + face->driver = driver; + face->memory = memory; + face->stream = stream; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + int i; + + + face->internal->incremental_interface = 0; + for ( i = 0; i < num_params && !face->internal->incremental_interface; + i++ ) + if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) + face->internal->incremental_interface = params[i].data; + } +#endif + + error = clazz->init_face( stream, + face, + (FT_Int)face_index, + num_params, + params ); + if ( error ) + goto Fail; + + /* select Unicode charmap by default */ + error2 = find_unicode_charmap( face ); + + /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ + /* is returned. */ + + /* no error should happen, but we want to play safe */ + if ( error2 && error2 != FT_Err_Invalid_CharMap_Handle ) + { + error = error2; + goto Fail; + } + + *aface = face; + + Fail: + if ( error ) + { + destroy_charmaps( face, memory ); + clazz->done_face( face ); + FT_FREE( internal ); + FT_FREE( face ); + *aface = 0; + } + + return error; + } + + + /* there's a Mac-specific extended implementation of FT_New_Face() */ + /* in src/base/ftmac.c */ + +#ifndef FT_MACINTOSH + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_Err_Invalid_Argument; + + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + + return FT_Open_Face( library, &args, face_index, aface ); + } + +#endif /* !FT_MACINTOSH */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `face' delayed to FT_Open_Face() */ + if ( !file_base ) + return FT_Err_Invalid_Argument; + + args.flags = FT_OPEN_MEMORY; + args.memory_base = file_base; + args.memory_size = file_size; + + return FT_Open_Face( library, &args, face_index, aface ); + } + + +#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) + + /* The behavior here is very similar to that in base/ftmac.c, but it */ + /* is designed to work on non-mac systems, so no mac specific calls. */ + /* */ + /* We look at the file and determine if it is a mac dfont file or a mac */ + /* resource file, or a macbinary file containing a mac resource file. */ + /* */ + /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ + /* the point, especially since there may be multiple `FOND' resources. */ + /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ + /* they occur in the file. */ + /* */ + /* Note that multiple `POST' resources do not mean multiple postscript */ + /* fonts; they all get jammed together to make what is essentially a */ + /* pfb file. */ + /* */ + /* We aren't interested in `NFNT' or `FONT' bitmap resources. */ + /* */ + /* As soon as we get an `sfnt' load it into memory and pass it off to */ + /* FT_Open_Face. */ + /* */ + /* If we have a (set of) `POST' resources, massage them into a (memory) */ + /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ + /* going to try to save the kerning info. After all that lives in the */ + /* `FOND' which isn't in the file containing the `POST' resources so */ + /* we don't really have access to it. */ + + + /* Finalizer for a memory stream; gets called by FT_Done_Face(). + It frees the memory it uses. */ + /* from ftmac.c */ + static void + memory_stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->base = 0; + stream->close = 0; + } + + + /* Create a new memory stream from a buffer and a size. */ + /* from ftmac.c */ + static FT_Error + new_memory_stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream_CloseFunc close, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !base ) + return FT_Err_Invalid_Argument; + + *astream = 0; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, base, size ); + + stream->close = close; + + *astream = stream; + + Exit: + return error; + } + + + /* Create a new FT_Face given a buffer and a driver name. */ + /* from ftmac.c */ + static 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_Open_Args args; + FT_Error error; + FT_Stream stream = NULL; + FT_Memory memory = library->memory; + + + error = new_memory_stream( library, + base, + size, + memory_stream_close, + &stream ); + if ( error ) + { + FT_FREE( base ); + return error; + } + + args.flags = FT_OPEN_STREAM; + args.stream = stream; + if ( driver_name ) + { + args.flags = args.flags | FT_OPEN_DRIVER; + args.driver = FT_Get_Module( library, driver_name ); + } + + error = FT_Open_Face( library, &args, face_index, aface ); + + if ( error == FT_Err_Ok ) + (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + else + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + } + + return error; + } + + + /* The resource header says we've got resource_cnt `POST' (type1) */ + /* resources in this file. They all need to be coalesced into */ + /* one lump which gets passed on to the type1 driver. */ + /* Here can be only one PostScript font in a file so face_index */ + /* must be 0 (or -1). */ + /* */ + static FT_Error + Mac_Read_POST_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error = FT_Err_Cannot_Open_Resource; + FT_Memory memory = library->memory; + FT_Byte* pfb_data; + int i, type, flags; + FT_Long len; + FT_Long pfb_len, pfb_pos, pfb_lenpos; + FT_Long rlen, temp; + + + if ( face_index == -1 ) + face_index = 0; + if ( face_index != 0 ) + return error; + + /* Find the length of all the POST resources, concatenated. Assume */ + /* worst case (each resource in its own section). */ + pfb_len = 0; + for ( i = 0; i < resource_cnt; ++i ) + { + error = FT_Stream_Seek( stream, offsets[i] ); + if ( error ) + goto Exit; + if ( FT_READ_LONG( temp ) ) + goto Exit; + pfb_len += temp + 6; + } + + if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + goto Exit; + + pfb_data[0] = 0x80; + pfb_data[1] = 1; /* Ascii section */ + pfb_data[2] = 0; /* 4-byte length, fill in later */ + pfb_data[3] = 0; + pfb_data[4] = 0; + pfb_data[5] = 0; + pfb_pos = 6; + pfb_lenpos = 2; + + len = 0; + type = 1; + for ( i = 0; i < resource_cnt; ++i ) + { + error = FT_Stream_Seek( stream, offsets[i] ); + if ( error ) + goto Exit2; + if ( FT_READ_LONG( rlen ) ) + goto Exit; + if ( FT_READ_USHORT( flags ) ) + goto Exit; + rlen -= 2; /* the flags are part of the resource */ + if ( ( flags >> 8 ) == type ) + len += rlen; + else + { + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + if ( ( flags >> 8 ) == 5 ) /* End of font mark */ + break; + + pfb_data[pfb_pos++] = 0x80; + + type = flags >> 8; + len = rlen; + + pfb_data[pfb_pos++] = (FT_Byte)type; + pfb_lenpos = pfb_pos; + pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + } + + error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); + pfb_pos += rlen; + } + + pfb_data[pfb_pos++] = 0x80; + pfb_data[pfb_pos++] = 3; + + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + return open_face_from_buffer( library, + pfb_data, + pfb_pos, + face_index, + "type1", + aface ); + + Exit2: + FT_FREE( pfb_data ); + + Exit: + return error; + } + + + /* The resource header says we've got resource_cnt `sfnt' */ + /* (TrueType/OpenType) resources in this file. Look through */ + /* them for the one indicated by face_index, load it into mem, */ + /* pass it on the the truetype driver and return it. */ + /* */ + static FT_Error + Mac_Read_sfnt_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Byte* sfnt_data; + FT_Error error; + FT_Long flag_offset; + FT_Long rlen; + int is_cff; + FT_Long face_index_in_resource = 0; + + + if ( face_index == -1 ) + face_index = 0; + if ( face_index >= resource_cnt ) + return FT_Err_Cannot_Open_Resource; + + flag_offset = offsets[face_index]; + error = FT_Stream_Seek( stream, flag_offset ); + if ( error ) + goto Exit; + + if ( FT_READ_LONG( rlen ) ) + goto Exit; + if ( rlen == -1 ) + return FT_Err_Cannot_Open_Resource; + + if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) ) + return error; + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); + if ( error ) + goto Exit; + + is_cff = rlen > 4 && sfnt_data[0] == 'O' && + sfnt_data[1] == 'T' && + sfnt_data[2] == 'T' && + sfnt_data[3] == 'O'; + + error = open_face_from_buffer( library, + sfnt_data, + rlen, + face_index_in_resource, + is_cff ? "cff" : "truetype", + aface ); + + Exit: + return error; + } + + + /* Check for a valid resource fork header, or a valid dfont */ + /* header. In a resource fork the first 16 bytes are repeated */ + /* at the location specified by bytes 4-7. In a dfont bytes */ + /* 4-7 point to 16 bytes of zeroes instead. */ + /* */ + static FT_Error + IsMacResource( FT_Library library, + FT_Stream stream, + FT_Long resource_offset, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Long map_offset, rdara_pos; + FT_Long *data_offsets; + FT_Long count; + + + error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, + &map_offset, &rdara_pos ); + if ( error ) + return error; + + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdara_pos, + FT_MAKE_TAG( 'P', 'O', 'S', 'T' ), + &data_offsets, &count ); + if ( !error ) + { + error = Mac_Read_POST_Resource( library, stream, data_offsets, count, + face_index, aface ); + FT_FREE( data_offsets ); + /* POST exists in an LWFN providing a single face */ + if ( !error ) + (*aface)->num_faces = 1; + return error; + } + + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdara_pos, + FT_MAKE_TAG( 's', 'f', 'n', 't' ), + &data_offsets, &count ); + if ( !error ) + { + FT_Long face_index_internal = face_index % count; + + + error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, + face_index_internal, aface ); + FT_FREE( data_offsets ); + if ( !error ) + (*aface)->num_faces = count; + } + + return error; + } + + + /* Check for a valid macbinary header, and if we find one */ + /* check that the (flattened) resource fork in it is valid. */ + /* */ + static FT_Error + IsMacBinary( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface ) + { + unsigned char header[128]; + FT_Error error; + FT_Long dlen, offset; + + + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + goto Exit; + + error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); + if ( error ) + goto Exit; + + if ( header[ 0] != 0 || + header[74] != 0 || + header[82] != 0 || + header[ 1] == 0 || + header[ 1] > 33 || + header[63] != 0 || + header[2 + header[1]] != 0 ) + return FT_Err_Unknown_File_Format; + + dlen = ( header[0x53] << 24 ) | + ( header[0x54] << 16 ) | + ( header[0x55] << 8 ) | + header[0x56]; +#if 0 + rlen = ( header[0x57] << 24 ) | + ( header[0x58] << 16 ) | + ( header[0x59] << 8 ) | + header[0x5a]; +#endif /* 0 */ + offset = 128 + ( ( dlen + 127 ) & ~127 ); + + return IsMacResource( library, stream, offset, face_index, aface ); + + Exit: + return error; + } + + + static FT_Error + load_face_in_embedded_rfork( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess + + FT_Memory memory = library->memory; + FT_Error error = FT_Err_Unknown_File_Format; + int i; + + char * file_names[FT_RACCESS_N_RULES]; + FT_Long offsets[FT_RACCESS_N_RULES]; + FT_Error errors[FT_RACCESS_N_RULES]; + + FT_Open_Args args2; + FT_Stream stream2; + + + FT_Raccess_Guess( library, stream, + args->pathname, file_names, offsets, errors ); + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + if ( errors[i] ) + { + FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i )); + continue; + } + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_names[i] ? file_names[i] : args->pathname; + + FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", + i, args2.pathname, offsets[i] )); + + error = FT_Stream_New( library, &args2, &stream2 ); + if ( error ) + { + FT_TRACE3(( "failed\n" )); + continue; + } + + error = IsMacResource( library, stream2, offsets[i], + face_index, aface ); + FT_Stream_Free( stream2, 0 ); + + FT_TRACE3(( "%s\n", error ? "failed": "successful" )); + + if ( !error ) + break; + } + + for (i = 0; i < FT_RACCESS_N_RULES; i++) + { + if ( file_names[i] ) + FT_FREE( file_names[i] ); + } + + /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ + if ( error ) + error = FT_Err_Unknown_File_Format; + + return error; + +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + + } + + + /* Check for some macintosh formats. */ + /* Is this a macbinary file? If so look at the resource fork. */ + /* Is this a mac dfont file? */ + /* Is this an old style resource fork? (in data) */ + /* Else call load_face_in_embedded_rfork to try extra rules */ + /* (defined in `ftrfork.c'). */ + /* */ + static FT_Error + load_mac_face( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + FT_Error error; + FT_UNUSED( args ); + + + error = IsMacBinary( library, stream, face_index, aface ); + if ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess + + FT_TRACE3(( "Try as dfont: %s ...", args->pathname )); + + error = IsMacResource( library, stream, 0, face_index, aface ); + + FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); + +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + + } + + if ( ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format || + FT_ERROR_BASE( error ) == FT_Err_Invalid_Stream_Operation ) && + ( args->flags & FT_OPEN_PATHNAME ) ) + error = load_face_in_embedded_rfork( library, stream, + face_index, aface, args ); + return error; + } + +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + FT_Face face = 0; + FT_ListNode node = 0; + FT_Bool external_stream; + + + /* test for valid `library' delayed to */ + /* FT_Stream_New() */ + + if ( ( !aface && face_index >= 0 ) || !args ) + return FT_Err_Invalid_Argument; + + external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && + args->stream ); + + /* create input stream */ + error = FT_Stream_New( library, args, &stream ); + if ( error ) + goto Exit; + + memory = library->memory; + + /* If the font driver is specified in the `args' structure, use */ + /* it. Otherwise, we scan the list of registered drivers. */ + if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) + { + driver = FT_DRIVER( args->driver ); + + /* not all modules are drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( driver ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + } + else + error = FT_Err_Invalid_Handle; + + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + else + { + /* check each font driver for an appropriate format */ + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + /* not all modules are font drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( cur[0] ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + + + driver = FT_DRIVER( cur[0] ); + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + + if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format ) + goto Fail3; + } + } + + Fail3: + /* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */ + /* it may be because we have an empty data fork, so we need to check */ + /* the resource fork. */ + if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format && + FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation ) + goto Fail2; + +#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) + error = load_mac_face( library, stream, face_index, aface, args ); + if ( !error ) + { + /* We don't want to go to Success here. We've already done that. */ + /* On the other hand, if we succeeded we still need to close this */ + /* stream (we opened a different stream which extracted the */ + /* interesting information out of this stream here. That stream */ + /* will still be open and the face will point to it). */ + FT_Stream_Free( stream, external_stream ); + return error; + } + + if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format ) + goto Fail2; +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + /* no driver is able to handle this format */ + error = FT_Err_Unknown_File_Format; + + Fail2: + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + + Success: + FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); + + /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ + if ( external_stream ) + face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; + + /* add the face object to its driver's list */ + if ( FT_NEW( node ) ) + goto Fail; + + node->data = face; + /* don't assume driver is the same as face->driver, so use */ + /* face->driver instead. */ + FT_List_Add( &face->driver->faces_list, node ); + + /* now allocate a glyph slot object for the face */ + FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); + + if ( face_index >= 0 ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( error ) + goto Fail; + + /* finally, allocate a size object for the face */ + { + FT_Size size; + + + FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); + + error = FT_New_Size( face, &size ); + if ( error ) + goto Fail; + + face->size = size; + } + } + + /* some checks */ + + if ( FT_IS_SCALABLE( face ) ) + { + if ( face->height < 0 ) + face->height = (FT_Short)-face->height; + + if ( !FT_HAS_VERTICAL( face ) ) + face->max_advance_height = (FT_Short)face->height; + } + + if ( FT_HAS_FIXED_SIZES( face ) ) + { + FT_Int i; + + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( bsize->height < 0 ) + bsize->height = (FT_Short)-bsize->height; + if ( bsize->x_ppem < 0 ) + bsize->x_ppem = (FT_Short)-bsize->x_ppem; + if ( bsize->y_ppem < 0 ) + bsize->y_ppem = -bsize->y_ppem; + } + } + + /* initialize internal face data */ + { + FT_Face_Internal internal = face->internal; + + + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + } + + if ( aface ) + *aface = face; + else + FT_Done_Face( face ); + + goto Exit; + + Fail: + FT_Done_Face( face ); + + Exit: + FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ) + { + FT_Open_Args open; + + + /* test for valid `face' delayed to FT_Attach_Stream() */ + + if ( !filepathname ) + return FT_Err_Invalid_Argument; + + open.stream = NULL; + open.flags = FT_OPEN_PATHNAME; + open.pathname = (char*)filepathname; + + return FT_Attach_Stream( face, &open ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ) + { + FT_Stream stream; + FT_Error error; + FT_Driver driver; + + FT_Driver_Class clazz; + + + /* test for valid `parameters' delayed to FT_Stream_New() */ + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + + error = FT_Stream_New( driver->root.library, parameters, &stream ); + if ( error ) + goto Exit; + + /* we implement FT_Attach_Stream in each driver through the */ + /* `attach_file' interface */ + + error = FT_Err_Unimplemented_Feature; + clazz = driver->clazz; + if ( clazz->attach_file ) + error = clazz->attach_file( face, stream ); + + /* close the attached stream */ + FT_Stream_Free( stream, + (FT_Bool)( parameters->stream && + ( parameters->flags & FT_OPEN_STREAM ) ) ); + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Face( FT_Face face ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_ListNode node; + + + error = FT_Err_Invalid_Face_Handle; + if ( face && face->driver ) + { + driver = face->driver; + memory = driver->root.memory; + + /* find face in driver's list */ + node = FT_List_Find( &driver->faces_list, face ); + if ( node ) + { + /* remove face object from the driver's list */ + FT_List_Remove( &driver->faces_list, node ); + FT_FREE( node ); + + /* now destroy the object proper */ + destroy_face( memory, face, driver ); + error = FT_Err_Ok; + } + } + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size *asize ) + { + FT_Error error; + FT_Memory memory; + FT_Driver driver; + FT_Driver_Class clazz; + + FT_Size size = 0; + FT_ListNode node = 0; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !asize ) + return FT_Err_Invalid_Size_Handle; + + if ( !face->driver ) + return FT_Err_Invalid_Driver_Handle; + + *asize = 0; + + driver = face->driver; + clazz = driver->clazz; + memory = face->memory; + + /* Allocate new size object and perform basic initialisation */ + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) + goto Exit; + + size->face = face; + + /* for now, do not use any internal fields in size objects */ + size->internal = 0; + + if ( clazz->init_size ) + error = clazz->init_size( size ); + + /* in case of success, add to the face's list */ + if ( !error ) + { + *asize = size; + node->data = size; + FT_List_Add( &face->sizes_list, node ); + } + + Exit: + if ( error ) + { + FT_FREE( node ); + FT_FREE( size ); + } + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Size( FT_Size size ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Face face; + FT_ListNode node; + + + if ( !size ) + return FT_Err_Invalid_Size_Handle; + + face = size->face; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + + memory = driver->root.memory; + + error = FT_Err_Ok; + node = FT_List_Find( &face->sizes_list, size ); + if ( node ) + { + FT_List_Remove( &face->sizes_list, node ); + FT_FREE( node ); + + if ( face->size == size ) + { + face->size = 0; + if ( face->sizes_list.head ) + face->size = (FT_Size)(face->sizes_list.head->data); + } + + destroy_size( memory, size, driver ); + } + else + error = FT_Err_Invalid_Size_Handle; + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ) + { + FT_Int i; + FT_Long w, h; + + + if ( !FT_HAS_FIXED_SIZES( face ) ) + return FT_Err_Invalid_Face_Handle; + + /* FT_Bitmap_Size doesn't provide enough info... */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + return FT_Err_Unimplemented_Feature; + + w = FT_REQUEST_WIDTH ( req ); + h = FT_REQUEST_HEIGHT( req ); + + if ( req->width && !req->height ) + h = w; + else if ( !req->width && req->height ) + w = h; + + w = FT_PIX_ROUND( w ); + h = FT_PIX_ROUND( h ); + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) + continue; + + if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) + { + if ( size_index ) + *size_index = (FT_ULong)i; + + return FT_Err_Ok; + } + } + + return FT_Err_Invalid_Pixel_Size; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ) + { + /* the factor 1.2 is a heuristical value */ + if ( !advance ) + advance = metrics->height * 12 / 10; + + metrics->vertBearingX = -( metrics->width / 2 ); + metrics->vertBearingY = ( advance - metrics->height ) / 2; + metrics->vertAdvance = advance; + } + + + static void + ft_recompute_scaled_metrics( FT_Face face, + FT_Size_Metrics* metrics ) + { + /* Compute root ascender, descender, test height, and max_advance */ + +#ifdef GRID_FIT_METRICS + metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, + metrics->y_scale ) ); + + metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, + metrics->y_scale ) ); + + metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, + metrics->y_scale ) ); + + metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, + metrics->x_scale ) ); +#else /* !GRID_FIT_METRICS */ + metrics->ascender = FT_MulFix( face->ascender, + metrics->y_scale ); + + metrics->descender = FT_MulFix( face->descender, + metrics->y_scale ); + + metrics->height = FT_MulFix( face->height, + metrics->y_scale ); + + metrics->max_advance = FT_MulFix( face->max_advance_width, + metrics->x_scale ); +#endif /* !GRID_FIT_METRICS */ + } + + + FT_BASE_DEF( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ) + { + FT_Size_Metrics* metrics; + FT_Bitmap_Size* bsize; + + + metrics = &face->size->metrics; + bsize = face->available_sizes + strike_index; + + metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); + + if ( FT_IS_SCALABLE( face ) ) + { + metrics->x_scale = FT_DivFix( bsize->x_ppem, + face->units_per_EM ); + metrics->y_scale = FT_DivFix( bsize->y_ppem, + face->units_per_EM ); + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + metrics->x_scale = 1L << 22; + metrics->y_scale = 1L << 22; + metrics->ascender = bsize->y_ppem; + metrics->descender = 0; + metrics->height = bsize->height << 6; + metrics->max_advance = bsize->x_ppem; + } + } + + + FT_BASE_DEF( void ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ) + { + FT_Size_Metrics* metrics; + + + metrics = &face->size->metrics; + + if ( FT_IS_SCALABLE( face ) ) + { + FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; + + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + w = h = face->units_per_EM; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + w = h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_BBOX: + w = face->bbox.xMax - face->bbox.xMin; + h = face->bbox.yMax - face->bbox.yMin; + break; + + case FT_SIZE_REQUEST_TYPE_CELL: + w = face->max_advance_width; + h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_SCALES: + metrics->x_scale = (FT_Fixed)req->width; + metrics->y_scale = (FT_Fixed)req->height; + if ( !metrics->x_scale ) + metrics->x_scale = metrics->y_scale; + else if ( !metrics->y_scale ) + metrics->y_scale = metrics->x_scale; + goto Calculate_Ppem; + + case FT_SIZE_REQUEST_TYPE_MAX: + break; + } + + /* to be on the safe side */ + if ( w < 0 ) + w = -w; + + if ( h < 0 ) + h = -h; + + scaled_w = FT_REQUEST_WIDTH ( req ); + scaled_h = FT_REQUEST_HEIGHT( req ); + + /* determine scales */ + if ( req->width ) + { + metrics->x_scale = FT_DivFix( scaled_w, w ); + + if ( req->height ) + { + metrics->y_scale = FT_DivFix( scaled_h, h ); + + if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) + { + if ( metrics->y_scale > metrics->x_scale ) + metrics->y_scale = metrics->x_scale; + else + metrics->x_scale = metrics->y_scale; + } + } + else + { + metrics->y_scale = metrics->x_scale; + scaled_h = FT_MulDiv( scaled_w, h, w ); + } + } + else + { + metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h ); + scaled_w = FT_MulDiv( scaled_h, w, h ); + } + + Calculate_Ppem: + /* calculate the ppems */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + { + scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); + scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); + } + + metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + FT_ZERO( metrics ); + metrics->x_scale = 1L << 22; + metrics->y_scale = 1L << 22; + } + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ) + { + FT_Driver_Class clazz; + + + if ( !face || !FT_HAS_FIXED_SIZES( face ) ) + return FT_Err_Invalid_Face_Handle; + + if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) + return FT_Err_Invalid_Argument; + + clazz = face->driver->clazz; + + if ( clazz->select_size ) + return clazz->select_size( face->size, (FT_ULong)strike_index ); + + FT_Select_Metrics( face, (FT_ULong)strike_index ); + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ) + { + FT_Driver_Class clazz; + FT_ULong strike_index; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !req || req->width < 0 || req->height < 0 || + req->type >= FT_SIZE_REQUEST_TYPE_MAX ) + return FT_Err_Invalid_Argument; + + clazz = face->driver->clazz; + + if ( clazz->request_size ) + return clazz->request_size( face->size, req ); + + /* + * The reason that a driver doesn't have `request_size' defined is + * either that the scaling here suffices or that the supported formats + * are bitmap-only and size matching is not implemented. + * + * In the latter case, a simple size matching is done. + */ + if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) + { + FT_Error error; + + + error = FT_Match_Size( face, req, 0, &strike_index ); + if ( error ) + return error; + + FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n", + strike_index )); + + return FT_Select_Size( face, (FT_Int)strike_index ); + } + + FT_Request_Metrics( face, req ); + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_RequestRec req; + + + if ( !char_width ) + char_width = char_height; + else if ( !char_height ) + char_height = char_width; + + if ( !horz_resolution ) + horz_resolution = vert_resolution; + else if ( !vert_resolution ) + vert_resolution = horz_resolution; + + if ( char_width < 1 * 64 ) + char_width = 1 * 64; + if ( char_height < 1 * 64 ) + char_height = 1 * 64; + + if ( !horz_resolution ) + horz_resolution = vert_resolution = 72; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = char_width; + req.height = char_height; + req.horiResolution = horz_resolution; + req.vertResolution = vert_resolution; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Size_RequestRec req; + + + if ( pixel_width == 0 ) + pixel_width = pixel_height; + else if ( pixel_height == 0 ) + pixel_height = pixel_width; + + if ( pixel_width < 1 ) + pixel_width = 1; + if ( pixel_height < 1 ) + pixel_height = 1; + + /* use `>=' to avoid potential compiler warning on 16bit platforms */ + if ( pixel_width >= 0xFFFFU ) + pixel_width = 0xFFFFU; + if ( pixel_height >= 0xFFFFU ) + pixel_height = 0xFFFFU; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = pixel_width << 6; + req.height = pixel_height << 6; + req.horiResolution = 0; + req.vertResolution = 0; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !akerning ) + return FT_Err_Invalid_Argument; + + driver = face->driver; + + akerning->x = 0; + akerning->y = 0; + + if ( driver->clazz->get_kerning ) + { + error = driver->clazz->get_kerning( face, + left_glyph, + right_glyph, + akerning ); + if ( !error ) + { + if ( kern_mode != FT_KERNING_UNSCALED ) + { + akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); + akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); + + if ( kern_mode != FT_KERNING_UNFITTED ) + { + /* we scale down kerning values for small ppem values */ + /* to avoid that rounding makes them too big. */ + /* `25' has been determined heuristically. */ + if ( face->size->metrics.x_ppem < 25 ) + akerning->x = FT_MulDiv( akerning->x, + face->size->metrics.x_ppem, 25 ); + if ( face->size->metrics.y_ppem < 25 ) + akerning->y = FT_MulDiv( akerning->y, + face->size->metrics.y_ppem, 25 ); + + akerning->x = FT_PIX_ROUND( akerning->x ); + akerning->y = FT_PIX_ROUND( akerning->y ); + } + } + } + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ) + { + FT_Service_Kerning service; + FT_Error error = FT_Err_Ok; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( !akerning ) + return FT_Err_Invalid_Argument; + + FT_FACE_FIND_SERVICE( face, service, KERNING ); + if ( !service ) + return FT_Err_Unimplemented_Feature; + + error = service->get_track( face, + point_size, + degree, + akerning ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + if ( encoding == FT_ENCODING_NONE ) + return FT_Err_Invalid_Argument; + + /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ + /* charmap available, i.e., one with UCS-4 characters, if possible. */ + /* */ + /* This is done by find_unicode_charmap() above, to share code. */ + if ( encoding == FT_ENCODING_UNICODE ) + return find_unicode_charmap( face ); + + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0]->encoding == encoding ) + { + face->charmap = cur[0]; + return 0; + } + } + + return FT_Err_Invalid_Argument; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == charmap ) + { + face->charmap = cur[0]; + return 0; + } + } + return FT_Err_Invalid_Argument; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ) + { + FT_Int i; + + + for ( i = 0; i < charmap->face->num_charmaps; i++ ) + if ( charmap->face->charmaps[i] == charmap ) + break; + + FT_ASSERT( i < charmap->face->num_charmaps ); + + return i; + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ) + { + FT_CMap_Class clazz = cmap->clazz; + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY(face); + + + if ( clazz->done ) + clazz->done( cmap ); + + FT_FREE( cmap ); + } + + + FT_BASE_DEF( void ) + FT_CMap_Done( FT_CMap cmap ) + { + if ( cmap ) + { + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error; + FT_Int i, j; + + + for ( i = 0; i < face->num_charmaps; i++ ) + { + if ( (FT_CMap)face->charmaps[i] == cmap ) + { + FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; + + + if ( FT_RENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) + return; + + /* remove it from our list of charmaps */ + for ( j = i + 1; j < face->num_charmaps; j++ ) + { + if ( j == face->num_charmaps - 1 ) + face->charmaps[j - 1] = last_charmap; + else + face->charmaps[j - 1] = face->charmaps[j]; + } + + face->num_charmaps--; + + if ( (FT_CMap)face->charmap == cmap ) + face->charmap = NULL; + + ft_cmap_done_internal( cmap ); + + break; + } + } + } + } + + + FT_BASE_DEF( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ) + { + FT_Error error = FT_Err_Ok; + FT_Face face; + FT_Memory memory; + FT_CMap cmap; + + + if ( clazz == NULL || charmap == NULL || charmap->face == NULL ) + return FT_Err_Invalid_Argument; + + face = charmap->face; + memory = FT_FACE_MEMORY( face ); + + if ( !FT_ALLOC( cmap, clazz->size ) ) + { + cmap->charmap = *charmap; + cmap->clazz = clazz; + + if ( clazz->init ) + { + error = clazz->init( cmap, init_data ); + if ( error ) + goto Fail; + } + + /* add it to our list of charmaps */ + if ( FT_RENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) + goto Fail; + + face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; + } + + Exit: + if ( acmap ) + *acmap = cmap; + + return error; + + Fail: + ft_cmap_done_internal( cmap ); + cmap = NULL; + goto Exit; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ) + { + FT_UInt result = 0; + + + if ( face && face->charmap ) + { + FT_CMap cmap = FT_CMAP( face->charmap ); + + + result = cmap->clazz->char_index( cmap, charcode ); + } + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + if ( face && face->charmap ) + { + gindex = FT_Get_Char_Index( face, 0 ); + if ( gindex == 0 ) + result = FT_Get_Next_Char( face, 0, &gindex ); + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong charcode, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + if ( face && face->charmap ) + { + FT_UInt32 code = (FT_UInt32)charcode; + FT_CMap cmap = FT_CMAP( face->charmap ); + + + gindex = cmap->clazz->char_next( cmap, &code ); + result = ( gindex == 0 ) ? 0 : code; + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ) + { + FT_UInt result = 0; + + + if ( face && FT_HAS_GLYPH_NAMES( face ) ) + { + FT_Service_GlyphDict service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + + if ( service && service->name_index ) + result = service->name_index( face, glyph_name ); + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + /* clean up buffer */ + if ( buffer && buffer_max > 0 ) + ((FT_Byte*)buffer)[0] = 0; + + if ( face && + glyph_index <= (FT_UInt)face->num_glyphs && + FT_HAS_GLYPH_NAMES( face ) ) + { + FT_Service_GlyphDict service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + + if ( service && service->get_name ) + error = service->get_name( face, glyph_index, buffer, buffer_max ); + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_Postscript_Name( FT_Face face ) + { + const char* result = NULL; + + + if ( !face ) + goto Exit; + + if ( !result ) + { + FT_Service_PsFontName service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + POSTSCRIPT_FONT_NAME ); + + if ( service && service->get_ps_font_name ) + result = service->get_ps_font_name( face ); + } + + Exit: + return result; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ) + { + void* table = 0; + FT_Service_SFNT_Table service; + + + if ( face && FT_IS_SFNT( face ) ) + { + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service != NULL ) + table = service->get_table( face, tag ); + } + + return table; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Service_SFNT_Table service; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_Err_Invalid_Face_Handle; + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service == NULL ) + return FT_Err_Unimplemented_Feature; + + return service->load_table( face, tag, offset, buffer, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ) + { + FT_Service_SFNT_Table service; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_Err_Invalid_Face_Handle; + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service == NULL ) + return FT_Err_Unimplemented_Feature; + + return service->table_info( face, table_index, tag, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return 0; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( service == NULL ) + return 0; + if ( service->get_cmap_info( charmap, &cmap_info )) + return 0; + + return cmap_info.language; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return -1; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( service == NULL ) + return -1; + if ( service->get_cmap_info( charmap, &cmap_info )) + return -1; + + return cmap_info.format; + } + + + /* documentation is in ftsizes.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Activate_Size( FT_Size size ) + { + FT_Face face; + + + if ( size == NULL ) + return FT_Err_Bad_Argument; + + face = size->face; + if ( face == NULL || face->driver == NULL ) + return FT_Err_Bad_Argument; + + /* we don't need anything more complex than that; all size objects */ + /* are already listed by the face */ + face->size = size; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* lookup a renderer by glyph format in the library's list */ + FT_BASE_DEF( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ) + { + FT_ListNode cur; + FT_Renderer result = 0; + + + if ( !library ) + goto Exit; + + cur = library->renderers.head; + + if ( node ) + { + if ( *node ) + cur = (*node)->next; + *node = 0; + } + + while ( cur ) + { + FT_Renderer renderer = FT_RENDERER( cur->data ); + + + if ( renderer->glyph_format == format ) + { + if ( node ) + *node = cur; + + result = renderer; + break; + } + cur = cur->next; + } + + Exit: + return result; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ) + { + FT_Face face = slot->face; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Renderer result = library->cur_renderer; + + + if ( !result || result->glyph_format != slot->format ) + result = FT_Lookup_Renderer( library, slot->format, 0 ); + + return result; + } + + + static void + ft_set_current_renderer( FT_Library library ) + { + FT_Renderer renderer; + + + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); + library->cur_renderer = renderer; + } + + + static FT_Error + ft_add_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_Error error; + FT_ListNode node; + + + if ( FT_NEW( node ) ) + goto Exit; + + { + FT_Renderer render = FT_RENDERER( module ); + FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; + + + render->clazz = clazz; + render->glyph_format = clazz->glyph_format; + + /* allocate raster object if needed */ + if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + clazz->raster_class->raster_new ) + { + error = clazz->raster_class->raster_new( memory, &render->raster ); + if ( error ) + goto Fail; + + render->raster_render = clazz->raster_class->raster_render; + render->render = clazz->render_glyph; + } + + /* add to list */ + node->data = module; + FT_List_Add( &library->renderers, node ); + + ft_set_current_renderer( library ); + } + + Fail: + if ( error ) + FT_FREE( node ); + + Exit: + return error; + } + + + static void + ft_remove_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_ListNode node; + + + node = FT_List_Find( &library->renderers, module ); + if ( node ) + { + FT_Renderer render = FT_RENDERER( module ); + + + /* release raster object, if any */ + if ( render->raster ) + render->clazz->raster_class->raster_done( render->raster ); + + /* remove from list */ + FT_List_Remove( &library->renderers, node ); + FT_FREE( node ); + + ft_set_current_renderer( library ); + } + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ) + { + /* test for valid `library' delayed to FT_Lookup_Renderer() */ + + return FT_Lookup_Renderer( library, format, 0 ); + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ) + { + FT_ListNode node; + FT_Error error = FT_Err_Ok; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !renderer ) + return FT_Err_Invalid_Argument; + + node = FT_List_Find( &library->renderers, renderer ); + if ( !node ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + FT_List_Up( &library->renderers, node ); + + if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) + library->cur_renderer = renderer; + + if ( num_params > 0 ) + { + FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode; + + + for ( ; num_params > 0; num_params-- ) + { + error = set_mode( renderer, parameters->tag, parameters->data ); + if ( error ) + break; + } + } + + Exit: + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Error error = FT_Err_Ok; + FT_Renderer renderer; + + + /* if it is already a bitmap, no need to do anything */ + switch ( slot->format ) + { + case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ + break; + + default: + { + FT_ListNode node = 0; + FT_Bool update = 0; + + + /* small shortcut for the very common case */ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + + error = FT_Err_Unimplemented_Feature; + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, NULL ); + if ( !error || + FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format. */ + + /* now, look for another renderer that supports the same */ + /* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + update = 1; + } + + /* if we changed the current renderer for the glyph image format */ + /* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + } + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Library library; + + + if ( !slot ) + return FT_Err_Invalid_Argument; + + library = FT_FACE_LIBRARY( slot->face ); + + return FT_Render_Glyph_Internal( library, slot, render_mode ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Destroy_Module */ + /* */ + /* */ + /* Destroys a given module object. For drivers, this also destroys */ + /* all child faces. */ + /* */ + /* */ + /* module :: A handle to the target driver object. */ + /* */ + /* */ + /* The driver _must_ be LOCKED! */ + /* */ + static void + Destroy_Module( FT_Module module ) + { + FT_Memory memory = module->memory; + FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + + + /* finalize client-data - before anything else */ + if ( module->generic.finalizer ) + module->generic.finalizer( module ); + + if ( library && library->auto_hinter == module ) + library->auto_hinter = 0; + + /* if the module is a renderer */ + if ( FT_MODULE_IS_RENDERER( module ) ) + ft_remove_renderer( module ); + + /* if the module is a font driver, add some steps */ + if ( FT_MODULE_IS_DRIVER( module ) ) + Destroy_Driver( FT_DRIVER( module ) ); + + /* finalize the module object */ + if ( clazz->module_done ) + clazz->module_done( module ); + + /* discard it */ + FT_FREE( module ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ) + { + FT_Error error; + FT_Memory memory; + FT_Module module; + FT_UInt nn; + + +#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ + FREETYPE_MINOR ) + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !clazz ) + return FT_Err_Invalid_Argument; + + /* check freetype version */ + if ( clazz->module_requires > FREETYPE_VER_FIXED ) + return FT_Err_Invalid_Version; + + /* look for a module with the same name in the library's table */ + for ( nn = 0; nn < library->num_modules; nn++ ) + { + module = library->modules[nn]; + if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) + { + /* this installed module has the same name, compare their versions */ + if ( clazz->module_version <= module->clazz->module_version ) + return FT_Err_Lower_Module_Version; + + /* remove the module from our list, then exit the loop to replace */ + /* it by our new version.. */ + FT_Remove_Module( library, module ); + break; + } + } + + memory = library->memory; + error = FT_Err_Ok; + + if ( library->num_modules >= FT_MAX_MODULES ) + { + error = FT_Err_Too_Many_Drivers; + goto Exit; + } + + /* allocate module object */ + if ( FT_ALLOC( module, clazz->module_size ) ) + goto Exit; + + /* base initialization */ + module->library = library; + module->memory = memory; + module->clazz = (FT_Module_Class*)clazz; + + /* check whether the module is a renderer - this must be performed */ + /* before the normal module initialization */ + if ( FT_MODULE_IS_RENDERER( module ) ) + { + /* add to the renderers list */ + error = ft_add_renderer( module ); + if ( error ) + goto Fail; + } + + /* is the module a auto-hinter? */ + if ( FT_MODULE_IS_HINTER( module ) ) + library->auto_hinter = module; + + /* if the module is a font driver */ + if ( FT_MODULE_IS_DRIVER( module ) ) + { + /* allocate glyph loader if needed */ + FT_Driver driver = FT_DRIVER( module ); + + + driver->clazz = (FT_Driver_Class)module->clazz; + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); + if ( error ) + goto Fail; + } + } + + if ( clazz->module_init ) + { + error = clazz->module_init( module ); + if ( error ) + goto Fail; + } + + /* add module to the library's table */ + library->modules[library->num_modules++] = module; + + Exit: + return error; + + Fail: + if ( FT_MODULE_IS_DRIVER( module ) ) + { + FT_Driver driver = FT_DRIVER( module ); + + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } + + if ( FT_MODULE_IS_RENDERER( module ) ) + { + FT_Renderer renderer = FT_RENDERER( module ); + + + if ( renderer->raster ) + renderer->clazz->raster_class->raster_done( renderer->raster ); + } + + FT_FREE( module ); + goto Exit; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ) + { + FT_Module result = 0; + FT_Module* cur; + FT_Module* limit; + + + if ( !library || !module_name ) + return result; + + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) + { + result = cur[0]; + break; + } + + return result; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ) + { + FT_Module module; + + + /* test for valid `library' delayed to FT_Get_Module() */ + + module = FT_Get_Module( library, mod_name ); + + return module ? module->clazz->module_interface : 0; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id ) + { + FT_Pointer result = NULL; + + if ( module ) + { + FT_ASSERT( module->clazz && module->clazz->get_interface ); + + /* first, look for the service in the module + */ + if ( module->clazz->get_interface ) + result = module->clazz->get_interface( module, service_id ); + + if ( result == NULL ) + { + /* we didn't find it, look in all other modules then + */ + FT_Library library = module->library; + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] != module ) + { + FT_ASSERT( cur[0]->clazz ); + + if ( cur[0]->clazz->get_interface ) + { + result = cur[0]->clazz->get_interface( cur[0], service_id ); + if ( result != NULL ) + break; + } + } + } + } + } + + return result; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ) + { + /* try to find the module from the table, then remove it from there */ + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( module ) + { + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == module ) + { + /* remove it from the table */ + library->num_modules--; + limit--; + while ( cur < limit ) + { + cur[0] = cur[1]; + cur++; + } + limit[0] = 0; + + /* destroy the module */ + Destroy_Module( module ); + + return FT_Err_Ok; + } + } + } + return FT_Err_Invalid_Driver_Handle; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ) + { + FT_Library library = 0; + FT_Error error; + + + if ( !memory ) + return FT_Err_Invalid_Argument; + +#ifdef FT_DEBUG_LEVEL_ERROR + /* init debugging support */ + ft_debug_init(); +#endif + + /* first of all, allocate the library object */ + if ( FT_NEW( library ) ) + return error; + + library->memory = memory; + + /* allocate the render pool */ + library->raster_pool_size = FT_RENDER_POOL_SIZE; + if ( FT_RENDER_POOL_SIZE > 0 ) + if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) ) + goto Fail; + + /* That's ok now */ + *alibrary = library; + + return FT_Err_Ok; + + Fail: + FT_FREE( library ); + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ) + { + FT_Int major = 0; + FT_Int minor = 0; + FT_Int patch = 0; + + + if ( library ) + { + major = library->version_major; + minor = library->version_minor; + patch = library->version_patch; + } + + if ( amajor ) + *amajor = major; + + if ( aminor ) + *aminor = minor; + + if ( apatch ) + *apatch = patch; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Library( FT_Library library ) + { + FT_Memory memory; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + memory = library->memory; + + /* Discard client-data */ + if ( library->generic.finalizer ) + library->generic.finalizer( library ); + + /* Close all faces in the library. If we don't do + * this, we can have some subtle memory leaks. + * Example: + * + * - the cff font driver uses the pshinter module in cff_size_done + * - if the pshinter module is destroyed before the cff font driver, + * opened FT_Face objects managed by the driver are not properly + * destroyed, resulting in a memory leak + */ + { + FT_UInt n; + + + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + FT_List faces; + + + if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) + continue; + + faces = &FT_DRIVER(module)->faces_list; + while ( faces->head ) + FT_Done_Face( FT_FACE( faces->head->data ) ); + } + } + + /* Close all other modules in the library */ +#if 1 + /* XXX Modules are removed in the reversed order so that */ + /* type42 module is removed before truetype module. This */ + /* avoids double free in some occasions. It is a hack. */ + while ( library->num_modules > 0 ) + FT_Remove_Module( library, + library->modules[library->num_modules - 1] ); +#else + { + FT_UInt n; + + + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + + + if ( module ) + { + Destroy_Module( module ); + library->modules[n] = 0; + } + } + } +#endif + + /* Destroy raster objects */ + FT_FREE( library->raster_pool ); + library->raster_pool_size = 0; + + FT_FREE( library ); + return FT_Err_Ok; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ) + { + if ( library && debug_hook && + hook_index < + ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) + library->debug_hooks[hook_index] = debug_hook; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ) + { + FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; + + + if ( library ) + { + FT_Module module = FT_Get_Module( library, "truetype" ); + + + if ( module ) + { + FT_Service_TrueTypeEngine service; + + + service = (FT_Service_TrueTypeEngine) + ft_module_get_service( module, + FT_SERVICE_ID_TRUETYPE_ENGINE ); + if ( service ) + result = service->engine_type; + } + } + + return result; + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE_DEF( FT_Error ) + ft_stub_set_char_sizes( FT_Size size, + FT_F26Dot6 width, + FT_F26Dot6 height, + FT_UInt horz_res, + FT_UInt vert_res ) + { + FT_Size_RequestRec req; + FT_Driver driver = size->face->driver; + + + if ( driver->clazz->request_size ) + { + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = width; + req.height = height; + + if ( horz_res == 0 ) + horz_res = vert_res; + + if ( vert_res == 0 ) + vert_res = horz_res; + + if ( horz_res == 0 ) + horz_res = vert_res = 72; + + req.horiResolution = horz_res; + req.vertResolution = vert_res; + + return driver->clazz->request_size( size, &req ); + } + + return 0; + } + + + FT_BASE_DEF( FT_Error ) + ft_stub_set_pixel_sizes( FT_Size size, + FT_UInt width, + FT_UInt height ) + { + FT_Size_RequestRec req; + FT_Driver driver = size->face->driver; + + + if ( driver->clazz->request_size ) + { + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = width << 6; + req.height = height << 6; + req.horiResolution = 0; + req.vertResolution = 0; + + return driver->clazz->request_size( size, &req ); + } + + return 0; + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + if ( glyph != NULL && + glyph->format == FT_GLYPH_FORMAT_COMPOSITE && + sub_index < glyph->num_subglyphs ) + { + FT_SubGlyph subg = glyph->subglyphs + sub_index; + + + *p_index = subg->index; + *p_flags = subg->flags; + *p_arg1 = subg->arg1; + *p_arg2 = subg->arg2; + *p_transform = subg->transform; + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftotval.c b/src/freetype2/base/ftotval.c new file mode 100644 index 0000000..b6de6db --- /dev/null +++ b/src/freetype2/base/ftotval.c @@ -0,0 +1,83 @@ +/***************************************************************************/ +/* */ +/* ftotval.c */ +/* */ +/* FreeType API for validating OpenType tables (body). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + +#include +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_OPENTYPE_VALIDATE_H + + + /* documentation is in ftotval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ) + { + FT_Service_OTvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + + if ( !( BASE_table && + GDEF_table && + GPOS_table && + GSUB_table && + JSTF_table ) ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + BASE_table, + GDEF_table, + GPOS_table, + GSUB_table, + JSTF_table ); + else + error = FT_Err_Unimplemented_Feature; + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( table ); + } + + +/* END */ diff --git a/src/freetype2/base/ftoutln.c b/src/freetype2/base/ftoutln.c new file mode 100644 index 0000000..6926f3a --- /dev/null +++ b/src/freetype2/base/ftoutln.c @@ -0,0 +1,1088 @@ +/***************************************************************************/ +/* */ +/* ftoutln.c */ +/* */ +/* FreeType outline management (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* All functions are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#include +#include FT_OUTLINE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_TRIGONOMETRY_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_outline + + + static + const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 }; + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_UInt first; /* index of first point in contour */ + FT_Int tag; /* current point's state */ + + FT_Int shift; + FT_Pos delta; + + + if ( !outline || !func_interface ) + return FT_Err_Invalid_Argument; + + shift = func_interface->shift; + delta = func_interface->delta; + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_Int last; /* index of last point in contour */ + + + last = outline->contours[n]; + if ( last < 0 ) + goto Invalid_Outline; + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); + v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); + vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return FT_Err_Invalid_Outline; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + FT_Error error; + + + if ( !anoutline || !memory ) + return FT_Err_Invalid_Argument; + + *anoutline = null_outline; + + if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) || + FT_NEW_ARRAY( anoutline->tags, numPoints ) || + FT_NEW_ARRAY( anoutline->contours, numContours ) ) + goto Fail; + + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_Short)numContours; + anoutline->flags |= FT_OUTLINE_OWNER; + + return FT_Err_Ok; + + Fail: + anoutline->flags |= FT_OUTLINE_OWNER; + FT_Outline_Done_Internal( memory, anoutline ); + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + return FT_Outline_New_Internal( library->memory, numPoints, + numContours, anoutline ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Check( FT_Outline* outline ) + { + if ( outline ) + { + FT_Int n_points = outline->n_points; + FT_Int n_contours = outline->n_contours; + FT_Int end0, end; + FT_Int n; + + + /* empty glyph? */ + if ( n_points == 0 && n_contours == 0 ) + return 0; + + /* check point and contour counts */ + if ( n_points <= 0 || n_contours <= 0 ) + goto Bad; + + end0 = end = -1; + for ( n = 0; n < n_contours; n++ ) + { + end = outline->contours[n]; + + /* note that we don't accept empty contours */ + if ( end <= end0 || end >= n_points ) + goto Bad; + + end0 = end; + } + + if ( end != n_points - 1 ) + goto Bad; + + /* XXX: check the tags array */ + return 0; + } + + Bad: + return FT_Err_Invalid_Argument; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ) + { + FT_Int is_owner; + + + if ( !source || !target || + source->n_points != target->n_points || + source->n_contours != target->n_contours ) + return FT_Err_Invalid_Argument; + + if ( source == target ) + return FT_Err_Ok; + + FT_ARRAY_COPY( target->points, source->points, source->n_points ); + + FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); + + FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); + + /* copy all flags, except the `FT_OUTLINE_OWNER' one */ + is_owner = target->flags & FT_OUTLINE_OWNER; + target->flags = source->flags; + + target->flags &= ~FT_OUTLINE_OWNER; + target->flags |= is_owner; + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ) + { + if ( memory && outline ) + { + if ( outline->flags & FT_OUTLINE_OWNER ) + { + FT_FREE( outline->points ); + FT_FREE( outline->tags ); + FT_FREE( outline->contours ); + } + *outline = null_outline; + + return FT_Err_Ok; + } + else + return FT_Err_Invalid_Argument; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ) + { + /* check for valid `outline' in FT_Outline_Done_Internal() */ + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + return FT_Outline_Done_Internal( library->memory, outline ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ) + { + FT_Pos xMin, yMin, xMax, yMax; + + + if ( outline && acbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + FT_Pos x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ) + { + FT_UShort n; + FT_Vector* vec = outline->points; + + + if ( !outline ) + return; + + for ( n = 0; n < outline->n_points; n++ ) + { + vec->x += xOffset; + vec->y += yOffset; + vec++; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Reverse( FT_Outline* outline ) + { + FT_UShort n; + FT_Int first, last; + + + if ( !outline ) + return; + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + last = outline->contours[n]; + + /* reverse point table */ + { + FT_Vector* p = outline->points + first; + FT_Vector* q = outline->points + last; + FT_Vector swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + /* reverse tags table */ + { + char* p = outline->tags + first; + char* q = outline->tags + last; + char swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + first = last + 1; + } + + outline->flags ^= FT_OUTLINE_REVERSE_FILL; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ) + { + FT_Error error; + FT_Bool update = 0; + FT_Renderer renderer; + FT_ListNode node; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !outline || !params ) + return FT_Err_Invalid_Argument; + + renderer = library->cur_renderer; + node = library->renderers.head; + + params->source = (void*)outline; + + error = FT_Err_Cannot_Render_Glyph; + while ( renderer ) + { + error = renderer->raster_render( renderer->raster, params ); + if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format */ + + /* now, look for another renderer that supports the same */ + /* format */ + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, + &node ); + update = 1; + } + + /* if we changed the current renderer for the glyph image format */ + /* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ) + { + FT_Raster_Params params; + + + if ( !abitmap ) + return FT_Err_Invalid_Argument; + + /* other checks are delayed to FT_Outline_Render() */ + + params.target = abitmap; + params.flags = 0; + + if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + params.flags |= FT_RASTER_FLAG_AA; + + return FT_Outline_Render( library, outline, ¶ms ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ) + { + FT_Pos xz, yz; + + + if ( !vector || !matrix ) + return; + + xz = FT_MulFix( vector->x, matrix->xx ) + + FT_MulFix( vector->y, matrix->xy ); + + yz = FT_MulFix( vector->x, matrix->yx ) + + FT_MulFix( vector->y, matrix->yy ); + + vector->x = xz; + vector->y = yz; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ) + { + FT_Vector* vec; + FT_Vector* limit; + + + if ( !outline || !matrix ) + return; + + vec = outline->points; + limit = vec + outline->n_points; + + for ( ; vec < limit; vec++ ) + FT_Vector_Transform( vec, matrix ); + } + + +#if 0 + +#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \ + do { \ + (first) = ( c > 0 ) ? (outline)->points + \ + (outline)->contours[c - 1] + 1 \ + : (outline)->points; \ + (last) = (outline)->points + (outline)->contours[c]; \ + } while ( 0 ) + + + /* Is a point in some contour? */ + /* */ + /* We treat every point of the contour as if it */ + /* it were ON. That is, we allow false positives, */ + /* but disallow false negatives. (XXX really?) */ + static FT_Bool + ft_contour_has( FT_Outline* outline, + FT_Short c, + FT_Vector* point ) + { + FT_Vector* first; + FT_Vector* last; + FT_Vector* a; + FT_Vector* b; + FT_UInt n = 0; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( a = first; a <= last; a++ ) + { + FT_Pos x; + FT_Int intersect; + + + b = ( a == last ) ? first : a + 1; + + intersect = ( a->y - point->y ) ^ ( b->y - point->y ); + + /* a and b are on the same side */ + if ( intersect >= 0 ) + { + if ( intersect == 0 && a->y == point->y ) + { + if ( ( a->x <= point->x && b->x >= point->x ) || + ( a->x >= point->x && b->x <= point->x ) ) + return 1; + } + + continue; + } + + x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); + + if ( x < point->x ) + n++; + else if ( x == point->x ) + return 1; + } + + return ( n % 2 ); + } + + + static FT_Bool + ft_contour_enclosed( FT_Outline* outline, + FT_UShort c ) + { + FT_Vector* first; + FT_Vector* last; + FT_Short i; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( i = 0; i < outline->n_contours; i++ ) + { + if ( i != c && ft_contour_has( outline, i, first ) ) + { + FT_Vector* pt; + + + for ( pt = first + 1; pt <= last; pt++ ) + if ( !ft_contour_has( outline, i, pt ) ) + return 0; + + return 1; + } + } + + return 0; + } + + + /* This version differs from the public one in that each */ + /* part (contour not enclosed in another contour) of the */ + /* outline is checked for orientation. This is */ + /* necessary for some buggy CJK fonts. */ + static FT_Orientation + ft_outline_get_orientation( FT_Outline* outline ) + { + FT_Short i; + FT_Vector* first; + FT_Vector* last; + FT_Orientation orient = FT_ORIENTATION_NONE; + + + first = outline->points; + for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) + { + FT_Vector* point; + FT_Vector* xmin_point; + FT_Pos xmin; + + + last = outline->points + outline->contours[i]; + + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + if ( ft_contour_enclosed( outline, i ) ) + continue; + + xmin = first->x; + xmin_point = first; + + for ( point = first + 1; point <= last; point++ ) + { + if ( point->x < xmin ) + { + xmin = point->x; + xmin_point = point; + } + } + + /* check the orientation of the contour */ + { + FT_Vector* prev; + FT_Vector* next; + FT_Orientation o; + + + prev = ( xmin_point == first ) ? last : xmin_point - 1; + next = ( xmin_point == last ) ? first : xmin_point + 1; + + if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > + FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) + o = FT_ORIENTATION_POSTSCRIPT; + else + o = FT_ORIENTATION_TRUETYPE; + + if ( orient == FT_ORIENTATION_NONE ) + orient = o; + else if ( orient != o ) + return FT_ORIENTATION_NONE; + } + } + + return orient; + } + +#endif /* 0 */ + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ) + { + FT_Vector* points; + FT_Vector v_prev, v_first, v_next, v_cur; + FT_Angle rotate, angle_in, angle_out; + FT_Int c, n, first; + FT_Int orientation; + + + if ( !outline ) + return FT_Err_Invalid_Argument; + + strength /= 2; + if ( strength == 0 ) + return FT_Err_Ok; + + orientation = FT_Outline_Get_Orientation( outline ); + if ( orientation == FT_ORIENTATION_NONE ) + { + if ( outline->n_contours ) + return FT_Err_Invalid_Argument; + else + return FT_Err_Ok; + } + + if ( orientation == FT_ORIENTATION_TRUETYPE ) + rotate = -FT_ANGLE_PI2; + else + rotate = FT_ANGLE_PI2; + + points = outline->points; + + first = 0; + for ( c = 0; c < outline->n_contours; c++ ) + { + int last = outline->contours[c]; + + + v_first = points[first]; + v_prev = points[last]; + v_cur = v_first; + + for ( n = first; n <= last; n++ ) + { + FT_Vector in, out; + FT_Angle angle_diff; + FT_Pos d; + FT_Fixed scale; + + + if ( n < last ) + v_next = points[n + 1]; + else + v_next = v_first; + + /* compute the in and out vectors */ + in.x = v_cur.x - v_prev.x; + in.y = v_cur.y - v_prev.y; + + out.x = v_next.x - v_cur.x; + out.y = v_next.y - v_cur.y; + + angle_in = FT_Atan2( in.x, in.y ); + angle_out = FT_Atan2( out.x, out.y ); + angle_diff = FT_Angle_Diff( angle_in, angle_out ); + scale = FT_Cos( angle_diff / 2 ); + + if ( scale < 0x4000L && scale > -0x4000L ) + in.x = in.y = 0; + else + { + d = FT_DivFix( strength, scale ); + + FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); + } + + outline->points[n].x = v_cur.x + strength + in.x; + outline->points[n].y = v_cur.y + strength + in.y; + + v_prev = v_cur; + v_cur = v_next; + } + + first = last + 1; + } + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ) + { + FT_Pos xmin = 32768L; + FT_Pos xmin_ymin = 32768L; + FT_Pos xmin_ymax = -32768L; + FT_Vector* xmin_first = NULL; + FT_Vector* xmin_last = NULL; + + short* contour; + + FT_Vector* first; + FT_Vector* last; + FT_Vector* prev; + FT_Vector* point; + + int i; + FT_Pos ray_y[3]; + FT_Orientation result[3]; + + + if ( !outline || outline->n_points <= 0 ) + return FT_ORIENTATION_TRUETYPE; + + /* We use the nonzero winding rule to find the orientation. */ + /* Since glyph outlines behave much more `regular' than arbitrary */ + /* cubic or quadratic curves, this test deals with the polygon */ + /* only which is spanned up by the control points. */ + + first = outline->points; + for ( contour = outline->contours; + contour < outline->contours + outline->n_contours; + contour++, first = last + 1 ) + { + FT_Pos contour_xmin = 32768L; + FT_Pos contour_xmax = -32768L; + FT_Pos contour_ymin = 32768L; + FT_Pos contour_ymax = -32768L; + + + last = outline->points + *contour; + + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + for ( point = first; point <= last; ++point ) + { + if ( point->x < contour_xmin ) + contour_xmin = point->x; + + if ( point->x > contour_xmax ) + contour_xmax = point->x; + + if ( point->y < contour_ymin ) + contour_ymin = point->y; + + if ( point->y > contour_ymax ) + contour_ymax = point->y; + } + + if ( contour_xmin < xmin && + contour_xmin != contour_xmax && + contour_ymin != contour_ymax ) + { + xmin = contour_xmin; + xmin_ymin = contour_ymin; + xmin_ymax = contour_ymax; + xmin_first = first; + xmin_last = last; + } + } + + if ( xmin == 32768 ) + return FT_ORIENTATION_TRUETYPE; + + ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2; + ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1; + ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2; + + for ( i = 0; i < 3; i++ ) + { + FT_Pos left_x; + FT_Pos right_x; + FT_Vector* left1; + FT_Vector* left2; + FT_Vector* right1; + FT_Vector* right2; + + + RedoRay: + left_x = 32768L; + right_x = -32768L; + + left1 = left2 = right1 = right2 = NULL; + + prev = xmin_last; + for ( point = xmin_first; point <= xmin_last; prev = point, ++point ) + { + FT_Pos tmp_x; + + + if ( point->y == ray_y[i] || prev->y == ray_y[i] ) + { + ray_y[i]++; + goto RedoRay; + } + + if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) || + ( point->y > ray_y[i] && prev->y > ray_y[i] ) ) + continue; + + tmp_x = FT_MulDiv( point->x - prev->x, + ray_y[i] - prev->y, + point->y - prev->y ) + prev->x; + + if ( tmp_x < left_x ) + { + left_x = tmp_x; + left1 = prev; + left2 = point; + } + + if ( tmp_x > right_x ) + { + right_x = tmp_x; + right1 = prev; + right2 = point; + } + } + + if ( left1 && right1 ) + { + if ( left1->y < left2->y && right1->y > right2->y ) + result[i] = FT_ORIENTATION_TRUETYPE; + else if ( left1->y > left2->y && right1->y < right2->y ) + result[i] = FT_ORIENTATION_POSTSCRIPT; + else + result[i] = FT_ORIENTATION_NONE; + } + } + + if ( result[0] != FT_ORIENTATION_NONE && + ( result[0] == result[1] || result[0] == result[2] ) ) + return result[0]; + + if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] ) + return result[1]; + + return FT_ORIENTATION_TRUETYPE; + } + + +/* END */ diff --git a/src/freetype2/base/ftpatent.c b/src/freetype2/base/ftpatent.c new file mode 100644 index 0000000..d63f191 --- /dev/null +++ b/src/freetype2/base/ftpatent.c @@ -0,0 +1,281 @@ +/***************************************************************************/ +/* */ +/* ftpatent.c */ +/* */ +/* FreeType API for checking patented TrueType bytecode instructions */ +/* (body). */ +/* */ +/* Copyright 2007 by David Turner. */ +/* */ +/* 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 +#include FT_FREETYPE_H +#include FT_TRUETYPE_TAGS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_STREAM_H +#include FT_SERVICE_SFNT_H +#include FT_SERVICE_TRUETYPE_GLYF_H + + + static FT_Bool + _tt_check_patents_in_range( FT_Stream stream, + FT_ULong size ) + { + FT_Bool result = FALSE; + FT_Error error; + FT_Bytes p, end; + + + if ( FT_FRAME_ENTER( size ) ) + return 0; + + p = stream->cursor; + end = p + size; + + while ( p < end ) + { + switch (p[0]) + { + case 0x06: /* SPvTL // */ + case 0x07: /* SPvTL + */ + case 0x08: /* SFvTL // */ + case 0x09: /* SFvTL + */ + case 0x0A: /* SPvFS */ + case 0x0B: /* SFvFS */ + result = TRUE; + goto Exit; + + case 0x40: + if ( p + 1 >= end ) + goto Exit; + + p += p[1] + 2; + break; + + case 0x41: + if ( p + 1 >= end ) + goto Exit; + + p += p[1] * 2 + 2; + break; + + case 0x71: /* DELTAP2 */ + case 0x72: /* DELTAP3 */ + case 0x73: /* DELTAC0 */ + case 0x74: /* DELTAC1 */ + case 0x75: /* DELTAC2 */ + result = TRUE; + goto Exit; + + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + p += ( p[0] - 0xB0 ) + 2; + break; + + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + p += ( p[0] - 0xB8 ) * 2 + 3; + break; + + default: + p += 1; + break; + } + } + + Exit: + FT_FRAME_EXIT(); + return result; + } + + + static FT_Bool + _tt_check_patents_in_table( FT_Face face, + FT_ULong tag ) + { + FT_Stream stream = face->stream; + FT_Error error; + FT_Service_SFNT_Table service; + FT_Bool result = FALSE; + + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + + if ( service ) + { + FT_ULong offset, size; + + + error = service->table_info( face, tag, &offset, &size ); + if ( error || + FT_STREAM_SEEK( offset ) ) + goto Exit; + + result = _tt_check_patents_in_range( stream, size ); + } + + Exit: + return result; + } + + + static FT_Bool + _tt_face_check_patents( FT_Face face ) + { + FT_Stream stream = face->stream; + FT_UInt gindex; + FT_Error error; + FT_Bool result; + + FT_Service_TTGlyf service; + + + result = _tt_check_patents_in_table( face, TTAG_fpgm ); + if ( result ) + goto Exit; + + result = _tt_check_patents_in_table( face, TTAG_prep ); + if ( result ) + goto Exit; + + FT_FACE_FIND_SERVICE( face, service, TT_GLYF ); + if ( service == NULL ) + goto Exit; + + for ( gindex = 0; gindex < (FT_UInt)face->num_glyphs; gindex++ ) + { + FT_ULong offset, num_ins, size; + FT_Int num_contours; + + + offset = service->get_location( face, gindex, &size ); + if ( size == 0 ) + continue; + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_SHORT( num_contours ) ) + continue; + + if ( num_contours >= 0 ) /* simple glyph */ + { + if ( FT_STREAM_SKIP( 8 + num_contours * 2 ) ) + continue; + } + else /* compound glyph */ + { + FT_Bool has_instr = 0; + + + if ( FT_STREAM_SKIP( 8 ) ) + continue; + + /* now read each component */ + for (;;) + { + FT_UInt flags, toskip; + + + if( FT_READ_USHORT( flags ) ) + break; + + toskip = 2 + 1 + 1; + + if ( ( flags & ( 1 << 0 ) ) != 0 ) /* ARGS_ARE_WORDS */ + toskip += 2; + + if ( ( flags & ( 1 << 3 ) ) != 0 ) /* WE_HAVE_A_SCALE */ + toskip += 2; + else if ( ( flags & ( 1 << 6 ) ) != 0 ) /* WE_HAVE_X_Y_SCALE */ + toskip += 4; + else if ( ( flags & ( 1 << 7 ) ) != 0 ) /* WE_HAVE_A_2x2 */ + toskip += 8; + + if ( ( flags & ( 1 << 8 ) ) != 0 ) /* WE_HAVE_INSTRUCTIONS */ + has_instr = 1; + + if ( FT_STREAM_SKIP( toskip ) ) + goto NextGlyph; + + if ( ( flags & ( 1 << 5 ) ) == 0 ) /* MORE_COMPONENTS */ + break; + } + + if ( !has_instr ) + goto NextGlyph; + } + + if ( FT_READ_USHORT( num_ins ) ) + continue; + + result = _tt_check_patents_in_range( stream, num_ins ); + if ( result ) + goto Exit; + + NextGlyph: + ; + } + + Exit: + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ) + { + FT_Bool result = FALSE; + + + if ( face && FT_IS_SFNT( face ) ) + result = _tt_face_check_patents( face ); + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ) + { + FT_Bool result = 0; + + +#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ + !defined( TT_CONFIG_OPTION_BYTECODE_INTEPRETER ) + if ( face && FT_IS_SFNT( face ) ) + { + result = !face->internal->ignore_unpatented_hinter; + face->internal->ignore_unpatented_hinter = !value; + } +#else + FT_UNUSED( face ); + FT_UNUSED( value ); +#endif + + return result; + } + +/* END */ diff --git a/src/freetype2/base/ftpfr.c b/src/freetype2/base/ftpfr.c new file mode 100644 index 0000000..9e930dd --- /dev/null +++ b/src/freetype2/base/ftpfr.c @@ -0,0 +1,132 @@ +/***************************************************************************/ +/* */ +/* ftpfr.c */ +/* */ +/* FreeType API for accessing PFR-specific data (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 +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_PFR_H + + + /* check the format */ + static FT_Service_PfrMetrics + ft_pfr_check( FT_Face face ) + { + FT_Service_PfrMetrics service; + + + FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS ); + + return service; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + FT_Error error = FT_Err_Ok; + FT_Service_PfrMetrics service; + + + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_metrics( face, + aoutline_resolution, + ametrics_resolution, + ametrics_x_scale, + ametrics_y_scale ); + } + else if ( face ) + { + FT_Fixed x_scale, y_scale; + + + /* this is not a PFR font */ + *aoutline_resolution = face->units_per_EM; + *ametrics_resolution = face->units_per_EM; + + x_scale = y_scale = 0x10000L; + if ( face->size ) + { + x_scale = face->size->metrics.x_scale; + y_scale = face->size->metrics.y_scale; + } + *ametrics_x_scale = x_scale; + *ametrics_y_scale = y_scale; + } + else + error = FT_Err_Invalid_Argument; + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + service = ft_pfr_check( face ); + if ( service ) + error = service->get_kerning( face, left, right, avector ); + else if ( face ) + error = FT_Get_Kerning( face, left, right, + FT_KERNING_UNSCALED, avector ); + else + error = FT_Err_Invalid_Argument; + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_advance( face, gindex, aadvance ); + } + else + /* XXX: TODO: PROVIDE ADVANCE-LOADING METHOD TO ALL FONT DRIVERS */ + error = FT_Err_Invalid_Argument; + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftrfork.c b/src/freetype2/base/ftrfork.c new file mode 100644 index 0000000..a4f726d --- /dev/null +++ b/src/freetype2/base/ftrfork.c @@ -0,0 +1,728 @@ +/***************************************************************************/ +/* */ +/* ftrfork.c */ +/* */ +/* Embedded resource forks accessor (body). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are */ +/* derived from ftobjs.c. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* Development of the code in this file is support of */ +/* Information-technology Promotion Agency, Japan. */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_RFORK_H + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Resource fork directory access ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ) + { + FT_Error error; + unsigned char head[16], head2[16]; + FT_Long map_pos, rdata_len; + int allzeros, allmatch, i; + FT_Long type_list; + + FT_UNUSED( library ); + + + error = FT_Stream_Seek( stream, rfork_offset ); + if ( error ) + return error; + + error = FT_Stream_Read( stream, (FT_Byte *)head, 16 ); + if ( error ) + return error; + + *rdata_pos = rfork_offset + ( ( head[0] << 24 ) | + ( head[1] << 16 ) | + ( head[2] << 8 ) | + head[3] ); + map_pos = rfork_offset + ( ( head[4] << 24 ) | + ( head[5] << 16 ) | + ( head[6] << 8 ) | + head[7] ); + rdata_len = ( head[ 8] << 24 ) | + ( head[ 9] << 16 ) | + ( head[10] << 8 ) | + head[11]; + + /* map_len = head[12] .. head[15] */ + + if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset ) + return FT_Err_Unknown_File_Format; + + error = FT_Stream_Seek( stream, map_pos ); + if ( error ) + return error; + + head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ + + error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); + if ( error ) + return error; + + allzeros = 1; + allmatch = 1; + for ( i = 0; i < 16; ++i ) + { + if ( head2[i] != 0 ) + allzeros = 0; + if ( head2[i] != head[i] ) + allmatch = 0; + } + if ( !allzeros && !allmatch ) + return FT_Err_Unknown_File_Format; + + /* If we have reached this point then it is probably a mac resource */ + /* file. Now, does it contain any interesting resources? */ + /* Skip handle to next resource map, the file resource number, and */ + /* attributes. */ + (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ + + 2 /* skip file resource number */ + + 2 ); /* skip attributes */ + + if ( FT_READ_USHORT( type_list ) ) + return error; + if ( type_list == -1 ) + return FT_Err_Unknown_File_Format; + + error = FT_Stream_Seek( stream, map_pos + type_list ); + if ( error ) + return error; + + *map_offset = map_pos + type_list; + return FT_Err_Ok; + } + + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Long **offsets, + FT_Long *count ) + { + FT_Error error; + int i, j, cnt, subcnt; + FT_Long tag_internal, rpos; + FT_Memory memory = library->memory; + FT_Long temp; + FT_Long *offsets_internal; + + + error = FT_Stream_Seek( stream, map_offset ); + if ( error ) + return error; + + if ( FT_READ_USHORT( cnt ) ) + return error; + cnt++; + + for ( i = 0; i < cnt; ++i ) + { + if ( FT_READ_LONG( tag_internal ) || + FT_READ_USHORT( subcnt ) || + FT_READ_USHORT( rpos ) ) + return error; + + FT_TRACE2(( "Resource tags: %c%c%c%c\n", + (char)( 0xff & ( tag_internal >> 24 ) ), + (char)( 0xff & ( tag_internal >> 16 ) ), + (char)( 0xff & ( tag_internal >> 8 ) ), + (char)( 0xff & ( tag_internal >> 0 ) ) )); + + if ( tag_internal == tag ) + { + *count = subcnt + 1; + rpos += map_offset; + + error = FT_Stream_Seek( stream, rpos ); + if ( error ) + return error; + + if ( FT_NEW_ARRAY( offsets_internal, *count ) ) + return error; + + for ( j = 0; j < *count; ++j ) + { + (void)FT_STREAM_SKIP( 2 ); /* resource id */ + (void)FT_STREAM_SKIP( 2 ); /* rsource name */ + + if ( FT_READ_LONG( temp ) ) + { + FT_FREE( offsets_internal ); + return error; + } + + offsets_internal[j] = rdata_pos + ( temp & 0xFFFFFFL ); + + (void)FT_STREAM_SKIP( 4 ); /* mbz */ + } + + *offsets = offsets_internal; + + return FT_Err_Ok; + } + } + + return FT_Err_Cannot_Open_Resource; + } + + +#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Guessing functions ****/ + /**** ****/ + /**** When you add a new guessing function, ****/ + /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef FT_Error + (*raccess_guess_func)( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + + /*************************************************************************/ + /**** ****/ + /**** Helper functions ****/ + /**** ****/ + /*************************************************************************/ + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char * base_file_name, + FT_Int32 magic, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char * file_name, + FT_Long *result_offset ); + + static char * + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ); + + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Long i; + + + raccess_guess_func funcs[FT_RACCESS_N_RULES] = + { + raccess_guess_apple_double, + raccess_guess_apple_single, + raccess_guess_darwin_ufs_export, + raccess_guess_darwin_hfsplus, + raccess_guess_vfat, + raccess_guess_linux_cap, + raccess_guess_linux_double, + raccess_guess_linux_netatalk, + }; + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + errors[i] = FT_Stream_Seek( stream, 0 ); + if ( errors[i] ) + continue ; + + errors[i] = (funcs[i])( library, stream, base_name, + &(new_names[i]), &(offsets[i]) ); + } + + return; + } + + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x07 ); + + + *result_file_name = NULL; + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = (0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x00); + + + *result_file_name = NULL; + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, "._" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + /* + Only meaningful on systems with hfs+ drivers (or Macs). + */ + FT_Error error; + char* newpath; + FT_Memory memory; + FT_Long base_file_len = ft_strlen( base_file_name ); + + FT_UNUSED( stream ); + + + memory = library->memory; + + if ( base_file_len > FT_INT_MAX ) + return FT_Err_Array_Too_Large; + + if ( FT_ALLOC( newpath, base_file_len + 6 ) ) + return error; + + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + "resource.frk/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, "%" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char * base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + ".AppleDouble/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char * base_file_name, + FT_Int32 magic, + FT_Long *result_offset ) + { + FT_Int32 magic_from_stream; + FT_Error error; + FT_Int32 version_number = 0; + FT_UShort n_of_entries; + + int i; + FT_UInt32 entry_id, entry_offset, entry_length = 0; + + const FT_UInt32 resource_fork_entry_id = 0x2; + + FT_UNUSED( library ); + FT_UNUSED( base_file_name ); + FT_UNUSED( version_number ); + FT_UNUSED( entry_length ); + + + if ( FT_READ_LONG( magic_from_stream ) ) + return error; + if ( magic_from_stream != magic ) + return FT_Err_Unknown_File_Format; + + if ( FT_READ_LONG( version_number ) ) + return error; + + /* filler */ + error = FT_Stream_Skip( stream, 16 ); + if ( error ) + return error; + + if ( FT_READ_USHORT( n_of_entries ) ) + return error; + if ( n_of_entries == 0 ) + return FT_Err_Unknown_File_Format; + + for ( i = 0; i < n_of_entries; i++ ) + { + if ( FT_READ_LONG( entry_id ) ) + return error; + if ( entry_id == resource_fork_entry_id ) + { + if ( FT_READ_LONG( entry_offset ) || + FT_READ_LONG( entry_length ) ) + continue; + *result_offset = entry_offset; + + return FT_Err_Ok; + } + else + FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ + } + + return FT_Err_Unknown_File_Format; + } + + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char * file_name, + FT_Long *result_offset ) + { + FT_Open_Args args2; + FT_Stream stream2; + char * nouse = NULL; + FT_Error error; + + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_name; + error = FT_Stream_New( library, &args2, &stream2 ); + if ( error ) + return error; + + error = raccess_guess_apple_double( library, stream2, file_name, + &nouse, result_offset ); + + FT_Stream_Free( stream2, 0 ); + + return error; + } + + + static char* + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ) + { + char* new_name; + char* tmp; + const char* slash; + unsigned new_length; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( error ); + + + new_length = ft_strlen( original_name ) + ft_strlen( insertion ); + if ( FT_ALLOC( new_name, new_length + 1 ) ) + return NULL; + + tmp = ft_strrchr( original_name, '/' ); + if ( tmp ) + { + ft_strncpy( new_name, original_name, tmp - original_name + 1 ); + new_name[tmp - original_name + 1] = '\0'; + slash = tmp + 1; + } + else + { + slash = original_name; + new_name[0] = '\0'; + } + + ft_strcat( new_name, insertion ); + ft_strcat( new_name, slash ); + + return new_name; + } + + +#else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + + /*************************************************************************/ + /* Dummy function; just sets errors */ + /*************************************************************************/ + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + int i; + + FT_UNUSED( library ); + FT_UNUSED( stream ); + FT_UNUSED( base_name ); + + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + offsets[i] = 0; + errors[i] = FT_Err_Unimplemented_Feature; + } + } + + +#endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + +/* END */ diff --git a/src/freetype2/base/ftstream.c b/src/freetype2/base/ftstream.c new file mode 100644 index 0000000..a067a1f --- /dev/null +++ b/src/freetype2/base/ftstream.c @@ -0,0 +1,842 @@ +/***************************************************************************/ +/* */ +/* ftstream.c */ +/* */ +/* I/O stream support (body). */ +/* */ +/* Copyright 2000-2001, 2002, 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 +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_DEBUG_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_stream + + + FT_BASE_DEF( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ) + { + stream->base = (FT_Byte*) base; + stream->size = size; + stream->pos = 0; + stream->cursor = 0; + stream->read = 0; + stream->close = 0; + } + + + FT_BASE_DEF( void ) + FT_Stream_Close( FT_Stream stream ) + { + if ( stream && stream->close ) + stream->close( stream ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ) + { + FT_Error error = FT_Err_Ok; + + + stream->pos = pos; + + if ( stream->read ) + { + if ( stream->read( stream, pos, 0, 0 ) ) + { + FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + } + } + /* note that seeking to the first position after the file is valid */ + else if ( pos > stream->size ) + { + FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + } + + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ) + { + return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) ); + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_Pos( FT_Stream stream ) + { + return stream->pos; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + if ( pos >= stream->size ) + { + FT_ERROR(( "FT_Stream_ReadAt: invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + return FT_Err_Invalid_Stream_Operation; + } + + if ( stream->read ) + read_bytes = stream->read( stream, pos, buffer, count ); + else + { + read_bytes = stream->size - pos; + if ( read_bytes > count ) + read_bytes = count; + + FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); + } + + stream->pos = pos + read_bytes; + + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_ReadAt:" )); + FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + error = FT_Err_Invalid_Stream_Operation; + } + + return error; + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong read_bytes = 0; + + + if ( stream->pos >= stream->size ) + goto Exit; + + if ( stream->read ) + read_bytes = stream->read( stream, stream->pos, buffer, count ); + else + { + read_bytes = stream->size - stream->pos; + if ( read_bytes > count ) + read_bytes = count; + + FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); + } + + stream->pos += read_bytes; + + Exit: + return read_bytes; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ) + { + FT_Error error; + + + error = FT_Stream_EnterFrame( stream, count ); + if ( !error ) + { + *pbytes = (FT_Byte*)stream->cursor; + + /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ + stream->cursor = 0; + stream->limit = 0; + } + + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ) + { + if ( stream->read ) + { + FT_Memory memory = stream->memory; + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, *pbytes ); + *pbytes = NULL; +#else + FT_FREE( *pbytes ); +#endif + } + *pbytes = 0; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + /* check for nested frame access */ + FT_ASSERT( stream && stream->cursor == 0 ); + + if ( stream->read ) + { + /* allocate the frame in memory */ + FT_Memory memory = stream->memory; + +#ifdef FT_DEBUG_MEMORY + /* assume _ft_debug_file and _ft_debug_lineno are already set */ + stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error ); + if ( error ) + goto Exit; +#else + if ( FT_QALLOC( stream->base, count ) ) + goto Exit; +#endif + /* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" )); + FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + FT_FREE( stream->base ); + error = FT_Err_Invalid_Stream_Operation; + } + stream->cursor = stream->base; + stream->limit = stream->cursor + count; + stream->pos += read_bytes; + } + else + { + /* check current and new position */ + if ( stream->pos >= stream->size || + stream->pos + count > stream->size ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", + stream->pos, count, stream->size )); + + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + + /* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ExitFrame( FT_Stream stream ) + { + /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ + /* that it is possible to access a frame of length 0 in */ + /* some weird fonts (usually, when accessing an array of */ + /* 0 records, like in some strange kern tables). */ + /* */ + /* In this case, the loader code handles the 0-length table */ + /* gracefully; however, stream.cursor is really set to 0 by the */ + /* FT_Stream_EnterFrame() call, and this is not an error. */ + /* */ + FT_ASSERT( stream ); + + if ( stream->read ) + { + FT_Memory memory = stream->memory; + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, stream->base ); + stream->base = NULL; +#else + FT_FREE( stream->base ); +#endif + } + stream->cursor = 0; + stream->limit = 0; + } + + + FT_BASE_DEF( FT_Char ) + FT_Stream_GetChar( FT_Stream stream ) + { + FT_Char result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + if ( stream->cursor < stream->limit ) + result = *stream->cursor++; + + return result; + } + + + FT_BASE_DEF( FT_Short ) + FT_Stream_GetShort( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_SHORT( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_Short ) + FT_Stream_GetShortLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_SHORT_LE( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_GetOffset( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 2 < stream->limit ) + result = FT_NEXT_OFF3( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_GetLong( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_LONG( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_GetLongLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_LONG_LE( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_Char ) + FT_Stream_ReadChar( FT_Stream stream, + FT_Error* error ) + { + FT_Byte result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + { + if ( stream->pos < stream->size ) + result = stream->base[stream->pos]; + else + goto Fail; + } + stream->pos++; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadChar: invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + FT_BASE_DEF( FT_Short ) + FT_Stream_ReadShort( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = FT_NEXT_SHORT( p ); + } + else + goto Fail; + + stream->pos += 2; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadShort:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + FT_BASE_DEF( FT_Short ) + FT_Stream_ReadShortLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = FT_NEXT_SHORT_LE( p ); + } + else + goto Fail; + + stream->pos += 2; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadShortLE:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_ReadOffset( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[3]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 2 < stream->size ) + { + if ( stream->read ) + { + if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = FT_NEXT_OFF3( p ); + } + else + goto Fail; + + stream->pos += 3; + + return result; + + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadOffset:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return 0; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_ReadLong( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = FT_NEXT_LONG( p ); + } + else + goto Fail; + + stream->pos += 4; + + return result; + + Fail: + FT_ERROR(( "FT_Stream_ReadLong: invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + *error = FT_Err_Invalid_Stream_Operation; + + return 0; + } + + + FT_BASE_DEF( FT_Long ) + FT_Stream_ReadLongLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + + + FT_ASSERT( stream ); + + *error = FT_Err_Ok; + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + { + p = stream->base + stream->pos; + } + + if ( p ) + result = FT_NEXT_LONG_LE( p ); + } + else + goto Fail; + + stream->pos += 4; + + return result; + + Fail: + FT_ERROR(( "FT_Stream_ReadLongLE:" )); + FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + *error = FT_Err_Invalid_Stream_Operation; + + return 0; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + FT_Byte* cursor = stream->cursor; + + + if ( !fields || !stream ) + return FT_Err_Invalid_Argument; + + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + + + switch ( fields->value ) + { + case ft_frame_start: /* access a new frame */ + error = FT_Stream_EnterFrame( stream, fields->offset ); + if ( error ) + goto Exit; + + frame_accessed = 1; + cursor = stream->cursor; + fields++; + continue; /* loop! */ + + case ft_frame_bytes: /* read a byte sequence */ + case ft_frame_skip: /* skip some bytes */ + { + FT_UInt len = fields->size; + + + if ( cursor + len > stream->limit ) + { + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + + if ( fields->value == ft_frame_bytes ) + { + p = (FT_Byte*)structure + fields->offset; + FT_MEM_COPY( p, cursor, len ); + } + cursor += len; + fields++; + continue; + } + + case ft_frame_byte: + case ft_frame_schar: /* read a single byte */ + value = FT_NEXT_BYTE(cursor); + sign_shift = 24; + break; + + case ft_frame_short_be: + case ft_frame_ushort_be: /* read a 2-byte big-endian short */ + value = FT_NEXT_USHORT(cursor); + sign_shift = 16; + break; + + case ft_frame_short_le: + case ft_frame_ushort_le: /* read a 2-byte little-endian short */ + value = FT_NEXT_USHORT_LE(cursor); + sign_shift = 16; + break; + + case ft_frame_long_be: + case ft_frame_ulong_be: /* read a 4-byte big-endian long */ + value = FT_NEXT_ULONG(cursor); + sign_shift = 0; + break; + + case ft_frame_long_le: + case ft_frame_ulong_le: /* read a 4-byte little-endian long */ + value = FT_NEXT_ULONG_LE(cursor); + sign_shift = 0; + break; + + case ft_frame_off3_be: + case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ + value = FT_NEXT_UOFF3(cursor); + sign_shift = 8; + break; + + case ft_frame_off3_le: + case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ + value = FT_NEXT_UOFF3_LE(cursor); + sign_shift = 8; + break; + + default: + /* otherwise, exit the loop */ + stream->cursor = cursor; + goto Exit; + } + + /* now, compute the signed value is necessary */ + if ( fields->value & FT_FRAME_OP_SIGNED ) + value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); + + /* finally, store the value in the object */ + + p = (FT_Byte*)structure + fields->offset; + switch ( fields->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)p = (FT_Byte)value; + break; + + case (16 / FT_CHAR_BIT): + *(FT_UShort*)p = (FT_UShort)value; + break; + + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)p = (FT_UInt32)value; + break; + + default: /* for 64-bit systems */ + *(FT_ULong*)p = (FT_ULong)value; + } + + /* go to next field */ + fields++; + } + while ( 1 ); + + Exit: + /* close the frame if it was opened by this read */ + if ( frame_accessed ) + FT_Stream_ExitFrame( stream ); + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftstroke.c b/src/freetype2/base/ftstroke.c new file mode 100644 index 0000000..8f7e045 --- /dev/null +++ b/src/freetype2/base/ftstroke.c @@ -0,0 +1,2010 @@ +/***************************************************************************/ +/* */ +/* ftstroke.c */ +/* */ +/* FreeType path stroker (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 +#include FT_STROKER_H +#include FT_TRIGONOMETRY_H +#include FT_OUTLINE_H +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_OBJECTS_H + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT ; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT + : FT_STROKER_BORDER_RIGHT ; + } + + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** BEZIER COMPUTATIONS *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + +#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 ) +#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 6 ) +#define FT_EPSILON 2 + +#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON ) + + + static FT_Pos + ft_pos_abs( FT_Pos x ) + { + return x >= 0 ? x : -x ; + } + + + static void + ft_conic_split( FT_Vector* base ) + { + FT_Pos a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + + + static FT_Bool + ft_conic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_out ) + { + FT_Vector d1, d2; + FT_Angle theta; + FT_Int close1, close2; + + + d1.x = base[1].x - base[2].x; + d1.y = base[1].y - base[2].y; + d2.x = base[0].x - base[1].x; + d2.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + + if ( close1 ) + { + if ( close2 ) + *angle_in = *angle_out = 0; + else + *angle_in = *angle_out = FT_Atan2( d2.x, d2.y ); + } + else if ( close2 ) + { + *angle_in = *angle_out = FT_Atan2( d1.x, d1.y ); + } + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d2.x, d2.y ); + } + + theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); + + return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); + } + + + static void + ft_cubic_split( FT_Vector* base ) + { + FT_Pos a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + + + static FT_Bool + ft_cubic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_mid, + FT_Angle *angle_out ) + { + FT_Vector d1, d2, d3; + FT_Angle theta1, theta2; + FT_Int close1, close2, close3; + + + d1.x = base[2].x - base[3].x; + d1.y = base[2].y - base[3].y; + d2.x = base[1].x - base[2].x; + d2.y = base[1].y - base[2].y; + d3.x = base[0].x - base[1].x; + d3.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y ); + + if ( close1 || close3 ) + { + if ( close2 ) + { + /* basically a point */ + *angle_in = *angle_out = *angle_mid = 0; + } + else if ( close1 ) + { + *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + else /* close2 */ + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + else if ( close2 ) + { + *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + + theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); + theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); + + return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && + theta2 < FT_SMALL_CUBIC_THRESHOLD ); + } + + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** STROKE BORDERS *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + + typedef enum + { + FT_STROKE_TAG_ON = 1, /* on-curve point */ + FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ + FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ + FT_STROKE_TAG_END = 8 /* sub-path end */ + + } FT_StrokeTags; + +#define FT_STROKE_TAG_BEGIN_END (FT_STROKE_TAG_BEGIN|FT_STROKE_TAG_END) + + typedef struct FT_StrokeBorderRec_ + { + FT_UInt num_points; + FT_UInt max_points; + FT_Vector* points; + FT_Byte* tags; + FT_Bool movable; + FT_Int start; /* index of current sub-path start point */ + FT_Memory memory; + FT_Bool valid; + + } FT_StrokeBorderRec, *FT_StrokeBorder; + + + static FT_Error + ft_stroke_border_grow( FT_StrokeBorder border, + FT_UInt new_points ) + { + FT_UInt old_max = border->max_points; + FT_UInt new_max = border->num_points + new_points; + FT_Error error = 0; + + + if ( new_max > old_max ) + { + FT_UInt cur_max = old_max; + FT_Memory memory = border->memory; + + + while ( cur_max < new_max ) + cur_max += ( cur_max >> 1 ) + 16; + + if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || + FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) + goto Exit; + + border->max_points = cur_max; + } + Exit: + return error; + } + + + static void + ft_stroke_border_close( FT_StrokeBorder border, + FT_Bool reverse ) + { + FT_UInt start = border->start; + FT_UInt count = border->num_points; + + + FT_ASSERT( border->start >= 0 ); + + /* don't record empty paths! */ + if ( count <= start + 1U ) + border->num_points = start; + else + { + /* copy the last point to the start of this sub-path, since */ + /* it contains the `adjusted' starting coordinates */ + border->num_points = --count; + border->points[start] = border->points[count]; + + if ( reverse ) + { + /* reverse the points */ + { + FT_Vector* vec1 = border->points + start + 1; + FT_Vector* vec2 = border->points + count - 1; + + + for ( ; vec1 < vec2; vec1++, vec2-- ) + { + FT_Vector tmp; + + + tmp = *vec1; + *vec1 = *vec2; + *vec2 = tmp; + } + } + + /* then the tags */ + { + FT_Byte* tag1 = border->tags + start + 1; + FT_Byte* tag2 = border->tags + count - 1; + + + for ( ; tag1 < tag2; tag1++, tag2-- ) + { + FT_Byte tmp; + + + tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + } + + border->tags[start ] |= FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= FT_STROKE_TAG_END; + } + + border->start = -1; + border->movable = 0; + } + + + static FT_Error + ft_stroke_border_lineto( FT_StrokeBorder border, + FT_Vector* to, + FT_Bool movable ) + { + FT_Error error = 0; + + + FT_ASSERT( border->start >= 0 ); + + if ( border->movable ) + { + /* move last point */ + border->points[border->num_points - 1] = *to; + } + else + { + /* add one point */ + error = ft_stroke_border_grow( border, 1 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *to; + tag[0] = FT_STROKE_TAG_ON; + + border->num_points += 1; + } + } + border->movable = movable; + return error; + } + + + static FT_Error + ft_stroke_border_conicto( FT_StrokeBorder border, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 2 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + vec[0] = *control; + vec[1] = *to; + + tag[0] = 0; + tag[1] = FT_STROKE_TAG_ON; + + border->num_points += 2; + } + border->movable = 0; + return error; + } + + + static FT_Error + ft_stroke_border_cubicto( FT_StrokeBorder border, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 3 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + + tag[0] = FT_STROKE_TAG_CUBIC; + tag[1] = FT_STROKE_TAG_CUBIC; + tag[2] = FT_STROKE_TAG_ON; + + border->num_points += 3; + } + border->movable = 0; + return error; + } + + +#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 ) + + + static FT_Error + ft_stroke_border_arcto( FT_StrokeBorder border, + FT_Vector* center, + FT_Fixed radius, + FT_Angle angle_start, + FT_Angle angle_diff ) + { + FT_Angle total, angle, step, rotate, next, theta; + FT_Vector a, b, a2, b2; + FT_Fixed length; + FT_Error error = 0; + + + /* compute start point */ + FT_Vector_From_Polar( &a, radius, angle_start ); + a.x += center->x; + a.y += center->y; + + total = angle_diff; + angle = angle_start; + rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2; + + while ( total != 0 ) + { + step = total; + if ( step > FT_ARC_CUBIC_ANGLE ) + step = FT_ARC_CUBIC_ANGLE; + + else if ( step < -FT_ARC_CUBIC_ANGLE ) + step = -FT_ARC_CUBIC_ANGLE; + + next = angle + step; + theta = step; + if ( theta < 0 ) + theta = -theta; + + theta >>= 1; + + /* compute end point */ + FT_Vector_From_Polar( &b, radius, next ); + b.x += center->x; + b.y += center->y; + + /* compute first and second control points */ + length = FT_MulDiv( radius, FT_Sin( theta ) * 4, + ( 0x10000L + FT_Cos( theta ) ) * 3 ); + + FT_Vector_From_Polar( &a2, length, angle + rotate ); + a2.x += a.x; + a2.y += a.y; + + FT_Vector_From_Polar( &b2, length, next - rotate ); + b2.x += b.x; + b2.y += b.y; + + /* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); + if ( error ) + break; + + /* process the rest of the arc ?? */ + a = b; + total -= step; + angle = next; + } + + return error; + } + + + static FT_Error + ft_stroke_border_moveto( FT_StrokeBorder border, + FT_Vector* to ) + { + /* close current open path if any ? */ + if ( border->start >= 0 ) + ft_stroke_border_close( border, 0 ); + + border->start = border->num_points; + border->movable = 0; + + return ft_stroke_border_lineto( border, to, 0 ); + } + + + static void + ft_stroke_border_init( FT_StrokeBorder border, + FT_Memory memory ) + { + border->memory = memory; + border->points = NULL; + border->tags = NULL; + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = 0; + } + + + static void + ft_stroke_border_reset( FT_StrokeBorder border ) + { + border->num_points = 0; + border->start = -1; + border->valid = 0; + } + + + static void + ft_stroke_border_done( FT_StrokeBorder border ) + { + FT_Memory memory = border->memory; + + + FT_FREE( border->points ); + FT_FREE( border->tags ); + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = 0; + } + + + static FT_Error + ft_stroke_border_get_counts( FT_StrokeBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_Error error = 0; + FT_UInt num_points = 0; + FT_UInt num_contours = 0; + + FT_UInt count = border->num_points; + FT_Vector* point = border->points; + FT_Byte* tags = border->tags; + FT_Int in_contour = 0; + + + for ( ; count > 0; count--, num_points++, point++, tags++ ) + { + if ( tags[0] & FT_STROKE_TAG_BEGIN ) + { + if ( in_contour != 0 ) + goto Fail; + + in_contour = 1; + } + else if ( in_contour == 0 ) + goto Fail; + + if ( tags[0] & FT_STROKE_TAG_END ) + { + if ( in_contour == 0 ) + goto Fail; + + in_contour = 0; + num_contours++; + } + } + + if ( in_contour != 0 ) + goto Fail; + + border->valid = 1; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + + Fail: + num_points = 0; + num_contours = 0; + goto Exit; + } + + + static void + ft_stroke_border_export( FT_StrokeBorder border, + FT_Outline* outline ) + { + /* copy point locations */ + FT_ARRAY_COPY( outline->points + outline->n_points, + border->points, + border->num_points ); + + /* copy tags */ + { + FT_UInt count = border->num_points; + FT_Byte* read = border->tags; + FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; + + + for ( ; count > 0; count--, read++, write++ ) + { + if ( *read & FT_STROKE_TAG_ON ) + *write = FT_CURVE_TAG_ON; + else if ( *read & FT_STROKE_TAG_CUBIC ) + *write = FT_CURVE_TAG_CUBIC; + else + *write = FT_CURVE_TAG_CONIC; + } + } + + /* copy contours */ + { + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_Short* write = outline->contours + outline->n_contours; + FT_Short idx = (FT_Short)outline->n_points; + + + for ( ; count > 0; count--, tags++, idx++ ) + { + if ( *tags & FT_STROKE_TAG_END ) + { + *write++ = idx; + outline->n_contours++; + } + } + } + + outline->n_points = (short)( outline->n_points + border->num_points ); + + FT_ASSERT( FT_Outline_Check( outline ) == 0 ); + } + + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** STROKER *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + +#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI ) + + typedef struct FT_StrokerRec_ + { + FT_Angle angle_in; + FT_Angle angle_out; + FT_Vector center; + FT_Bool first_point; + FT_Bool subpath_open; + FT_Angle subpath_angle; + FT_Vector subpath_start; + + FT_Stroker_LineCap line_cap; + FT_Stroker_LineJoin line_join; + FT_Fixed miter_limit; + FT_Fixed radius; + + FT_Bool valid; + FT_StrokeBorderRec borders[2]; + FT_Memory memory; + + } FT_StrokerRec; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ) + { + FT_Error error; + FT_Memory memory; + FT_Stroker stroker; + + + if ( !library ) + return FT_Err_Invalid_Argument; + + memory = library->memory; + + if ( !FT_NEW( stroker ) ) + { + stroker->memory = memory; + + ft_stroke_border_init( &stroker->borders[0], memory ); + ft_stroke_border_init( &stroker->borders[1], memory ); + } + *astroker = stroker; + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ) + { + stroker->radius = radius; + stroker->line_cap = line_cap; + stroker->line_join = line_join; + stroker->miter_limit = miter_limit; + + FT_Stroker_Rewind( stroker ); + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Rewind( FT_Stroker stroker ) + { + if ( stroker ) + { + ft_stroke_border_reset( &stroker->borders[0] ); + ft_stroke_border_reset( &stroker->borders[1] ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Done( FT_Stroker stroker ) + { + if ( stroker ) + { + FT_Memory memory = stroker->memory; + + + ft_stroke_border_done( &stroker->borders[0] ); + ft_stroke_border_done( &stroker->borders[1] ); + + stroker->memory = NULL; + FT_FREE( stroker ); + } + } + + + /* creates a circular arc at a corner or cap */ + static FT_Error + ft_stroker_arcto( FT_Stroker stroker, + FT_Int side ) + { + FT_Angle total, rotate; + FT_Fixed radius = stroker->radius; + FT_Error error = 0; + FT_StrokeBorder border = stroker->borders + side; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( total == FT_ANGLE_PI ) + total = -rotate * 2; + + error = ft_stroke_border_arcto( border, + &stroker->center, + radius, + stroker->angle_in + rotate, + total ); + border->movable = 0; + return error; + } + + + /* adds a cap at the end of an opened path */ + static FT_Error + ft_stroker_cap( FT_Stroker stroker, + FT_Angle angle, + FT_Int side ) + { + FT_Error error = 0; + + + if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) + { + /* add a round cap */ + stroker->angle_in = angle; + stroker->angle_out = angle + FT_ANGLE_PI; + error = ft_stroker_arcto( stroker, side ); + } + else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + { + /* add a square cap */ + FT_Vector delta, delta2; + FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); + FT_Fixed radius = stroker->radius; + FT_StrokeBorder border = stroker->borders + side; + + + FT_Vector_From_Polar( &delta2, radius, angle + rotate ); + FT_Vector_From_Polar( &delta, radius, angle ); + + delta.x += stroker->center.x + delta2.x; + delta.y += stroker->center.y + delta2.y; + + error = ft_stroke_border_lineto( border, &delta, 0 ); + if ( error ) + goto Exit; + + FT_Vector_From_Polar( &delta2, radius, angle - rotate ); + FT_Vector_From_Polar( &delta, radius, angle ); + + delta.x += delta2.x + stroker->center.x; + delta.y += delta2.y + stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, 0 ); + } + + Exit: + return error; + } + + + /* process an inside corner, i.e. compute intersection */ + static FT_Error + ft_stroker_inside( FT_Stroker stroker, + FT_Int side) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Angle phi, theta, rotate; + FT_Fixed length, thcos, sigma; + FT_Vector delta; + FT_Error error = 0; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute median angle */ + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( theta == FT_ANGLE_PI ) + theta = rotate; + else + theta = theta / 2; + + phi = stroker->angle_in + theta; + + thcos = FT_Cos( theta ); + sigma = FT_MulFix( stroker->miter_limit, thcos ); + + /* TODO: find better criterion to switch off the optimization */ + if ( sigma < 0x10000L ) + { + FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + border->movable = 0; + } + else + { + length = FT_DivFix( stroker->radius, thcos ); + + FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + } + + error = ft_stroke_border_lineto( border, &delta, 0 ); + + return error; + } + + + /* process an outside corner, i.e. compute bevel/miter/round */ + static FT_Error + ft_stroker_outside( FT_Stroker stroker, + FT_Int side ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Error error; + FT_Angle rotate; + + + if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) + { + error = ft_stroker_arcto( stroker, side ); + } + else + { + /* this is a mitered or beveled corner */ + FT_Fixed sigma, radius = stroker->radius; + FT_Angle theta, phi; + FT_Fixed thcos; + FT_Bool miter; + + + rotate = FT_SIDE_TO_ROTATE( side ); + miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER ); + + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( theta == FT_ANGLE_PI ) + { + theta = rotate; + phi = stroker->angle_in; + } + else + { + theta = theta / 2; + phi = stroker->angle_in + theta + rotate; + } + + thcos = FT_Cos( theta ); + sigma = FT_MulFix( stroker->miter_limit, thcos ); + + if ( sigma >= 0x10000L ) + miter = 0; + + if ( miter ) /* this is a miter (broken angle) */ + { + FT_Vector middle, delta; + FT_Fixed length; + + + /* compute middle point */ + FT_Vector_From_Polar( &middle, + FT_MulFix( radius, stroker->miter_limit ), + phi ); + middle.x += stroker->center.x; + middle.y += stroker->center.y; + + /* compute first angle point */ + length = FT_MulFix( radius, + FT_DivFix( 0x10000L - sigma, + ft_pos_abs( FT_Sin( theta ) ) ) ); + + FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, 0 ); + if ( error ) + goto Exit; + + /* compute second angle point */ + FT_Vector_From_Polar( &delta, length, phi - rotate ); + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, 0 ); + if ( error ) + goto Exit; + + /* finally, add a movable end point */ + FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, 1 ); + } + + else /* this is a bevel (intersection) */ + { + FT_Fixed length; + FT_Vector delta; + + + length = FT_DivFix( stroker->radius, thcos ); + + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, 0 ); + if (error) goto Exit; + + /* now add end point */ + FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, 1 ); + } + } + + Exit: + return error; + } + + + static FT_Error + ft_stroker_process_corner( FT_Stroker stroker ) + { + FT_Error error = 0; + FT_Angle turn; + FT_Int inside_side; + + + turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn == 0 ) + goto Exit; + + /* when we turn to the right, the inside side is 0 */ + inside_side = 0; + + /* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; + + /* process the inside side */ + error = ft_stroker_inside( stroker, inside_side ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, 1 - inside_side ); + + Exit: + return error; + } + + + /* add two points to the left and right borders corresponding to the */ + /* start of the subpath.. */ + static FT_Error + ft_stroker_subpath_start( FT_Stroker stroker, + FT_Angle start_angle ) + { + FT_Vector delta; + FT_Vector point; + FT_Error error; + FT_StrokeBorder border; + + + FT_Vector_From_Polar( &delta, stroker->radius, + start_angle + FT_ANGLE_PI2 ); + + point.x = stroker->center.x + delta.x; + point.y = stroker->center.y + delta.y; + + border = stroker->borders; + error = ft_stroke_border_moveto( border, &point ); + if ( error ) + goto Exit; + + point.x = stroker->center.x - delta.x; + point.y = stroker->center.y - delta.y; + + border++; + error = ft_stroke_border_moveto( border, &point ); + + /* save angle for last cap */ + stroker->subpath_angle = start_angle; + stroker->first_point = 0; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ) + { + FT_Error error = 0; + FT_StrokeBorder border; + FT_Vector delta; + FT_Angle angle; + FT_Int side; + + delta.x = to->x - stroker->center.x; + delta.y = to->y - stroker->center.y; + + angle = FT_Atan2( delta.x, delta.y ); + FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); + + /* process corner if necessary */ + if ( stroker->first_point ) + { + /* This is the first segment of a subpath. We need to */ + /* add a point to each border at their respective starting */ + /* point locations. */ + error = ft_stroker_subpath_start( stroker, angle ); + if ( error ) + goto Exit; + } + else + { + /* process the current corner */ + stroker->angle_out = angle; + error = ft_stroker_process_corner( stroker ); + if ( error ) + goto Exit; + } + + /* now add a line segment to both the "inside" and "outside" paths */ + + for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) + { + FT_Vector point; + + + point.x = to->x + delta.x; + point.y = to->y + delta.y; + + error = ft_stroke_border_lineto( border, &point, 1 ); + if ( error ) + goto Exit; + + delta.x = -delta.x; + delta.y = -delta.y; + } + + stroker->angle_in = angle; + stroker->center = *to; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error = 0; + FT_Vector bez_stack[34]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 30; + FT_Angle start_angle; + FT_Bool first_arc = 1; + + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control; + arc[2] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_out; + + + angle_in = angle_out = 0; /* remove compiler warnings */ + + if ( arc < limit && + !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) + { + ft_conic_split( arc ); + arc += 2; + continue; + } + + if ( first_arc ) + { + first_arc = 0; + + start_angle = angle_in; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, start_angle ); + else + { + stroker->angle_out = start_angle; + error = ft_stroker_process_corner( stroker ); + } + } + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl, end; + FT_Angle theta, phi, rotate; + FT_Fixed length; + FT_Int side; + + + theta = FT_Angle_Diff( angle_in, angle_out ) / 2; + phi = angle_in + theta; + length = FT_DivFix( stroker->radius, FT_Cos( theta ) ); + + for ( side = 0; side <= 1; side++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control point */ + FT_Vector_From_Polar( &ctrl, length, phi + rotate ); + ctrl.x += arc[1].x; + ctrl.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + error = ft_stroke_border_conicto( stroker->borders + side, + &ctrl, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 2; + + if ( arc < bez_stack ) + stroker->angle_in = angle_out; + } + + stroker->center = *to; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error = 0; + FT_Vector bez_stack[37]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 32; + FT_Angle start_angle; + FT_Bool first_arc = 1; + + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control2; + arc[2] = *control1; + arc[3] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_mid, angle_out; + + + /* remove compiler warnings */ + angle_in = angle_out = angle_mid = 0; + + if ( arc < limit && + !ft_cubic_is_small_enough( arc, &angle_in, + &angle_mid, &angle_out ) ) + { + ft_cubic_split( arc ); + arc += 3; + continue; + } + + if ( first_arc ) + { + first_arc = 0; + + /* process corner if necessary */ + start_angle = angle_in; + + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, start_angle ); + else + { + stroker->angle_out = start_angle; + error = ft_stroker_process_corner( stroker ); + } + if ( error ) + goto Exit; + } + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl1, ctrl2, end; + FT_Angle theta1, phi1, theta2, phi2, rotate; + FT_Fixed length1, length2; + FT_Int side; + + + theta1 = ft_pos_abs( angle_mid - angle_in ) / 2; + theta2 = ft_pos_abs( angle_out - angle_mid ) / 2; + phi1 = (angle_mid + angle_in ) / 2; + phi2 = (angle_mid + angle_out ) / 2; + length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) ); + length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) ); + + for ( side = 0; side <= 1; side++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control points */ + FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); + ctrl1.x += arc[2].x; + ctrl1.y += arc[2].y; + + FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); + ctrl2.x += arc[1].x; + ctrl2.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + error = ft_stroke_border_cubicto( stroker->borders + side, + &ctrl1, &ctrl2, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 3; + if ( arc < bez_stack ) + stroker->angle_in = angle_out; + } + + stroker->center = *to; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ) + { + /* We cannot process the first point, because there is not enough */ + /* information regarding its corner/cap. The latter will be processed */ + /* in the "end_subpath" routine. */ + /* */ + stroker->first_point = 1; + stroker->center = *to; + stroker->subpath_open = open; + + /* record the subpath start point index for each border */ + stroker->subpath_start = *to; + return 0; + } + + + static FT_Error + ft_stroker_add_reverse_left( FT_Stroker stroker, + FT_Bool open ) + { + FT_StrokeBorder right = stroker->borders + 0; + FT_StrokeBorder left = stroker->borders + 1; + FT_Int new_points; + FT_Error error = 0; + + + FT_ASSERT( left->start >= 0 ); + + new_points = left->num_points - left->start; + if ( new_points > 0 ) + { + error = ft_stroke_border_grow( right, (FT_UInt)new_points ); + if ( error ) + goto Exit; + + { + FT_Vector* dst_point = right->points + right->num_points; + FT_Byte* dst_tag = right->tags + right->num_points; + FT_Vector* src_point = left->points + left->num_points - 1; + FT_Byte* src_tag = left->tags + left->num_points - 1; + + while ( src_point >= left->points + left->start ) + { + *dst_point = *src_point; + *dst_tag = *src_tag; + + if ( open ) + dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END; + else + { + FT_Byte ttag = (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END ); + + + /* switch begin/end tags if necessary */ + if ( ttag == FT_STROKE_TAG_BEGIN || + ttag == FT_STROKE_TAG_END ) + dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END; + + } + + src_point--; + src_tag--; + dst_point++; + dst_tag++; + } + } + + left->num_points = left->start; + right->num_points += new_points; + + right->movable = 0; + left->movable = 0; + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + /* there's a lot of magic in this function! */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ) + { + FT_Error error = 0; + + if ( stroker->subpath_open ) + { + FT_StrokeBorder right = stroker->borders; + + /* All right, this is an opened path, we need to add a cap between */ + /* right & left, add the reverse of left, then add a final cap */ + /* between left & right. */ + error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); + if ( error ) + goto Exit; + + /* add reversed points from "left" to "right" */ + error = ft_stroker_add_reverse_left( stroker, 1 ); + if ( error ) + goto Exit; + + /* now add the final cap */ + stroker->center = stroker->subpath_start; + error = ft_stroker_cap( stroker, + stroker->subpath_angle + FT_ANGLE_PI, 0 ); + if ( error ) + goto Exit; + + /* Now end the right subpath accordingly. The left one is */ + /* rewind and doesn't need further processing. */ + ft_stroke_border_close( right, 0 ); + } + else + { + FT_Angle turn; + FT_Int inside_side; + + /* close the path if needed */ + if ( stroker->center.x != stroker->subpath_start.x || + stroker->center.y != stroker->subpath_start.y ) + { + error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); + if ( error ) + goto Exit; + } + + /* process the corner */ + stroker->angle_out = stroker->subpath_angle; + turn = FT_Angle_Diff( stroker->angle_in, + stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn != 0 ) + { + /* when we turn to the right, the inside side is 0 */ + inside_side = 0; + + /* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; + + error = ft_stroker_inside( stroker, inside_side ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, 1 - inside_side ); + if ( error ) + goto Exit; + } + + /* then end our two subpaths */ + ft_stroke_border_close( stroker->borders + 0, 1 ); + ft_stroke_border_close( stroker->borders + 1, 0 ); + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt num_points = 0, num_contours = 0; + FT_Error error; + + + if ( !stroker || border > 1 ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt count1, count2, num_points = 0; + FT_UInt count3, count4, num_contours = 0; + FT_Error error; + + + error = ft_stroke_border_get_counts( stroker->borders + 0, + &count1, &count2 ); + if ( error ) + goto Exit; + + error = ft_stroke_border_get_counts( stroker->borders + 1, + &count3, &count4 ); + if ( error ) + goto Exit; + + num_points = count1 + count3; + num_contours = count2 + count4; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ) + { + if ( border == FT_STROKER_BORDER_LEFT || + border == FT_STROKER_BORDER_RIGHT ) + { + FT_StrokeBorder sborder = & stroker->borders[border]; + + + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ) + { + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); + } + + + /* documentation is in ftstroke.h */ + + /* + * The following is very similar to FT_Outline_Decompose, except + * that we do support opened paths, and do not scale the outline. + */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_UInt first; /* index of first point in contour */ + FT_Int tag; /* current point's state */ + + + if ( !outline || !stroker ) + return FT_Err_Invalid_Argument; + + FT_Stroker_Rewind( stroker ); + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_UInt last; /* index of last point in contour */ + + + last = outline->contours[n]; + limit = outline->points + last; + + /* skip empty points; we don't stroke these */ + if ( last <= first ) + { + first = last + 1; + continue; + } + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* First point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = FT_Stroker_BeginSubPath( stroker, &v_start, opened ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = point->x; + vec.y = point->y; + + error = FT_Stroker_LineTo( stroker, &vec ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = point->x; + v_control.y = point->y; + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec = point[0]; + + if ( tag == FT_CURVE_TAG_ON ) + { + error = FT_Stroker_ConicTo( stroker, &v_control, &vec ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_start ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1 = point[-2]; + vec2 = point[-1]; + + if ( point <= limit ) + { + FT_Vector vec; + + + vec = point[0]; + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); + if ( error ) + goto Exit; + continue; + } + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); + goto Close; + } + } + } + + Close: + if ( error ) + goto Exit; + + error = FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return FT_Err_Invalid_Outline; + } + + + extern const FT_Glyph_Class ft_outline_glyph_class; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ) + { + FT_Error error = FT_Err_Invalid_Argument; + FT_Glyph glyph = NULL; + + + if ( pglyph == NULL ) + goto Exit; + + glyph = *pglyph; + if ( glyph == NULL || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + error = FT_Stroker_ParseOutline( stroker, outline, 0 ); + if ( error ) + goto Fail; + + (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, num_contours, outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_Export( stroker, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ) + { + FT_Error error = FT_Err_Invalid_Argument; + FT_Glyph glyph = NULL; + + + if ( pglyph == NULL ) + goto Exit; + + glyph = *pglyph; + if ( glyph == NULL || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph; + FT_StrokerBorder border; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + border = FT_Outline_GetOutsideBorder( outline ); + if ( inside ) + { + if ( border == FT_STROKER_BORDER_LEFT ) + border = FT_STROKER_BORDER_RIGHT; + else + border = FT_STROKER_BORDER_LEFT; + } + + error = FT_Stroker_ParseOutline( stroker, outline, 0 ); + if ( error ) + goto Fail; + + (void)FT_Stroker_GetBorderCounts( stroker, border, + &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, + num_contours, + outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_ExportBorder( stroker, border, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftsynth.c b/src/freetype2/base/ftsynth.c new file mode 100644 index 0000000..ff88ce9 --- /dev/null +++ b/src/freetype2/base/ftsynth.c @@ -0,0 +1,159 @@ +/***************************************************************************/ +/* */ +/* ftsynth.c */ +/* */ +/* FreeType synthesizing code for emboldening and slanting (body). */ +/* */ +/* Copyright 2000-2001, 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 +#include FT_SYNTHESIS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_OUTLINE_H +#include FT_BITMAP_H + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL OBLIQUING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ) + { + FT_Matrix transform; + FT_Outline* outline = &slot->outline; + + + /* only oblique outline glyphs */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return; + + /* we don't touch the advance width */ + + /* For italic, simply apply a shear transform, with an angle */ + /* of about 12 degrees. */ + + transform.xx = 0x10000L; + transform.yx = 0x00000L; + + transform.xy = 0x06000L; + transform.yy = 0x10000L; + + FT_Outline_Transform( outline, &transform ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + 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 ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ) + { + FT_Library library = slot->library; + FT_Face face = FT_SLOT_FACE( slot ); + FT_Error error; + FT_Pos xstr, ystr; + + + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && + slot->format != FT_GLYPH_FORMAT_BITMAP ) + return; + + /* some reasonable strength */ + xstr = FT_MulFix( face->units_per_EM, + face->size->metrics.y_scale ) / 24; + ystr = xstr; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + error = FT_Outline_Embolden( &slot->outline, xstr ); + /* ignore error */ + + /* this is more than enough for most glyphs; if you need accurate */ + /* values, you have to call FT_Outline_Get_CBox */ + xstr = xstr * 2; + ystr = xstr; + } + else if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + { + xstr = FT_PIX_FLOOR( xstr ); + if ( xstr == 0 ) + xstr = 1 << 6; + ystr = FT_PIX_FLOOR( ystr ); + + error = FT_GlyphSlot_Own_Bitmap( slot ); + if ( error ) + return; + + error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + if ( error ) + return; + } + + if ( slot->advance.x ) + slot->advance.x += xstr; + + if ( slot->advance.y ) + slot->advance.y += ystr; + + slot->metrics.width += xstr; + slot->metrics.height += ystr; + slot->metrics.horiBearingY += ystr; + slot->metrics.horiAdvance += xstr; + slot->metrics.vertBearingX -= xstr / 2; + slot->metrics.vertBearingY += ystr; + slot->metrics.vertAdvance += ystr; + + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + slot->bitmap_top += ystr >> 6; + } + + +/* END */ diff --git a/src/freetype2/base/ftsystem.c b/src/freetype2/base/ftsystem.c new file mode 100644 index 0000000..f61a3ed --- /dev/null +++ b/src/freetype2/base/ftsystem.c @@ -0,0 +1,301 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* ANSI-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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 file contains the default interface used by FreeType to access */ + /* low-level, i.e. memory management, i/o access as well as thread */ + /* synchronisation. It can be replaced by user-specific routines if */ + /* necessary. */ + /* */ + /*************************************************************************/ + + +#include +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_SYSTEM_H +#include FT_ERRORS_H +#include FT_TYPES_H + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* It is not necessary to do any error checking for the */ + /* allocation-related functions. This will be done by the higher level */ + /* routines like ft_mem_alloc() or ft_mem_realloc(). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_alloc */ + /* */ + /* */ + /* The memory allocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* size :: The requested size in bytes. */ + /* */ + /* */ + /* The address of newly allocated block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return ft_smalloc( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_realloc */ + /* */ + /* */ + /* The memory reallocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* */ + /* The address of the reallocated memory block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return ft_srealloc( block, new_size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_free */ + /* */ + /* */ + /* The memory release function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + ft_sfree( block ); + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* 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_io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* */ + /* ft_ansi_stream_close */ + /* */ + /* */ + /* The function to close a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_ansi_stream_close( FT_Stream stream ) + { + ft_fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_ansi_stream_io */ + /* */ + /* */ + /* The function to open a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + /* offset :: The position in the data stream to start reading. */ + /* */ + /* buffer :: The address of buffer to store the read data. */ + /* */ + /* count :: The number of bytes to read from the stream. */ + /* */ + /* */ + /* The number of bytes actually read. */ + /* */ + FT_CALLBACK_DEF( unsigned long ) + ft_ansi_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_FILE* file; + + + file = STREAM_FILE( stream ); + + ft_fseek( file, offset, SEEK_SET ); + + return (unsigned long)ft_fread( buffer, 1, count, file ); + } + + + /* documentation is in ftstream.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + FT_FILE* file; + + + if ( !stream ) + return FT_Err_Invalid_Stream_Handle; + + file = ft_fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_Err_Cannot_Open_Resource; + } + + ft_fseek( file, 0, SEEK_END ); + stream->size = ft_ftell( file ); + ft_fseek( file, 0, SEEK_SET ); + + stream->descriptor.pointer = file; + stream->pathname.pointer = (char*)filepathname; + stream->pos = 0; + + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = 0; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + memory->free( memory, memory ); + } + + +/* END */ diff --git a/src/freetype2/base/fttrigon.c b/src/freetype2/base/fttrigon.c new file mode 100644 index 0000000..9f51394 --- /dev/null +++ b/src/freetype2/base/fttrigon.c @@ -0,0 +1,546 @@ +/***************************************************************************/ +/* */ +/* fttrigon.c */ +/* */ +/* FreeType trigonometric functions (body). */ +/* */ +/* Copyright 2001, 2002, 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 +#include FT_INTERNAL_OBJECTS_H +#include FT_TRIGONOMETRY_H + + + /* the following is 0.2715717684432231 * 2^30 */ +#define FT_TRIG_COSCALE 0x11616E8EUL + + /* this table was generated for FT_PI = 180L << 16, i.e. degrees */ +#define FT_TRIG_MAX_ITERS 23 + + static const FT_Fixed + ft_trig_arctan_table[24] = + { + 4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L, + 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L + }; + + /* the Cordic shrink factor, multiplied by 2^32 */ +#define FT_TRIG_SCALE 1166391785UL /* 0x4585BA38UL */ + + +#ifdef FT_CONFIG_HAS_INT64 + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Fixed s; + FT_Int64 v; + + + s = val; + val = ( val >= 0 ) ? val : -val; + + v = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL; + val = (FT_Fixed)( v >> 32 ); + + return ( s >= 0 ) ? val : -val; + } + +#else /* !FT_CONFIG_HAS_INT64 */ + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Fixed s; + FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3; + + + s = val; + val = ( val >= 0 ) ? val : -val; + + v1 = (FT_UInt32)val >> 16; + v2 = (FT_UInt32)val & 0xFFFFL; + + k1 = FT_TRIG_SCALE >> 16; /* constant */ + k2 = FT_TRIG_SCALE & 0xFFFFL; /* constant */ + + hi = k1 * v1; + lo1 = k1 * v2 + k2 * v1; /* can't overflow */ + + lo2 = ( k2 * v2 ) >> 16; + lo3 = ( lo1 >= lo2 ) ? lo1 : lo2; + lo1 += lo2; + + hi += lo1 >> 16; + if ( lo1 < lo3 ) + hi += 0x10000UL; + + val = (FT_Fixed)hi; + + return ( s >= 0 ) ? val : -val; + } + +#endif /* !FT_CONFIG_HAS_INT64 */ + + + static FT_Int + ft_trig_prenorm( FT_Vector* vec ) + { + FT_Fixed x, y, z; + FT_Int shift; + + + x = vec->x; + y = vec->y; + + z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y ); + shift = 0; + +#if 1 + /* determine msb bit index in `shift' */ + if ( z >= ( 1L << 16 ) ) + { + z >>= 16; + shift += 16; + } + if ( z >= ( 1L << 8 ) ) + { + z >>= 8; + shift += 8; + } + if ( z >= ( 1L << 4 ) ) + { + z >>= 4; + shift += 4; + } + if ( z >= ( 1L << 2 ) ) + { + z >>= 2; + shift += 2; + } + if ( z >= ( 1L << 1 ) ) + { + z >>= 1; + shift += 1; + } + + if ( shift <= 27 ) + { + shift = 27 - shift; + vec->x = x << shift; + vec->y = y << shift; + } + else + { + shift -= 27; + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } + +#else /* 0 */ + + if ( z < ( 1L << 27 ) ) + { + do + { + shift++; + z <<= 1; + } while ( z < ( 1L << 27 ) ); + vec->x = x << shift; + vec->y = y << shift; + } + else if ( z > ( 1L << 28 ) ) + { + do + { + shift++; + z >>= 1; + } while ( z > ( 1L << 28 ) ); + + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } + +#endif /* 0 */ + + return shift; + } + + + static void + ft_trig_pseudo_rotate( FT_Vector* vec, + FT_Angle theta ) + { + FT_Int i; + FT_Fixed x, y, xtemp; + const FT_Fixed *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Get angle between -90 and 90 degrees */ + while ( theta <= -FT_ANGLE_PI2 ) + { + x = -x; + y = -y; + theta += FT_ANGLE_PI; + } + + while ( theta > FT_ANGLE_PI2 ) + { + x = -x; + y = -y; + theta -= FT_ANGLE_PI; + } + + /* Initial pseudorotation, with left shift */ + arctanptr = ft_trig_arctan_table; + + if ( theta < 0 ) + { + xtemp = x + ( y << 1 ); + y = y - ( x << 1 ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( y << 1 ); + y = y + ( x << 1 ); + x = xtemp; + theta -= *arctanptr++; + } + + /* Subsequent pseudorotations, with right shifts */ + i = 0; + do + { + if ( theta < 0 ) + { + xtemp = x + ( y >> i ); + y = y - ( x >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( y >> i ); + y = y + ( x >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } while ( ++i < FT_TRIG_MAX_ITERS ); + + vec->x = x; + vec->y = y; + } + + + static void + ft_trig_pseudo_polarize( FT_Vector* vec ) + { + FT_Fixed theta; + FT_Fixed yi, i; + FT_Fixed x, y; + const FT_Fixed *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Get the vector into the right half plane */ + theta = 0; + if ( x < 0 ) + { + x = -x; + y = -y; + theta = 2 * FT_ANGLE_PI2; + } + + if ( y > 0 ) + theta = - theta; + + arctanptr = ft_trig_arctan_table; + + if ( y < 0 ) + { + /* Rotate positive */ + yi = y + ( x << 1 ); + x = x - ( y << 1 ); + y = yi; + theta -= *arctanptr++; /* Subtract angle */ + } + else + { + /* Rotate negative */ + yi = y - ( x << 1 ); + x = x + ( y << 1 ); + y = yi; + theta += *arctanptr++; /* Add angle */ + } + + i = 0; + do + { + if ( y < 0 ) + { + /* Rotate positive */ + yi = y + ( x >> i ); + x = x - ( y >> i ); + y = yi; + theta -= *arctanptr++; + } + else + { + /* Rotate negative */ + yi = y - ( x >> i ); + x = x + ( y >> i ); + y = yi; + theta += *arctanptr++; + } + } while ( ++i < FT_TRIG_MAX_ITERS ); + + /* round theta */ + if ( theta >= 0 ) + theta = FT_PAD_ROUND( theta, 32 ); + else + theta = -FT_PAD_ROUND( -theta, 32 ); + + vec->x = x; + vec->y = theta; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Cos( FT_Angle angle ) + { + FT_Vector v; + + + v.x = FT_TRIG_COSCALE >> 2; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + + return v.x / ( 1 << 12 ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Sin( FT_Angle angle ) + { + return FT_Cos( FT_ANGLE_PI2 - angle ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Tan( FT_Angle angle ) + { + FT_Vector v; + + + v.x = FT_TRIG_COSCALE >> 2; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + + return FT_DivFix( v.y, v.x ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Atan2( FT_Fixed dx, + FT_Fixed dy ) + { + FT_Vector v; + + + if ( dx == 0 && dy == 0 ) + return 0; + + v.x = dx; + v.y = dy; + ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ) + { + vec->x = FT_TRIG_COSCALE >> 2; + vec->y = 0; + ft_trig_pseudo_rotate( vec, angle ); + vec->x >>= 12; + vec->y >>= 12; + } + + + /* these macros return 0 for positive numbers, + and -1 for negative ones */ +#define FT_SIGN_LONG( x ) ( (x) >> ( FT_SIZEOF_LONG * 8 - 1 ) ) +#define FT_SIGN_INT( x ) ( (x) >> ( FT_SIZEOF_INT * 8 - 1 ) ) +#define FT_SIGN_INT32( x ) ( (x) >> 31 ) +#define FT_SIGN_INT16( x ) ( (x) >> 15 ) + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ) + { + FT_Int shift; + FT_Vector v; + + + v.x = vec->x; + v.y = vec->y; + + if ( angle && ( v.x != 0 || v.y != 0 ) ) + { + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); + + if ( shift > 0 ) + { + FT_Int32 half = 1L << ( shift - 1 ); + + + vec->x = ( v.x + half + FT_SIGN_LONG( v.x ) ) >> shift; + vec->y = ( v.y + half + FT_SIGN_LONG( v.y ) ) >> shift; + } + else + { + shift = -shift; + vec->x = v.x << shift; + vec->y = v.y << shift; + } + } + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ) + { + FT_Int shift; + FT_Vector v; + + + v = *vec; + + /* handle trivial cases */ + if ( v.x == 0 ) + { + return ( v.y >= 0 ) ? v.y : -v.y; + } + else if ( v.y == 0 ) + { + return ( v.x >= 0 ) ? v.x : -v.x; + } + + /* general case */ + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + if ( shift > 0 ) + return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift; + + return v.x << -shift; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ) + { + FT_Int shift; + FT_Vector v; + + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift ); + *angle = v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ) + { + vec->x = length; + vec->y = 0; + + FT_Vector_Rotate( vec, angle ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ) + { + FT_Angle delta = angle2 - angle1; + + + delta %= FT_ANGLE_2PI; + if ( delta < 0 ) + delta += FT_ANGLE_2PI; + + if ( delta > FT_ANGLE_PI ) + delta -= FT_ANGLE_2PI; + + return delta; + } + + +/* END */ diff --git a/src/freetype2/base/fttype1.c b/src/freetype2/base/fttype1.c new file mode 100644 index 0000000..3975584 --- /dev/null +++ b/src/freetype2/base/fttype1.c @@ -0,0 +1,94 @@ +/***************************************************************************/ +/* */ +/* fttype1.c */ +/* */ +/* FreeType utility file for PS names support (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 +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_SERVICE_H +#include FT_SERVICE_POSTSCRIPT_INFO_H + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + if ( face ) + { + FT_Service_PsInfo service = NULL; + + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_info ) + error = service->ps_get_font_info( face, afont_info ); + } + + return error; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ) + { + FT_Int result = 0; + FT_Service_PsInfo service = NULL; + + + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_has_glyph_names ) + result = service->ps_has_glyph_names( face ); + } + + return result; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec* afont_private ) + { + FT_Error error = FT_Err_Invalid_Argument; + + + if ( face ) + { + FT_Service_PsInfo service = NULL; + + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_private ) + error = service->ps_get_font_private( face, afont_private ); + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftutil.c b/src/freetype2/base/ftutil.c new file mode 100644 index 0000000..5f77be5 --- /dev/null +++ b/src/freetype2/base/ftutil.c @@ -0,0 +1,501 @@ +/***************************************************************************/ +/* */ +/* ftutil.c */ +/* */ +/* FreeType utility file for memory and list management (body). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_OBJECTS_H +#include FT_LIST_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_memory + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** M E M O R Y M A N A G E M E N T *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer block = ft_mem_qalloc( memory, size, &error ); + + if ( !error && size > 0 ) + FT_MEM_ZERO( block, size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + FT_Pointer block = NULL; + + + if ( size > 0 ) + { + block = memory->alloc( memory, size ); + if ( block == NULL ) + error = FT_Err_Out_Of_Memory; + } + else if ( size < 0 ) + { + /* may help catch/prevent security issues */ + error = FT_Err_Invalid_Argument; + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + block = ft_mem_qrealloc( memory, item_size, + cur_count, new_count, block, &error ); + if ( !error && new_count > cur_count ) + FT_MEM_ZERO( (char*)block + cur_count * item_size, + ( new_count - cur_count ) * item_size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + + /* Note that we now accept `item_size == 0' as a valid parameter, in + * order to cover very weird cases where an ALLOC_MULT macro would be + * called. + */ + if ( cur_count < 0 || new_count < 0 || item_size < 0 ) + { + /* may help catch/prevent nasty security issues */ + error = FT_Err_Invalid_Argument; + } + else if ( new_count == 0 || item_size == 0 ) + { + ft_mem_free( memory, block ); + block = NULL; + } + else if ( new_count > FT_INT_MAX/item_size ) + { + error = FT_Err_Array_Too_Large; + } + else if ( cur_count == 0 ) + { + FT_ASSERT( block == NULL ); + + block = ft_mem_alloc( memory, new_count*item_size, &error ); + } + else + { + FT_Pointer block2; + FT_Long cur_size = cur_count*item_size; + FT_Long new_size = new_count*item_size; + + + block2 = memory->realloc( memory, cur_size, new_size, block ); + if ( block2 == NULL ) + error = FT_Err_Out_Of_Memory; + else + block = block2; + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( void ) + ft_mem_free( FT_Memory memory, + const void *P ) + { + if ( P ) + memory->free( memory, (void*)P ); + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer p = ft_mem_qalloc( memory, size, &error ); + + + if ( !error && address ) + ft_memcpy( p, address, size ); + + *p_error = error; + return p; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ) + { + FT_ULong len = str ? (FT_ULong)ft_strlen( str ) + 1 + : 0; + + + return ft_mem_dup( memory, str, len, p_error ); + } + + + FT_BASE_DEF( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ) + { + while ( size > 1 && *src != 0 ) + { + *dst++ = *src++; + size--; + } + + *dst = 0; /* always zero-terminate */ + + return *src != 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** D O U B L Y L I N K E D L I S T S *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#undef FT_COMPONENT +#define FT_COMPONENT trace_list + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ) + { + FT_ListNode cur; + + + cur = list->head; + while ( cur ) + { + if ( cur->data == data ) + return cur; + + cur = cur->next; + } + + return (FT_ListNode)0; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Add( FT_List list, + FT_ListNode node ) + { + FT_ListNode before = list->tail; + + + node->next = 0; + node->prev = before; + + if ( before ) + before->next = node; + else + list->head = node; + + list->tail = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ) + { + FT_ListNode after = list->head; + + + node->next = after; + node->prev = 0; + + if ( !after ) + list->tail = node; + else + after->prev = node; + + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + before = node->prev; + after = node->next; + + if ( before ) + before->next = after; + else + list->head = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Up( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + before = node->prev; + after = node->next; + + /* check whether we are already on top of the list */ + if ( !before ) + return; + + before->next = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + + node->prev = 0; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ) + { + FT_ListNode cur = list->head; + FT_Error error = FT_Err_Ok; + + + while ( cur ) + { + FT_ListNode next = cur->next; + + + error = iterator( cur, user ); + if ( error ) + break; + + cur = next; + } + + return error; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ) + { + FT_ListNode cur; + + + cur = list->head; + while ( cur ) + { + FT_ListNode next = cur->next; + void* data = cur->data; + + + if ( destroy ) + destroy( memory, data, user ); + + FT_FREE( cur ); + cur = next; + } + + list->head = 0; + list->tail = 0; + } + + + FT_BASE_DEF( FT_UInt32 ) + ft_highpow2( FT_UInt32 value ) + { + FT_UInt32 value2; + + + /* + * We simply clear the lowest bit in each iteration. When + * we reach 0, we know that the previous value was our result. + */ + for ( ;; ) + { + value2 = value & (value - 1); /* clear lowest bit */ + if ( value2 == 0 ) + break; + + value = value2; + } + return value; + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE_DEF( FT_Error ) + FT_Alloc( FT_Memory memory, + FT_Long size, + void* *P ) + { + FT_Error error; + + + (void)FT_ALLOC( *P, size ); + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_QAlloc( FT_Memory memory, + FT_Long size, + void* *p ) + { + FT_Error error; + + + (void)FT_QALLOC( *p, size ); + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Realloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *P ) + { + FT_Error error; + + + (void)FT_REALLOC( *P, current, size ); + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_QRealloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *p ) + { + FT_Error error; + + + (void)FT_QREALLOC( *p, current, size ); + return error; + } + + + FT_BASE_DEF( void ) + FT_Free( FT_Memory memory, + void* *P ) + { + if ( *P ) + FT_MEM_FREE( *P ); + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + +/* END */ diff --git a/src/freetype2/base/ftwinfnt.c b/src/freetype2/base/ftwinfnt.c new file mode 100644 index 0000000..bc2e90e --- /dev/null +++ b/src/freetype2/base/ftwinfnt.c @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* ftwinfnt.c */ +/* */ +/* FreeType API for accessing Windows FNT specific info (body). */ +/* */ +/* Copyright 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 +#include FT_WINFONTS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_WINFNT_H + + + /* documentation is in ftwinfnt.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *header ) + { + FT_Service_WinFnt service; + FT_Error error; + + + error = FT_Err_Invalid_Argument; + + if ( face != NULL ) + { + FT_FACE_LOOKUP_SERVICE( face, service, WINFNT ); + + if ( service != NULL ) + { + error = service->get_header( face, header ); + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/base/ftxf86.c b/src/freetype2/base/ftxf86.c new file mode 100644 index 0000000..a4bf767 --- /dev/null +++ b/src/freetype2/base/ftxf86.c @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* ftxf86.c */ +/* */ +/* FreeType utility file for X11 support (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 +#include FT_XFREE86_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_XFREE86_NAME_H + + + /* documentation is in ftxf86.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_X11_Font_Format( FT_Face face ) + { + const char* result = NULL; + + + if ( face ) + FT_FACE_FIND_SERVICE( face, result, XF86_NAME ); + + return result; + } + + +/* END */ diff --git a/src/freetype2/bdf/bdf.c b/src/freetype2/bdf/bdf.c new file mode 100644 index 0000000..f95fb76 --- /dev/null +++ b/src/freetype2/bdf/bdf.c @@ -0,0 +1,34 @@ +/* bdf.c + + FreeType font driver for bdf files + + Copyright (C) 2001, 2002 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include +#include "bdflib.c" +#include "bdfdrivr.c" + + +/* END */ diff --git a/src/freetype2/bdf/bdf.h b/src/freetype2/bdf/bdf.h new file mode 100644 index 0000000..1b64426 --- /dev/null +++ b/src/freetype2/bdf/bdf.h @@ -0,0 +1,295 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001, 2002, 2003, 2004 Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef __BDF_H__ +#define __BDF_H__ + + +/* + * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher + */ + +#include +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + +/* Imported from bdfP.h */ + +#define _bdf_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] & ( 1 << ( (e) & 31 ) ) ) +#define _bdf_set_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] |= ( 1 << ( (e) & 31 ) ) ) +#define _bdf_clear_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] &= ~( 1 << ( (e) & 31 ) ) ) + +/* end of bdfP.h */ + + + /*************************************************************************/ + /* */ + /* BDF font options macros and types. */ + /* */ + /*************************************************************************/ + + +#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */ +#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */ +#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */ +#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */ +#define BDF_MONOWIDTH 0x10 /* Font has mono width. */ +#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */ + +#define BDF_ALL_SPACING ( BDF_PROPORTIONAL | \ + BDF_MONOWIDTH | \ + BDF_CHARCELL ) + +#define BDF_DEFAULT_LOAD_OPTIONS ( BDF_CORRECT_METRICS | \ + BDF_KEEP_COMMENTS | \ + BDF_KEEP_UNENCODED | \ + BDF_PROPORTIONAL ) + + + typedef struct bdf_options_t_ + { + int correct_metrics; + int keep_unencoded; + int keep_comments; + int font_spacing; + + } bdf_options_t; + + + /* Callback function type for unknown configuration options. */ + typedef int + (*bdf_options_callback_t)( bdf_options_t* opts, + char** params, + unsigned long nparams, + void* client_data ); + + + /*************************************************************************/ + /* */ + /* BDF font property macros and types. */ + /* */ + /*************************************************************************/ + + +#define BDF_ATOM 1 +#define BDF_INTEGER 2 +#define BDF_CARDINAL 3 + + + /* This structure represents a particular property of a font. */ + /* There are a set of defaults and each font has their own. */ + typedef struct bdf_property_t_ + { + char* name; /* Name of the property. */ + int format; /* Format of the property. */ + int builtin; /* A builtin property. */ + union + { + char* atom; + long int32; + unsigned long card32; + + } value; /* Value of the property. */ + + } bdf_property_t; + + + /*************************************************************************/ + /* */ + /* BDF font metric and glyph types. */ + /* */ + /*************************************************************************/ + + + typedef struct bdf_bbx_t_ + { + unsigned short width; + unsigned short height; + + short x_offset; + short y_offset; + + short ascent; + short descent; + + } bdf_bbx_t; + + + typedef struct bdf_glyph_t_ + { + char* name; /* Glyph name. */ + long encoding; /* Glyph encoding. */ + unsigned short swidth; /* Scalable width. */ + unsigned short dwidth; /* Device width. */ + bdf_bbx_t bbx; /* Glyph bounding box. */ + unsigned char* bitmap; /* Glyph bitmap. */ + unsigned long bpr; /* Number of bytes used per row. */ + unsigned short bytes; /* Number of bytes used for the bitmap. */ + + } bdf_glyph_t; + + + typedef struct _hashnode_ + { + const char* key; + void* data; + + } _hashnode, *hashnode; + + + typedef struct hashtable_ + { + int limit; + int size; + int used; + hashnode* table; + + } hashtable; + + + typedef struct bdf_glyphlist_t_ + { + unsigned short pad; /* Pad to 4-byte boundary. */ + unsigned short bpp; /* Bits per pixel. */ + long start; /* Beginning encoding value of glyphs. */ + long end; /* Ending encoding value of glyphs. */ + bdf_glyph_t* glyphs; /* Glyphs themselves. */ + unsigned long glyphs_size; /* Glyph structures allocated. */ + unsigned long glyphs_used; /* Glyph structures used. */ + bdf_bbx_t bbx; /* Overall bounding box of glyphs. */ + + } bdf_glyphlist_t; + + + typedef struct bdf_font_t_ + { + char* name; /* Name of the font. */ + bdf_bbx_t bbx; /* Font bounding box. */ + + long point_size; /* Point size of the font. */ + unsigned long resolution_x; /* Font horizontal resolution. */ + unsigned long resolution_y; /* Font vertical resolution. */ + + int spacing; /* Font spacing value. */ + + unsigned short monowidth; /* Logical width for monowidth font. */ + + long default_char; /* Encoding of the default glyph. */ + + long font_ascent; /* Font ascent. */ + long font_descent; /* Font descent. */ + + unsigned long glyphs_size; /* Glyph structures allocated. */ + unsigned long glyphs_used; /* Glyph structures used. */ + bdf_glyph_t* glyphs; /* Glyphs themselves. */ + + unsigned long unencoded_size; /* Unencoded glyph struct. allocated. */ + unsigned long unencoded_used; /* Unencoded glyph struct. used. */ + bdf_glyph_t* unencoded; /* Unencoded glyphs themselves. */ + + unsigned long props_size; /* Font properties allocated. */ + unsigned long props_used; /* Font properties used. */ + bdf_property_t* props; /* Font properties themselves. */ + + char* comments; /* Font comments. */ + unsigned long comments_len; /* Length of comment string. */ + + bdf_glyphlist_t overflow; /* Storage used for glyph insertion. */ + + void* internal; /* Internal data for the font. */ + + unsigned long nmod[2048]; /* Bitmap indicating modified glyphs. */ + unsigned long umod[2048]; /* Bitmap indicating modified */ + /* unencoded glyphs. */ + unsigned short modified; /* Boolean indicating font modified. */ + unsigned short bpp; /* Bits per pixel. */ + + FT_Memory memory; + + bdf_property_t* user_props; + unsigned long nuser_props; + hashtable proptbl; + + } bdf_font_t; + + + /*************************************************************************/ + /* */ + /* Types for load/save callbacks. */ + /* */ + /*************************************************************************/ + + + /* Error codes. */ +#define BDF_MISSING_START -1 +#define BDF_MISSING_FONTNAME -2 +#define BDF_MISSING_SIZE -3 +#define BDF_MISSING_CHARS -4 +#define BDF_MISSING_STARTCHAR -5 +#define BDF_MISSING_ENCODING -6 +#define BDF_MISSING_BBX -7 + +#define BDF_OUT_OF_MEMORY -20 + +#define BDF_INVALID_LINE -100 + + + /*************************************************************************/ + /* */ + /* BDF font API. */ + /* */ + /*************************************************************************/ + + FT_LOCAL( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory memory, + bdf_options_t* opts, + bdf_font_t* *font ); + + FT_LOCAL( void ) + bdf_free_font( bdf_font_t* font ); + + FT_LOCAL( bdf_property_t * ) + bdf_get_property( char* name, + bdf_font_t* font ); + + FT_LOCAL( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ); + + +FT_END_HEADER + + +#endif /* __BDF_H__ */ + + +/* END */ diff --git a/src/freetype2/bdf/bdfdrivr.c b/src/freetype2/bdf/bdfdrivr.c new file mode 100644 index 0000000..74cc2f1 --- /dev/null +++ b/src/freetype2/bdf/bdfdrivr.c @@ -0,0 +1,848 @@ +/* bdfdrivr.c + + FreeType font driver for bdf files + + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include + +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_OBJECTS_H +#include FT_BDF_H + +#include FT_SERVICE_BDF_H +#include FT_SERVICE_XFREE86_NAME_H + +#include "bdf.h" +#include "bdfdrivr.h" + +#include "bdferror.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_bdfdriver + + + typedef struct BDF_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_encodings; + BDF_encoding_el* encodings; + + } BDF_CMapRec, *BDF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + bdf_cmap_init( FT_CMap bdfcmap, + FT_Pointer init_data ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap ); + FT_UNUSED( init_data ); + + + cmap->num_encodings = face->bdffont->glyphs_used; + cmap->encodings = face->en_table; + + return BDF_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + bdf_cmap_done( FT_CMap bdfcmap ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + + + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_index( FT_CMap bdfcmap, + FT_UInt32 charcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_UInt result = 0; + + + min = 0; + max = cmap->num_encodings; + + while ( min < max ) + { + FT_UInt32 code; + + + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + break; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_next( FT_CMap bdfcmap, + FT_UInt32 *acharcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_UInt32 charcode = *acharcode + 1; + FT_UInt result = 0; + + + min = 0; + max = cmap->num_encodings; + + while ( min < max ) + { + FT_UInt32 code; + + + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + goto Exit; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + + Exit: + *acharcode = charcode; + return result; + } + + + FT_CALLBACK_TABLE_DEF + const FT_CMap_ClassRec bdf_cmap_class = + { + sizeof ( BDF_CMapRec ), + bdf_cmap_init, + bdf_cmap_done, + bdf_cmap_char_index, + bdf_cmap_char_next + }; + + + static FT_Error + bdf_interpret_style( BDF_Face bdf ) + { + FT_Error error = BDF_Err_Ok; + FT_Face face = FT_FACE( bdf ); + FT_Memory memory = face->memory; + bdf_font_t* font = bdf->bdffont; + bdf_property_t* prop; + + int nn, len; + char* strings[4] = { NULL, NULL, NULL, NULL }; + int lengths[4]; + + + face->style_flags = 0; + + prop = bdf_get_font_property( font, (char *)"SLANT" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) + ? (char *)"Oblique" + : (char *)"Italic"; + } + + prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = (char *)"Bold"; + } + + prop = bdf_get_font_property( font, (char *)"SETWIDTH_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (char *)(prop->value.atom); + + prop = bdf_get_font_property( font, (char *)"ADD_STYLE_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (char *)(prop->value.atom); + + len = 0; + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = (char *)"Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_ALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + char* src = strings[nn]; + + + len = lengths[nn]; + + if ( src == NULL ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + int mm; + + + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + BDF_Face_Done( FT_Face bdfface ) /* BDF_Face */ + { + BDF_Face face = (BDF_Face)bdfface; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + bdf_free_font( face->bdffont ); + + FT_FREE( face->en_table ); + + FT_FREE( face->charset_encoding ); + FT_FREE( face->charset_registry ); + FT_FREE( bdfface->family_name ); + FT_FREE( bdfface->style_name ); + + FT_FREE( bdfface->available_sizes ); + + FT_FREE( face->bdffont ); + + FT_TRACE4(( "BDF_Face_Done: done face\n" )); + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Face_Init( FT_Stream stream, + FT_Face bdfface, /* BDF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error = BDF_Err_Ok; + BDF_Face face = (BDF_Face)bdfface; + FT_Memory memory = FT_FACE_MEMORY( face ); + + bdf_font_t* font = NULL; + bdf_options_t options; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + options.correct_metrics = 1; /* FZ XXX: options semantics */ + options.keep_unencoded = 1; + options.keep_comments = 0; + options.font_spacing = BDF_PROPORTIONAL; + + error = bdf_load_font( stream, memory, &options, &font ); + if ( error == BDF_Err_Missing_Startfont_Field ) + { + FT_TRACE2(( "[not a valid BDF file]\n" )); + goto Fail; + } + else if ( error ) + goto Exit; + + /* we have a bdf font: let's construct the face object */ + face->bdffont = font; + { + bdf_property_t* prop = NULL; + + + FT_TRACE4(( "number of glyphs: %d (%d)\n", + font->glyphs_size, + font->glyphs_used )); + FT_TRACE4(( "number of unencoded glyphs: %d (%d)\n", + font->unencoded_size, + font->unencoded_used )); + + bdfface->num_faces = 1; + bdfface->face_index = 0; + bdfface->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_FAST_GLYPHS; + + prop = bdf_get_font_property( font, "SPACING" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || + *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) + bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ + /* FZ XXX: I need a font to implement this */ + + prop = bdf_get_font_property( font, "FAMILY_NAME" ); + if ( prop && prop->value.atom ) + { + if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) ) + goto Exit; + } + else + bdfface->family_name = 0; + + if ( ( error = bdf_interpret_style( face ) ) != 0 ) + goto Exit; + + /* the number of glyphs (with one slot for the undefined glyph */ + /* at position 0 and all unencoded glyphs) */ + bdfface->num_glyphs = font->glyphs_size + 1; + + bdfface->num_fixed_sizes = 1; + if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = bdfface->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + + + FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); + + bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); + + prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); + if ( prop ) + bsize->width = (FT_Short)( ( prop->value.int32 + 5 ) / 10 ); + else + bsize->width = (FT_Short)( bsize->height * 2/3 ); + + prop = bdf_get_font_property( font, "POINT_SIZE" ); + if ( prop ) + /* convert from 722.7 decipoints to 72 points per inch */ + bsize->size = + (FT_Pos)( ( prop->value.int32 * 64 * 7200 + 36135L ) / 72270L ); + else + bsize->size = bsize->width << 6; + + prop = bdf_get_font_property( font, "PIXEL_SIZE" ); + if ( prop ) + bsize->y_ppem = (FT_Short)prop->value.int32 << 6; + + prop = bdf_get_font_property( font, "RESOLUTION_X" ); + if ( prop ) + resolution_x = (FT_Short)prop->value.int32; + + prop = bdf_get_font_property( font, "RESOLUTION_Y" ); + if ( prop ) + resolution_y = (FT_Short)prop->value.int32; + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = bsize->y_ppem * resolution_y / 72; + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; + else + bsize->x_ppem = bsize->y_ppem; + } + + /* encoding table */ + { + bdf_glyph_t* cur = font->glyphs; + unsigned long n; + + + if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) ) + goto Exit; + + face->default_glyph = 0; + for ( n = 0; n < font->glyphs_size; n++ ) + { + (face->en_table[n]).enc = cur[n].encoding; + FT_TRACE4(( "idx %d, val 0x%lX\n", n, cur[n].encoding )); + (face->en_table[n]).glyph = (FT_Short)n; + + if ( cur[n].encoding == font->default_char ) + face->default_glyph = n; + } + } + + /* charmaps */ + { + bdf_property_t *charset_registry = 0, *charset_encoding = 0; + FT_Bool unicode_charmap = 0; + + + charset_registry = + bdf_get_font_property( font, "CHARSET_REGISTRY" ); + charset_encoding = + bdf_get_font_property( font, "CHARSET_ENCODING" ); + if ( charset_registry && charset_encoding ) + { + if ( charset_registry->format == BDF_ATOM && + charset_encoding->format == BDF_ATOM && + charset_registry->value.atom && + charset_encoding->value.atom ) + { + const char* s; + + + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + + /* Uh, oh, compare first letters manually to avoid dependency */ + /* on locales. */ + s = face->charset_registry; + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( face->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + } + + { + FT_CharMapRec charmap; + + + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; + charmap.platform_id = 0; + charmap.encoding_id = 0; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = 3; + charmap.encoding_id = 1; + } + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + +#if 0 + /* Select default charmap */ + if ( bdfface->num_charmaps ) + bdfface->charmap = bdfface->charmaps[0]; +#endif + } + + goto Exit; + } + } + + /* otherwise assume Adobe standard encoding */ + + { + FT_CharMapRec charmap; + + + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.platform_id = 7; + charmap.encoding_id = 0; + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + + /* Select default charmap */ + if ( bdfface->num_charmaps ) + bdfface->charmap = bdfface->charmaps[0]; + } + } + } + + Exit: + return error; + + Fail: + BDF_Face_Done( bdfface ); + return BDF_Err_Unknown_File_Format; + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = bdffont->font_ascent << 6; + size->metrics.descender = -bdffont->font_descent << 6; + size->metrics.max_advance = bdffont->bbx.width << 6; + + return BDF_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FT_Face face = size->face; + FT_Bitmap_Size* bsize = face->available_sizes; + bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; + FT_Error error = BDF_Err_Invalid_Pixel_Size; + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( bsize->y_ppem + 32 ) >> 6 ) + error = BDF_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( bdffont->font_ascent + + bdffont->font_descent ) ) + error = BDF_Err_Ok; + break; + + default: + error = BDF_Err_Unimplemented_Feature; + break; + } + + if ( error ) + return error; + else + return BDF_Size_Select( size, 0 ); + } + + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); + FT_Face face = FT_FACE( bdf ); + FT_Error error = BDF_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + bdf_glyph_t glyph; + int bpp = bdf->bdffont->bpp; + + FT_UNUSED( load_flags ); + + + if ( !face || glyph_index >= (FT_UInt)face->num_glyphs ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + /* index 0 is the undefined glyph */ + if ( glyph_index == 0 ) + glyph_index = bdf->default_glyph; + else + glyph_index--; + + /* slot, bitmap => freetype, glyph => bdflib */ + glyph = bdf->bdffont->glyphs[glyph_index]; + + bitmap->rows = glyph.bbx.height; + bitmap->width = glyph.bbx.width; + bitmap->pitch = glyph.bpr; + + /* note: we don't allocate a new array to hold the bitmap; */ + /* we can simply point to it */ + ft_glyphslot_set_bitmap( slot, glyph.bitmap ); + + switch ( bpp ) + { + case 1: + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + break; + case 2: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; + break; + case 4: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; + break; + case 8: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + break; + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = glyph.bbx.x_offset; + slot->bitmap_top = glyph.bbx.ascent; + + slot->metrics.horiAdvance = glyph.dwidth << 6; + slot->metrics.horiBearingX = glyph.bbx.x_offset << 6; + slot->metrics.horiBearingY = glyph.bbx.ascent << 6; + slot->metrics.width = bitmap->width << 6; + slot->metrics.height = bitmap->rows << 6; + + /* + * XXX DWIDTH1 and VVECTOR should be parsed and + * used here, provided such fonts do exist. + */ + ft_synthesize_vertical_metrics( &slot->metrics, + bdf->bdffont->bbx.height << 6 ); + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + static FT_Error + bdf_get_bdf_property( BDF_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + bdf_property_t* prop; + + + FT_ASSERT( face && face->bdffont ); + + prop = bdf_get_font_property( face->bdffont, prop_name ); + if ( prop ) + { + switch ( prop->format ) + { + case BDF_ATOM: + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + break; + + case BDF_INTEGER: + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = prop->value.int32; + break; + + case BDF_CARDINAL: + aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; + aproperty->u.cardinal = prop->value.card32; + break; + + default: + goto Fail; + } + return 0; + } + + Fail: + return BDF_Err_Invalid_Argument; + } + + + static FT_Error + bdf_get_charset_id( BDF_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + *acharset_encoding = face->charset_encoding; + *acharset_registry = face->charset_registry; + + return 0; + } + + + static const FT_Service_BDFRec bdf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, + (FT_BDF_GetPropertyFunc) bdf_get_bdf_property + }; + + + /* + * + * SERVICES LIST + * + */ + + static const FT_ServiceDescRec bdf_services[] = + { + { FT_SERVICE_ID_BDF, &bdf_service_bdf }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_BDF }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + bdf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( bdf_services, name ); + } + + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec bdf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "bdf", + 0x10000L, + 0x20000L, + + 0, + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) bdf_driver_requester + }, + + sizeof ( BDF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + BDF_Face_Init, + BDF_Face_Done, + 0, /* FT_Size_InitFunc */ + 0, /* FT_Size_DoneFunc */ + 0, /* FT_Slot_InitFunc */ + 0, /* FT_Slot_DoneFunc */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + BDF_Glyph_Load, + + 0, /* FT_Face_GetKerningFunc */ + 0, /* FT_Face_AttachFunc */ + 0, /* FT_Face_GetAdvancesFunc */ + + BDF_Size_Request, + BDF_Size_Select + }; + + +/* END */ diff --git a/src/freetype2/bdf/bdfdrivr.h b/src/freetype2/bdf/bdfdrivr.h new file mode 100644 index 0000000..86f40ee --- /dev/null +++ b/src/freetype2/bdf/bdfdrivr.h @@ -0,0 +1,76 @@ +/* bdfdrivr.h + + FreeType font driver for bdf fonts + + Copyright (C) 2001, 2002, 2003, 2004 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __BDFDRIVR_H__ +#define __BDFDRIVR_H__ + +#include +#include FT_INTERNAL_DRIVER_H + +#include "bdf.h" + + +FT_BEGIN_HEADER + + + typedef struct BDF_encoding_el_ + { + FT_ULong enc; + FT_UShort glyph; + + } BDF_encoding_el; + + + typedef struct BDF_FaceRec_ + { + FT_FaceRec root; + + char* charset_encoding; + char* charset_registry; + + bdf_font_t* bdffont; + + BDF_encoding_el* en_table; + + FT_CharMap charmap_handle; + FT_CharMapRec charmap; /* a single charmap per face */ + + FT_UInt default_glyph; + + } BDF_FaceRec, *BDF_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class; + + +FT_END_HEADER + + +#endif /* __BDFDRIVR_H__ */ + + +/* END */ diff --git a/src/freetype2/bdf/bdferror.h b/src/freetype2/bdf/bdferror.h new file mode 100644 index 0000000..b27fa33 --- /dev/null +++ b/src/freetype2/bdf/bdferror.h @@ -0,0 +1,44 @@ +/* + * Copyright 2001, 2002 Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /*************************************************************************/ + /* */ + /* This file is used to define the BDF error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __BDFERROR_H__ +#define __BDFERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX BDF_Err_ +#define FT_ERR_BASE FT_Mod_Err_BDF + +#include FT_ERRORS_H + +#endif /* __BDFERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/bdf/bdflib.c b/src/freetype2/bdf/bdflib.c new file mode 100644 index 0000000..512cd62 --- /dev/null +++ b/src/freetype2/bdf/bdflib.c @@ -0,0 +1,2472 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 + * Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /*************************************************************************/ + /* */ + /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */ + /* */ + /* taken from Mark Leisher's xmbdfed package */ + /* */ + /*************************************************************************/ + + +#include + +#include FT_FREETYPE_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_OBJECTS_H + +#include "bdf.h" +#include "bdferror.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_bdflib + + + /*************************************************************************/ + /* */ + /* Default BDF font options. */ + /* */ + /*************************************************************************/ + + + static const bdf_options_t _bdf_opts = + { + 1, /* Correct metrics. */ + 1, /* Preserve unencoded glyphs. */ + 0, /* Preserve comments. */ + BDF_PROPORTIONAL /* Default spacing. */ + }; + + + /*************************************************************************/ + /* */ + /* Builtin BDF font properties. */ + /* */ + /*************************************************************************/ + + /* List of most properties that might appear in a font. Doesn't include */ + /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ + + static const bdf_property_t _bdf_properties[] = + { + { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, + { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, + { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, + { (char *)"COMMENT", BDF_ATOM, 1, { 0 } }, + { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } }, + { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, + { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } }, + { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"FONT", BDF_ATOM, 1, { 0 } }, + { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, + { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } }, + { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, + { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"NOTICE", BDF_ATOM, 1, { 0 } }, + { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } }, + { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, + { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"SLANT", BDF_ATOM, 1, { 0 } }, + { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SPACING", BDF_ATOM, 1, { 0 } }, + { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, + { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, + }; + + static const unsigned long + _num_bdf_properties = sizeof ( _bdf_properties ) / + sizeof ( _bdf_properties[0] ); + + + /*************************************************************************/ + /* */ + /* Hash table utilities for the properties. */ + /* */ + /*************************************************************************/ + + /* XXX: Replace this with FreeType's hash functions */ + + +#define INITIAL_HT_SIZE 241 + + typedef void + (*hash_free_func)( hashnode node ); + + static hashnode* + hash_bucket( const char* key, + hashtable* ht ) + { + const char* kp = key; + unsigned long res = 0; + hashnode* bp = ht->table, *ndp; + + + /* Mocklisp hash function. */ + while ( *kp ) + res = ( res << 5 ) - res + *kp++; + + ndp = bp + ( res % ht->size ); + while ( *ndp ) + { + kp = (*ndp)->key; + if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 ) + break; + ndp--; + if ( ndp < bp ) + ndp = bp + ( ht->size - 1 ); + } + + return ndp; + } + + + static FT_Error + hash_rehash( hashtable* ht, + FT_Memory memory ) + { + hashnode* obp = ht->table, *bp, *nbp; + int i, sz = ht->size; + FT_Error error = BDF_Err_Ok; + + + ht->size <<= 1; + ht->limit = ht->size / 3; + + if ( FT_NEW_ARRAY( ht->table, ht->size ) ) + goto Exit; + + for ( i = 0, bp = obp; i < sz; i++, bp++ ) + { + if ( *bp ) + { + nbp = hash_bucket( (*bp)->key, ht ); + *nbp = *bp; + } + } + FT_FREE( obp ); + + Exit: + return error; + } + + + static FT_Error + hash_init( hashtable* ht, + FT_Memory memory ) + { + int sz = INITIAL_HT_SIZE; + FT_Error error = BDF_Err_Ok; + + + ht->size = sz; + ht->limit = sz / 3; + ht->used = 0; + + if ( FT_NEW_ARRAY( ht->table, sz ) ) + goto Exit; + + Exit: + return error; + } + + + static void + hash_free( hashtable* ht, + FT_Memory memory ) + { + if ( ht != 0 ) + { + int i, sz = ht->size; + hashnode* bp = ht->table; + + + for ( i = 0; i < sz; i++, bp++ ) + FT_FREE( *bp ); + + FT_FREE( ht->table ); + } + } + + + static FT_Error + hash_insert( char* key, + void* data, + hashtable* ht, + FT_Memory memory ) + { + hashnode nn, *bp = hash_bucket( key, ht ); + FT_Error error = BDF_Err_Ok; + + + nn = *bp; + if ( !nn ) + { + if ( FT_NEW( nn ) ) + goto Exit; + *bp = nn; + + nn->key = key; + nn->data = data; + + if ( ht->used >= ht->limit ) + { + error = hash_rehash( ht, memory ); + if ( error ) + goto Exit; + } + ht->used++; + } + else + nn->data = data; + + Exit: + return error; + } + + + static hashnode + hash_lookup( const char* key, + hashtable* ht ) + { + hashnode *np = hash_bucket( key, ht ); + + + return *np; + } + + + /*************************************************************************/ + /* */ + /* Utility types and functions. */ + /* */ + /*************************************************************************/ + + + /* Function type for parsing lines of a BDF font. */ + + typedef FT_Error + (*_bdf_line_func_t)( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ); + + + /* List structure for splitting lines into fields. */ + + typedef struct _bdf_list_t_ + { + char** field; + unsigned long size; + unsigned long used; + FT_Memory memory; + + } _bdf_list_t; + + + /* Structure used while loading BDF fonts. */ + + typedef struct _bdf_parse_t_ + { + unsigned long flags; + unsigned long cnt; + unsigned long row; + + short minlb; + short maxlb; + short maxrb; + short maxas; + short maxds; + + short rbearing; + + char* glyph_name; + long glyph_enc; + + bdf_font_t* font; + bdf_options_t* opts; + + unsigned long have[2048]; + _bdf_list_t list; + + FT_Memory memory; + + } _bdf_parse_t; + + +#define setsbit( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) +#define sbitset( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) + + + static void + _bdf_list_init( _bdf_list_t* list, + FT_Memory memory ) + { + FT_ZERO( list ); + list->memory = memory; + } + + + static void + _bdf_list_done( _bdf_list_t* list ) + { + FT_Memory memory = list->memory; + + + if ( memory ) + { + FT_FREE( list->field ); + FT_ZERO( list ); + } + } + + + static FT_Error + _bdf_list_ensure( _bdf_list_t* list, + int num_items ) + { + FT_Error error = BDF_Err_Ok; + + + if ( num_items > (int)list->size ) + { + int oldsize = list->size; + int newsize = oldsize + ( oldsize >> 1 ) + 4; + int bigsize = FT_INT_MAX / sizeof ( char* ); + FT_Memory memory = list->memory; + + + if ( oldsize == bigsize ) + { + error = BDF_Err_Out_Of_Memory; + goto Exit; + } + else if ( newsize < oldsize || newsize > bigsize ) + newsize = bigsize; + + if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) ) + goto Exit; + + list->size = newsize; + } + + Exit: + return error; + } + + + static void + _bdf_list_shift( _bdf_list_t* list, + unsigned long n ) + { + unsigned long i, u; + + + if ( list == 0 || list->used == 0 || n == 0 ) + return; + + if ( n >= list->used ) + { + list->used = 0; + return; + } + + for ( u = n, i = 0; u < list->used; i++, u++ ) + list->field[i] = list->field[u]; + list->used -= n; + } + + + static char * + _bdf_list_join( _bdf_list_t* list, + int c, + unsigned long *alen ) + { + unsigned long i, j; + char *fp, *dp; + + + *alen = 0; + + if ( list == 0 || list->used == 0 ) + return 0; + + dp = list->field[0]; + for ( i = j = 0; i < list->used; i++ ) + { + fp = list->field[i]; + while ( *fp ) + dp[j++] = *fp++; + + if ( i + 1 < list->used ) + dp[j++] = (char)c; + } + dp[j] = 0; + + *alen = j; + return dp; + } + + + /* An empty string for empty fields. */ + + static const char empty[1] = { 0 }; /* XXX eliminate this */ + + + static FT_Error + _bdf_list_split( _bdf_list_t* list, + char* separators, + char* line, + unsigned long linelen ) + { + int mult, final_empty; + char *sp, *ep, *end; + char seps[32]; + FT_Error error = BDF_Err_Ok; + + + /* Initialize the list. */ + list->used = 0; + + /* If the line is empty, then simply return. */ + if ( linelen == 0 || line[0] == 0 ) + goto Exit; + + /* In the original code, if the `separators' parameter is NULL or */ + /* empty, the list is split into individual bytes. We don't need */ + /* this, so an error is signaled. */ + if ( separators == 0 || *separators == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + /* Prepare the separator bitmap. */ + FT_MEM_ZERO( seps, 32 ); + + /* If the very last character of the separator string is a plus, then */ + /* set the `mult' flag to indicate that multiple separators should be */ + /* collapsed into one. */ + for ( mult = 0, sp = separators; sp && *sp; sp++ ) + { + if ( *sp == '+' && *( sp + 1 ) == 0 ) + mult = 1; + else + setsbit( seps, *sp ); + } + + /* Break the line up into fields. */ + for ( final_empty = 0, sp = ep = line, end = sp + linelen; + sp < end && *sp; ) + { + /* Collect everything that is not a separator. */ + for ( ; *ep && !sbitset( seps, *ep ); ep++ ) + ; + + /* Resize the list if necessary. */ + if ( list->used == list->size ) + { + error = _bdf_list_ensure( list, list->used + 1 ); + if ( error ) + goto Exit; + } + + /* Assign the field appropriately. */ + list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty; + + sp = ep; + + if ( mult ) + { + /* If multiple separators should be collapsed, do it now by */ + /* setting all the separator characters to 0. */ + for ( ; *ep && sbitset( seps, *ep ); ep++ ) + *ep = 0; + } + else if ( *ep != 0 ) + /* Don't collapse multiple separators by making them 0, so just */ + /* make the one encountered 0. */ + *ep++ = 0; + + final_empty = ( ep > sp && *ep == 0 ); + sp = ep; + } + + /* Finally, NULL-terminate the list. */ + if ( list->used + final_empty >= list->size ) + { + error = _bdf_list_ensure( list, list->used + final_empty + 1 ); + if ( error ) + goto Exit; + } + + if ( final_empty ) + list->field[list->used++] = (char*)empty; + + list->field[list->used] = 0; + + Exit: + return error; + } + + +#define NO_SKIP 256 /* this value cannot be stored in a 'char' */ + + + static FT_Error + _bdf_readstream( FT_Stream stream, + _bdf_line_func_t callback, + void* client_data, + unsigned long *lno ) + { + _bdf_line_func_t cb; + unsigned long lineno, buf_size; + int refill, bytes, hold, to_skip; + int start, end, cursor, avail; + char* buf = 0; + FT_Memory memory = stream->memory; + FT_Error error = BDF_Err_Ok; + + + if ( callback == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + /* initial size and allocation of the input buffer */ + buf_size = 1024; + + if ( FT_NEW_ARRAY( buf, buf_size ) ) + goto Exit; + + cb = callback; + lineno = 1; + buf[0] = 0; + start = 0; + end = 0; + avail = 0; + cursor = 0; + refill = 1; + to_skip = NO_SKIP; + bytes = 0; /* make compiler happy */ + + for (;;) + { + if ( refill ) + { + bytes = (int)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor, + (FT_ULong)(buf_size - cursor) ); + avail = cursor + bytes; + cursor = 0; + refill = 0; + } + + end = start; + + /* should we skip an optional character like \n or \r? */ + if ( start < avail && buf[start] == to_skip ) + { + start += 1; + to_skip = NO_SKIP; + continue; + } + + /* try to find the end of the line */ + while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) + end++; + + /* if we hit the end of the buffer, try shifting its content */ + /* or even resizing it */ + if ( end >= avail ) + { + if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */ + break; /* ignore it then exit */ + + if ( start == 0 ) + { + /* this line is definitely too long; try resizing the input */ + /* buffer a bit to handle it. */ + FT_ULong new_size; + + + if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + new_size = buf_size * 2; + if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) + goto Exit; + + cursor = buf_size; + buf_size = new_size; + } + else + { + bytes = avail - start; + + FT_MEM_COPY( buf, buf + start, bytes ); + + cursor = bytes; + avail -= bytes; + start = 0; + } + refill = 1; + continue; + } + + /* Temporarily NUL-terminate the line. */ + hold = buf[end]; + buf[end] = 0; + + /* XXX: Use encoding independent value for 0x1a */ + if ( buf[start] != '#' && buf[start] != 0x1a && end > start ) + { + error = (*cb)( buf + start, end - start, lineno, + (void*)&cb, client_data ); + if ( error ) + break; + } + + lineno += 1; + buf[end] = (char)hold; + start = end + 1; + + if ( hold == '\n' ) + to_skip = '\r'; + else if ( hold == '\r' ) + to_skip = '\n'; + else + to_skip = NO_SKIP; + } + + *lno = lineno; + + Exit: + FT_FREE( buf ); + return error; + } + + + /* XXX: make this work with EBCDIC also */ + + static const unsigned char a2i[128] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + static const unsigned char odigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const unsigned char ddigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const unsigned char hdigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + +#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) ) + + + /* Routine to convert an ASCII string into an unsigned long integer. */ + static unsigned long + _bdf_atoul( char* s, + char** end, + int base ) + { + unsigned long v; + const unsigned char* dmap; + + + if ( s == 0 || *s == 0 ) + return 0; + + /* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + + for ( v = 0; isdigok( dmap, *s ); s++ ) + v = v * base + a2i[(int)*s]; + + if ( end != 0 ) + *end = s; + + return v; + } + + + /* Routine to convert an ASCII string into an signed long integer. */ + static long + _bdf_atol( char* s, + char** end, + int base ) + { + long v, neg; + const unsigned char* dmap; + + + if ( s == 0 || *s == 0 ) + return 0; + + /* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* Check for a minus sign. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + /* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + + for ( v = 0; isdigok( dmap, *s ); s++ ) + v = v * base + a2i[(int)*s]; + + if ( end != 0 ) + *end = s; + + return ( !neg ) ? v : -v; + } + + + /* Routine to convert an ASCII string into an signed short integer. */ + static short + _bdf_atos( char* s, + char** end, + int base ) + { + short v, neg; + const unsigned char* dmap; + + + if ( s == 0 || *s == 0 ) + return 0; + + /* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* Check for a minus. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + /* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + + for ( v = 0; isdigok( dmap, *s ); s++ ) + v = (short)( v * base + a2i[(int)*s] ); + + if ( end != 0 ) + *end = s; + + return (short)( ( !neg ) ? v : -v ); + } + + + /* Routine to compare two glyphs by encoding so they can be sorted. */ + static int + by_encoding( const void* a, + const void* b ) + { + bdf_glyph_t *c1, *c2; + + + c1 = (bdf_glyph_t *)a; + c2 = (bdf_glyph_t *)b; + + if ( c1->encoding < c2->encoding ) + return -1; + + if ( c1->encoding > c2->encoding ) + return 1; + + return 0; + } + + + static FT_Error + bdf_create_property( char* name, + int format, + bdf_font_t* font ) + { + unsigned long n; + bdf_property_t* p; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; + + + /* First check to see if the property has */ + /* already been added or not. If it has, then */ + /* simply ignore it. */ + if ( hash_lookup( name, &(font->proptbl) ) ) + goto Exit; + + if ( FT_RENEW_ARRAY( font->user_props, + font->nuser_props, + font->nuser_props + 1 ) ) + goto Exit; + + p = font->user_props + font->nuser_props; + FT_ZERO( p ); + + n = (unsigned long)( ft_strlen( name ) + 1 ); + + if ( FT_NEW_ARRAY( p->name, n ) ) + goto Exit; + + FT_MEM_COPY( (char *)p->name, name, n ); + + p->format = format; + p->builtin = 0; + + n = _num_bdf_properties + font->nuser_props; + + error = hash_insert( p->name, (void *)n, &(font->proptbl), memory ); + if ( error ) + goto Exit; + + font->nuser_props++; + + Exit: + return error; + } + + + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_property( char* name, + bdf_font_t* font ) + { + hashnode hn; + unsigned long propid; + + + if ( name == 0 || *name == 0 ) + return 0; + + if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 ) + return 0; + + propid = (unsigned long)hn->data; + if ( propid >= _num_bdf_properties ) + return font->user_props + ( propid - _num_bdf_properties ); + + return (bdf_property_t*)_bdf_properties + propid; + } + + + /*************************************************************************/ + /* */ + /* BDF font file parsing flags and functions. */ + /* */ + /*************************************************************************/ + + + /* Parse flags. */ + +#define _BDF_START 0x0001 +#define _BDF_FONT_NAME 0x0002 +#define _BDF_SIZE 0x0004 +#define _BDF_FONT_BBX 0x0008 +#define _BDF_PROPS 0x0010 +#define _BDF_GLYPHS 0x0020 +#define _BDF_GLYPH 0x0040 +#define _BDF_ENCODING 0x0080 +#define _BDF_SWIDTH 0x0100 +#define _BDF_DWIDTH 0x0200 +#define _BDF_BBX 0x0400 +#define _BDF_BITMAP 0x0800 + +#define _BDF_SWIDTH_ADJ 0x1000 + +#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \ + _BDF_ENCODING | \ + _BDF_SWIDTH | \ + _BDF_DWIDTH | \ + _BDF_BBX | \ + _BDF_BITMAP ) + +#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL +#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL + + + /* Auto correction messages. */ +#define ACMSG1 "FONT_ASCENT property missing. " \ + "Added \"FONT_ASCENT %hd\".\n" +#define ACMSG2 "FONT_DESCENT property missing. " \ + "Added \"FONT_DESCENT %hd\".\n" +#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n" +#define ACMSG4 "Font left bearing != actual left bearing. " \ + "Old: %hd New: %hd.\n" +#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" +#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n" +#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n" +#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" +#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" +#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" +#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" +#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n" +#define ACMSG13 "Glyph %ld extra rows removed.\n" +#define ACMSG14 "Glyph %ld extra columns removed.\n" +#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" + + /* Error messages. */ +#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n" +#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" +#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" +#define ERRMSG4 "[line %ld] BBX too big.\n" + + + static FT_Error + _bdf_add_comment( bdf_font_t* font, + char* comment, + unsigned long len ) + { + char* cp; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; + + + if ( FT_RENEW_ARRAY( font->comments, + font->comments_len, + font->comments_len + len + 1 ) ) + goto Exit; + + cp = font->comments + font->comments_len; + + FT_MEM_COPY( cp, comment, len ); + cp[len] = '\n'; + + font->comments_len += len + 1; + + Exit: + return error; + } + + + /* Set the spacing from the font name if it exists, or set it to the */ + /* default specified in the options. */ + static FT_Error + _bdf_set_default_spacing( bdf_font_t* font, + bdf_options_t* opts ) + { + unsigned long len; + char name[256]; + _bdf_list_t list; + FT_Memory memory; + FT_Error error = BDF_Err_Ok; + + + if ( font == 0 || font->name == 0 || font->name[0] == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + memory = font->memory; + + _bdf_list_init( &list, memory ); + + font->spacing = opts->font_spacing; + + len = (unsigned long)( ft_strlen( font->name ) + 1 ); + /* Limit ourselves to 256 characters in the font name. */ + if ( len >= 256 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + FT_MEM_COPY( name, font->name, len ); + + error = _bdf_list_split( &list, (char *)"-", name, len ); + if ( error ) + goto Fail; + + if ( list.used == 15 ) + { + switch ( list.field[11][0] ) + { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + + Fail: + _bdf_list_done( &list ); + + Exit: + return error; + } + + + /* Determine whether the property is an atom or not. If it is, then */ + /* clean it up so the double quotes are removed if they exist. */ + static int + _bdf_is_atom( char* line, + unsigned long linelen, + char** name, + char** value, + bdf_font_t* font ) + { + int hold; + char *sp, *ep; + bdf_property_t* p; + + + *name = sp = ep = line; + + while ( *ep && *ep != ' ' && *ep != '\t' ) + ep++; + + hold = -1; + if ( *ep ) + { + hold = *ep; + *ep = 0; + } + + p = bdf_get_property( sp, font ); + + /* Restore the character that was saved before any return can happen. */ + if ( hold != -1 ) + *ep = (char)hold; + + /* If the property exists and is not an atom, just return here. */ + if ( p && p->format != BDF_ATOM ) + return 0; + + /* The property is an atom. Trim all leading and trailing whitespace */ + /* and double quotes for the atom value. */ + sp = ep; + ep = line + linelen; + + /* Trim the leading whitespace if it exists. */ + *sp++ = 0; + while ( *sp && + ( *sp == ' ' || *sp == '\t' ) ) + sp++; + + /* Trim the leading double quote if it exists. */ + if ( *sp == '"' ) + sp++; + *value = sp; + + /* Trim the trailing whitespace if it exists. */ + while ( ep > sp && + ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) + *--ep = 0; + + /* Trim the trailing double quote if it exists. */ + if ( ep > sp && *( ep - 1 ) == '"' ) + *--ep = 0; + + return 1; + } + + + static FT_Error + _bdf_add_property( bdf_font_t* font, + char* name, + char* value ) + { + unsigned long propid; + hashnode hn; + bdf_property_t *prop, *fp; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; + + + /* First, check to see if the property already exists in the font. */ + if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 ) + { + /* The property already exists in the font, so simply replace */ + /* the value of the property with the current value. */ + fp = font->props + (unsigned long)hn->data; + + switch ( fp->format ) + { + case BDF_ATOM: + /* Delete the current atom if it exists. */ + FT_FREE( fp->value.atom ); + + if ( value && value[0] != 0 ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.int32 = _bdf_atol( value, 0, 10 ); + break; + + case BDF_CARDINAL: + fp->value.card32 = _bdf_atoul( value, 0, 10 ); + break; + + default: + ; + } + + goto Exit; + } + + /* See whether this property type exists yet or not. */ + /* If not, create it. */ + hn = hash_lookup( name, &(font->proptbl) ); + if ( hn == 0 ) + { + error = bdf_create_property( name, BDF_ATOM, font ); + if ( error ) + goto Exit; + hn = hash_lookup( name, &(font->proptbl) ); + } + + /* Allocate another property if this is overflow. */ + if ( font->props_used == font->props_size ) + { + if ( font->props_size == 0 ) + { + if ( FT_NEW_ARRAY( font->props, 1 ) ) + goto Exit; + } + else + { + if ( FT_RENEW_ARRAY( font->props, + font->props_size, + font->props_size + 1 ) ) + goto Exit; + } + + fp = font->props + font->props_size; + FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) ); + font->props_size++; + } + + propid = (unsigned long)hn->data; + if ( propid >= _num_bdf_properties ) + prop = font->user_props + ( propid - _num_bdf_properties ); + else + prop = (bdf_property_t*)_bdf_properties + propid; + + fp = font->props + font->props_used; + + fp->name = prop->name; + fp->format = prop->format; + fp->builtin = prop->builtin; + + switch ( prop->format ) + { + case BDF_ATOM: + fp->value.atom = 0; + if ( value != 0 && value[0] ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.int32 = _bdf_atol( value, 0, 10 ); + break; + + case BDF_CARDINAL: + fp->value.card32 = _bdf_atoul( value, 0, 10 ); + break; + } + + /* If the property happens to be a comment, then it doesn't need */ + /* to be added to the internal hash table. */ + if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) { + /* Add the property to the font property table. */ + error = hash_insert( fp->name, + (void *)font->props_used, + (hashtable *)font->internal, + memory ); + if ( error ) + goto Exit; + } + + font->props_used++; + + /* Some special cases need to be handled here. The DEFAULT_CHAR */ + /* property needs to be located if it exists in the property list, the */ + /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ + /* present, and the SPACING property should override the default */ + /* spacing. */ + if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 ) + font->default_char = fp->value.int32; + else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 ) + font->font_ascent = fp->value.int32; + else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 ) + font->font_descent = fp->value.int32; + else if ( ft_memcmp( name, "SPACING", 7 ) == 0 ) + { + if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) + font->spacing = BDF_PROPORTIONAL; + else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) + font->spacing = BDF_MONOWIDTH; + else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) + font->spacing = BDF_CHARCELL; + } + + Exit: + return error; + } + + + static const unsigned char nibble_mask[8] = + { + 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE + }; + + + /* Actually parse the glyph info and bitmaps. */ + static FT_Error + _bdf_parse_glyphs( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + int c, mask_index; + char* s; + unsigned char* bp; + unsigned long i, slen, nibbles; + + _bdf_parse_t* p; + bdf_glyph_t* glyph; + bdf_font_t* font; + + FT_Memory memory; + FT_Error error = BDF_Err_Ok; + + FT_UNUSED( call_data ); + FT_UNUSED( lineno ); /* only used in debug mode */ + + + p = (_bdf_parse_t *)client_data; + + font = p->font; + memory = font->memory; + + /* Check for a comment. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = _bdf_add_comment( p->font, s, linelen ); + goto Exit; + } + + /* The very first thing expected is the number of glyphs. */ + if ( !( p->flags & _BDF_GLYPHS ) ) + { + if ( ft_memcmp( line, "CHARS", 5 ) != 0 ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); + error = BDF_Err_Missing_Chars_Field; + goto Exit; + } + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 ); + + /* Make sure the number of glyphs is non-zero. */ + if ( p->cnt == 0 ) + font->glyphs_size = 64; + + /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ + /* number of code points available in Unicode). */ + if ( p->cnt >= 1114112UL ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + + if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) + goto Exit; + + p->flags |= _BDF_GLYPHS; + + goto Exit; + } + + /* Check for the ENDFONT field. */ + if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 ) + { + /* Sort the glyphs by encoding. */ + ft_qsort( (char *)font->glyphs, + font->glyphs_used, + sizeof ( bdf_glyph_t ), + by_encoding ); + + p->flags &= ~_BDF_START; + + goto Exit; + } + + /* Check for the ENDCHAR field. */ + if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 ) + { + p->glyph_enc = 0; + p->flags &= ~_BDF_GLYPH_BITS; + + goto Exit; + } + + /* Check to see whether a glyph is being scanned but should be */ + /* ignored because it is an unencoded glyph. */ + if ( ( p->flags & _BDF_GLYPH ) && + p->glyph_enc == -1 && + p->opts->keep_unencoded == 0 ) + goto Exit; + + /* Check for the STARTCHAR field. */ + if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 ) + { + /* Set the character name in the parse info first until the */ + /* encoding can be checked for an unencoded character. */ + FT_FREE( p->glyph_name ); + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + _bdf_list_shift( &p->list, 1 ); + + s = _bdf_list_join( &p->list, ' ', &slen ); + + if ( !s ) + { + error = BDF_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) ) + goto Exit; + + FT_MEM_COPY( p->glyph_name, s, slen + 1 ); + + p->flags |= _BDF_GLYPH; + + goto Exit; + } + + /* Check for the ENCODING field. */ + if ( ft_memcmp( line, "ENCODING", 8 ) == 0 ) + { + if ( !( p->flags & _BDF_GLYPH ) ) + { + /* Missing STARTCHAR field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); + error = BDF_Err_Missing_Startchar_Field; + goto Exit; + } + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 ); + + /* Check that the encoding is in the range [0,65536] because */ + /* otherwise p->have (a bitmap with static size) overflows. */ + if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 ) + { + error = BDF_Err_Invalid_File_Format; + goto Exit; + } + + /* Check to see whether this encoding has already been encountered. */ + /* If it has then change it to unencoded so it gets added if */ + /* indicated. */ + if ( p->glyph_enc >= 0 ) + { + if ( _bdf_glyph_modified( p->have, p->glyph_enc ) ) + { + /* Emit a message saying a glyph has been moved to the */ + /* unencoded area. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12, + p->glyph_enc, p->glyph_name )); + p->glyph_enc = -1; + font->modified = 1; + } + else + _bdf_set_glyph_modified( p->have, p->glyph_enc ); + } + + if ( p->glyph_enc >= 0 ) + { + /* Make sure there are enough glyphs allocated in case the */ + /* number of characters happen to be wrong. */ + if ( font->glyphs_used == font->glyphs_size ) + { + if ( FT_RENEW_ARRAY( font->glyphs, + font->glyphs_size, + font->glyphs_size + 64 ) ) + goto Exit; + + font->glyphs_size += 64; + } + + glyph = font->glyphs + font->glyphs_used++; + glyph->name = p->glyph_name; + glyph->encoding = p->glyph_enc; + + /* Reset the initial glyph info. */ + p->glyph_name = 0; + } + else + { + /* Unencoded glyph. Check to see whether it should */ + /* be added or not. */ + if ( p->opts->keep_unencoded != 0 ) + { + /* Allocate the next unencoded glyph. */ + if ( font->unencoded_used == font->unencoded_size ) + { + if ( FT_RENEW_ARRAY( font->unencoded , + font->unencoded_size, + font->unencoded_size + 4 ) ) + goto Exit; + + font->unencoded_size += 4; + } + + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; + } + else + /* Free up the glyph name if the unencoded shouldn't be */ + /* kept. */ + FT_FREE( p->glyph_name ); + + p->glyph_name = 0; + } + + /* Clear the flags that might be added when width and height are */ + /* checked for consistency. */ + p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK ); + + p->flags |= _BDF_ENCODING; + + goto Exit; + } + + /* Point at the glyph being constructed. */ + if ( p->glyph_enc == -1 ) + glyph = font->unencoded + ( font->unencoded_used - 1 ); + else + glyph = font->glyphs + ( font->glyphs_used - 1 ); + + /* Check to see whether a bitmap is being constructed. */ + if ( p->flags & _BDF_BITMAP ) + { + /* If there are more rows than are specified in the glyph metrics, */ + /* ignore the remaining lines. */ + if ( p->row >= (unsigned long)glyph->bbx.height ) + { + if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) ) + { + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); + p->flags |= _BDF_GLYPH_HEIGHT_CHECK; + font->modified = 1; + } + + goto Exit; + } + + /* Only collect the number of nibbles indicated by the glyph */ + /* metrics. If there are more columns, they are simply ignored. */ + nibbles = glyph->bpr << 1; + bp = glyph->bitmap + p->row * glyph->bpr; + + for ( i = 0; i < nibbles; i++ ) + { + c = line[i]; + *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); + if ( i + 1 < nibbles && ( i & 1 ) ) + *++bp = 0; + } + + /* Remove possible garbage at the right. */ + mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; + if ( glyph->bbx.width ) + *bp &= nibble_mask[mask_index]; + + /* If any line has extra columns, indicate they have been removed. */ + if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) && + !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) + { + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); + p->flags |= _BDF_GLYPH_WIDTH_CHECK; + font->modified = 1; + } + + p->row++; + goto Exit; + } + + /* Expect the SWIDTH (scalable width) field next. */ + if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 ) + { + if ( !( p->flags & _BDF_ENCODING ) ) + { + /* Missing ENCODING field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); + error = BDF_Err_Missing_Encoding_Field; + goto Exit; + } + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); + p->flags |= _BDF_SWIDTH; + + goto Exit; + } + + /* Expect the DWIDTH (scalable width) field next. */ + if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 ) + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); + + if ( !( p->flags & _BDF_SWIDTH ) ) + { + /* Missing SWIDTH field. Emit an auto correction message and set */ + /* the scalable width from the device width. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); + + glyph->swidth = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + } + + p->flags |= _BDF_DWIDTH; + goto Exit; + } + + /* Expect the BBX field next. */ + if ( ft_memcmp( line, "BBX", 3 ) == 0 ) + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); + glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); + glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); + glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); + + /* Generate the ascent and descent of the character. */ + glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); + glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); + + /* Determine the overall font bounding box as the characters are */ + /* loaded so corrections can be done later if indicated. */ + p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); + p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); + + p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); + + p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); + p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); + p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); + + if ( !( p->flags & _BDF_DWIDTH ) ) + { + /* Missing DWIDTH field. Emit an auto correction message and set */ + /* the device width to the glyph width. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); + glyph->dwidth = glyph->bbx.width; + } + + /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ + /* value if necessary. */ + if ( p->opts->correct_metrics != 0 ) + { + /* Determine the point size of the glyph. */ + unsigned short sw = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + + + if ( sw != glyph->swidth ) + { + glyph->swidth = sw; + + if ( p->glyph_enc == -1 ) + _bdf_set_glyph_modified( font->umod, + font->unencoded_used - 1 ); + else + _bdf_set_glyph_modified( font->nmod, glyph->encoding ); + + p->flags |= _BDF_SWIDTH_ADJ; + font->modified = 1; + } + } + + p->flags |= _BDF_BBX; + goto Exit; + } + + /* And finally, gather up the bitmap. */ + if ( ft_memcmp( line, "BITMAP", 6 ) == 0 ) + { + unsigned long bitmap_size; + + + if ( !( p->flags & _BDF_BBX ) ) + { + /* Missing BBX field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); + error = BDF_Err_Missing_Bbx_Field; + goto Exit; + } + + /* Allocate enough space for the bitmap. */ + glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; + + bitmap_size = glyph->bpr * glyph->bbx.height; + if ( bitmap_size > 0xFFFFU ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); + error = BDF_Err_Bbx_Too_Big; + goto Exit; + } + else + glyph->bytes = (unsigned short)bitmap_size; + + if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) + goto Exit; + + p->row = 0; + p->flags |= _BDF_BITMAP; + + goto Exit; + } + + error = BDF_Err_Invalid_File_Format; + + Exit: + return error; + } + + + /* Load the font properties. */ + static FT_Error + _bdf_parse_properties( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long vlen; + _bdf_line_func_t* next; + _bdf_parse_t* p; + char* name; + char* value; + char nbuf[128]; + FT_Error error = BDF_Err_Ok; + + FT_UNUSED( lineno ); + + + next = (_bdf_line_func_t *)call_data; + p = (_bdf_parse_t *) client_data; + + /* Check for the end of the properties. */ + if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 ) + { + /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ + /* encountered yet, then make sure they are added as properties and */ + /* make sure they are set from the font bounding box info. */ + /* */ + /* This is *always* done regardless of the options, because X11 */ + /* requires these two fields to compile fonts. */ + if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) + { + p->font->font_ascent = p->font->bbx.ascent; + ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); + error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf ); + if ( error ) + goto Exit; + + FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); + p->font->modified = 1; + } + + if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) + { + p->font->font_descent = p->font->bbx.descent; + ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); + error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf ); + if ( error ) + goto Exit; + + FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); + p->font->modified = 1; + } + + p->flags &= ~_BDF_PROPS; + *next = _bdf_parse_glyphs; + + goto Exit; + } + + /* Ignore the _XFREE86_GLYPH_RANGES properties. */ + if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) + goto Exit; + + /* Handle COMMENT fields and properties in a special way to preserve */ + /* the spacing. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + name = value = line; + value += 7; + if ( *value ) + *value++ = 0; + error = _bdf_add_property( p->font, name, value ); + if ( error ) + goto Exit; + } + else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) + { + error = _bdf_add_property( p->font, name, value ); + if ( error ) + goto Exit; + } + else + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + name = p->list.field[0]; + + _bdf_list_shift( &p->list, 1 ); + value = _bdf_list_join( &p->list, ' ', &vlen ); + + error = _bdf_add_property( p->font, name, value ); + if ( error ) + goto Exit; + } + + Exit: + return error; + } + + + /* Load the font header. */ + static FT_Error + _bdf_parse_start( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long slen; + _bdf_line_func_t* next; + _bdf_parse_t* p; + bdf_font_t* font; + char *s; + + FT_Memory memory = NULL; + FT_Error error = BDF_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + next = (_bdf_line_func_t *)call_data; + p = (_bdf_parse_t *) client_data; + + if ( p->font ) + memory = p->font->memory; + + /* Check for a comment. This is done to handle those fonts that have */ + /* comments before the STARTFONT line for some reason. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments != 0 && p->font != 0 ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + + error = _bdf_add_comment( p->font, s, linelen ); + if ( error ) + goto Exit; + /* here font is not defined! */ + } + + goto Exit; + } + + if ( !( p->flags & _BDF_START ) ) + { + memory = p->memory; + + if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 ) + { + /* No STARTFONT field is a good indication of a problem. */ + error = BDF_Err_Missing_Startfont_Field; + goto Exit; + } + + p->flags = _BDF_START; + font = p->font = 0; + + if ( FT_NEW( font ) ) + goto Exit; + p->font = font; + + font->memory = p->memory; + p->memory = 0; + + { /* setup */ + unsigned long i; + bdf_property_t* prop; + + + error = hash_init( &(font->proptbl), memory ); + if ( error ) + goto Exit; + for ( i = 0, prop = (bdf_property_t*)_bdf_properties; + i < _num_bdf_properties; i++, prop++ ) + { + error = hash_insert( prop->name, (void *)i, + &(font->proptbl), memory ); + if ( error ) + goto Exit; + } + } + + if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) ) + goto Exit; + error = hash_init( (hashtable *)p->font->internal,memory ); + if ( error ) + goto Exit; + p->font->spacing = p->opts->font_spacing; + p->font->default_char = -1; + + goto Exit; + } + + /* Check for the start of the properties. */ + if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 ) + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 ); + + if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) + goto Exit; + + p->flags |= _BDF_PROPS; + *next = _bdf_parse_properties; + + goto Exit; + } + + /* Check for the FONTBOUNDINGBOX field. */ + if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) + { + if ( !(p->flags & _BDF_SIZE ) ) + { + /* Missing the SIZE field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); + error = BDF_Err_Missing_Size_Field; + goto Exit; + } + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); + p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); + + p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); + p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); + + p->font->bbx.ascent = (short)( p->font->bbx.height + + p->font->bbx.y_offset ); + + p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); + + p->flags |= _BDF_FONT_BBX; + + goto Exit; + } + + /* The next thing to check for is the FONT field. */ + if ( ft_memcmp( line, "FONT", 4 ) == 0 ) + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + _bdf_list_shift( &p->list, 1 ); + + s = _bdf_list_join( &p->list, ' ', &slen ); + + if ( !s ) + { + error = BDF_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) + goto Exit; + FT_MEM_COPY( p->font->name, s, slen + 1 ); + + /* If the font name is an XLFD name, set the spacing to the one in */ + /* the font name. If there is no spacing fall back on the default. */ + error = _bdf_set_default_spacing( p->font, p->opts ); + if ( error ) + goto Exit; + + p->flags |= _BDF_FONT_NAME; + + goto Exit; + } + + /* Check for the SIZE field. */ + if ( ft_memcmp( line, "SIZE", 4 ) == 0 ) + { + if ( !( p->flags & _BDF_FONT_NAME ) ) + { + /* Missing the FONT field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); + error = BDF_Err_Missing_Font_Field; + goto Exit; + } + + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + + p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 ); + p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 ); + p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 ); + + /* Check for the bits per pixel field. */ + if ( p->list.used == 5 ) + { + unsigned short bitcount, i, shift; + + + p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 ); + + /* Only values 1, 2, 4, 8 are allowed. */ + shift = p->font->bpp; + bitcount = 0; + for ( i = 0; shift > 0; i++ ) + { + if ( shift & 1 ) + bitcount = i; + shift >>= 1; + } + + shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) ); + + if ( p->font->bpp > shift || p->font->bpp != shift ) + { + /* select next higher value */ + p->font->bpp = (unsigned short)( shift << 1 ); + FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); + } + } + else + p->font->bpp = 1; + + p->flags |= _BDF_SIZE; + + goto Exit; + } + + error = BDF_Err_Invalid_File_Format; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* API. */ + /* */ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory extmemory, + bdf_options_t* opts, + bdf_font_t* *font ) + { + unsigned long lineno = 0; /* make compiler happy */ + _bdf_parse_t *p; + + FT_Memory memory = extmemory; + FT_Error error = BDF_Err_Ok; + + + if ( FT_NEW( p ) ) + goto Exit; + + memory = NULL; + p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); + p->minlb = 32767; + p->memory = extmemory; /* only during font creation */ + + _bdf_list_init( &p->list, extmemory ); + + error = _bdf_readstream( stream, _bdf_parse_start, + (void *)p, &lineno ); + if ( error ) + goto Fail; + + if ( p->font != 0 ) + { + /* If the font is not proportional, set the font's monowidth */ + /* field to the width of the font bounding box. */ + memory = p->font->memory; + + if ( p->font->spacing != BDF_PROPORTIONAL ) + p->font->monowidth = p->font->bbx.width; + + /* If the number of glyphs loaded is not that of the original count, */ + /* indicate the difference. */ + if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, + p->font->glyphs_used + p->font->unencoded_used )); + p->font->modified = 1; + } + + /* Once the font has been loaded, adjust the overall font metrics if */ + /* necessary. */ + if ( p->opts->correct_metrics != 0 && + ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) + { + if ( p->maxrb - p->minlb != p->font->bbx.width ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG3, + p->font->bbx.width, p->maxrb - p->minlb )); + p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); + p->font->modified = 1; + } + + if ( p->font->bbx.x_offset != p->minlb ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG4, + p->font->bbx.x_offset, p->minlb )); + p->font->bbx.x_offset = p->minlb; + p->font->modified = 1; + } + + if ( p->font->bbx.ascent != p->maxas ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG5, + p->font->bbx.ascent, p->maxas )); + p->font->bbx.ascent = p->maxas; + p->font->modified = 1; + } + + if ( p->font->bbx.descent != p->maxds ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG6, + p->font->bbx.descent, p->maxds )); + p->font->bbx.descent = p->maxds; + p->font->bbx.y_offset = (short)( -p->maxds ); + p->font->modified = 1; + } + + if ( p->maxas + p->maxds != p->font->bbx.height ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG7, + p->font->bbx.height, p->maxas + p->maxds )); + p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); + } + + if ( p->flags & _BDF_SWIDTH_ADJ ) + FT_TRACE2(( "bdf_load_font: " ACMSG8 )); + } + } + + if ( p->flags & _BDF_START ) + { + { + /* The ENDFONT field was never reached or did not exist. */ + if ( !( p->flags & _BDF_GLYPHS ) ) + { + /* Error happened while parsing header. */ + FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); + error = BDF_Err_Corrupted_Font_Header; + goto Exit; + } + else + { + /* Error happened when parsing glyphs. */ + FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); + error = BDF_Err_Corrupted_Font_Glyphs; + goto Exit; + } + } + } + + if ( p->font != 0 ) + { + /* Make sure the comments are NULL terminated if they exist. */ + memory = p->font->memory; + + if ( p->font->comments_len > 0 ) { + if ( FT_RENEW_ARRAY( p->font->comments, + p->font->comments_len, + p->font->comments_len + 1 ) ) + goto Fail; + + p->font->comments[p->font->comments_len] = 0; + } + } + else if ( error == BDF_Err_Ok ) + error = BDF_Err_Invalid_File_Format; + + *font = p->font; + + Exit: + if ( p ) + { + _bdf_list_done( &p->list ); + + memory = extmemory; + + FT_FREE( p ); + } + + return error; + + Fail: + bdf_free_font( p->font ); + + memory = extmemory; + + FT_FREE( p->font ); + + goto Exit; + } + + + FT_LOCAL_DEF( void ) + bdf_free_font( bdf_font_t* font ) + { + bdf_property_t* prop; + unsigned long i; + bdf_glyph_t* glyphs; + FT_Memory memory; + + + if ( font == 0 ) + return; + + memory = font->memory; + + FT_FREE( font->name ); + + /* Free up the internal hash table of property names. */ + if ( font->internal ) + { + hash_free( (hashtable *)font->internal, memory ); + FT_FREE( font->internal ); + } + + /* Free up the comment info. */ + FT_FREE( font->comments ); + + /* Free up the properties. */ + for ( i = 0; i < font->props_size; i++ ) + { + if ( font->props[i].format == BDF_ATOM ) + FT_FREE( font->props[i].value.atom ); + } + + FT_FREE( font->props ); + + /* Free up the character info. */ + for ( i = 0, glyphs = font->glyphs; + i < font->glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; + i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + FT_FREE( font->glyphs ); + FT_FREE( font->unencoded ); + + /* Free up the overflow storage if it was used. */ + for ( i = 0, glyphs = font->overflow.glyphs; + i < font->overflow.glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + FT_FREE( font->overflow.glyphs ); + + /* bdf_cleanup */ + hash_free( &(font->proptbl), memory ); + + /* Free up the user defined properties. */ + for (prop = font->user_props, i = 0; + i < font->nuser_props; i++, prop++ ) + { + FT_FREE( prop->name ); + if ( prop->format == BDF_ATOM ) + FT_FREE( prop->value.atom ); + } + + FT_FREE( font->user_props ); + + /* FREE( font ); */ /* XXX Fixme */ + } + + + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ) + { + hashnode hn; + + + if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) + return 0; + + hn = hash_lookup( name, (hashtable *)font->internal ); + + return hn ? ( font->props + (unsigned long)hn->data ) : 0; + } + + +/* END */ diff --git a/src/freetype2/cache/ftcache.c b/src/freetype2/cache/ftcache.c new file mode 100644 index 0000000..d41e91e --- /dev/null +++ b/src/freetype2/cache/ftcache.c @@ -0,0 +1,31 @@ +/***************************************************************************/ +/* */ +/* ftcache.c */ +/* */ +/* The FreeType Caching sub-system (body only). */ +/* */ +/* Copyright 2000-2001, 2003 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 +#include "ftcmru.c" +#include "ftcmanag.c" +#include "ftccache.c" +#include "ftccmap.c" +#include "ftcglyph.c" +#include "ftcimage.c" +#include "ftcsbits.c" +#include "ftcbasic.c" + +/* END */ diff --git a/src/freetype2/cache/ftcbasic.c b/src/freetype2/cache/ftcbasic.c new file mode 100644 index 0000000..a568b97 --- /dev/null +++ b/src/freetype2/cache/ftcbasic.c @@ -0,0 +1,811 @@ +/***************************************************************************/ +/* */ +/* ftcbasic.c */ +/* */ +/* The FreeType basic cache interface (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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_CACHE_H +#include "ftcglyph.h" +#include "ftcimage.h" +#include "ftcsbits.h" +#include FT_INTERNAL_MEMORY_H + +#include "ftccback.h" +#include "ftcerror.h" + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* + * These structures correspond to the FTC_Font and FTC_ImageDesc types + * that were defined in version 2.1.7. + */ + typedef struct FTC_OldFontRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_OldFontRec, *FTC_OldFont; + + + typedef struct FTC_OldImageDescRec_ + { + FTC_OldFontRec font; + FT_UInt32 flags; + + } FTC_OldImageDescRec, *FTC_OldImageDesc; + + + /* + * Notice that FTC_OldImageDescRec and FTC_ImageTypeRec are nearly + * identical, bit-wise. The only difference is that the `width' and + * `height' fields are expressed as 16-bit integers in the old structure, + * and as normal `int' in the new one. + * + * We are going to perform a weird hack to detect which structure is + * being passed to the image and sbit caches. If the new structure's + * `width' is larger than 0x10000, we assume that we are really receiving + * an FTC_OldImageDesc. + */ + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * Basic Families + * + */ + typedef struct FTC_BasicAttrRec_ + { + FTC_ScalerRec scaler; + FT_UInt load_flags; + + } FTC_BasicAttrRec, *FTC_BasicAttrs; + +#define FTC_BASIC_ATTR_COMPARE( a, b ) \ + FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \ + (a)->load_flags == (b)->load_flags ) + +#define FTC_BASIC_ATTR_HASH( a ) \ + ( FTC_SCALER_HASH( &(a)->scaler ) + 31*(a)->load_flags ) + + + typedef struct FTC_BasicQueryRec_ + { + FTC_GQueryRec gquery; + FTC_BasicAttrRec attrs; + + } FTC_BasicQueryRec, *FTC_BasicQuery; + + + typedef struct FTC_BasicFamilyRec_ + { + FTC_FamilyRec family; + FTC_BasicAttrRec attrs; + + } FTC_BasicFamilyRec, *FTC_BasicFamily; + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_family_compare( FTC_MruNode ftcfamily, + FT_Pointer ftcquery ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + + + return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_init( FTC_MruNode ftcfamily, + FT_Pointer ftcquery, + FT_Pointer ftccache ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + FTC_Cache cache = (FTC_Cache)ftccache; + + + FTC_Family_Init( FTC_FAMILY( family ), cache ); + family->attrs = query->attrs; + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ftc_basic_family_get_count( FTC_Family ftcfamily, + FTC_Manager manager ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Face face; + FT_UInt result = 0; + + + error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, + &face ); + if ( !error ) + result = face->num_glyphs; + + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_bitmap( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Size size; + + + error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); + if ( !error ) + { + FT_Face face = size->face; + + + error = FT_Load_Glyph( face, gindex, + family->attrs.load_flags | FT_LOAD_RENDER ); + if ( !error ) + *aface = face; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_glyph( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FTC_Scaler scaler = &family->attrs.scaler; + FT_Face face; + FT_Size size; + + + /* we will now load the glyph image */ + error = FTC_Manager_LookupSize( cache->manager, + scaler, + &size ); + if ( !error ) + { + face = size->face; + + error = FT_Load_Glyph( face, gindex, family->attrs.load_flags ); + if ( !error ) + { + if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || + face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if ( !error ) + { + *aglyph = glyph; + goto Exit; + } + } + else + error = FTC_Err_Invalid_Argument; + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, + FT_Pointer ftcface_id, + FTC_Cache cache ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; + FT_Bool result; + + + result = FT_BOOL( family->attrs.scaler.face_id == face_id ); + if ( result ) + { + /* we must call this function to avoid this node from appearing + * in later lookups with the same face_id! + */ + FTC_GNode_UnselectFamily( gnode, cache ); + } + return result; + } + + + /* + * + * basic image cache + * + */ + + FT_CALLBACK_TABLE_DEF + const FTC_IFamilyClassRec ftc_basic_image_family_class = + { + { + sizeof ( FTC_BasicFamilyRec ), + ftc_basic_family_compare, + ftc_basic_family_init, + 0, /* FTC_MruNode_ResetFunc */ + 0 /* FTC_MruNode_DoneFunc */ + }, + ftc_basic_family_load_glyph + }; + + + FT_CALLBACK_TABLE_DEF + const FTC_GCacheClassRec ftc_basic_image_cache_class = + { + { + ftc_inode_new, + ftc_inode_weight, + ftc_gnode_compare, + ftc_basic_gnode_compare_faceid, + ftc_inode_free, + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, + ftc_gcache_done + }, + (FTC_MruListClass)&ftc_basic_image_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_image_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FTC_BasicQueryRec query; + FTC_INode node = 0; /* make compiler happy */ + FT_Error error; + FT_UInt32 hash; + + + /* some argument checks are delayed to FTC_Cache_Lookup */ + if ( !aglyph ) + { + error = FTC_Err_Invalid_Argument; + goto Exit; + } + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* + * This one is a major hack used to detect whether we are passed a + * regular FTC_ImageType handle, or a legacy FTC_OldImageDesc one. + */ + if ( type->width >= 0x10000 ) + { + FTC_OldImageDesc desc = (FTC_OldImageDesc)type; + + + query.attrs.scaler.face_id = desc->font.face_id; + query.attrs.scaler.width = desc->font.pix_width; + query.attrs.scaler.height = desc->font.pix_height; + query.attrs.load_flags = desc->flags; + } + else + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + { + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = type->flags; + } + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + +#if 1 /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_GNode_Compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, gindex, + FTC_GQUERY( &query ), + (FTC_Node*) &node ); +#endif + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = FTC_NODE( node ); + FTC_NODE( node )->ref_count++; + } + } + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FTC_BasicQueryRec query; + FTC_INode node = 0; /* make compiler happy */ + FT_Error error; + FT_UInt32 hash; + + + /* some argument checks are delayed to FTC_Cache_Lookup */ + if ( !aglyph || !scaler ) + { + error = FTC_Err_Invalid_Argument; + goto Exit; + } + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = load_flags; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_GNode_Compare, + hash, gindex, + &query, + node, + error ); + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = FTC_NODE( node ); + FTC_NODE( node )->ref_count++; + } + } + + Exit: + return error; + } + + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* yet another backwards-legacy structure */ + typedef struct FTC_OldImage_Desc_ + { + FTC_FontRec font; + FT_UInt image_type; + + } FTC_OldImage_Desc; + + +#define FTC_OLD_IMAGE_FORMAT( x ) ( (x) & 7 ) + + +#define ftc_old_image_format_bitmap 0x0000 +#define ftc_old_image_format_outline 0x0001 + +#define ftc_old_image_format_mask 0x000F + +#define ftc_old_image_flag_monochrome 0x0010 +#define ftc_old_image_flag_unhinted 0x0020 +#define ftc_old_image_flag_autohinted 0x0040 +#define ftc_old_image_flag_unscaled 0x0080 +#define ftc_old_image_flag_no_sbits 0x0100 + + /* monochrome bitmap */ +#define ftc_old_image_mono ftc_old_image_format_bitmap | \ + ftc_old_image_flag_monochrome + + /* anti-aliased bitmap */ +#define ftc_old_image_grays ftc_old_image_format_bitmap + + /* scaled outline */ +#define ftc_old_image_outline ftc_old_image_format_outline + + + static void + ftc_image_type_from_old_desc( FTC_ImageType typ, + FTC_OldImage_Desc* desc ) + { + typ->face_id = desc->font.face_id; + typ->width = desc->font.pix_width; + typ->height = desc->font.pix_height; + + /* convert image type flags to load flags */ + { + FT_UInt load_flags = FT_LOAD_DEFAULT; + FT_UInt type = desc->image_type; + + + /* determine load flags, depending on the font description's */ + /* image type */ + + if ( FTC_OLD_IMAGE_FORMAT( type ) == ftc_old_image_format_bitmap ) + { + if ( type & ftc_old_image_flag_monochrome ) + load_flags |= FT_LOAD_MONOCHROME; + + /* disable embedded bitmaps loading if necessary */ + if ( type & ftc_old_image_flag_no_sbits ) + load_flags |= FT_LOAD_NO_BITMAP; + } + else + { + /* we want an outline, don't load embedded bitmaps */ + load_flags |= FT_LOAD_NO_BITMAP; + + if ( type & ftc_old_image_flag_unscaled ) + load_flags |= FT_LOAD_NO_SCALE; + } + + /* always render glyphs to bitmaps */ + load_flags |= FT_LOAD_RENDER; + + if ( type & ftc_old_image_flag_unhinted ) + load_flags |= FT_LOAD_NO_HINTING; + + if ( type & ftc_old_image_flag_autohinted ) + load_flags |= FT_LOAD_FORCE_AUTOHINT; + + typ->flags = load_flags; + } + } + + + FT_EXPORT( FT_Error ) + FTC_Image_Cache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + FT_EXPORT( FT_Error ) + FTC_Image_Cache_Lookup( FTC_ImageCache icache, + FTC_OldImage_Desc* desc, + FT_UInt gindex, + FT_Glyph *aglyph ); + + + FT_EXPORT_DEF( FT_Error ) + FTC_Image_Cache_New( FTC_Manager manager, + FTC_ImageCache *acache ) + { + return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache ); + } + + + + FT_EXPORT_DEF( FT_Error ) + FTC_Image_Cache_Lookup( FTC_ImageCache icache, + FTC_OldImage_Desc* desc, + FT_UInt gindex, + FT_Glyph *aglyph ) + { + FTC_ImageTypeRec type0; + + + if ( !desc ) + return FTC_Err_Invalid_Argument; + + ftc_image_type_from_old_desc( &type0, desc ); + + return FTC_ImageCache_Lookup( (FTC_ImageCache)icache, + &type0, + gindex, + aglyph, + NULL ); + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * + * basic small bitmap cache + * + */ + + + FT_CALLBACK_TABLE_DEF + const FTC_SFamilyClassRec ftc_basic_sbit_family_class = + { + { + sizeof( FTC_BasicFamilyRec ), + ftc_basic_family_compare, + ftc_basic_family_init, + 0, /* FTC_MruNode_ResetFunc */ + 0 /* FTC_MruNode_DoneFunc */ + }, + ftc_basic_family_get_count, + ftc_basic_family_load_bitmap + }; + + + FT_CALLBACK_TABLE_DEF + const FTC_GCacheClassRec ftc_basic_sbit_cache_class = + { + { + ftc_snode_new, + ftc_snode_weight, + ftc_snode_compare, + ftc_basic_gnode_compare_faceid, + ftc_snode_free, + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, + ftc_gcache_done + }, + (FTC_MruListClass)&ftc_basic_sbit_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_SNode node = 0; /* make compiler happy */ + FT_UInt32 hash; + + + if ( anode ) + *anode = NULL; + + /* other argument checks delayed to FTC_Cache_Lookup */ + if ( !ansbit ) + return FTC_Err_Invalid_Argument; + + *ansbit = NULL; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* This one is a major hack used to detect whether we are passed a + * regular FTC_ImageType handle, or a legacy FTC_OldImageDesc one. + */ + if ( type->width >= 0x10000 ) + { + FTC_OldImageDesc desc = (FTC_OldImageDesc)type; + + + query.attrs.scaler.face_id = desc->font.face_id; + query.attrs.scaler.width = desc->font.pix_width; + query.attrs.scaler.height = desc->font.pix_height; + query.attrs.load_flags = desc->flags; + } + else + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + { + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = type->flags; + } + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + +#if 1 /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_SNode_Compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, + gindex, + FTC_GQUERY( &query ), + (FTC_Node*)&node ); +#endif + if ( error ) + goto Exit; + + *ansbit = node->sbits + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = FTC_NODE( node ); + FTC_NODE( node )->ref_count++; + } + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_SNode node = 0; /* make compiler happy */ + FT_UInt32 hash; + + + if ( anode ) + *anode = NULL; + + /* other argument checks delayed to FTC_Cache_Lookup */ + if ( !ansbit || !scaler ) + return FTC_Err_Invalid_Argument; + + *ansbit = NULL; + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = load_flags; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_SNode_Compare, + hash, gindex, + &query, + node, + error ); + if ( error ) + goto Exit; + + *ansbit = node->sbits + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = FTC_NODE( node ); + FTC_NODE( node )->ref_count++; + } + + Exit: + return error; + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_EXPORT( FT_Error ) + FTC_SBit_Cache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + FT_EXPORT( FT_Error ) + FTC_SBit_Cache_Lookup( FTC_SBitCache cache, + FTC_OldImage_Desc* desc, + FT_UInt gindex, + FTC_SBit *ansbit ); + + + FT_EXPORT_DEF( FT_Error ) + FTC_SBit_Cache_New( FTC_Manager manager, + FTC_SBitCache *acache ) + { + return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache ); + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_SBit_Cache_Lookup( FTC_SBitCache cache, + FTC_OldImage_Desc* desc, + FT_UInt gindex, + FTC_SBit *ansbit ) + { + FTC_ImageTypeRec type0; + + + if ( !desc ) + return FT_Err_Invalid_Argument; + + ftc_image_type_from_old_desc( &type0, desc ); + + return FTC_SBitCache_Lookup( (FTC_SBitCache)cache, + &type0, + gindex, + ansbit, + NULL ); + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + +/* END */ diff --git a/src/freetype2/cache/ftccache.c b/src/freetype2/cache/ftccache.c new file mode 100644 index 0000000..f3e699c --- /dev/null +++ b/src/freetype2/cache/ftccache.c @@ -0,0 +1,592 @@ +/***************************************************************************/ +/* */ +/* ftccache.c */ +/* */ +/* The FreeType internal cache interface (body). */ +/* */ +/* Copyright 2000-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include "ftcmanag.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftccback.h" +#include "ftcerror.h" + + +#define FTC_HASH_MAX_LOAD 2 +#define FTC_HASH_MIN_LOAD 1 +#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) + +/* this one _must_ be a power of 2! */ +#define FTC_HASH_INITIAL_SIZE 8 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* add a new node to the head of the manager's circular MRU list */ + static void + ftc_node_mru_link( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Prepend( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes++; + } + + + /* remove a node from the manager's MRU list */ + static void + ftc_node_mru_unlink( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Remove( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes--; + } + + +#ifndef FTC_INLINE + + /* move a node to the head of the manager's MRU list */ + static void + ftc_node_mru_up( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, + (FTC_MruNode)node ); + } + +#endif /* !FTC_INLINE */ + + + /* Note that this function cannot fail. If we cannot re-size the + * buckets array appropriately, we simply degrade the hash table's + * performance! + */ + static void + ftc_cache_resize( FTC_Cache cache ) + { + for (;;) + { + FTC_Node node, *pnode; + FT_UInt p = cache->p; + FT_UInt mask = cache->mask; + FT_UInt count = mask + p + 1; /* number of buckets */ + + + /* do we need to shrink the buckets array? */ + if ( cache->slack < 0 ) + { + FTC_Node new_list = NULL; + + + /* try to expand the buckets array _before_ splitting + * the bucket lists + */ + if ( p >= mask ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't expand the array, leave immediately */ + if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) ) + break; + } + + /* split a single bucket */ + pnode = cache->buckets + p; + + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; + + if ( node->hash & ( mask + 1 ) ) + { + *pnode = node->link; + node->link = new_list; + new_list = node; + } + else + pnode = &node->link; + } + + cache->buckets[p + mask + 1] = new_list; + + cache->slack += FTC_HASH_MAX_LOAD; + + if ( p >= mask ) + { + cache->mask = 2 * mask + 1; + cache->p = 0; + } + else + cache->p = p + 1; + } + + /* do we need to expand the buckets array? */ + else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD ) + { + FT_UInt old_index = p + mask; + FTC_Node* pold; + + + if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) + break; + + if ( p == 0 ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't shrink the array, leave immediately */ + if ( FT_RENEW_ARRAY( cache->buckets, + ( mask + 1 ) * 2, mask + 1 ) ) + break; + + cache->mask >>= 1; + p = cache->mask; + } + else + p--; + + pnode = cache->buckets + p; + while ( *pnode ) + pnode = &(*pnode)->link; + + pold = cache->buckets + old_index; + *pnode = *pold; + *pold = NULL; + + cache->slack -= FTC_HASH_MAX_LOAD; + cache->p = p; + } + else /* the hash table is balanced */ + break; + } + } + + + /* remove a node from its cache's hash table */ + static void + ftc_node_hash_unlink( FTC_Node node0, + FTC_Cache cache ) + { + FTC_Node *pnode; + FT_UInt idx; + + + idx = (FT_UInt)( node0->hash & cache->mask ); + if ( idx < cache->p ) + idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) ); + + pnode = cache->buckets + idx; + + for (;;) + { + FTC_Node node = *pnode; + + + if ( node == NULL ) + { + FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" )); + return; + } + + if ( node == node0 ) + break; + + pnode = &(*pnode)->link; + } + + *pnode = node0->link; + node0->link = NULL; + + cache->slack++; + ftc_cache_resize( cache ); + } + + + /* add a node to the `top' of its cache's hash table */ + static void + ftc_node_hash_link( FTC_Node node, + FTC_Cache cache ) + { + FTC_Node *pnode; + FT_UInt idx; + + + idx = (FT_UInt)( node->hash & cache->mask ); + if ( idx < cache->p ) + idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) ); + + pnode = cache->buckets + idx; + + node->link = *pnode; + *pnode = node; + + cache->slack--; + ftc_cache_resize( cache ); + } + + + /* remove a node from the cache manager */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_BASE_DEF( void ) +#else + FT_LOCAL_DEF( void ) +#endif + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ) + { + FTC_Cache cache; + + +#ifdef FT_DEBUG_ERROR + /* find node's cache */ + if ( node->cache_index >= manager->num_caches ) + { + FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + cache = manager->caches[node->cache_index]; + +#ifdef FT_DEBUG_ERROR + if ( cache == NULL ) + { + FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* remove node from cache's hash table */ + ftc_node_hash_unlink( node, cache ); + + /* now finalize it */ + cache->clazz.node_free( node, cache ); + +#if 0 + /* check, just in case of general corruption :-) */ + if ( manager->num_nodes == 0 ) + FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n", + manager->num_nodes )); +#endif + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ABSTRACT CACHE CLASS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) + { + return ftc_cache_init( cache ); + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_cache_init( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + cache->p = 0; + cache->mask = FTC_HASH_INITIAL_SIZE - 1; + cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; + + (void)FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ); + return error; + } + + + static void + FTC_Cache_Clear( FTC_Cache cache ) + { + if ( cache ) + { + FTC_Manager manager = cache->manager; + FT_UFast i; + FT_UInt count; + + + count = cache->p + cache->mask + 1; + + for ( i = 0; i < count; i++ ) + { + FTC_Node *pnode = cache->buckets + i, next, node = *pnode; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* now finalize it */ + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + cache->clazz.node_free( node, cache ); + node = next; + } + cache->buckets[i] = NULL; + } + ftc_cache_resize( cache ); + } + } + + + FT_LOCAL_DEF( void ) + ftc_cache_done( FTC_Cache cache ) + { + if ( cache->memory ) + { + FT_Memory memory = cache->memory; + + + FTC_Cache_Clear( cache ); + + FT_FREE( cache->buckets ); + cache->mask = 0; + cache->p = 0; + cache->slack = 0; + + cache->memory = NULL; + } + } + + + FT_LOCAL_DEF( void ) + FTC_Cache_Done( FTC_Cache cache ) + { + ftc_cache_done( cache ); + } + + + static void + ftc_cache_add( FTC_Cache cache, + FT_UInt32 hash, + FTC_Node node ) + { + node->hash = hash; + node->cache_index = (FT_UInt16) cache->index; + node->ref_count = 0; + + ftc_node_hash_link( node, cache ); + ftc_node_mru_link( node, cache->manager ); + + { + FTC_Manager manager = cache->manager; + + + manager->cur_weight += cache->clazz.node_weight( node, cache ); + + if ( manager->cur_weight >= manager->max_weight ) + { + node->ref_count++; + FTC_Manager_Compress( manager ); + node->ref_count--; + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_Error error; + FTC_Node node; + + + /* + * We use the FTC_CACHE_TRYLOOP macros to support out-of-memory + * errors (OOM) correctly, i.e., by flushing the cache progressively + * in order to make more room. + */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = cache->clazz.node_new( &node, query, cache ); + } + FTC_CACHE_TRYLOOP_END(); + + if ( error ) + node = NULL; + else + { + /* don't assume that the cache has the same number of buckets, since + * our allocation request might have triggered global cache flushing + */ + ftc_cache_add( cache, hash, node ); + } + + *anode = node; + return error; + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_UFast idx; + FTC_Node* bucket; + FTC_Node* pnode; + FTC_Node node; + FT_Error error = 0; + + FTC_Node_CompareFunc compare = cache->clazz.node_compare; + + + if ( cache == NULL || anode == NULL ) + return FT_Err_Invalid_Argument; + + idx = hash & cache->mask; + if ( idx < cache->p ) + idx = hash & ( cache->mask * 2 + 1 ); + + bucket = cache->buckets + idx; + pnode = bucket; + for (;;) + { + node = *pnode; + if ( node == NULL ) + goto NewNode; + + if ( node->hash == hash && compare( node, query, cache ) ) + break; + + pnode = &node->link; + } + + if ( node != *bucket ) + { + *pnode = node->link; + node->link = *bucket; + *bucket = node; + } + + /* move to head of MRU list */ + { + FTC_Manager manager = cache->manager; + + + if ( node != manager->nodes_list ) + ftc_node_mru_up( node, manager ); + } + *anode = node; + return error; + + NewNode: + return FTC_Cache_NewNode( cache, hash, query, anode ); + } + +#endif /* !FTC_INLINE */ + + + FT_LOCAL_DEF( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ) + { + FT_UFast i, count; + FTC_Manager manager = cache->manager; + FTC_Node frees = NULL; + + + count = cache->p + cache->mask; + for ( i = 0; i < count; i++ ) + { + FTC_Node* bucket = cache->buckets + i; + FTC_Node* pnode = bucket; + + + for ( ;; ) + { + FTC_Node node = *pnode; + + + if ( node == NULL ) + break; + + if ( cache->clazz.node_remove_faceid( node, face_id, cache ) ) + { + *pnode = node->link; + node->link = frees; + frees = node; + } + else + pnode = &node->link; + } + } + + /* remove all nodes in the free list */ + while ( frees ) + { + FTC_Node node; + + + node = frees; + frees = node->link; + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + ftc_node_mru_unlink( node, manager ); + + cache->clazz.node_free( node, cache ); + + cache->slack++; + } + + ftc_cache_resize( cache ); + } + + +/* END */ diff --git a/src/freetype2/cache/ftccache.h b/src/freetype2/cache/ftccache.h new file mode 100644 index 0000000..8c0a7c9 --- /dev/null +++ b/src/freetype2/cache/ftccache.h @@ -0,0 +1,317 @@ +/***************************************************************************/ +/* */ +/* ftccache.h */ +/* */ +/* FreeType internal cache interface (specification). */ +/* */ +/* Copyright 2000-2001, 2002, 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 __FTCCACHE_H__ +#define __FTCCACHE_H__ + + +#include "ftcmru.h" + +FT_BEGIN_HEADER + + /* handle to cache object */ + typedef struct FTC_CacheRec_* FTC_Cache; + + /* handle to cache class */ + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Each cache controls one or more cache nodes. Each node is part of */ + /* the global_lru list of the manager. Its `data' field however is used */ + /* as a reference count for now. */ + /* */ + /* A node can be anything, depending on the type of information held by */ + /* the cache. It can be an individual glyph image, a set of bitmaps */ + /* glyphs for a given size, some metrics, etc. */ + /* */ + /*************************************************************************/ + + /* structure size should be 20 bytes on 32-bits machines */ + typedef struct FTC_NodeRec_ + { + FTC_MruNodeRec mru; /* circular mru list pointer */ + FTC_Node link; /* used for hashing */ + FT_UInt32 hash; /* used for hashing too */ + FT_UShort cache_index; /* index of cache the node belongs to */ + FT_Short ref_count; /* reference count for this node */ + + } FTC_NodeRec; + + +#define FTC_NODE( x ) ( (FTC_Node)(x) ) +#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) + +#define FTC_NODE__NEXT( x ) FTC_NODE( (x)->mru.next ) +#define FTC_NODE__PREV( x ) FTC_NODE( (x)->mru.prev ) + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_BASE( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* initialize a new cache node */ + typedef FT_Error + (*FTC_Node_NewFunc)( FTC_Node *pnode, + FT_Pointer query, + FTC_Cache cache ); + + typedef FT_ULong + (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); + + /* compare a node to a given key pair */ + typedef FT_Bool + (*FTC_Node_CompareFunc)( FTC_Node node, + FT_Pointer key, + FTC_Cache cache ); + + + typedef void + (*FTC_Node_FreeFunc)( FTC_Node node, + FTC_Cache cache ); + + typedef FT_Error + (*FTC_Cache_InitFunc)( FTC_Cache cache ); + + typedef void + (*FTC_Cache_DoneFunc)( FTC_Cache cache ); + + + typedef struct FTC_CacheClassRec_ + { + FTC_Node_NewFunc node_new; + FTC_Node_WeightFunc node_weight; + FTC_Node_CompareFunc node_compare; + FTC_Node_CompareFunc node_remove_faceid; + FTC_Node_FreeFunc node_free; + + FT_UInt cache_size; + FTC_Cache_InitFunc cache_init; + FTC_Cache_DoneFunc cache_done; + + } FTC_CacheClassRec; + + + /* each cache really implements a dynamic hash table to manage its nodes */ + typedef struct FTC_CacheRec_ + { + FT_UFast p; + FT_UFast mask; + FT_Long slack; + FTC_Node* buckets; + + FTC_CacheClassRec clazz; /* local copy, for speed */ + + FTC_Manager manager; + FT_Memory memory; + FT_UInt index; /* in manager's table */ + + FTC_CacheClass org_class; /* original class pointer */ + + } FTC_CacheRec; + + +#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) +#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) + + + /* default cache initialize */ + FT_LOCAL( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); + + /* default cache finalizer */ + FT_LOCAL( void ) + FTC_Cache_Done( FTC_Cache cache ); + + /* Call this function to lookup the cache. If no corresponding + * node is found, a new one is automatically created. This function + * is capable of flushing the cache adequately to make room for the + * new cache object. + */ + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); +#endif + + FT_LOCAL( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); + + /* Remove all nodes that relate to a given face_id. This is useful + * when un-installing fonts. Note that if a cache node relates to + * the face_id, but is locked (i.e., has `ref_count > 0'), the node + * will _not_ be destroyed, but its internal face_id reference will + * be modified. + * + * The final result will be that the node will never come back + * in further lookup requests, and will be flushed on demand from + * the cache normally when its reference count reaches 0. + */ + FT_LOCAL( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ); + + +#ifdef FTC_INLINE + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_Node *_bucket, *_pnode, _node; \ + FTC_Cache _cache = FTC_CACHE(cache); \ + FT_UInt32 _hash = (FT_UInt32)(hash); \ + FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ + FT_UInt _idx; \ + \ + \ + error = 0; \ + node = NULL; \ + _idx = _hash & _cache->mask; \ + if ( _idx < _cache->p ) \ + _idx = _hash & ( _cache->mask*2 + 1 ); \ + \ + _bucket = _pnode = _cache->buckets + _idx; \ + for (;;) \ + { \ + _node = *_pnode; \ + if ( _node == NULL ) \ + goto _NewNode; \ + \ + if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) ) \ + break; \ + \ + _pnode = &_node->link; \ + } \ + \ + if ( _node != *_bucket ) \ + { \ + *_pnode = _node->link; \ + _node->link = *_bucket; \ + *_bucket = _node; \ + } \ + \ + { \ + FTC_Manager _manager = _cache->manager; \ + void* _nl = &_manager->nodes_list; \ + \ + \ + if ( _node != _manager->nodes_list ) \ + FTC_MruNode_Up( (FTC_MruNode*)_nl, \ + (FTC_MruNode)_node ); \ + } \ + goto _Ok; \ + \ + _NewNode: \ + error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ + \ + _Ok: \ + _pnode = (FTC_Node*)(void*)&(node); \ + *_pnode = _node; \ + FT_END_STMNT + +#else /* !FTC_INLINE */ + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, \ + (FTC_Node*)&(node) ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + + /* + * This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry + * loop to flush the cache repeatedly in case of memory overflows. + * + * It is used when creating a new cache node, or within a lookup + * that needs to allocate data (e.g., the sbit cache lookup). + * + * Example: + * + * { + * FTC_CACHE_TRYLOOP( cache ) + * error = load_data( ... ); + * FTC_CACHE_TRYLOOP_END() + * } + * + */ +#define FTC_CACHE_TRYLOOP( cache ) \ + { \ + FTC_Manager _try_manager = FTC_CACHE( cache )->manager; \ + FT_UInt _try_count = 4; \ + \ + \ + for (;;) \ + { \ + FT_UInt _try_done; + + +#define FTC_CACHE_TRYLOOP_END() \ + if ( !error || error != FT_Err_Out_Of_Memory ) \ + break; \ + \ + _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \ + if ( _try_done == 0 ) \ + break; \ + \ + if ( _try_done == _try_count ) \ + { \ + _try_count *= 2; \ + if ( _try_count < _try_done || \ + _try_count > _try_manager->num_nodes ) \ + _try_count = _try_manager->num_nodes; \ + } \ + } \ + } + + /* */ + +FT_END_HEADER + + +#endif /* __FTCCACHE_H__ */ + + +/* END */ diff --git a/src/freetype2/cache/ftccback.h b/src/freetype2/cache/ftccback.h new file mode 100644 index 0000000..86e72a7 --- /dev/null +++ b/src/freetype2/cache/ftccback.h @@ -0,0 +1,90 @@ +/***************************************************************************/ +/* */ +/* ftccback.h */ +/* */ +/* Callback functions of the caching sub-system (specification only). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + +#ifndef __FTCCBACK_H__ +#define __FTCCBACK_H__ + +#include +#include FT_CACHE_H +#include "ftcmru.h" +#include "ftcimage.h" +#include "ftcmanag.h" +#include "ftcglyph.h" +#include "ftcsbits.h" + + + FT_LOCAL( void ) + ftc_inode_free( FTC_Node inode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_inode_new( FTC_Node *pinode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_ULong ) + ftc_inode_weight( FTC_Node inode, + FTC_Cache cache ); + + + FT_LOCAL( void ) + ftc_snode_free( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_snode_new( FTC_Node *psnode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_ULong ) + ftc_snode_weight( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Bool ) + ftc_snode_compare( FTC_Node snode, + FT_Pointer gquery, + FTC_Cache cache ); + + + FT_LOCAL( FT_Bool ) + ftc_gnode_compare( FTC_Node gnode, + FT_Pointer gquery, + FTC_Cache cache ); + + + FT_LOCAL( FT_Error ) + ftc_gcache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_gcache_done( FTC_Cache cache ); + + + FT_LOCAL( FT_Error ) + ftc_cache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_cache_done( FTC_Cache cache ); + +#ifndef FT_CONFIG_OPTION_OLD_INTERNALS + FT_LOCAL( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); +#endif + +#endif /* __FTCCBACK_H__ */ + +/* END */ diff --git a/src/freetype2/cache/ftccmap.c b/src/freetype2/cache/ftccmap.c new file mode 100644 index 0000000..aa59307 --- /dev/null +++ b/src/freetype2/cache/ftccmap.c @@ -0,0 +1,413 @@ +/***************************************************************************/ +/* */ +/* ftccmap.c */ +/* */ +/* FreeType CharMap cache (body) */ +/* */ +/* Copyright 2000-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_FREETYPE_H +#include FT_CACHE_H +#include "ftcmanag.h" +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_DEBUG_H +#include FT_TRUETYPE_IDS_H + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_cache + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + typedef enum FTC_OldCMapType_ + { + FTC_OLD_CMAP_BY_INDEX = 0, + FTC_OLD_CMAP_BY_ENCODING = 1, + FTC_OLD_CMAP_BY_ID = 2 + + } FTC_OldCMapType; + + + typedef struct FTC_OldCMapIdRec_ + { + FT_UInt platform; + FT_UInt encoding; + + } FTC_OldCMapIdRec, *FTC_OldCMapId; + + + typedef struct FTC_OldCMapDescRec_ + { + FTC_FaceID face_id; + FTC_OldCMapType type; + + union + { + FT_UInt index; + FT_Encoding encoding; + FTC_OldCMapIdRec id; + + } u; + + } FTC_OldCMapDescRec, *FTC_OldCMapDesc; + +#endif /* FT_CONFIG_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* Each FTC_CMapNode contains a simple array to map a range of character */ + /* codes to equivalent glyph indices. */ + /* */ + /* For now, the implementation is very basic: Each node maps a range of */ + /* 128 consecutive character codes to their corresponding glyph indices. */ + /* */ + /* We could do more complex things, but I don't think it is really very */ + /* useful. */ + /* */ + /*************************************************************************/ + + + /* number of glyph indices / character code per node */ +#define FTC_CMAP_INDICES_MAX 128 + + /* compute a query/node hash */ +#define FTC_CMAP_HASH( faceid, index, charcode ) \ + ( FTC_FACE_ID_HASH( faceid ) + 211 * ( index ) + \ + ( (char_code) / FTC_CMAP_INDICES_MAX ) ) + + /* the charmap query */ + typedef struct FTC_CMapQueryRec_ + { + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 char_code; + + } FTC_CMapQueryRec, *FTC_CMapQuery; + +#define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x)) +#define FTC_CMAP_QUERY_HASH( x ) \ + FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code ) + + /* the cmap cache node */ + typedef struct FTC_CMapNodeRec_ + { + FTC_NodeRec node; + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 first; /* first character in node */ + FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ + + } FTC_CMapNodeRec, *FTC_CMapNode; + +#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) +#define FTC_CMAP_NODE_HASH( x ) \ + FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first ) + + /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ + /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ +#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHARMAP NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( void ) + ftc_cmap_node_free( FTC_Node ftcnode, + FTC_Cache cache ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FT_Memory memory = cache->memory; + + + FT_FREE( node ); + } + + + /* initialize a new cmap node */ + FT_CALLBACK_DEF( FT_Error ) + ftc_cmap_node_new( FTC_Node *ftcanode, + FT_Pointer ftcquery, + FTC_Cache cache ) + { + FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_Error error; + FT_Memory memory = cache->memory; + FTC_CMapNode node; + FT_UInt nn; + + + if ( !FT_NEW( node ) ) + { + node->face_id = query->face_id; + node->cmap_index = query->cmap_index; + node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * + FTC_CMAP_INDICES_MAX; + + for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) + node->indices[nn] = FTC_CMAP_UNKNOWN; + } + + *anode = node; + return error; + } + + + /* compute the weight of a given cmap node */ + FT_CALLBACK_DEF( FT_ULong ) + ftc_cmap_node_weight( FTC_Node cnode, + FTC_Cache cache ) + { + FT_UNUSED( cnode ); + FT_UNUSED( cache ); + + return sizeof ( *cnode ); + } + + + /* compare a cmap node to a given query */ + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_compare( FTC_Node ftcnode, + FT_Pointer ftcquery, + FTC_Cache cache ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_UNUSED( cache ); + + + if ( node->face_id == query->face_id && + node->cmap_index == query->cmap_index ) + { + FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); + + + return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); + } + + return 0; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_remove_faceid( FTC_Node ftcnode, + FT_Pointer ftcface_id, + FTC_Cache cache ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FT_UNUSED( cache ); + + return FT_BOOL( node->face_id == face_id ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_TABLE_DEF + const FTC_CacheClassRec ftc_cmap_cache_class = + { + ftc_cmap_node_new, + ftc_cmap_node_weight, + ftc_cmap_node_compare, + ftc_cmap_node_remove_faceid, + ftc_cmap_node_free, + + sizeof ( FTC_CacheRec ), + ftc_cache_init, + ftc_cache_done, + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ) + { + return FTC_Manager_RegisterCache( manager, + &ftc_cmap_cache_class, + FTC_CACHE_P( acache ) ); + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* + * Unfortunately, it is not possible to support binary backwards + * compatibility in the cmap cache. The FTC_CMapCache_Lookup signature + * changes were too deep, and there is no clever hackish way to detect + * what kind of structure we are being passed. + * + * On the other hand it seems that no production code is using this + * function on Unix distributions. + */ + +#endif + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ) + { + FTC_Cache cache = FTC_CACHE( cmap_cache ); + FTC_CMapQueryRec query; + FTC_CMapNode node; + FT_Error error; + FT_UInt gindex = 0; + FT_UInt32 hash; + + + if ( !cache ) + { + FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); + return 0; + } + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* + * Detect a call from a rogue client that thinks it is linking + * to FreeType 2.1.7. This is possible because the third parameter + * is then a character code, and we have never seen any font with + * more than a few charmaps, so if the index is very large... + * + * It is also very unlikely that a rogue client is interested + * in Unicode values 0 to 15. + * + * NOTE: The original threshold was 4, but we found a font from the + * Adobe Acrobat Reader Pack, named `KozMinProVI-Regular.otf', + * which contains more than 5 charmaps. + */ + if ( cmap_index >= 16 ) + { + FTC_OldCMapDesc desc = (FTC_OldCMapDesc) face_id; + + + char_code = (FT_UInt32)cmap_index; + query.face_id = desc->face_id; + + + switch ( desc->type ) + { + case FTC_OLD_CMAP_BY_INDEX: + query.cmap_index = desc->u.index; + query.char_code = (FT_UInt32)cmap_index; + break; + + case FTC_OLD_CMAP_BY_ENCODING: + { + FT_Face face; + + + error = FTC_Manager_LookupFace( cache->manager, desc->face_id, + &face ); + if ( error ) + return 0; + + FT_Select_Charmap( face, desc->u.encoding ); + + return FT_Get_Char_Index( face, char_code ); + } + + default: + return 0; + } + } + else + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + { + query.face_id = face_id; + query.cmap_index = (FT_UInt)cmap_index; + query.char_code = char_code; + } + + hash = FTC_CMAP_HASH( face_id, cmap_index, char_code ); + +#if 1 + FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, + node, error ); +#else + error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node ); +#endif + if ( error ) + goto Exit; + + FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX ); + + /* something rotten can happen with rogue clients */ + if ( (FT_UInt)( char_code - node->first >= FTC_CMAP_INDICES_MAX ) ) + return 0; + + gindex = node->indices[char_code - node->first]; + if ( gindex == FTC_CMAP_UNKNOWN ) + { + FT_Face face; + + + gindex = 0; + + error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face ); + if ( error ) + goto Exit; + + if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) + { + FT_CharMap old, cmap = NULL; + + + old = face->charmap; + cmap = face->charmaps[cmap_index]; + + if ( old != cmap ) + FT_Set_Charmap( face, cmap ); + + gindex = FT_Get_Char_Index( face, char_code ); + + if ( old != cmap ) + FT_Set_Charmap( face, old ); + } + + node->indices[char_code - node->first] = (FT_UShort)gindex; + } + + Exit: + return gindex; + } + + +/* END */ diff --git a/src/freetype2/cache/ftcerror.h b/src/freetype2/cache/ftcerror.h new file mode 100644 index 0000000..5998d42 --- /dev/null +++ b/src/freetype2/cache/ftcerror.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* ftcerror.h */ +/* */ +/* Caching sub-system error codes (specification only). */ +/* */ +/* Copyright 2001 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 caching sub-system error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __FTCERROR_H__ +#define __FTCERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX FTC_Err_ +#define FT_ERR_BASE FT_Mod_Err_Cache + +#include FT_ERRORS_H + +#endif /* __FTCERROR_H__ */ + +/* END */ diff --git a/src/freetype2/cache/ftcglyph.c b/src/freetype2/cache/ftcglyph.c new file mode 100644 index 0000000..5c03abe --- /dev/null +++ b/src/freetype2/cache/ftcglyph.c @@ -0,0 +1,211 @@ +/***************************************************************************/ +/* */ +/* ftcglyph.c */ +/* */ +/* FreeType Glyph Image (FT_Glyph) cache (body). */ +/* */ +/* Copyright 2000-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_CACHE_H +#include "ftcglyph.h" +#include FT_ERRORS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftccback.h" +#include "ftcerror.h" + + + /* create a new chunk node, setting its cache index and ref count */ + FT_LOCAL_DEF( void ) + FTC_GNode_Init( FTC_GNode gnode, + FT_UInt gindex, + FTC_Family family ) + { + gnode->family = family; + gnode->gindex = gindex; + family->num_nodes++; + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ) + { + FTC_Family family = gnode->family; + + + gnode->family = NULL; + if ( family && --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, cache ); + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_Done( FTC_GNode gnode, + FTC_Cache cache ) + { + /* finalize the node */ + gnode->gindex = 0; + + FTC_GNode_UnselectFamily( gnode, cache ); + } + + + FT_LOCAL_DEF( FT_Bool ) + ftc_gnode_compare( FTC_Node ftcgnode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FT_UNUSED( cache ); + + + return FT_BOOL( gnode->family == gquery->family && + gnode->gindex == gquery->gindex ); + } + + + FT_LOCAL_DEF( FT_Bool ) + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ) + { + return ftc_gnode_compare( FTC_NODE( gnode ), gquery, NULL ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHUNK SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ) + { + FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS( cache ); + + + family->clazz = clazz->family_class; + family->num_nodes = 0; + family->cache = cache; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_gcache_init( FTC_Cache ftccache ) + { + FTC_GCache cache = (FTC_GCache)ftccache; + FT_Error error; + + + error = FTC_Cache_Init( FTC_CACHE( cache ) ); + if ( !error ) + { + FTC_GCacheClass clazz = (FTC_GCacheClass)FTC_CACHE( cache )->org_class; + + FTC_MruList_Init( &cache->families, + clazz->family_class, + 0, /* no maximum here! */ + cache, + FTC_CACHE( cache )->memory ); + } + + return error; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ) + { + return ftc_gcache_init( FTC_CACHE( cache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ftc_gcache_done( FTC_Cache ftccache ) + { + FTC_GCache cache = (FTC_GCache)ftccache; + + + FTC_Cache_Done( (FTC_Cache)cache ); + FTC_MruList_Done( &cache->families ); + } + + +#if 0 + + FT_LOCAL_DEF( void ) + FTC_GCache_Done( FTC_GCache cache ) + { + ftc_gcache_done( FTC_CACHE( cache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ) + { + return FTC_Manager_RegisterCache( manager, (FTC_CacheClass)clazz, + (FTC_Cache*)acache ); + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_UInt32 hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ) + { + FT_Error error; + + + query->gindex = gindex; + + FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error ); + if ( !error ) + { + FTC_Family family = query->family; + + + /* prevent the family from being destroyed too early when an */ + /* out-of-memory condition occurs during glyph node initialization. */ + family->num_nodes++; + + error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, anode ); + + if ( --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, cache ); + } + return error; + } + +#endif /* !FTC_INLINE */ + + +/* END */ diff --git a/src/freetype2/cache/ftcglyph.h b/src/freetype2/cache/ftcglyph.h new file mode 100644 index 0000000..87a4199 --- /dev/null +++ b/src/freetype2/cache/ftcglyph.h @@ -0,0 +1,322 @@ +/***************************************************************************/ +/* */ +/* ftcglyph.h */ +/* */ +/* FreeType abstract glyph cache (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2004, 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. */ +/* */ +/***************************************************************************/ + + + /* + * + * FTC_GCache is an _abstract_ cache object optimized to store glyph + * data. It works as follows: + * + * - It manages FTC_GNode objects. Each one of them can hold one or more + * glyph `items'. Item types are not specified in the FTC_GCache but + * in classes that extend it. + * + * - Glyph attributes, like face ID, character size, render mode, etc., + * can be grouped into abstract `glyph families'. This avoids storing + * the attributes within the FTC_GCache, since it is likely that many + * FTC_GNodes will belong to the same family in typical uses. + * + * - Each FTC_GNode is thus an FTC_Node with two additional fields: + * + * * gindex: A glyph index, or the first index in a glyph range. + * * family: A pointer to a glyph `family'. + * + * - Family types are not fully specific in the FTC_Family type, but + * by classes that extend it. + * + * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. + * They share an FTC_Family sub-class called FTC_BasicFamily which is + * used to store the following data: face ID, pixel/point sizes, load + * flags. For more details see the file `src/cache/ftcbasic.c'. + * + * Client applications can extend FTC_GNode with their own FTC_GNode + * and FTC_Family sub-classes to implement more complex caches (e.g., + * handling automatic synthesis, like obliquing & emboldening, colored + * glyphs, etc.). + * + * See also the FTC_ICache & FTC_SCache classes in `ftcimage.h' and + * `ftcsbits.h', which both extend FTC_GCache with additional + * optimizations. + * + * A typical FTC_GCache implementation must provide at least the + * following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: + * my_node_new (must call FTC_GNode_Init) + * my_node_free (must call FTC_GNode_Done) + * my_node_compare (must call FTC_GNode_Compare) + * my_node_remove_faceid (must call ftc_gnode_unselect in case + * of match) + * + * - FTC_Family sub-class, e.g. MyFamily, with relevant methods: + * my_family_compare + * my_family_init + * my_family_reset (optional) + * my_family_done + * + * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query + * data. + * + * - Constant structures for a FTC_GNodeClass. + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New. + * + * - MyCacheLookup with a call to FTC_GCache_Lookup. This function will + * automatically: + * + * - Search for the corresponding family in the cache, or create + * a new one if necessary. Put it in FTC_GQUERY(myquery).family + * + * - Call FTC_Cache_Lookup. + * + * If it returns NULL, you should create a new node, then call + * ftc_cache_add as usual. + */ + + + /*************************************************************************/ + /* */ + /* Important: The functions defined in this file are only used to */ + /* implement an abstract glyph cache class. You need to */ + /* provide additional logic to implement a complete cache. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTCGLYPH_H__ +#define __FTCGLYPH_H__ + + +#include +#include "ftcmanag.h" + + +FT_BEGIN_HEADER + + + /* + * We can group glyphs into `families'. Each family correspond to a + * given face ID, character size, transform, etc. + * + * Families are implemented as MRU list nodes. They are + * reference-counted. + */ + + typedef struct FTC_FamilyRec_ + { + FTC_MruNodeRec mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_Cache cache; + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; + +#define FTC_FAMILY(x) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) + + + typedef struct FTC_GNodeRec_ + { + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; + + } FTC_GNodeRec, *FTC_GNode; + +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) + + + typedef struct FTC_GQueryRec_ + { + FT_UInt gindex; + FTC_Family family; + + } FTC_GQueryRec, *FTC_GQuery; + +#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) + + + /*************************************************************************/ + /* */ + /* These functions are exported so that they can be called from */ + /* user-provided cache classes; otherwise, they are really part of the */ + /* cache sub-system internals. */ + /* */ + + /* must be called by derived FTC_Node_InitFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Init( FTC_GNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_Family family ); + + /* returns TRUE iff the query's glyph index correspond to the node; */ + /* this assumes that the `family' and `hash' fields of the query are */ + /* already correctly set */ + FT_LOCAL( FT_Bool ) + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ); + + /* call this function to clear a node's family -- this is necessary */ + /* to implement the `node_remove_faceid' cache method correctly */ + FT_LOCAL( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ); + + /* must be called by derived FTC_Node_DoneFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + FT_LOCAL( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ); + + typedef struct FTC_GCacheRec_ + { + FTC_CacheRec cache; + FTC_MruListRec families; + + } FTC_GCacheRec, *FTC_GCache; + +#define FTC_GCACHE( x ) ((FTC_GCache)(x)) + + +#if 0 + /* can be used as @FTC_Cache_InitFunc */ + FT_LOCAL( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ); +#endif + + +#if 0 + /* can be used as @FTC_Cache_DoneFunc */ + FT_LOCAL( void ) + FTC_GCache_Done( FTC_GCache cache ); +#endif + + + /* the glyph cache class adds fields for the family implementation */ + typedef struct FTC_GCacheClassRec_ + { + FTC_CacheClassRec clazz; + FTC_MruListClass family_class; + + } FTC_GCacheClassRec; + + typedef const FTC_GCacheClassRec* FTC_GCacheClass; + +#define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x)) + +#define FTC_CACHE__GCACHE_CLASS( x ) \ + FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class ) +#define FTC_CACHE__FAMILY_CLASS( x ) \ + ( (FTC_MruListClass)FTC_CACHE__GCACHE_CLASS( x )->family_class ) + + + /* convenience function; use it instead of FTC_Manager_Register_Cache */ + FT_LOCAL( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ); + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_UInt32 hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ); +#endif + + + /* */ + + +#define FTC_FAMILY_FREE( family, cache ) \ + FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \ + (FTC_MruNode)(family) ) + + +#ifdef FTC_INLINE + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_GCache _gcache = FTC_GCACHE( cache ); \ + FTC_GQuery _gquery = (FTC_GQuery)( query ); \ + FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ + \ + \ + _gquery->gindex = (gindex); \ + \ + FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ + _gquery->family, error ); \ + if ( !error ) \ + { \ + FTC_Family _gqfamily = _gquery->family; \ + \ + \ + _gqfamily->num_nodes++; \ + \ + FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ + \ + if ( --_gqfamily->num_nodes == 0 ) \ + FTC_FAMILY_FREE( _gqfamily, _gcache ); \ + } \ + FT_END_STMNT + /* */ + +#else /* !FTC_INLINE */ + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + void* _n = &(node); \ + \ + \ + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, \ + FTC_GQUERY( query ), (FTC_Node*)_n ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + +FT_END_HEADER + + +#endif /* __FTCGLYPH_H__ */ + + +/* END */ diff --git a/src/freetype2/cache/ftcimage.c b/src/freetype2/cache/ftcimage.c new file mode 100644 index 0000000..15d4e80 --- /dev/null +++ b/src/freetype2/cache/ftcimage.c @@ -0,0 +1,163 @@ +/***************************************************************************/ +/* */ +/* ftcimage.c */ +/* */ +/* FreeType Image cache (body). */ +/* */ +/* Copyright 2000-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_CACHE_H +#include "ftcimage.h" +#include FT_INTERNAL_MEMORY_H + +#include "ftccback.h" +#include "ftcerror.h" + + + /* finalize a given glyph image node */ + FT_LOCAL_DEF( void ) + ftc_inode_free( FTC_Node ftcinode, + FTC_Cache cache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_Memory memory = cache->memory; + + + if ( inode->glyph ) + { + FT_Done_Glyph( inode->glyph ); + inode->glyph = NULL; + } + + FTC_GNode_Done( FTC_GNODE( inode ), cache ); + FT_FREE( inode ); + } + + + FT_LOCAL_DEF( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ) + { + ftc_inode_free( FTC_NODE( inode ), cache ); + } + + + /* initialize a new glyph image node */ + FT_LOCAL_DEF( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_INode inode; + + + if ( !FT_NEW( inode ) ) + { + FTC_GNode gnode = FTC_GNODE( inode ); + FTC_Family family = gquery->family; + FT_UInt gindex = gquery->gindex; + FTC_IFamilyClass clazz = FTC_CACHE__IFAMILY_CLASS( cache ); + + + /* initialize its inner fields */ + FTC_GNode_Init( gnode, gindex, family ); + + /* we will now load the glyph image */ + error = clazz->family_load_glyph( family, gindex, cache, + &inode->glyph ); + if ( error ) + { + FTC_INode_Free( inode, cache ); + inode = NULL; + } + } + + *pinode = inode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_inode_new( FTC_Node *ftcpinode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_INode *pinode = (FTC_INode*)ftcpinode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_INode_New( pinode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_ULong ) + ftc_inode_weight( FTC_Node ftcinode, + FTC_Cache ftccache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_ULong size = 0; + FT_Glyph glyph = inode->glyph; + + FT_UNUSED( ftccache ); + + + switch ( glyph->format ) + { + case FT_GLYPH_FORMAT_BITMAP: + { + FT_BitmapGlyph bitg; + + + bitg = (FT_BitmapGlyph)glyph; + size = bitg->bitmap.rows * ft_labs( bitg->bitmap.pitch ) + + sizeof ( *bitg ); + } + break; + + case FT_GLYPH_FORMAT_OUTLINE: + { + FT_OutlineGlyph outg; + + + outg = (FT_OutlineGlyph)glyph; + size = outg->outline.n_points * + ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + + outg->outline.n_contours * sizeof ( FT_Short ) + + sizeof ( *outg ); + } + break; + + default: + ; + } + + size += sizeof ( *inode ); + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ) + { + return ftc_inode_weight( FTC_NODE( inode ), NULL ); + } + +#endif /* 0 */ + + +/* END */ diff --git a/src/freetype2/cache/ftcimage.h b/src/freetype2/cache/ftcimage.h new file mode 100644 index 0000000..20d5d3e --- /dev/null +++ b/src/freetype2/cache/ftcimage.h @@ -0,0 +1,107 @@ +/***************************************************************************/ +/* */ +/* ftcimage.h */ +/* */ +/* FreeType Generic Image cache (specification) */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /* + * FTC_ICache is an _abstract_ cache used to store a single FT_Glyph + * image per cache node. + * + * FTC_ICache extends FTC_GCache. For an implementation example, + * see FTC_ImageCache in `src/cache/ftbasic.c'. + */ + + + /*************************************************************************/ + /* */ + /* Each image cache really manages FT_Glyph objects. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCIMAGE_H__ +#define __FTCIMAGE_H__ + + +#include +#include FT_CACHE_H +#include "ftcglyph.h" + +FT_BEGIN_HEADER + + + /* the FT_Glyph image node type - we store only 1 glyph per node */ + typedef struct FTC_INodeRec_ + { + FTC_GNodeRec gnode; + FT_Glyph glyph; + + } FTC_INodeRec, *FTC_INode; + +#define FTC_INODE( x ) ( (FTC_INode)( x ) ) +#define FTC_INODE_GINDEX( x ) FTC_GNODE(x)->gindex +#define FTC_INODE_FAMILY( x ) FTC_GNODE(x)->family + + typedef FT_Error + (*FTC_IFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ); + + typedef struct FTC_IFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_IFamily_LoadGlyphFunc family_load_glyph; + + } FTC_IFamilyClassRec; + + typedef const FTC_IFamilyClassRec* FTC_IFamilyClass; + +#define FTC_IFAMILY_CLASS( x ) ((FTC_IFamilyClass)(x)) + +#define FTC_CACHE__IFAMILY_CLASS( x ) \ + FTC_IFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class ) + + + /* can be used as a @FTC_Node_FreeFunc */ + FT_LOCAL( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ); + + /* Can be used as @FTC_Node_NewFunc. `gquery.index' and `gquery.family' + * must be set correctly. This function will call the `family_load_glyph' + * method to load the FT_Glyph into the cache node. + */ + FT_LOCAL( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + /* can be used as @FTC_Node_WeightFunc */ + FT_LOCAL( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ); +#endif + + + /* */ + +FT_END_HEADER + +#endif /* __FTCIMAGE_H__ */ + + +/* END */ diff --git a/src/freetype2/cache/ftcmanag.c b/src/freetype2/cache/ftcmanag.c new file mode 100644 index 0000000..9d7347c --- /dev/null +++ b/src/freetype2/cache/ftcmanag.c @@ -0,0 +1,732 @@ +/***************************************************************************/ +/* */ +/* ftcmanag.c */ +/* */ +/* FreeType Cache Manager (body). */ +/* */ +/* Copyright 2000-2001, 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 +#include FT_CACHE_H +#include "ftcmanag.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_SIZES_H + +#include "ftccback.h" +#include "ftcerror.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_cache + +#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data ) + + + static FT_Error + ftc_scaler_lookup_size( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Face face; + FT_Size size = NULL; + FT_Error error; + + + error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); + if ( error ) + goto Exit; + + error = FT_New_Size( face, &size ); + if ( error ) + goto Exit; + + FT_Activate_Size( size ); + + if ( scaler->pixel ) + error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); + else + error = FT_Set_Char_Size( face, scaler->width, scaler->height, + scaler->x_res, scaler->y_res ); + if ( error ) + { + FT_Done_Size( size ); + size = NULL; + } + + Exit: + *asize = size; + return error; + } + + + typedef struct FTC_SizeNodeRec_ + { + FTC_MruNodeRec node; + FT_Size size; + FTC_ScalerRec scaler; + + } FTC_SizeNodeRec, *FTC_SizeNode; + + + FT_CALLBACK_DEF( void ) + ftc_size_node_done( FTC_MruNode ftcnode, + FT_Pointer data ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FT_Size size = node->size; + FT_UNUSED( data ); + + + if ( size ) + FT_Done_Size( size ); + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_size_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcscaler ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Scaler scaler0 = &node->scaler; + + + if ( FTC_SCALER_COMPARE( scaler0, scaler ) ) + { + FT_Activate_Size( node->size ); + return 1; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcscaler, + FT_Pointer ftcmanager ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_reset( FTC_MruNode ftcnode, + FT_Pointer ftcscaler, + FT_Pointer ftcmanager ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + FT_Done_Size( node->size ); + + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + FT_CALLBACK_TABLE_DEF + const FTC_MruListClassRec ftc_size_list_class = + { + sizeof ( FTC_SizeNodeRec ), + ftc_size_node_compare, + ftc_size_node_init, + ftc_size_node_reset, + ftc_size_node_done + }; + + + /* helper function used by ftc_face_node_done */ + static FT_Bool + ftc_size_node_compare_faceid( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->scaler.face_id == face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Error error; + FTC_SizeNode node; + + + if ( asize == NULL ) + return FTC_Err_Bad_Argument; + + *asize = NULL; + + if ( !manager ) + return FTC_Err_Invalid_Cache_Handle; + +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare, + node, error ); + +#else + error = FTC_MruList_Lookup( &manager->sizes, scaler, (FTC_MruNode*)&node ); +#endif + + if ( !error ) + *asize = node->size; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE MRU IMPLEMENTATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct FTC_FaceNodeRec_ + { + FTC_MruNodeRec node; + FTC_FaceID face_id; + FT_Face face; + + } FTC_FaceNodeRec, *FTC_FaceNode; + + + FT_CALLBACK_DEF( FT_Error ) + ftc_face_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcface_id, + FT_Pointer ftcmanager ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_Manager manager = (FTC_Manager)ftcmanager; + FT_Error error; + + + node->face_id = face_id; + + error = manager->request_face( face_id, + manager->library, + manager->request_data, + &node->face ); + if ( !error ) + { + /* destroy initial size object; it will be re-created later */ + if ( node->face->size ) + FT_Done_Size( node->face->size ); + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + ftc_face_node_done( FTC_MruNode ftcnode, + FT_Pointer ftcmanager ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + /* we must begin by removing all scalers for the target face */ + /* from the manager's list */ + FTC_MruList_RemoveSelection( &manager->sizes, + ftc_size_node_compare_faceid, + node->face_id ); + + /* all right, we can discard the face now */ + FT_Done_Face( node->face ); + node->face = NULL; + node->face_id = NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_face_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->face_id == face_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FTC_MruListClassRec ftc_face_list_class = + { + sizeof ( FTC_FaceNodeRec), + + ftc_face_node_compare, + ftc_face_node_init, + 0, /* FTC_MruNode_ResetFunc */ + ftc_face_node_done + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + FT_Error error; + FTC_FaceNode node; + + + if ( aface == NULL ) + return FTC_Err_Bad_Argument; + + *aface = NULL; + + if ( !manager ) + return FTC_Err_Invalid_Cache_Handle; + + /* we break encapsulation for the sake of speed */ +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare, + node, error ); + +#else + error = FTC_MruList_Lookup( &manager->faces, face_id, (FTC_MruNode*)&node ); +#endif + + if ( !error ) + *aface = node->face; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ) + { + FT_Error error; + FT_Memory memory; + FTC_Manager manager = 0; + + + if ( !library ) + return FTC_Err_Invalid_Library_Handle; + + memory = library->memory; + + if ( FT_NEW( manager ) ) + goto Exit; + + if ( max_faces == 0 ) + max_faces = FTC_MAX_FACES_DEFAULT; + + if ( max_sizes == 0 ) + max_sizes = FTC_MAX_SIZES_DEFAULT; + + if ( max_bytes == 0 ) + max_bytes = FTC_MAX_BYTES_DEFAULT; + + manager->library = library; + manager->memory = memory; + manager->max_weight = max_bytes; + + manager->request_face = requester; + manager->request_data = req_data; + + FTC_MruList_Init( &manager->faces, + &ftc_face_list_class, + max_faces, + manager, + memory ); + + FTC_MruList_Init( &manager->sizes, + &ftc_size_list_class, + max_sizes, + manager, + memory ); + + *amanager = manager; + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Done( FTC_Manager manager ) + { + FT_Memory memory; + FT_UInt idx; + + + if ( !manager || !manager->library ) + return; + + memory = manager->memory; + + /* now discard all caches */ + for (idx = manager->num_caches; idx-- > 0; ) + { + FTC_Cache cache = manager->caches[idx]; + + + if ( cache ) + { + cache->clazz.cache_done( cache ); + FT_FREE( cache ); + manager->caches[idx] = NULL; + } + } + manager->num_caches = 0; + + /* discard faces and sizes */ + FTC_MruList_Done( &manager->sizes ); + FTC_MruList_Done( &manager->faces ); + + manager->library = NULL; + manager->memory = NULL; + + FT_FREE( manager ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Reset( FTC_Manager manager ) + { + if ( manager ) + { + FTC_MruList_Reset( &manager->sizes ); + FTC_MruList_Reset( &manager->faces ); + } + /* XXX: FIXME: flush the caches? */ + } + + +#ifdef FT_DEBUG_ERROR + + static void + FTC_Manager_Check( FTC_Manager manager ) + { + FTC_Node node, first; + + + first = manager->nodes_list; + + /* check node weights */ + if ( first ) + { + FT_ULong weight = 0; + + + node = first; + + do + { + FTC_Cache cache = manager->caches[node->cache_index]; + + + if ( (FT_UInt)node->cache_index >= manager->num_caches ) + FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n", + node->cache_index )); + else + weight += cache->clazz.node_weight( node, cache ); + + node = FTC_NODE__NEXT( node ); + + } while ( node != first ); + + if ( weight != manager->cur_weight ) + FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", + manager->cur_weight, weight )); + } + + /* check circular list */ + if ( first ) + { + FT_UFast count = 0; + + + node = first; + do + { + count++; + node = FTC_NODE__NEXT( node ); + + } while ( node != first ); + + if ( count != manager->num_nodes ) + FT_ERROR(( + "FTC_Manager_Check: invalid cache node count %d instead of %d\n", + manager->num_nodes, count )); + } + } + +#endif /* FT_DEBUG_ERROR */ + + + /* `Compress' the manager's data, i.e., get rid of old cache nodes */ + /* that are not referenced anymore in order to limit the total */ + /* memory used by the cache. */ + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( void ) + FTC_Manager_Compress( FTC_Manager manager ) + { + FTC_Node node, first; + + + if ( !manager ) + return; + + first = manager->nodes_list; + +#ifdef FT_DEBUG_ERROR + FTC_Manager_Check( manager ); + + FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n", + manager->cur_weight, manager->max_weight, + manager->num_nodes )); +#endif + + if ( manager->cur_weight < manager->max_weight || first == NULL ) + return; + + /* go to last node -- it's a circular list */ + node = FTC_NODE__PREV( first ); + do + { + FTC_Node prev; + + + prev = ( node == first ) ? NULL : FTC_NODE__PREV( node ); + + if ( node->ref_count <= 0 ) + ftc_node_destroy( node, manager ); + + node = prev; + + } while ( node && manager->cur_weight > manager->max_weight ); + } + + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ) + { + FT_Error error = FTC_Err_Invalid_Argument; + FTC_Cache cache = NULL; + + + if ( manager && clazz && acache ) + { + FT_Memory memory = manager->memory; + + + if ( manager->num_caches >= FTC_MAX_CACHES ) + { + error = FTC_Err_Too_Many_Caches; + FT_ERROR(( "%s: too many registered caches\n", + "FTC_Manager_Register_Cache" )); + goto Exit; + } + + if ( !FT_ALLOC( cache, clazz->cache_size ) ) + { + cache->manager = manager; + cache->memory = memory; + cache->clazz = clazz[0]; + cache->org_class = clazz; + + /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ + /* IF IT IS NOT SET CORRECTLY */ + cache->index = manager->num_caches; + + error = clazz->cache_init( cache ); + if ( error ) + { + clazz->cache_done( cache ); + FT_FREE( cache ); + goto Exit; + } + + manager->caches[manager->num_caches++] = cache; + } + } + + Exit: + *acache = cache; + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ) + { + FTC_Node first = manager->nodes_list; + FTC_Node node; + FT_UInt result; + + + /* try to remove `count' nodes from the list */ + if ( first == NULL ) /* empty list! */ + return 0; + + /* go to last node - it's a circular list */ + node = FTC_NODE__PREV(first); + for ( result = 0; result < count; ) + { + FTC_Node prev = FTC_NODE__PREV( node ); + + + /* don't touch locked nodes */ + if ( node->ref_count <= 0 ) + { + ftc_node_destroy( node, manager ); + result++; + } + + if ( node == first ) + break; + + node = prev; + } + return result; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ) + { + FT_UInt nn; + + /* this will remove all FTC_SizeNode that correspond to + * the face_id as well + */ + FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id ); + + for ( nn = 0; nn < manager->num_caches; nn++ ) + FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ) + { + if ( node && (FT_UInt)node->cache_index < manager->num_caches ) + node->ref_count--; + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + return FTC_Manager_LookupFace( manager, face_id, aface ); + } + + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_Font font, + FT_Face *aface, + FT_Size *asize ) + { + FTC_ScalerRec scaler; + FT_Error error; + FT_Size size; + FT_Face face; + + + scaler.face_id = font->face_id; + scaler.width = font->pix_width; + scaler.height = font->pix_height; + scaler.pixel = TRUE; + scaler.x_res = 0; + scaler.y_res = 0; + + error = FTC_Manager_LookupSize( manager, &scaler, &size ); + if ( error ) + { + face = NULL; + size = NULL; + } + else + face = size->face; + + if ( aface ) + *aface = face; + + if ( asize ) + *asize = size; + + return error; + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + +/* END */ diff --git a/src/freetype2/cache/ftcmanag.h b/src/freetype2/cache/ftcmanag.h new file mode 100644 index 0000000..3fdc2c7 --- /dev/null +++ b/src/freetype2/cache/ftcmanag.h @@ -0,0 +1,175 @@ +/***************************************************************************/ +/* */ +/* ftcmanag.h */ +/* */ +/* FreeType Cache Manager (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* A cache manager is in charge of the following: */ + /* */ + /* - Maintain a mapping between generic FTC_FaceIDs and live FT_Face */ + /* objects. The mapping itself is performed through a user-provided */ + /* callback. However, the manager maintains a small cache of FT_Face */ + /* and FT_Size objects in order to speed up things considerably. */ + /* */ + /* - Manage one or more cache objects. Each cache is in charge of */ + /* holding a varying number of `cache nodes'. Each cache node */ + /* represents a minimal amount of individually accessible cached */ + /* data. For example, a cache node can be an FT_Glyph image */ + /* containing a vector outline, or some glyph metrics, or anything */ + /* else. */ + /* */ + /* Each cache node has a certain size in bytes that is added to the */ + /* total amount of `cache memory' within the manager. */ + /* */ + /* All cache nodes are located in a global LRU list, where the oldest */ + /* node is at the tail of the list. */ + /* */ + /* Each node belongs to a single cache, and includes a reference */ + /* count to avoid destroying it (due to caching). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTCMANAG_H__ +#define __FTCMANAG_H__ + + +#include +#include FT_CACHE_H +#include "ftcmru.h" +#include "ftccache.h" + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /*
*/ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + +#define FTC_MAX_FACES_DEFAULT 2 +#define FTC_MAX_SIZES_DEFAULT 4 +#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */ + + /* maximum number of caches registered in a single manager */ +#define FTC_MAX_CACHES 16 + + + typedef struct FTC_ManagerRec_ + { + FT_Library library; + FT_Memory memory; + + FTC_Node nodes_list; + FT_ULong max_weight; + FT_ULong cur_weight; + FT_UInt num_nodes; + + FTC_Cache caches[FTC_MAX_CACHES]; + FT_UInt num_caches; + + FTC_MruListRec faces; + FTC_MruListRec sizes; + + FT_Pointer request_data; + FTC_Face_Requester request_face; + + } FTC_ManagerRec; + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_Manager_Compress */ + /* */ + /* */ + /* This function is used to check the state of the cache manager if */ + /* its `num_bytes' field is greater than its `max_bytes' field. It */ + /* will flush as many old cache nodes as possible (ignoring cache */ + /* nodes with a non-zero reference count). */ + /* */ + /* */ + /* manager :: A handle to the cache manager. */ + /* */ + /* */ + /* Client applications should not call this function directly. It is */ + /* normally invoked by specific cache implementations. */ + /* */ + /* The reason this function is exported is to allow client-specific */ + /* cache classes. */ + /* */ + FT_LOCAL( void ) + FTC_Manager_Compress( FTC_Manager manager ); + + + /* try to flush `count' old nodes from the cache; return the number + * of really flushed nodes + */ + FT_LOCAL( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ); + + + /* this must be used internally for the moment */ + FT_LOCAL( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ); + + /* */ + +#define FTC_SCALER_COMPARE( a, b ) \ + ( (a)->face_id == (b)->face_id && \ + (a)->width == (b)->width && \ + (a)->height == (b)->height && \ + ((a)->pixel != 0) == ((b)->pixel != 0) && \ + ( (a)->pixel || \ + ( (a)->x_res == (b)->x_res && \ + (a)->y_res == (b)->y_res ) ) ) + +#define FTC_SCALER_HASH( q ) \ + ( FTC_FACE_ID_HASH( (q)->face_id ) + \ + (q)->width + (q)->height*7 + \ + ( (q)->pixel ? 0 : ( (q)->x_res*33 ^ (q)->y_res*61 ) ) ) + + /* */ + +FT_END_HEADER + +#endif /* __FTCMANAG_H__ */ + + +/* END */ diff --git a/src/freetype2/cache/ftcmru.c b/src/freetype2/cache/ftcmru.c new file mode 100644 index 0000000..3a6c625 --- /dev/null +++ b/src/freetype2/cache/ftcmru.c @@ -0,0 +1,357 @@ +/***************************************************************************/ +/* */ +/* ftcmru.c */ +/* */ +/* FreeType MRU support (body). */ +/* */ +/* Copyright 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_CACHE_H +#include "ftcmru.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftcerror.h" + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + if ( first ) + { + FTC_MruNode last = first->prev; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + { + fprintf( stderr, "FTC_MruNode_Prepend: invalid action!\n" ); + exit( 2 ); + } + cnode = cnode->next; + + } while ( cnode != first ); + } +#endif + + first->prev = node; + last->next = node; + node->next = first; + node->prev = last; + } + else + { + node->next = node; + node->prev = node; + } + *plist = node; + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + FT_ASSERT( first != NULL ); + + if ( first != node ) + { + FTC_MruNode prev, next, last; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Up: invalid action!\n" ); + exit( 2 ); + Ok: + } +#endif + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + last = first->prev; + + last->next = node; + first->prev = node; + + node->next = first; + node->prev = last; + + *plist = node; + } + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + FTC_MruNode prev, next; + + + FT_ASSERT( first != NULL ); + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Remove: invalid action!\n" ); + exit( 2 ); + Ok: + } +#endif + + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + if ( node == next ) + { + FT_ASSERT( first == node ); + FT_ASSERT( prev == node ); + + *plist = NULL; + } + else if ( node == first ) + *plist = next; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ) + { + list->num_nodes = 0; + list->max_nodes = max_nodes; + list->nodes = NULL; + list->clazz = *clazz; + list->data = data; + list->memory = memory; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Reset( FTC_MruList list ) + { + while ( list->nodes ) + FTC_MruList_Remove( list, list->nodes ); + + FT_ASSERT( list->num_nodes == 0 ); + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Done( FTC_MruList list ) + { + FTC_MruList_Reset( list ); + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ) + { + FTC_MruNode_CompareFunc compare = list->clazz.node_compare; + FTC_MruNode first, node; + + + first = list->nodes; + node = NULL; + + if ( first ) + { + node = first; + do + { + if ( compare( node, key ) ) + { + if ( node != first ) + FTC_MruNode_Up( &list->nodes, node ); + + return node; + } + + node = node->next; + + } while ( node != first); + } + + return NULL; + } +#endif + + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FT_Error error; + FTC_MruNode node; + FT_Memory memory = list->memory; + + + if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 ) + { + node = list->nodes->prev; + + FT_ASSERT( node ); + + if ( list->clazz.node_reset ) + { + FTC_MruNode_Up( &list->nodes, node ); + + error = list->clazz.node_reset( node, key, list->data ); + if ( !error ) + goto Exit; + } + + FTC_MruNode_Remove( &list->nodes, node ); + list->num_nodes--; + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + } + else if ( FT_ALLOC( node, list->clazz.node_size ) ) + goto Exit; + + error = list->clazz.node_init( node, key, list->data ); + if ( error ) + goto Fail; + + FTC_MruNode_Prepend( &list->nodes, node ); + list->num_nodes++; + + Exit: + *anode = node; + return error; + + Fail: + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + goto Exit; + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FTC_MruNode node; + + + node = FTC_MruList_Find( list, key ); + if ( node == NULL ) + return FTC_MruList_New( list, key, anode ); + + *anode = node; + return 0; + } +#endif /* FTC_INLINE */ + + FT_LOCAL_DEF( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ) + { + FTC_MruNode_Remove( &list->nodes, node ); + list->num_nodes--; + + { + FT_Memory memory = list->memory; + + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + } + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ) + { + FTC_MruNode first, node, next; + + + first = list->nodes; + while ( first && ( selection == NULL || selection( first, key ) ) ) + { + FTC_MruList_Remove( list, first ); + first = list->nodes; + } + + if ( first ) + { + node = first->next; + while ( node != first ) + { + next = node->next; + + if ( selection( node, key ) ) + FTC_MruList_Remove( list, node ); + + node = next; + } + } + } + + +/* END */ diff --git a/src/freetype2/cache/ftcmru.h b/src/freetype2/cache/ftcmru.h new file mode 100644 index 0000000..c8f0c6e --- /dev/null +++ b/src/freetype2/cache/ftcmru.h @@ -0,0 +1,247 @@ +/***************************************************************************/ +/* */ +/* ftcmru.h */ +/* */ +/* Simple MRU list-cache (specification). */ +/* */ +/* Copyright 2000-2001, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* An MRU is a list that cannot hold more than a certain number of */ + /* elements (`max_elements'). All elements in the list are sorted in */ + /* least-recently-used order, i.e., the `oldest' element is at the tail */ + /* of the list. */ + /* */ + /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ + /* the list is searched for an element with the corresponding key. If */ + /* it is found, the element is moved to the head of the list and is */ + /* returned. */ + /* */ + /* If no corresponding element is found, the lookup routine will try to */ + /* obtain a new element with the relevant key. If the list is already */ + /* full, the oldest element from the list is discarded and replaced by a */ + /* new one; a new element is added to the list otherwise. */ + /* */ + /* Note that it is possible to pre-allocate the element list nodes. */ + /* This is handy if `max_elements' is sufficiently small, as it saves */ + /* allocations/releases during the lookup process. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCMRU_H__ +#define __FTCMRU_H__ + + +#include +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + +#define xxFT_DEBUG_ERROR +#define FTC_INLINE + +FT_BEGIN_HEADER + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + FTC_MruNode prev; + + } FTC_MruNodeRec; + + + FT_LOCAL( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ); + + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + + typedef FT_Bool + (*FTC_MruNode_CompareFunc)( FTC_MruNode node, + FT_Pointer key ); + + typedef FT_Error + (*FTC_MruNode_InitFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef FT_Error + (*FTC_MruNode_ResetFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef void + (*FTC_MruNode_DoneFunc)( FTC_MruNode node, + FT_Pointer data ); + + + typedef struct FTC_MruListClassRec_ + { + FT_UInt node_size; + FTC_MruNode_CompareFunc node_compare; + FTC_MruNode_InitFunc node_init; + FTC_MruNode_ResetFunc node_reset; + FTC_MruNode_DoneFunc node_done; + + } FTC_MruListClassRec; + + typedef struct FTC_MruListRec_ + { + FT_UInt num_nodes; + FT_UInt max_nodes; + FTC_MruNode nodes; + FT_Pointer data; + FTC_MruListClassRec clazz; + FT_Memory memory; + + } FTC_MruListRec; + + + FT_LOCAL( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ); + + FT_LOCAL( void ) + FTC_MruList_Reset( FTC_MruList list ); + + + FT_LOCAL( void ) + FTC_MruList_Done( FTC_MruList list ); + + + FT_LOCAL( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ); + + FT_LOCAL( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ); + + +#ifdef FTC_INLINE + +#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \ + FT_BEGIN_STMNT \ + FTC_MruNode* _pfirst = &(list)->nodes; \ + FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \ + FTC_MruNode _first, _node, *_pnode; \ + \ + \ + error = 0; \ + _first = *(_pfirst); \ + _node = NULL; \ + \ + if ( _first ) \ + { \ + _node = _first; \ + do \ + { \ + if ( _compare( _node, (key) ) ) \ + { \ + if ( _node != _first ) \ + FTC_MruNode_Up( _pfirst, _node ); \ + \ + _pnode = (FTC_MruNode*)(void*)&(node); \ + *_pnode = _node; \ + goto _MruOk; \ + } \ + _node = _node->next; \ + \ + } while ( _node != _first) ; \ + } \ + \ + error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \ + _MruOk: \ + ; \ + FT_END_STMNT + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error ) + +#else /* !FTC_INLINE */ + + FT_LOCAL( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ); + + FT_LOCAL( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *pnode ); + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) + +#endif /* !FTC_INLINE */ + + +#define FTC_MRULIST_LOOP( list, node ) \ + FT_BEGIN_STMNT \ + FTC_MruNode _first = (list)->nodes; \ + \ + \ + if ( _first ) \ + { \ + FTC_MruNode _node = _first; \ + \ + \ + do \ + { \ + *(FTC_MruNode*)&(node) = _node; + + +#define FTC_MRULIST_LOOP_END() \ + _node = _node->next; \ + \ + } while ( _node != _first ); \ + } \ + FT_END_STMNT + + /* */ + +FT_END_HEADER + + +#endif /* __FTCMRU_H__ */ + + +/* END */ diff --git a/src/freetype2/cache/ftcsbits.c b/src/freetype2/cache/ftcsbits.c new file mode 100644 index 0000000..72f139d --- /dev/null +++ b/src/freetype2/cache/ftcsbits.c @@ -0,0 +1,401 @@ +/***************************************************************************/ +/* */ +/* ftcsbits.c */ +/* */ +/* FreeType sbits manager (body). */ +/* */ +/* Copyright 2000-2001, 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 +#include FT_CACHE_H +#include "ftcsbits.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_ERRORS_H + +#include "ftccback.h" +#include "ftcerror.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SBIT CACHE NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ftc_sbit_copy_bitmap( FTC_SBit sbit, + FT_Bitmap* bitmap, + FT_Memory memory ) + { + FT_Error error; + FT_Int pitch = bitmap->pitch; + FT_ULong size; + + + if ( pitch < 0 ) + pitch = -pitch; + + size = (FT_ULong)( pitch * bitmap->rows ); + + if ( !FT_ALLOC( sbit->buffer, size ) ) + FT_MEM_COPY( sbit->buffer, bitmap->buffer, size ); + + return error; + } + + + FT_LOCAL_DEF( void ) + ftc_snode_free( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_SBit sbit = snode->sbits; + FT_UInt count = snode->count; + FT_Memory memory = cache->memory; + + + for ( ; count > 0; sbit++, count-- ) + FT_FREE( sbit->buffer ); + + FTC_GNode_Done( FTC_GNODE( snode ), cache ); + + FT_FREE( snode ); + } + + + FT_LOCAL_DEF( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ) + { + ftc_snode_free( FTC_NODE( snode ), cache ); + } + + + /* + * This function tries to load a small bitmap within a given FTC_SNode. + * Note that it returns a non-zero error code _only_ in the case of + * out-of-memory condition. For all other errors (e.g., corresponding + * to a bad font file), this function will mark the sbit as `unavailable' + * and return a value of 0. + * + * You should also read the comment within the @ftc_snode_compare + * function below to see how out-of-memory is handled during a lookup. + */ + static FT_Error + ftc_snode_load( FTC_SNode snode, + FTC_Manager manager, + FT_UInt gindex, + FT_ULong *asize ) + { + FT_Error error; + FTC_GNode gnode = FTC_GNODE( snode ); + FTC_Family family = gnode->family; + FT_Memory memory = manager->memory; + FT_Face face; + FTC_SBit sbit; + FTC_SFamilyClass clazz; + + + if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count ) + { + FT_ERROR(( "ftc_snode_load: invalid glyph index" )); + return FTC_Err_Invalid_Argument; + } + + sbit = snode->sbits + ( gindex - gnode->gindex ); + clazz = (FTC_SFamilyClass)family->clazz; + + sbit->buffer = 0; + + error = clazz->family_load_glyph( family, gindex, manager, &face ); + if ( error ) + goto BadGlyph; + + { + FT_Int temp; + FT_GlyphSlot slot = face->glyph; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Int xadvance, yadvance; + + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + FT_ERROR(( "%s: glyph loaded didn't return a bitmap!\n", + "ftc_snode_load" )); + goto BadGlyph; + } + + /* Check that our values fit into 8-bit containers! */ + /* If this is not the case, our bitmap is too large */ + /* and we will leave it as `missing' with sbit.buffer = 0 */ + +#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d ) +#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d ) + + /* horizontal advance in pixels */ + xadvance = ( slot->advance.x + 32 ) >> 6; + yadvance = ( slot->advance.y + 32 ) >> 6; + + if ( !CHECK_BYTE( bitmap->rows ) || + !CHECK_BYTE( bitmap->width ) || + !CHECK_CHAR( bitmap->pitch ) || + !CHECK_CHAR( slot->bitmap_left ) || + !CHECK_CHAR( slot->bitmap_top ) || + !CHECK_CHAR( xadvance ) || + !CHECK_CHAR( yadvance ) ) + goto BadGlyph; + + sbit->width = (FT_Byte)bitmap->width; + sbit->height = (FT_Byte)bitmap->rows; + sbit->pitch = (FT_Char)bitmap->pitch; + sbit->left = (FT_Char)slot->bitmap_left; + sbit->top = (FT_Char)slot->bitmap_top; + sbit->xadvance = (FT_Char)xadvance; + sbit->yadvance = (FT_Char)yadvance; + sbit->format = (FT_Byte)bitmap->pixel_mode; + sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); + + /* copy the bitmap into a new buffer -- ignore error */ + error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); + + /* now, compute size */ + if ( asize ) + *asize = FT_ABS( sbit->pitch ) * sbit->height; + + } /* glyph loading successful */ + + /* ignore the errors that might have occurred -- */ + /* we mark unloaded glyphs with `sbit.buffer == 0' */ + /* and `width == 255', `height == 0' */ + /* */ + if ( error && error != FTC_Err_Out_Of_Memory ) + { + BadGlyph: + sbit->width = 255; + sbit->height = 0; + sbit->buffer = NULL; + error = 0; + if ( asize ) + *asize = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_SNode snode = NULL; + FT_UInt gindex = gquery->gindex; + FTC_Family family = gquery->family; + + FTC_SFamilyClass clazz = FTC_CACHE__SFAMILY_CLASS( cache ); + FT_UInt total; + + + total = clazz->family_get_count( family, cache->manager ); + if ( total == 0 || gindex >= total ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + if ( !FT_NEW( snode ) ) + { + FT_UInt count, start; + + + start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE ); + count = total - start; + if ( count > FTC_SBIT_ITEMS_PER_NODE ) + count = FTC_SBIT_ITEMS_PER_NODE; + + FTC_GNode_Init( FTC_GNODE( snode ), start, family ); + + snode->count = count; + + error = ftc_snode_load( snode, + cache->manager, + gindex, + NULL ); + if ( error ) + { + FTC_SNode_Free( snode, cache ); + snode = NULL; + } + } + + Exit: + *psnode = snode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_snode_new( FTC_Node *ftcpsnode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_SNode *psnode = (FTC_SNode*)ftcpsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_SNode_New( psnode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_ULong ) + ftc_snode_weight( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FT_UInt count = snode->count; + FTC_SBit sbit = snode->sbits; + FT_Int pitch; + FT_ULong size; + + FT_UNUSED( cache ); + + + FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE ); + + /* the node itself */ + size = sizeof ( *snode ); + + for ( ; count > 0; count--, sbit++ ) + { + if ( sbit->buffer ) + { + pitch = sbit->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + /* add the size of a given glyph image */ + size += pitch * sbit->height; + } + } + + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_ULong ) + FTC_SNode_Weight( FTC_SNode snode ) + { + return ftc_snode_weight( FTC_NODE( snode ), NULL ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Bool ) + ftc_snode_compare( FTC_Node ftcsnode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FTC_GNode gnode = FTC_GNODE( snode ); + FT_UInt gindex = gquery->gindex; + FT_Bool result; + + + result = FT_BOOL( gnode->family == gquery->family && + (FT_UInt)( gindex - gnode->gindex ) < snode->count ); + if ( result ) + { + /* check if we need to load the glyph bitmap now */ + FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex ); + + + /* + * The following code illustrates what to do when you want to + * perform operations that may fail within a lookup function. + * + * Here, we want to load a small bitmap on-demand; we thus + * need to call the `ftc_snode_load' function which may return + * a non-zero error code only when we are out of memory (OOM). + * + * The correct thing to do is to use @FTC_CACHE_TRYLOOP and + * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop + * that is capable of flushing the cache incrementally when + * an OOM errors occur. + * + * However, we need to `lock' the node before this operation to + * prevent it from being flushed within the loop. + * + * When we exit the loop, we unlock the node, then check the `error' + * variable. If it is non-zero, this means that the cache was + * completely flushed and that no usable memory was found to load + * the bitmap. + * + * We then prefer to return a value of 0 (i.e., NO MATCH). This + * ensures that the caller will try to allocate a new node. + * This operation consequently _fail_ and the lookup function + * returns the appropriate OOM error code. + * + * Note that `buffer == NULL && width == 255' is a hack used to + * tag `unavailable' bitmaps in the array. We should never try + * to load these. + * + */ + + if ( sbit->buffer == NULL && sbit->width != 255 ) + { + FT_ULong size; + FT_Error error; + + + ftcsnode->ref_count++; /* lock node to prevent flushing */ + /* in retry loop */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = ftc_snode_load( snode, cache->manager, gindex, &size ); + } + FTC_CACHE_TRYLOOP_END(); + + ftcsnode->ref_count--; /* unlock the node */ + + if ( error ) + result = 0; + else + cache->manager->cur_weight += size; + } + } + + return result; + } + + + FT_LOCAL_DEF( FT_Bool ) + FTC_SNode_Compare( FTC_SNode snode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + return ftc_snode_compare( FTC_NODE( snode ), gquery, cache ); + } + + +/* END */ diff --git a/src/freetype2/cache/ftcsbits.h b/src/freetype2/cache/ftcsbits.h new file mode 100644 index 0000000..6261745 --- /dev/null +++ b/src/freetype2/cache/ftcsbits.h @@ -0,0 +1,98 @@ +/***************************************************************************/ +/* */ +/* ftcsbits.h */ +/* */ +/* A small-bitmap cache (specification). */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCSBITS_H__ +#define __FTCSBITS_H__ + + +#include +#include FT_CACHE_H +#include "ftcglyph.h" + + +FT_BEGIN_HEADER + +#define FTC_SBIT_ITEMS_PER_NODE 16 + + typedef struct FTC_SNodeRec_ + { + FTC_GNodeRec gnode; + FT_UInt count; + FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE]; + + } FTC_SNodeRec, *FTC_SNode; + + +#define FTC_SNODE( x ) ( (FTC_SNode)( x ) ) +#define FTC_SNODE_GINDEX( x ) FTC_GNODE( x )->gindex +#define FTC_SNODE_FAMILY( x ) FTC_GNODE( x )->family + + typedef FT_UInt + (*FTC_SFamily_GetCountFunc)( FTC_Family family, + FTC_Manager manager ); + + typedef FT_Error + (*FTC_SFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ); + + typedef struct FTC_SFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_SFamily_GetCountFunc family_get_count; + FTC_SFamily_LoadGlyphFunc family_load_glyph; + + } FTC_SFamilyClassRec; + + typedef const FTC_SFamilyClassRec* FTC_SFamilyClass; + +#define FTC_SFAMILY_CLASS( x ) ((FTC_SFamilyClass)(x)) + +#define FTC_CACHE__SFAMILY_CLASS( x ) \ + FTC_SFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS( x )->family_class ) + + + FT_LOCAL( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + FT_LOCAL( FT_ULong ) + FTC_SNode_Weight( FTC_SNode inode ); +#endif + + + FT_LOCAL( FT_Bool ) + FTC_SNode_Compare( FTC_SNode snode, + FTC_GQuery gquery, + FTC_Cache cache ); + + /* */ + +FT_END_HEADER + +#endif /* __FTCSBITS_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cff.c b/src/freetype2/cff/cff.c new file mode 100644 index 0000000..e6d8954 --- /dev/null +++ b/src/freetype2/cff/cff.c @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* cff.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include +#include "cffdrivr.c" +#include "cffparse.c" +#include "cffload.c" +#include "cffobjs.c" +#include "cffgload.c" +#include "cffcmap.c" + +/* END */ diff --git a/src/freetype2/cff/cffcmap.c b/src/freetype2/cff/cffcmap.c new file mode 100644 index 0000000..fffc5fc --- /dev/null +++ b/src/freetype2/cff/cffcmap.c @@ -0,0 +1,220 @@ +/***************************************************************************/ +/* */ +/* cffcmap.c */ +/* */ +/* CFF character mapping table (cmap) support (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 "cffcmap.h" +#include "cffload.h" + +#include "cfferrs.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_encoding_init( CFF_CMapStd cmap ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Encoding encoding = &cff->encoding; + + + cmap->gids = encoding->codes; + + return 0; + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_encoding_done( CFF_CMapStd cmap ) + { + cmap->gids = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_index( CFF_CMapStd cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + + + if ( char_code < 256 ) + result = cmap->gids[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_next( CFF_CMapStd cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + *pchar_code = 0; + + if ( char_code < 255 ) + { + FT_UInt code = (FT_UInt)(char_code + 1); + + + for (;;) + { + if ( code >= 256 ) + break; + + result = cmap->gids[code]; + if ( result != 0 ) + { + *pchar_code = code; + break; + } + + code++; + } + } + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + cff_cmap_encoding_class_rec = + { + sizeof ( CFF_CMapStdRec ), + + (FT_CMap_InitFunc) cff_cmap_encoding_init, + (FT_CMap_DoneFunc) cff_cmap_encoding_done, + (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char* ) + cff_sid_to_glyph_name( TT_Face face, + FT_UInt idx ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + FT_UInt sid = charset->sids[idx]; + + + return cff_index_get_sid_string( &cff->string_index, sid, psnames ); + } + + + FT_CALLBACK_DEF( void ) + cff_sid_free_glyph_name( TT_Face face, + const char* gname ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( gname ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_unicode_init( PS_Unicodes unicodes ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + /* can't build Unicode map for CID-keyed font */ + if ( !charset->sids ) + return CFF_Err_Invalid_Argument; + + return psnames->unicodes_init( memory, + unicodes, + cff->num_glyphs, + (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name, + (PS_FreeGlyphNameFunc)&cff_sid_free_glyph_name, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_unicode_done( PS_Unicodes unicodes ) + { + FT_Face face = FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_index( PS_Unicodes unicodes, + FT_UInt32 char_code ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_next( PS_Unicodes unicodes, + FT_UInt32 *pchar_code ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + cff_cmap_unicode_class_rec = + { + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) cff_cmap_unicode_init, + (FT_CMap_DoneFunc) cff_cmap_unicode_done, + (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next + }; + + +/* END */ diff --git a/src/freetype2/cff/cffcmap.h b/src/freetype2/cff/cffcmap.h new file mode 100644 index 0000000..3809b85 --- /dev/null +++ b/src/freetype2/cff/cffcmap.h @@ -0,0 +1,69 @@ +/***************************************************************************/ +/* */ +/* cffcmap.h */ +/* */ +/* CFF character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CFFCMAP_H__ +#define __CFFCMAP_H__ + +#include "cffobjs.h" + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct CFF_CMapStdRec_* CFF_CMapStd; + + typedef struct CFF_CMapStdRec_ + { + FT_CMapRec cmap; + FT_UShort* gids; /* up to 256 elements */ + + } CFF_CMapStdRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + cff_cmap_encoding_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + cff_cmap_unicode_class_rec; + + +FT_END_HEADER + +#endif /* __CFFCMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cffdrivr.c b/src/freetype2/cff/cffdrivr.c new file mode 100644 index 0000000..952e88e --- /dev/null +++ b/src/freetype2/cff/cffdrivr.c @@ -0,0 +1,499 @@ +/***************************************************************************/ +/* */ +/* cffdrivr.c */ +/* */ +/* OpenType font driver implementation (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_FREETYPE_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_TRUETYPE_IDS_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_SERVICE_POSTSCRIPT_INFO_H +#include FT_SERVICE_TT_CMAP_H + +#include "cffdrivr.h" +#include "cffgload.h" +#include "cffload.h" +#include "cffcmap.h" + +#include "cfferrs.h" + +#include FT_SERVICE_XFREE86_NAME_H +#include FT_SERVICE_GLYPH_DICT_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_cffdriver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) + + + /*************************************************************************/ + /* */ + /* */ + /* cff_get_kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings, are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_kerning( FT_Face ttface, /* TT_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face face = (TT_Face)ttface; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + + return CFF_Err_Ok; + } + + +#undef PAIR_TAG + + + /*************************************************************************/ + /* */ + /* */ + /* Load_Glyph */ + /* */ + /* */ + /* A driver method used to load a glyph within a given glyph slot. */ + /* */ + /* */ + /* slot :: A handle to the target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled, loaded, etc. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_??? constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_CALLBACK_DEF( FT_Error ) + Load_Glyph( FT_GlyphSlot cffslot, /* CFF_GlyphSlot */ + FT_Size cffsize, /* CFF_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_GlyphSlot slot = (CFF_GlyphSlot)cffslot; + CFF_Size size = (CFF_Size)cffsize; + + + if ( !slot ) + return CFF_Err_Invalid_Slot_Handle; + + /* check whether we want a scaled outline or bitmap */ + if ( !size ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + /* reset the size object if necessary */ + if ( size ) + { + /* these two objects must have the same parent */ + if ( cffsize->face != cffslot->face ) + return CFF_Err_Invalid_Face_Handle; + } + + /* now load the glyph outline if necessary */ + error = cff_slot_load( slot, size, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /* + * GLYPH DICT SERVICE + * + */ + + static FT_Error + cff_get_glyph_name( CFF_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + CFF_Font font = (CFF_Font)face->extra.data; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_String* gname; + FT_UShort sid; + FT_Service_PsCMaps psnames; + FT_Error error; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + { + FT_ERROR(( "cff_get_glyph_name:" )); + FT_ERROR(( " cannot get glyph name from CFF & CEF fonts\n" )); + FT_ERROR(( " " )); + FT_ERROR(( " without the `PSNames' module\n" )); + error = CFF_Err_Unknown_File_Format; + goto Exit; + } + + /* first, locate the sid in the charset table */ + sid = font->charset.sids[glyph_index]; + + /* now, lookup the name itself */ + gname = cff_index_get_sid_string( &font->string_index, sid, psnames ); + + if ( gname ) + FT_STRCPYN( buffer, gname, buffer_max ); + + FT_FREE( gname ); + error = CFF_Err_Ok; + + Exit: + return error; + } + + + static FT_UInt + cff_get_name_index( CFF_Face face, + FT_String* glyph_name ) + { + CFF_Font cff; + CFF_Charset charset; + FT_Service_PsCMaps psnames; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_String* name; + FT_UShort sid; + FT_UInt i; + FT_Int result; + + + cff = (CFF_FontRec *)face->extra.data; + charset = &cff->charset; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + return 0; + + for ( i = 0; i < cff->num_glyphs; i++ ) + { + sid = charset->sids[i]; + + if ( sid > 390 ) + name = cff_index_get_name( &cff->string_index, sid - 391 ); + else + name = (FT_String *)psnames->adobe_std_strings( sid ); + + if ( !name ) + continue; + + result = ft_strcmp( glyph_name, name ); + + if ( sid > 390 ) + FT_FREE( name ); + + if ( !result ) + return i; + } + + return 0; + } + + + static const FT_Service_GlyphDictRec cff_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)cff_get_name_index, + }; + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Int + cff_ps_has_glyph_names( FT_Face face ) + { + return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0; + } + + + static FT_Error + cff_ps_get_font_info( CFF_Face face, + PS_FontInfoRec* afont_info ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Error error = FT_Err_Ok; + + + if ( cff && cff->font_info == NULL ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + PS_FontInfoRec *font_info; + FT_Memory memory = face->root.memory; + + + if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) ) + goto Fail; + + font_info->version = cff_index_get_sid_string( &cff->string_index, + dict->version, + cff->psnames ); + font_info->notice = cff_index_get_sid_string( &cff->string_index, + dict->notice, + cff->psnames ); + font_info->full_name = cff_index_get_sid_string( &cff->string_index, + dict->full_name, + cff->psnames ); + font_info->family_name = cff_index_get_sid_string( &cff->string_index, + dict->family_name, + cff->psnames ); + font_info->weight = cff_index_get_sid_string( &cff->string_index, + dict->weight, + cff->psnames ); + font_info->italic_angle = dict->italic_angle; + font_info->is_fixed_pitch = dict->is_fixed_pitch; + font_info->underline_position = (FT_Short)dict->underline_position; + font_info->underline_thickness = (FT_Short)dict->underline_thickness; + + cff->font_info = font_info; + } + + *afont_info = *cff->font_info; + + Fail: + return error; + } + + + static const FT_Service_PsInfoRec cff_service_ps_info = + { + (PS_GetFontInfoFunc) cff_ps_get_font_info, + (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, + (PS_GetFontPrivateFunc)NULL /* unsupported with CFF fonts */ + }; + + + /* + * TT CMAP INFO + * + * If the charmap is a synthetic Unicode encoding cmap or + * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO + * service defined in SFNT module. + * + * Otherwise call the service function in the sfnt module. + * + */ + static FT_Error + cff_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + FT_Error error = CFF_Err_Ok; + + + cmap_info->language = 0; + + if ( cmap->clazz != &cff_cmap_encoding_class_rec && + cmap->clazz != &cff_cmap_unicode_class_rec ) + { + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt = FT_Get_Module( library, "sfnt" ); + FT_Service_TTCMaps service = + (FT_Service_TTCMaps)ft_module_get_service( sfnt, + FT_SERVICE_ID_TT_CMAP ); + + + if ( service && service->get_cmap_info ) + error = service->get_cmap_info( charmap, cmap_info ); + } + + return error; + } + + + static const FT_Service_TTCMapsRec cff_service_get_cmap_info = + { + (TT_CMap_Info_GetFunc)cff_get_cmap_info + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + static const FT_ServiceDescRec cff_services[] = + { + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_CFF }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info }, +#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES + { FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict }, +#endif + { FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cff_get_interface( FT_Module driver, /* CFF_Driver */ + const char* module_interface ) + { + FT_Module sfnt; + FT_Module_Interface result; + + + result = ft_service_list_lookup( cff_services, module_interface ); + if ( result != NULL ) + return result; + + /* we pass our request to the `sfnt' module */ + sfnt = FT_Get_Module( driver->library, "sfnt" ); + + return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec cff_driver_class = + { + /* begin with the FT_Module_Class fields */ + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + + sizeof( CFF_DriverRec ), + "cff", + 0x10000L, + 0x20000L, + + 0, /* module-specific interface */ + + cff_driver_init, + cff_driver_done, + cff_get_interface, + }, + + /* now the specific driver fields */ + sizeof( TT_FaceRec ), + sizeof( CFF_SizeRec ), + sizeof( CFF_GlyphSlotRec ), + + cff_face_init, + cff_face_done, + cff_size_init, + cff_size_done, + cff_slot_init, + cff_slot_done, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + + Load_Glyph, + + cff_get_kerning, + 0, /* FT_Face_AttachFunc */ + 0, /* FT_Face_GetAdvancesFunc */ + + cff_size_request, + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + cff_size_select +#else + 0 /* FT_Size_SelectFunc */ +#endif + }; + + +/* END */ diff --git a/src/freetype2/cff/cffdrivr.h b/src/freetype2/cff/cffdrivr.h new file mode 100644 index 0000000..553848c --- /dev/null +++ b/src/freetype2/cff/cffdrivr.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* cffdrivr.h */ +/* */ +/* High-level OpenType driver interface (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CFFDRIVER_H__ +#define __CFFDRIVER_H__ + + +#include +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const FT_Driver_ClassRec cff_driver_class; + + +FT_END_HEADER + +#endif /* __CFFDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cfferrs.h b/src/freetype2/cff/cfferrs.h new file mode 100644 index 0000000..1b2a5c9 --- /dev/null +++ b/src/freetype2/cff/cfferrs.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* cfferrs.h */ +/* */ +/* CFF error codes (specification only). */ +/* */ +/* Copyright 2001 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 CFF error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __CFFERRS_H__ +#define __CFFERRS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX CFF_Err_ +#define FT_ERR_BASE FT_Mod_Err_CFF + + +#include FT_ERRORS_H + +#endif /* __CFFERRS_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cffgload.c b/src/freetype2/cff/cffgload.c new file mode 100644 index 0000000..0e2a179 --- /dev/null +++ b/src/freetype2/cff/cffgload.c @@ -0,0 +1,2634 @@ +/***************************************************************************/ +/* */ +/* cffgload.c */ +/* */ +/* OpenType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_OUTLINE_H +#include FT_TRUETYPE_TAGS_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + +#include "cffobjs.h" +#include "cffload.h" +#include "cffgload.h" + +#include "cfferrs.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_cffgload + + + typedef enum CFF_Operator_ + { + cff_op_unknown = 0, + + cff_op_rmoveto, + cff_op_hmoveto, + cff_op_vmoveto, + + cff_op_rlineto, + cff_op_hlineto, + cff_op_vlineto, + + cff_op_rrcurveto, + cff_op_hhcurveto, + cff_op_hvcurveto, + cff_op_rcurveline, + cff_op_rlinecurve, + cff_op_vhcurveto, + cff_op_vvcurveto, + + cff_op_flex, + cff_op_hflex, + cff_op_hflex1, + cff_op_flex1, + + cff_op_endchar, + + cff_op_hstem, + cff_op_vstem, + cff_op_hstemhm, + cff_op_vstemhm, + + cff_op_hintmask, + cff_op_cntrmask, + cff_op_dotsection, /* deprecated, acts as no-op */ + + cff_op_abs, + cff_op_add, + cff_op_sub, + cff_op_div, + cff_op_neg, + cff_op_random, + cff_op_mul, + cff_op_sqrt, + + cff_op_blend, + + cff_op_drop, + cff_op_exch, + cff_op_index, + cff_op_roll, + cff_op_dup, + + cff_op_put, + cff_op_get, + cff_op_store, + cff_op_load, + + cff_op_and, + cff_op_or, + cff_op_not, + cff_op_eq, + cff_op_ifelse, + + cff_op_callsubr, + cff_op_callgsubr, + cff_op_return, + + /* do not remove */ + cff_op_max + + } CFF_Operator; + + +#define CFF_COUNT_CHECK_WIDTH 0x80 +#define CFF_COUNT_EXACT 0x40 +#define CFF_COUNT_CLEAR_STACK 0x20 + + + static const FT_Byte cff_argument_counts[] = + { + 0, /* unknown */ + + 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */ + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + + 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 13, /* flex */ + 7, + 9, + 11, + + 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */ + + 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */ + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + + 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */ + 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */ + 0, /* dotsection */ + + 1, /* abs */ + 2, + 2, + 2, + 1, + 0, + 2, + 1, + + 1, /* blend */ + + 1, /* drop */ + 2, + 1, + 2, + 1, + + 2, /* put */ + 1, + 4, + 3, + + 2, /* and */ + 2, + 1, + 2, + 4, + + 1, /* callsubr */ + 1, + 0 + }; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* cff_builder_init */ + /* */ + /* */ + /* Initializes a given glyph builder. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + static void + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->root.internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = 0; + builder->hints_funcs = 0; + + if ( hinting && size ) + { + builder->hints_globals = size->root.internal; + builder->hints_funcs = glyph->root.internal->glyph_hints; + } + } + + if ( size ) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cff_builder_done */ + /* */ + /* */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + static void + cff_builder_done( CFF_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cff_compute_bias */ + /* */ + /* */ + /* Computes the bias value in dependence of the number of glyph */ + /* subroutines. */ + /* */ + /* */ + /* num_subrs :: The number of glyph subroutines. */ + /* */ + /* */ + /* The bias value. */ + static FT_Int + cff_compute_bias( FT_UInt num_subrs ) + { + FT_Int result; + + + if ( num_subrs < 1240 ) + result = 107; + else if ( num_subrs < 33900U ) + result = 1131; + else + result = 32768U; + + return result; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cff_decoder_init */ + /* */ + /* */ + /* Initializes a given glyph decoder. */ + /* */ + /* */ + /* decoder :: A pointer to the glyph builder to initialize. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* slot :: The current glyph object. */ + /* */ + FT_LOCAL_DEF( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + /* clear everything */ + FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); + + /* initialize builder */ + cff_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* initialize Type2 decoder */ + decoder->num_globals = cff->num_global_subrs; + decoder->globals = cff->global_subrs; + decoder->globals_bias = cff_compute_bias( decoder->num_globals ); + + decoder->hint_mode = hint_mode; + } + + + /* this function is used to select the locals subrs array */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + FT_UInt glyph_index ) + { + CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data; + CFF_SubFont sub = &cff->top_font; + FT_Error error = CFF_Err_Ok; + + + /* manage CID fonts */ + if ( cff->num_subfonts >= 1 ) + { + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index ); + + + if ( fd_index >= cff->num_subfonts ) + { + FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + sub = cff->subfonts[fd_index]; + } + + decoder->num_locals = sub->num_local_subrs; + decoder->locals = sub->local_subrs; + decoder->locals_bias = cff_compute_bias( decoder->num_locals ); + + decoder->glyph_width = sub->private_dict.default_width; + decoder->nominal_width = sub->private_dict.nominal_width; + + Exit: + return error; + } + + + /* check that there is enough space for `count' more points */ + static FT_Error + check_points( CFF_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + static void + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + point->x = x >> 16; + point->y = y >> 16; + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + + builder->last = *point; + } + + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + static FT_Error + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = check_points( builder, 1 ); + if ( !error ) + cff_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + static FT_Error + cff_builder_add_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return CFF_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + static FT_Error + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = CFF_Err_Ok; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = cff_builder_add_contour( builder ); + if ( !error ) + error = cff_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + static void + cff_builder_close_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + + + if ( !outline ) + return; + + /* XXXX: We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + + + if ( outline->n_contours > 1 ) + { + first = outline->contours[outline->n_contours - 2] + 1; + p1 = outline->points + first; + } + + /* `delete' last point only if it coincides with the first */ + /* point and if it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + + + static FT_Int + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ) + { + FT_UInt n; + FT_UShort glyph_sid; + + + /* CID-keyed fonts don't have glyph names */ + if ( !cff->charset.sids ) + return -1; + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + /* Get code to SID mapping from `cff_standard_encoding'. */ + glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode ); + + for ( n = 0; n < cff->num_glyphs; n++ ) + { + if ( cff->charset.sids[n] == glyph_sid ) + return n; + } + + return -1; + } + + + static FT_Error + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + FT_Error error = + face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &data ); + + + *pointer = (FT_Byte*)data.pointer; + *length = data.length; + + return error; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)(face->extra.data); + + + return cff_index_access_element( &cff->charstrings_index, glyph_index, + pointer, length ); + } + } + + + static void + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ) + { +#ifndef FT_CONFIG_OPTION_INCREMENTAL + FT_UNUSED( length ); +#endif + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + + + data.pointer = *pointer; + data.length = length; + + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object,&data ); + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)(face->extra.data); + + + cff_index_forget_element( &cff->charstrings_index, pointer ); + } + } + + + static FT_Error + cff_operator_seac( CFF_Decoder* decoder, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + CFF_Builder* builder = &decoder->builder; + FT_Int bchar_index, achar_index; + TT_Face face = decoder->builder.face; + FT_Vector left_bearing, advance; + FT_Byte* charstring; + FT_ULong charstring_len; + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Incremental fonts don't necessarily have valid charsets. */ + /* They use the character code, not the glyph index, in this case. */ + if ( face->root.internal->incremental_interface ) + { + bchar_index = bchar; + achar_index = achar; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + CFF_Font cff = (CFF_Font)(face->extra.data); + + + bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar ); + achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cff_operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return CFF_Err_Syntax_Error; + } + + /* If we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( builder->no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)( adx >> 16 ); + subg->arg2 = (FT_Int)( ady >> 16 ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + } + + FT_GlyphLoader_Prepare( builder->loader ); + + /* First load `bchar' in builder */ + error = cff_get_glyph_data( face, bchar_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len ); + + if ( error ) + goto Exit; + + cff_free_glyph_data( face, &charstring, charstring_len ); + } + + /* Save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = builder->left_bearing; + advance = builder->advance; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + + builder->pos_x = adx; + builder->pos_y = ady; + + /* Now load `achar' on top of the base outline. */ + error = cff_get_glyph_data( face, achar_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len ); + + if ( error ) + goto Exit; + + cff_free_glyph_data( face, &charstring, charstring_len ); + } + + /* Restore the left side bearing and advance width */ + /* of the base character. */ + builder->left_bearing = left_bearing; + builder->advance = advance; + + builder->pos_x = 0; + builder->pos_y = 0; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cff_decoder_parse_charstrings */ + /* */ + /* */ + /* Parses a given Type 2 charstrings program. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* */ + /* charstring_base :: The base of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ) + { + FT_Error error; + CFF_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CFF_Builder* builder = &decoder->builder; + FT_Pos x, y; + FT_Fixed seed; + FT_Fixed* stack; + + T2_Hints_Funcs hinter; + + + /* set default width */ + decoder->num_hints = 0; + decoder->read_width = 1; + + /* compute random seed from stack address of parameter */ + seed = (FT_Fixed)(char*)&seed ^ + (FT_Fixed)(char*)&decoder ^ + (FT_Fixed)(char*)&charstring_base; + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; + if ( seed == 0 ) + seed = 0x7384; + + /* initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + stack = decoder->top; + + hinter = (T2_Hints_Funcs)builder->hints_funcs; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = CFF_Err_Ok; + + x = builder->pos_x; + y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + /* now execute loop */ + while ( ip < limit ) + { + CFF_Operator op; + FT_Byte v; + + + /********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + v = *ip++; + if ( v >= 32 || v == 28 ) + { + FT_Int shift = 16; + FT_Int32 val; + + + /* this is an operand, push it on the stack */ + if ( v == 28 ) + { + if ( ip + 1 >= limit ) + goto Syntax_Error; + val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] ); + ip += 2; + } + else if ( v < 247 ) + val = (FT_Long)v - 139; + else if ( v < 251 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108; + } + else if ( v < 255 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108; + } + else + { + if ( ip + 3 >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)ip[0] << 24 ) | + ( (FT_Int32)ip[1] << 16 ) | + ( (FT_Int32)ip[2] << 8 ) | + ip[3]; + ip += 4; + shift = 0; + } + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + + val <<= shift; + *decoder->top++ = val; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( val & 0xFFFFL ) ) + FT_TRACE4(( " %ld", (FT_Int32)( val >> 16 ) )); + else + FT_TRACE4(( " %.2f", val / 65536.0 )); +#endif + + } + else + { + FT_Fixed* args = decoder->top; + FT_Int num_args = (FT_Int)( args - decoder->stack ); + FT_Int req_args; + + + /* find operator */ + op = cff_op_unknown; + + switch ( v ) + { + case 1: + op = cff_op_hstem; + break; + case 3: + op = cff_op_vstem; + break; + case 4: + op = cff_op_vmoveto; + break; + case 5: + op = cff_op_rlineto; + break; + case 6: + op = cff_op_hlineto; + break; + case 7: + op = cff_op_vlineto; + break; + case 8: + op = cff_op_rrcurveto; + break; + case 10: + op = cff_op_callsubr; + break; + case 11: + op = cff_op_return; + break; + case 12: + { + if ( ip >= limit ) + goto Syntax_Error; + v = *ip++; + + switch ( v ) + { + case 0: + op = cff_op_dotsection; + break; + case 3: + op = cff_op_and; + break; + case 4: + op = cff_op_or; + break; + case 5: + op = cff_op_not; + break; + case 8: + op = cff_op_store; + break; + case 9: + op = cff_op_abs; + break; + case 10: + op = cff_op_add; + break; + case 11: + op = cff_op_sub; + break; + case 12: + op = cff_op_div; + break; + case 13: + op = cff_op_load; + break; + case 14: + op = cff_op_neg; + break; + case 15: + op = cff_op_eq; + break; + case 18: + op = cff_op_drop; + break; + case 20: + op = cff_op_put; + break; + case 21: + op = cff_op_get; + break; + case 22: + op = cff_op_ifelse; + break; + case 23: + op = cff_op_random; + break; + case 24: + op = cff_op_mul; + break; + case 26: + op = cff_op_sqrt; + break; + case 27: + op = cff_op_dup; + break; + case 28: + op = cff_op_exch; + break; + case 29: + op = cff_op_index; + break; + case 30: + op = cff_op_roll; + break; + case 34: + op = cff_op_hflex; + break; + case 35: + op = cff_op_flex; + break; + case 36: + op = cff_op_hflex1; + break; + case 37: + op = cff_op_flex1; + break; + default: + /* decrement ip for syntax error message */ + ip--; + } + } + break; + case 14: + op = cff_op_endchar; + break; + case 16: + op = cff_op_blend; + break; + case 18: + op = cff_op_hstemhm; + break; + case 19: + op = cff_op_hintmask; + break; + case 20: + op = cff_op_cntrmask; + break; + case 21: + op = cff_op_rmoveto; + break; + case 22: + op = cff_op_hmoveto; + break; + case 23: + op = cff_op_vstemhm; + break; + case 24: + op = cff_op_rcurveline; + break; + case 25: + op = cff_op_rlinecurve; + break; + case 26: + op = cff_op_vvcurveto; + break; + case 27: + op = cff_op_hhcurveto; + break; + case 29: + op = cff_op_callgsubr; + break; + case 30: + op = cff_op_vhcurveto; + break; + case 31: + op = cff_op_hvcurveto; + break; + default: + ; + } + if ( op == cff_op_unknown ) + goto Syntax_Error; + + /* check arguments */ + req_args = cff_argument_counts[op]; + if ( req_args & CFF_COUNT_CHECK_WIDTH ) + { + args = stack; + + if ( num_args > 0 && decoder->read_width ) + { + /* If `nominal_width' is non-zero, the number is really a */ + /* difference against `nominal_width'. Else, the number here */ + /* is truly a width, not a difference against `nominal_width'. */ + /* If the font does not set `nominal_width', then */ + /* `nominal_width' defaults to zero, and so we can set */ + /* `glyph_width' to `nominal_width' plus number on the stack */ + /* -- for either case. */ + + FT_Int set_width_ok; + + + switch ( op ) + { + case cff_op_hmoveto: + case cff_op_vmoveto: + set_width_ok = num_args & 2; + break; + + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + case cff_op_rmoveto: + case cff_op_hintmask: + case cff_op_cntrmask: + set_width_ok = num_args & 1; + break; + + case cff_op_endchar: + /* If there is a width specified for endchar, we either have */ + /* 1 argument or 5 arguments. We like to argue. */ + set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) ); + break; + + default: + set_width_ok = 0; + break; + } + + if ( set_width_ok ) + { + decoder->glyph_width = decoder->nominal_width + + ( stack[0] >> 16 ); + + /* Consumed an argument. */ + num_args--; + args++; + } + } + + decoder->read_width = 0; + req_args = 0; + } + + req_args &= 15; + if ( num_args < req_args ) + goto Stack_Underflow; + args -= req_args; + num_args -= req_args; + + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + /* the number of arguments is always even here */ + FT_TRACE4(( op == cff_op_hstem ? " hstem" : + ( op == cff_op_vstem ? " vstem" : + ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) )); + + if ( hinter ) + hinter->stems( hinter->hints, + ( op == cff_op_hstem || op == cff_op_hstemhm ), + num_args / 2, + args ); + + decoder->num_hints += num_args / 2; + args = stack; + break; + + case cff_op_hintmask: + case cff_op_cntrmask: + FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" )); + + /* implement vstem when needed -- */ + /* the specification doesn't say it, but this also works */ + /* with the 'cntrmask' operator */ + /* */ + if ( num_args > 0 ) + { + if ( hinter ) + hinter->stems( hinter->hints, + 0, + num_args / 2, + args ); + + decoder->num_hints += num_args / 2; + } + + if ( hinter ) + { + if ( op == cff_op_hintmask ) + hinter->hintmask( hinter->hints, + builder->current->n_points, + decoder->num_hints, + ip ); + else + hinter->counter( hinter->hints, + decoder->num_hints, + ip ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt maskbyte; + + + FT_TRACE4(( " " )); + + for ( maskbyte = 0; + maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3); + maskbyte++, ip++ ) + FT_TRACE4(( "0x%02X", *ip )); + } +#else + ip += ( decoder->num_hints + 7 ) >> 3; +#endif + if ( ip >= limit ) + goto Syntax_Error; + args = stack; + break; + + case cff_op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x += args[0]; + y += args[1]; + args = stack; + break; + + case cff_op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + y += args[0]; + args = stack; + break; + + case cff_op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x += args[0]; + args = stack; + break; + + case cff_op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_args / 2 ) ) + goto Fail; + + if ( num_args < 2 || num_args & 1 ) + goto Stack_Underflow; + + args = stack; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + } + args = stack; + break; + + case cff_op_hlineto: + case cff_op_vlineto: + { + FT_Int phase = ( op == cff_op_hlineto ); + + + FT_TRACE4(( op == cff_op_hlineto ? " hlineto" + : " vlineto" )); + + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_args ) ) + goto Fail; + + args = stack; + while ( args < decoder->top ) + { + if ( phase ) + x += args[0]; + else + y += args[0]; + + if ( cff_builder_add_point1( builder, x, y ) ) + goto Fail; + + args++; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rrcurveto: + FT_TRACE4(( " rrcurveto" )); + + /* check number of arguments; must be a multiple of 6 */ + if ( num_args % 6 != 0 ) + goto Stack_Underflow; + + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_args / 2 ) ) + goto Fail; + + args = stack; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args += 6; + } + args = stack; + break; + + case cff_op_vvcurveto: + FT_TRACE4(( " vvcurveto" )); + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args = stack; + if ( num_args & 1 ) + { + x += args[0]; + args++; + num_args--; + } + + if ( num_args % 4 != 0 ) + goto Stack_Underflow; + + if ( check_points( builder, 3 * ( num_args / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + y += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + y += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + break; + + case cff_op_hhcurveto: + FT_TRACE4(( " hhcurveto" )); + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args = stack; + if ( num_args & 1 ) + { + y += args[0]; + args++; + num_args--; + } + + if ( num_args % 4 != 0 ) + goto Stack_Underflow; + + if ( check_points( builder, 3 * ( num_args / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + break; + + case cff_op_vhcurveto: + case cff_op_hvcurveto: + { + FT_Int phase; + + + FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto" + : " hvcurveto" )); + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args = stack; + if ( num_args < 4 || ( num_args % 4 ) > 1 ) + goto Stack_Underflow; + + if ( check_points( builder, ( num_args / 4 ) * 3 ) ) + goto Stack_Underflow; + + phase = ( op == cff_op_hvcurveto ); + + while ( num_args >= 4 ) + { + num_args -= 4; + if ( phase ) + { + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + y += args[3]; + if ( num_args == 1 ) + x += args[4]; + cff_builder_add_point( builder, x, y, 1 ); + } + else + { + y += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[3]; + if ( num_args == 1 ) + y += args[4]; + cff_builder_add_point( builder, x, y, 1 ); + } + args += 4; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rlinecurve: + { + FT_Int num_lines = ( num_args - 6 ) / 2; + + + FT_TRACE4(( " rlinecurve" )); + + if ( num_args < 8 || ( num_args - 6 ) & 1 ) + goto Stack_Underflow; + + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, num_lines + 3 ) ) + goto Fail; + + args = stack; + + /* first, add the line segments */ + while ( num_lines > 0 ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + num_lines--; + } + + /* then the curve */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + } + break; + + case cff_op_rcurveline: + { + FT_Int num_curves = ( num_args - 2 ) / 6; + + + FT_TRACE4(( " rcurveline" )); + + if ( num_args < 8 || ( num_args - 2 ) % 6 ) + goto Stack_Underflow; + + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_curves*3 + 2 ) ) + goto Fail; + + args = stack; + + /* first, add the curves */ + while ( num_curves > 0 ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args += 6; + num_curves--; + } + + /* then the final line */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + } + break; + + case cff_op_hflex1: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex1" )); + + args = stack; + + /* adding five more points; 4 control points, 1 on-curve point */ + /* make sure we have enough space for the start point if it */ + /* needs to be added */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + + /* Record the starting point's y position for later use */ + start_y = y; + + /* first control point */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x += args[4]; + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x += args[5]; + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x += args[6]; + y += args[7]; + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start */ + x += args[8]; + y = start_y; + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_hflex: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex" )); + + args = stack; + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's y-position for later use */ + start_y = y; + + /* first control point */ + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x += args[4]; + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x += args[5]; + y = start_y; + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start point's */ + /* y-value -- we don't add this point, though */ + x += args[6]; + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex1: + { + FT_Pos start_x, start_y; /* record start x, y values for */ + /* alter use */ + FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */ + /* algorithm below */ + FT_Int horizontal, count; + + + FT_TRACE4(( " flex1" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's x, y position for later use */ + start_x = x; + start_y = y; + + /* XXX: figure out whether this is supposed to be a horizontal */ + /* or vertical flex; the Type 2 specification is vague... */ + + args = stack; + + /* grab up to the last argument */ + for ( count = 5; count > 0; count-- ) + { + dx += args[0]; + dy += args[1]; + args += 2; + } + + /* rewind */ + args = stack; + + if ( dx < 0 ) dx = -dx; + if ( dy < 0 ) dy = -dy; + + /* strange test, but here it is... */ + horizontal = ( dx > dy ); + + for ( count = 5; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) ); + args += 2; + } + + /* is last operand an x- or y-delta? */ + if ( horizontal ) + { + x += args[0]; + y = start_y; + } + else + { + x = start_x; + y += args[0]; + } + + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex: + { + FT_UInt count; + + + FT_TRACE4(( " flex" )); + + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + + args = stack; + for ( count = 6; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, + (FT_Bool)( count == 4 || count == 1 ) ); + args += 2; + } + + args = stack; + } + break; + + case cff_op_endchar: + FT_TRACE4(( " endchar" )); + + /* We are going to emulate the seac operator. */ + if ( num_args == 4 ) + { + /* Save glyph width so that the subglyphs don't overwrite it. */ + FT_Pos glyph_width = decoder->glyph_width; + + + error = cff_operator_seac( decoder, + args[0], + args[1], + (FT_Int)( args[2] >> 16 ), + (FT_Int)( args[3] >> 16 ) ); + args += 4; + + decoder->glyph_width = glyph_width; + } + else + { + if ( !error ) + error = CFF_Err_Ok; + + cff_builder_close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + builder->current->n_points ) ) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + } + + /* return now! */ + FT_TRACE4(( "\n\n" )); + return error; + + case cff_op_abs: + FT_TRACE4(( " abs" )); + + if ( args[0] < 0 ) + args[0] = -args[0]; + args++; + break; + + case cff_op_add: + FT_TRACE4(( " add" )); + + args[0] += args[1]; + args++; + break; + + case cff_op_sub: + FT_TRACE4(( " sub" )); + + args[0] -= args[1]; + args++; + break; + + case cff_op_div: + FT_TRACE4(( " div" )); + + args[0] = FT_DivFix( args[0], args[1] ); + args++; + break; + + case cff_op_neg: + FT_TRACE4(( " neg" )); + + args[0] = -args[0]; + args++; + break; + + case cff_op_random: + { + FT_Fixed Rand; + + + FT_TRACE4(( " rand" )); + + Rand = seed; + if ( Rand >= 0x8000L ) + Rand++; + + args[0] = Rand; + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + args++; + } + break; + + case cff_op_mul: + FT_TRACE4(( " mul" )); + + args[0] = FT_MulFix( args[0], args[1] ); + args++; + break; + + case cff_op_sqrt: + FT_TRACE4(( " sqrt" )); + + if ( args[0] > 0 ) + { + FT_Int count = 9; + FT_Fixed root = args[0]; + FT_Fixed new_root; + + + for (;;) + { + new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; + if ( new_root == root || count <= 0 ) + break; + root = new_root; + } + args[0] = new_root; + } + else + args[0] = 0; + args++; + break; + + case cff_op_drop: + /* nothing */ + FT_TRACE4(( " drop" )); + + break; + + case cff_op_exch: + { + FT_Fixed tmp; + + + FT_TRACE4(( " exch" )); + + tmp = args[0]; + args[0] = args[1]; + args[1] = tmp; + args += 2; + } + break; + + case cff_op_index: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " index" )); + + if ( idx < 0 ) + idx = 0; + else if ( idx > num_args - 2 ) + idx = num_args - 2; + args[0] = args[-( idx + 1 )]; + args++; + } + break; + + case cff_op_roll: + { + FT_Int count = (FT_Int)( args[0] >> 16 ); + FT_Int idx = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " roll" )); + + if ( count <= 0 ) + count = 1; + + args -= count; + if ( args < stack ) + goto Stack_Underflow; + + if ( idx >= 0 ) + { + while ( idx > 0 ) + { + FT_Fixed tmp = args[count - 1]; + FT_Int i; + + + for ( i = count - 2; i >= 0; i-- ) + args[i + 1] = args[i]; + args[0] = tmp; + idx--; + } + } + else + { + while ( idx < 0 ) + { + FT_Fixed tmp = args[0]; + FT_Int i; + + + for ( i = 0; i < count - 1; i++ ) + args[i] = args[i + 1]; + args[count - 1] = tmp; + idx++; + } + } + args += count; + } + break; + + case cff_op_dup: + FT_TRACE4(( " dup" )); + + args[1] = args[0]; + args++; + break; + + case cff_op_put: + { + FT_Fixed val = args[0]; + FT_Int idx = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " put" )); + + if ( idx >= 0 && idx < decoder->len_buildchar ) + decoder->buildchar[idx] = val; + } + break; + + case cff_op_get: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + FT_Fixed val = 0; + + + FT_TRACE4(( " get" )); + + if ( idx >= 0 && idx < decoder->len_buildchar ) + val = decoder->buildchar[idx]; + + args[0] = val; + args++; + } + break; + + case cff_op_store: + FT_TRACE4(( " store ")); + + goto Unimplemented; + + case cff_op_load: + FT_TRACE4(( " load" )); + + goto Unimplemented; + + case cff_op_dotsection: + /* this operator is deprecated and ignored by the parser */ + FT_TRACE4(( " dotsection" )); + break; + + case cff_op_and: + { + FT_Fixed cond = args[0] && args[1]; + + + FT_TRACE4(( " and" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_or: + { + FT_Fixed cond = args[0] || args[1]; + + + FT_TRACE4(( " or" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_eq: + { + FT_Fixed cond = !args[0]; + + + FT_TRACE4(( " eq" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_ifelse: + { + FT_Fixed cond = ( args[2] <= args[3] ); + + + FT_TRACE4(( " ifelse" )); + + if ( !cond ) + args[0] = args[1]; + args++; + } + break; + + case cff_op_callsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->locals_bias ); + + + FT_TRACE4(( " callsubr(%d)", idx )); + + if ( idx >= decoder->num_locals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" )); + FT_ERROR(( " invalid local subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->locals[idx]; + zone->limit = decoder->locals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_callgsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->globals_bias ); + + + FT_TRACE4(( " callgsubr(%d)", idx )); + + if ( idx >= decoder->num_globals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" )); + FT_ERROR(( " invalid global subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->globals[idx]; + zone->limit = decoder->globals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_return: + FT_TRACE4(( " return" )); + + if ( decoder->zone <= decoder->zones ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + + decoder->zone--; + zone = decoder->zone; + ip = zone->cursor; + limit = zone->limit; + break; + + default: + Unimplemented: + FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); + + if ( ip[-1] == 12 ) + FT_ERROR(( " %d", ip[0] )); + FT_ERROR(( "\n" )); + + return CFF_Err_Unimplemented_Feature; + } + + decoder->top = args; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + + Fail: + return error; + + Syntax_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" )); + return CFF_Err_Invalid_File_Format; + + Stack_Underflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" )); + return CFF_Err_Too_Few_Arguments; + + Stack_Overflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" )); + return CFF_Err_Stack_Overflow; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#if 0 /* unused until we support pure CFF fonts */ + + + FT_LOCAL_DEF( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ) + { + FT_Error error = CFF_Err_Ok; + CFF_Decoder decoder; + FT_Int glyph_index; + CFF_Font cff = (CFF_Font)face->other; + + + *max_advance = 0; + + /* Initialize load decoder */ + cff_decoder_init( &decoder, face, 0, 0, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width. */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + /* now get load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = cff_decoder_prepare( &decoder, glyph_index ); + if ( !error ) + error = cff_decoder_parse_charstrings( &decoder, + charstring, + charstring_len ); + + cff_free_glyph_data( face, &charstring, &charstring_len ); + } + + /* ignore the error if one has occurred -- skip to next glyph */ + error = CFF_Err_Ok; + } + + *max_advance = decoder.builder.advance.x; + + return CFF_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_Decoder decoder; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting; + CFF_Font cff = (CFF_Font)face->extra.data; + + FT_Matrix font_matrix; + FT_Vector font_offset; + + + /* in a CID-keyed font, consider `glyph_index' as a CID and map */ + /* it immediately to the real glyph_index -- if it isn't a */ + /* subsetted font, glyph_indices and CIDs are identical, though */ + if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && + cff->charset.cids ) + { + glyph_index = cff_charset_cid_to_gindex( &cff->charset, glyph_index ); + if ( glyph_index == 0 ) + return CFF_Err_Invalid_Argument; + } + else if ( glyph_index >= cff->num_glyphs ) + return CFF_Err_Invalid_Argument; + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + if ( size ) + { + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap if any */ + /* */ + /* XXX: The convention should be emphasized in */ + /* the documents because it can be confusing. */ + if ( size ) + { + CFF_Face cff_face = (CFF_Face)size->root.face; + SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; + FT_Stream stream = cff_face->root.stream; + + + if ( size->strike_index != 0xFFFFFFFFUL && + sfnt->load_eblc && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + TT_SBit_MetricsRec metrics; + + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_Int)load_flags, + stream, + &glyph->root.bitmap, + &metrics ); + + if ( !error ) + { + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + glyph->root.metrics.width = (FT_Pos)metrics.width << 6; + glyph->root.metrics.height = (FT_Pos)metrics.height << 6; + + glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + + glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->root.bitmap_left = metrics.vertBearingX; + glyph->root.bitmap_top = metrics.vertBearingY; + } + else + { + glyph->root.bitmap_left = metrics.horiBearingX; + glyph->root.bitmap_top = metrics.horiBearingY; + } + return error; + } + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* return immediately if we only want the embedded bitmaps */ + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return CFF_Err_Invalid_Argument; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ + + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + cff_decoder_init( &decoder, face, size, glyph, hinting, + FT_LOAD_TARGET_MODE( load_flags ) ); + + decoder.builder.no_recurse = + (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); + + /* now load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = cff_decoder_prepare( &decoder, glyph_index ); + if ( !error ) + { + error = cff_decoder_parse_charstrings( &decoder, + charstring, + charstring_len ); + + cff_free_glyph_data( face, &charstring, charstring_len ); + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Control data and length may not be available for incremental */ + /* fonts. */ + if ( face->root.internal->incremental_interface ) + { + glyph->root.control_data = 0; + glyph->root.control_len = 0; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* We set control_data and control_len if charstrings is loaded. */ + /* See how charstring loads at cff_index_access_element() in */ + /* cffload.c. */ + { + CFF_Index csindex = &cff->charstrings_index; + + + if ( csindex->offsets ) + { + glyph->root.control_data = csindex->bytes + + csindex->offsets[glyph_index] - 1; + glyph->root.control_len = charstring_len; + } + } + } + } + + /* save new glyph tables */ + cff_builder_done( &decoder.builder ); + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && + face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = decoder.builder.left_bearing.x; + metrics.bearing_y = decoder.builder.left_bearing.y; + metrics.advance = decoder.builder.advance.x; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + decoder.builder.left_bearing.x = metrics.bearing_x; + decoder.builder.left_bearing.y = metrics.bearing_y; + decoder.builder.advance.x = metrics.advance; + decoder.builder.advance.y = 0; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + if ( !error ) + { + if ( cff->num_subfonts >= 1 ) + { + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, + glyph_index ); + + + font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; + font_offset = cff->subfonts[fd_index]->font_dict.font_offset; + } + else + { + font_matrix = cff->top_font.font_dict.font_matrix; + font_offset = cff->top_font.font_dict.font_offset; + } + + /* Now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax. */ + + /* For composite glyphs, return only left side bearing and */ + /* advance width. */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = glyph->root.internal; + + + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.glyph_width; + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + FT_Vector advance; + FT_Bool has_vertical_info; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.glyph_width; + glyph->root.linearHoriAdvance = decoder.glyph_width; + glyph->root.internal->glyph_transformed = 0; + + has_vertical_info = FT_BOOL( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 && + face->vertical.long_metrics != 0 ); + + /* get the vertical metrics from the vtmx table if we have one */ + if ( has_vertical_info ) + { + FT_Short vertBearingY = 0; + FT_UShort vertAdvance = 0; + + + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, + glyph_index, + &vertBearingY, + &vertAdvance ); + metrics->vertBearingY = vertBearingY; + metrics->vertAdvance = vertAdvance; + } + else + { + /* make up vertical ones */ + if ( face->os2.version != 0xFFFFU ) + metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + } + + glyph->root.linearVertAdvance = metrics->vertAdvance; + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + glyph->root.outline.flags = 0; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* apply the font matrix */ + if ( !( font_matrix.xx == 0x10000L && + font_matrix.yy == 0x10000L && + font_matrix.xy == 0 && + font_matrix.yx == 0 ) ) + FT_Outline_Transform( &glyph->root.outline, &font_matrix ); + + if ( !( font_offset.x == 0 && + font_offset.y == 0 ) ) + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, font_offset.y ); + + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + font_offset.y; + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &glyph->root.outline; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( has_vertical_info ) + metrics->vertBearingX = -metrics->width / 2; + else + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/cff/cffgload.h b/src/freetype2/cff/cffgload.h new file mode 100644 index 0000000..f67864a --- /dev/null +++ b/src/freetype2/cff/cffgload.h @@ -0,0 +1,208 @@ +/***************************************************************************/ +/* */ +/* cffgload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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 __CFFGLOAD_H__ +#define __CFFGLOAD_H__ + + +#include +#include FT_FREETYPE_H +#include "cffobjs.h" + + +FT_BEGIN_HEADER + + +#define CFF_MAX_OPERANDS 48 +#define CFF_MAX_SUBRS_CALLS 32 + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_Builder */ + /* */ + /* */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* loader :: The current glyph loader. */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ + /* */ + /* scale_y :: The vertical scale (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (if composite glyph). */ + /* */ + /* pos_y :: The vertical translation (if composite glyph). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* bbox :: Unused. */ + /* */ + /* path_begun :: A flag which indicates that a new path has begun. */ + /* */ + /* load_points :: If this flag is not set, no points are loaded. */ + /* */ + /* no_recurse :: Set but not used. */ + /* */ + /* metrics_only :: A boolean indicating that we only want to compute */ + /* the metrics of a given glyph, not load all of its */ + /* points. */ + /* */ + /* hints_funcs :: Auxiliary pointer for hinting. */ + /* */ + /* hints_globals :: Auxiliary pointer for hinting. */ + /* */ + typedef struct CFF_Builder_ + { + FT_Memory memory; + TT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + } CFF_Builder; + + + /* execution context charstring zone */ + + typedef struct CFF_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } CFF_Decoder_Zone; + + + typedef struct CFF_Decoder_ + { + CFF_Builder builder; + CFF_Font cff; + + FT_Fixed stack[CFF_MAX_OPERANDS + 1]; + FT_Fixed* top; + + CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1]; + CFF_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + FT_Pos glyph_width; + FT_Pos nominal_width; + + FT_Bool read_width; + FT_Int num_hints; + FT_Fixed* buildchar; + FT_Int len_buildchar; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + FT_Byte** glyph_names; /* for pure CFF fonts only */ + FT_UInt num_glyphs; /* number of glyphs in font */ + + FT_Render_Mode hint_mode; + + } CFF_Decoder; + + + FT_LOCAL( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode ); + + FT_LOCAL( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + FT_UInt glyph_index ); + +#if 0 /* unused until we support pure CFF fonts */ + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + FT_LOCAL( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + FT_LOCAL( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* __CFFGLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cffload.c b/src/freetype2/cff/cffload.c new file mode 100644 index 0000000..dd2f113 --- /dev/null +++ b/src/freetype2/cff/cffload.c @@ -0,0 +1,1598 @@ +/***************************************************************************/ +/* */ +/* cffload.c */ +/* */ +/* OpenType and CFF data/program tables loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_STREAM_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_TRUETYPE_TAGS_H +#include FT_TYPE1_TABLES_H + +#include "cffload.h" +#include "cffparse.h" + +#include "cfferrs.h" + + +#if 1 + static const FT_UShort cff_isoadobe_charset[229] = + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228 + }; + + static const FT_UShort cff_expert_charset[166] = + { + 0, 1, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 + }; + + static const FT_UShort cff_expertsubset_charset[87] = + { + 0, 1, 231, 232, 235, 236, 237, 238, + 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, + 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 + }; + + static const FT_UShort cff_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, + 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, + 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, + 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, + 146, 147, 148, 149, 0, 0, 0, 0 + }; + + static const FT_UShort cff_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 0, 0, + 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, + 110, 267, 268, 269, 0, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, + 309, 310, 311, 0, 312, 0, 0, 312, + 0, 0, 314, 315, 0, 0, 316, 317, + 318, 0, 0, 0, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 0, 0, + 326, 150, 164, 169, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378 + }; +#endif + + + FT_LOCAL_DEF( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ) + { + return (FT_UShort)(charcode < 256 ? cff_standard_encoding[charcode] : 0); + } + + + /*************************************************************************/ + /* */ + /* 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_cffload + + + /* read an offset from the index's stream current position */ + static FT_ULong + cff_index_read_offset( CFF_Index idx, + FT_Error *errorp ) + { + FT_Error error; + FT_Stream stream = idx->stream; + FT_Byte tmp[4]; + FT_ULong result = 0; + + + if ( !FT_STREAM_READ( tmp, idx->off_size ) ) + { + FT_Int nn; + + + for ( nn = 0; nn < idx->off_size; nn++ ) + result = ( result << 8 ) | tmp[nn]; + } + + *errorp = error; + return result; + } + + + static FT_Error + cff_index_init( CFF_Index idx, + FT_Stream stream, + FT_Bool load ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort count; + + + FT_MEM_ZERO( idx, sizeof ( *idx ) ); + + idx->stream = stream; + idx->start = FT_STREAM_POS(); + if ( !FT_READ_USHORT( count ) && + count > 0 ) + { + FT_Byte offsize; + FT_ULong size; + + + /* there is at least one element; read the offset size, */ + /* then access the offset table to compute the index's total size */ + if ( FT_READ_BYTE( offsize ) ) + goto Exit; + + if ( offsize < 1 || offsize > 4 ) + { + error = FT_Err_Invalid_Table; + goto Exit; + } + + idx->count = count; + idx->off_size = offsize; + size = (FT_ULong)( count + 1 ) * offsize; + + idx->data_offset = idx->start + 3 + size; + + if ( FT_STREAM_SKIP( size - offsize ) ) + goto Exit; + + size = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( size == 0 ) + { + error = CFF_Err_Invalid_Table; + goto Exit; + } + + idx->data_size = --size; + + if ( load ) + { + /* load the data */ + if ( FT_FRAME_EXTRACT( size, idx->bytes ) ) + goto Exit; + } + else + { + /* skip the data */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + static void + cff_index_done( CFF_Index idx ) + { + if ( idx->stream ) + { + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->bytes ) + FT_FRAME_RELEASE( idx->bytes ); + + FT_FREE( idx->offsets ); + FT_MEM_ZERO( idx, sizeof ( *idx ) ); + } + } + + + static FT_Error + cff_index_load_offsets( CFF_Index idx ) + { + FT_Error error = 0; + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->count > 0 && idx->offsets == NULL ) + { + FT_Byte offsize = idx->off_size; + FT_ULong data_size; + FT_Byte* p; + FT_Byte* p_end; + FT_ULong* poff; + + + data_size = (FT_ULong)( idx->count + 1 ) * offsize; + + if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + 3 ) || + FT_FRAME_ENTER( data_size ) ) + goto Exit; + + poff = idx->offsets; + p = (FT_Byte*)stream->cursor; + p_end = p + data_size; + + switch ( offsize ) + { + case 1: + for ( ; p < p_end; p++, poff++ ) + poff[0] = p[0]; + break; + + case 2: + for ( ; p < p_end; p += 2, poff++ ) + poff[0] = FT_PEEK_USHORT( p ); + break; + + case 3: + for ( ; p < p_end; p += 3, poff++ ) + poff[0] = FT_PEEK_OFF3( p ); + break; + + default: + for ( ; p < p_end; p += 4, poff++ ) + poff[0] = FT_PEEK_ULONG( p ); + } + + FT_FRAME_EXIT(); + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + /* allocate a table containing pointers to an index's elements */ + static FT_Error + cff_index_get_pointers( CFF_Index idx, + FT_Byte*** table ) + { + FT_Error error = CFF_Err_Ok; + FT_Memory memory = idx->stream->memory; + FT_ULong n, offset, old_offset; + FT_Byte** t; + + + *table = 0; + + if ( idx->offsets == NULL ) + { + error = cff_index_load_offsets( idx ); + if ( error ) + goto Exit; + } + + if ( idx->count > 0 && !FT_NEW_ARRAY( t, idx->count + 1 ) ) + { + old_offset = 1; + for ( n = 0; n <= idx->count; n++ ) + { + offset = idx->offsets[n]; + if ( !offset ) + offset = old_offset; + + /* two sanity checks for invalid offset tables */ + else if ( offset < old_offset ) + offset = old_offset; + + else if ( offset - 1 >= idx->data_size && n < idx->count ) + offset = old_offset; + + t[n] = idx->bytes + offset - 1; + + old_offset = offset; + } + *table = t; + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ) + { + FT_Error error = CFF_Err_Ok; + + + if ( idx && idx->count > element ) + { + /* compute start and end offsets */ + FT_Stream stream = idx->stream; + FT_ULong off1, off2 = 0; + + + /* load offsets from file or the offset table */ + if ( !idx->offsets ) + { + FT_ULong pos = element * idx->off_size; + + + if ( FT_STREAM_SEEK( idx->start + 3 + pos ) ) + goto Exit; + + off1 = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( off1 != 0 ) + { + do + { + element++; + off2 = cff_index_read_offset( idx, &error ); + } + while ( off2 == 0 && element < idx->count ); + } + } + else /* use offsets table */ + { + off1 = idx->offsets[element]; + if ( off1 ) + { + do + { + element++; + off2 = idx->offsets[element]; + + } while ( off2 == 0 && element < idx->count ); + } + } + + /* access element */ + if ( off1 && off2 > off1 ) + { + *pbyte_len = off2 - off1; + + if ( idx->bytes ) + { + /* this index was completely loaded in memory, that's easy */ + *pbytes = idx->bytes + off1 - 1; + } + else + { + /* this index is still on disk/file, access it through a frame */ + if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) || + FT_FRAME_EXTRACT( off2 - off1, *pbytes ) ) + goto Exit; + } + } + else + { + /* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = CFF_Err_Invalid_Argument; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ) + { + if ( idx->bytes == 0 ) + { + FT_Stream stream = idx->stream; + + + FT_FRAME_RELEASE( *pbytes ); + } + } + + + FT_LOCAL_DEF( FT_String* ) + cff_index_get_name( CFF_Index idx, + FT_UInt element ) + { + FT_Memory memory = idx->stream->memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = 0; + + + error = cff_index_access_element( idx, element, &bytes, &byte_len ); + if ( error ) + goto Exit; + + if ( !FT_ALLOC( name, byte_len + 1 ) ) + { + FT_MEM_COPY( name, bytes, byte_len ); + name[byte_len] = 0; + } + cff_index_forget_element( idx, &bytes ); + + Exit: + return name; + } + + + FT_LOCAL_DEF( FT_String* ) + cff_index_get_sid_string( CFF_Index idx, + FT_UInt sid, + FT_Service_PsCMaps psnames ) + { + /* value 0xFFFFU indicates a missing dictionary entry */ + if ( sid == 0xFFFFU ) + return 0; + + /* if it is not a standard string, return it */ + if ( sid > 390 ) + return cff_index_get_name( idx, sid - 391 ); + + /* CID-keyed CFF fonts don't have glyph names */ + if ( !psnames ) + return 0; + + /* that's a standard string, fetch a copy from the PSName module */ + { + FT_String* name = 0; + const char* adobe_name = psnames->adobe_std_strings( sid ); + + + if ( adobe_name ) + { + FT_Memory memory = idx->stream->memory; + FT_Error error; + + + (void)FT_STRDUP( name, adobe_name ); + + FT_UNUSED( error ); + } + + return name; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** FD Select table support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + + static void + CFF_Done_FD_Select( CFF_FDSelect fdselect, + FT_Stream stream ) + { + if ( fdselect->data ) + FT_FRAME_RELEASE( fdselect->data ); + + fdselect->data_size = 0; + fdselect->format = 0; + fdselect->range_count = 0; + } + + + static FT_Error + CFF_Load_FD_Select( CFF_FDSelect fdselect, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong offset ) + { + FT_Error error; + FT_Byte format; + FT_UInt num_ranges; + + + /* read format */ + if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) ) + goto Exit; + + fdselect->format = format; + fdselect->cache_count = 0; /* clear cache */ + + switch ( format ) + { + case 0: /* format 0, that's simple */ + fdselect->data_size = num_glyphs; + goto Load_Data; + + case 3: /* format 3, a tad more complex */ + if ( FT_READ_USHORT( num_ranges ) ) + goto Exit; + + fdselect->data_size = num_ranges * 3 + 2; + + Load_Data: + if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) ) + goto Exit; + break; + + default: /* hmm... that's wrong */ + error = CFF_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ) + { + FT_Byte fd = 0; + + + switch ( fdselect->format ) + { + case 0: + fd = fdselect->data[glyph_index]; + break; + + case 3: + /* first, compare to cache */ + if ( (FT_UInt)( glyph_index - fdselect->cache_first ) < + fdselect->cache_count ) + { + fd = fdselect->cache_fd; + break; + } + + /* then, lookup the ranges array */ + { + FT_Byte* p = fdselect->data; + FT_Byte* p_limit = p + fdselect->data_size; + FT_Byte fd2; + FT_UInt first, limit; + + + first = FT_NEXT_USHORT( p ); + do + { + if ( glyph_index < first ) + break; + + fd2 = *p++; + limit = FT_NEXT_USHORT( p ); + + if ( glyph_index < limit ) + { + fd = fd2; + + /* update cache */ + fdselect->cache_first = first; + fdselect->cache_count = limit-first; + fdselect->cache_fd = fd2; + break; + } + first = limit; + + } while ( p < p_limit ); + } + break; + + default: + ; + } + + return fd; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** CFF font support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + cff_charset_compute_cids( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_UInt i; + FT_UShort max_cid = 0; + + + if ( charset->max_cid > 0 ) + goto Exit; + + for ( i = 0; i < num_glyphs; i++ ) + if ( charset->sids[i] > max_cid ) + max_cid = charset->sids[i]; + max_cid++; + + if ( FT_NEW_ARRAY( charset->cids, max_cid ) ) + goto Exit; + + for ( i = 0; i < num_glyphs; i++ ) + charset->cids[charset->sids[i]] = (FT_UShort)i; + + charset->max_cid = max_cid; + charset->num_glyphs = num_glyphs; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ) + { + FT_UInt result = 0; + + + if ( cid < charset->max_cid ) + result = charset->cids[cid]; + + return result; + } + + + static void + cff_charset_free_cids( CFF_Charset charset, + FT_Memory memory ) + { + FT_FREE( charset->cids ); + charset->max_cid = 0; + } + + + static void + cff_charset_done( CFF_Charset charset, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + cff_charset_free_cids( charset, memory ); + + FT_FREE( charset->sids ); + charset->format = 0; + charset->offset = 0; + } + + + static FT_Error + cff_charset_load( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset, + FT_Bool invert ) + { + FT_Memory memory = stream->memory; + FT_Error error = CFF_Err_Ok; + FT_UShort glyph_sid; + + + /* If the the offset is greater than 2, we have to parse the */ + /* charset table. */ + if ( offset > 2 ) + { + FT_UInt j; + + + charset->offset = base_offset + offset; + + /* Get the format of the table. */ + if ( FT_STREAM_SEEK( charset->offset ) || + FT_READ_BYTE( charset->format ) ) + goto Exit; + + /* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* assign the .notdef glyph */ + charset->sids[0] = 0; + + switch ( charset->format ) + { + case 0: + if ( num_glyphs > 0 ) + { + if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) + goto Exit; + + for ( j = 1; j < num_glyphs; j++ ) + charset->sids[j] = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + } + break; + + case 1: + case 2: + { + FT_UInt nleft; + FT_UInt i; + + + j = 1; + + while ( j < num_glyphs ) + { + /* Read the first glyph sid of the range. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Read the number of glyphs in the range. */ + if ( charset->format == 2 ) + { + if ( FT_READ_USHORT( nleft ) ) + goto Exit; + } + else + { + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + } + + /* Fill in the range of sids -- `nleft + 1' glyphs. */ + for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) + charset->sids[j] = glyph_sid; + } + } + break; + + default: + FT_ERROR(( "cff_charset_load: invalid table format!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } + else + { + /* Parse default tables corresponding to offset == 0, 1, or 2. */ + /* CFF specification intimates the following: */ + /* */ + /* In order to use a predefined charset, the following must be */ + /* true: The charset constructed for the glyphs in the font's */ + /* charstrings dictionary must match the predefined charset in */ + /* the first num_glyphs. */ + + charset->offset = offset; /* record charset type */ + + switch ( (FT_UInt)offset ) + { + case 0: + if ( num_glyphs > 229 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe ISO-Latin)!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); + + break; + + case 1: + if ( num_glyphs > 166 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe Expert)!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); + + break; + + case 2: + if ( num_glyphs > 87 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe Expert Subset)!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); + + break; + + default: + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } + + /* we have to invert the `sids' array for subsetted CID-keyed fonts */ + if ( invert ) + error = cff_charset_compute_cids( charset, num_glyphs, memory ); + + Exit: + /* Clean up if there was an error. */ + if ( error ) + { + FT_FREE( charset->sids ); + FT_FREE( charset->cids ); + charset->format = 0; + charset->offset = 0; + charset->sids = 0; + } + + return error; + } + + + static void + cff_encoding_done( CFF_Encoding encoding ) + { + encoding->format = 0; + encoding->offset = 0; + encoding->count = 0; + } + + + static FT_Error + cff_encoding_load( CFF_Encoding encoding, + CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Error error = CFF_Err_Ok; + FT_UInt count; + FT_UInt j; + FT_UShort glyph_sid; + FT_UInt glyph_code; + + + /* Check for charset->sids. If we do not have this, we fail. */ + if ( !charset->sids ) + { + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + /* Zero out the code to gid/sid mappings. */ + for ( j = 0; j < 256; j++ ) + { + encoding->sids [j] = 0; + encoding->codes[j] = 0; + } + + /* Note: The encoding table in a CFF font is indexed by glyph index; */ + /* the first encoded glyph index is 1. Hence, we read the character */ + /* code (`glyph_code') at index j and make the assignment: */ + /* */ + /* encoding->codes[glyph_code] = j + 1 */ + /* */ + /* We also make the assignment: */ + /* */ + /* encoding->sids[glyph_code] = charset->sids[j + 1] */ + /* */ + /* This gives us both a code to GID and a code to SID mapping. */ + + if ( offset > 1 ) + { + encoding->offset = base_offset + offset; + + /* we need to parse the table to determine its size */ + if ( FT_STREAM_SEEK( encoding->offset ) || + FT_READ_BYTE( encoding->format ) || + FT_READ_BYTE( count ) ) + goto Exit; + + switch ( encoding->format & 0x7F ) + { + case 0: + { + FT_Byte* p; + + + /* By convention, GID 0 is always ".notdef" and is never */ + /* coded in the font. Hence, the number of codes found */ + /* in the table is `count+1'. */ + /* */ + encoding->count = count + 1; + + if ( FT_FRAME_ENTER( count ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + + for ( j = 1; j <= count; j++ ) + { + glyph_code = *p++; + + /* Make sure j is not too big. */ + if ( j < num_glyphs ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)j; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[j]; + } + } + + FT_FRAME_EXIT(); + } + break; + + case 1: + { + FT_UInt nleft; + FT_UInt i = 1; + FT_UInt k; + + + encoding->count = 0; + + /* Parse the Format1 ranges. */ + for ( j = 0; j < count; j++, i += nleft ) + { + /* Read the first glyph code of the range. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the number of codes in the range. */ + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + + /* Increment nleft, so we read `nleft + 1' codes/sids. */ + nleft++; + + /* compute max number of character codes */ + if ( (FT_UInt)nleft > encoding->count ) + encoding->count = nleft; + + /* Fill in the range of codes/sids. */ + for ( k = i; k < nleft + i; k++, glyph_code++ ) + { + /* Make sure k is not too big. */ + if ( k < num_glyphs && glyph_code < 256 ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)k; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[k]; + } + } + } + + /* simple check; one never knows what can be found in a font */ + if ( encoding->count > 256 ) + encoding->count = 256; + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + + /* Parse supplemental encodings, if any. */ + if ( encoding->format & 0x80 ) + { + FT_UInt gindex; + + + /* count supplements */ + if ( FT_READ_BYTE( count ) ) + goto Exit; + + for ( j = 0; j < count; j++ ) + { + /* Read supplemental glyph code. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the SID associated with this glyph code. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = glyph_sid; + + /* First, look up GID which has been assigned to */ + /* SID glyph_sid. */ + for ( gindex = 0; gindex < num_glyphs; gindex++ ) + { + if ( charset->sids[gindex] == glyph_sid ) + { + encoding->codes[glyph_code] = (FT_UShort)gindex; + break; + } + } + } + } + } + else + { + /* We take into account the fact a CFF font can use a predefined */ + /* encoding without containing all of the glyphs encoded by this */ + /* encoding (see the note at the end of section 12 in the CFF */ + /* specification). */ + + switch ( (FT_UInt)offset ) + { + case 0: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 ); + goto Populate; + + case 1: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 ); + + Populate: + /* Construct code to GID mapping from code to SID mapping */ + /* and charset. */ + + encoding->count = 0; + + error = cff_charset_compute_cids( charset, num_glyphs, + stream->memory ); + if ( error ) + goto Exit; + + for ( j = 0; j < 256; j++ ) + { + FT_UInt sid = encoding->sids[j]; + FT_UInt gid = 0; + + + if ( sid ) + gid = cff_charset_cid_to_gindex( charset, sid ); + + if ( gid != 0 ) + { + encoding->codes[j] = (FT_UShort)gid; + + if ( encoding->count < j + 1 ) + encoding->count = j + 1; + } + else + { + encoding->codes[j] = 0; + encoding->sids [j] = 0; + } + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format!\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } + + Exit: + + /* Clean up if there was an error. */ + return error; + } + + + static FT_Error + cff_subfont_load( CFF_SubFont font, + CFF_Index idx, + FT_UInt font_index, + FT_Stream stream, + FT_ULong base_offset ) + { + FT_Error error; + CFF_ParserRec parser; + FT_Byte* dict = NULL; + FT_ULong dict_len; + CFF_FontRecDict top = &font->font_dict; + CFF_Private priv = &font->private_dict; + + + cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict ); + + /* set defaults */ + FT_MEM_ZERO( top, sizeof ( *top ) ); + + top->underline_position = -100L << 16; + top->underline_thickness = 50L << 16; + top->charstring_type = 2; + top->font_matrix.xx = 0x10000L; + top->font_matrix.yy = 0x10000L; + top->cid_count = 8720; + + /* we use the implementation specific SID value 0xFFFF to indicate */ + /* missing entries */ + top->version = 0xFFFFU; + top->notice = 0xFFFFU; + top->copyright = 0xFFFFU; + top->full_name = 0xFFFFU; + top->family_name = 0xFFFFU; + top->weight = 0xFFFFU; + top->embedded_postscript = 0xFFFFU; + + top->cid_registry = 0xFFFFU; + top->cid_ordering = 0xFFFFU; + top->cid_font_name = 0xFFFFU; + + error = cff_index_access_element( idx, font_index, &dict, &dict_len ) || + cff_parser_run( &parser, dict, dict + dict_len ); + + cff_index_forget_element( idx, &dict ); + + if ( error ) + goto Exit; + + /* if it is a CID font, we stop there */ + if ( top->cid_registry != 0xFFFFU ) + goto Exit; + + /* parse the private dictionary, if any */ + if ( top->private_offset && top->private_size ) + { + /* set defaults */ + FT_MEM_ZERO( priv, sizeof ( *priv ) ); + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + cff_parser_init( &parser, CFF_CODE_PRIVATE, priv ); + + if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) || + FT_FRAME_ENTER( font->font_dict.private_size ) ) + goto Exit; + + error = cff_parser_run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + + /* ensure that `num_blue_values' is even */ + priv->num_blue_values &= ~1; + } + + /* read the local subrs, if any */ + if ( priv->local_subrs_offset ) + { + if ( FT_STREAM_SEEK( base_offset + top->private_offset + + priv->local_subrs_offset ) ) + goto Exit; + + error = cff_index_init( &font->local_subrs_index, stream, 1 ); + if ( error ) + goto Exit; + + font->num_local_subrs = font->local_subrs_index.count; + error = cff_index_get_pointers( &font->local_subrs_index, + &font->local_subrs ); + if ( error ) + goto Exit; + } + + Exit: + return error; + } + + + static void + cff_subfont_done( FT_Memory memory, + CFF_SubFont subfont ) + { + if ( subfont ) + { + cff_index_done( &subfont->local_subrs_index ); + FT_FREE( subfont->local_subrs ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_font_load( FT_Stream stream, + FT_Int face_index, + CFF_Font font ) + { + static const FT_Frame_Field cff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRec + + FT_FRAME_START( 4 ), + FT_FRAME_BYTE( version_major ), + FT_FRAME_BYTE( version_minor ), + FT_FRAME_BYTE( header_size ), + FT_FRAME_BYTE( absolute_offsize ), + FT_FRAME_END + }; + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; + CFF_FontRecDict dict; + + + FT_ZERO( font ); + + font->stream = stream; + font->memory = memory; + dict = &font->top_font.font_dict; + base_offset = FT_STREAM_POS(); + + /* read CFF font header */ + if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) + goto Exit; + + /* check format */ + if ( font->version_major != 1 || + font->header_size < 4 || + font->absolute_offsize > 4 ) + { + FT_TRACE2(( "[not a CFF font header!]\n" )); + error = CFF_Err_Unknown_File_Format; + goto Exit; + } + + /* skip the rest of the header */ + if ( FT_STREAM_SKIP( font->header_size - 4 ) ) + goto Exit; + + /* read the name, top dict, string and global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->name_index, + stream, 0 ) ) || + FT_SET_ERROR( cff_index_init( &font->font_dict_index, + stream, 0 ) ) || + FT_SET_ERROR( cff_index_init( &font->string_index, + stream, 0 ) ) || + FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1 ) ) ) + goto Exit; + + /* well, we don't really forget the `disabled' fonts... */ + font->num_faces = font->name_index.count; + if ( face_index >= (FT_Int)font->num_faces ) + { + FT_ERROR(( "cff_font_load: incorrect face index = %d\n", + face_index )); + error = CFF_Err_Invalid_Argument; + } + + /* in case of a font format check, simply exit now */ + if ( face_index < 0 ) + goto Exit; + + /* now, parse the top-level font dictionary */ + error = cff_subfont_load( &font->top_font, + &font->font_dict_index, + face_index, + stream, + base_offset ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) + goto Exit; + + error = cff_index_init( &font->charstrings_index, stream, 0 ); + if ( error ) + goto Exit; + + /* now, check for a CID font */ + if ( dict->cid_registry != 0xFFFFU ) + { + CFF_IndexRec fd_index; + CFF_SubFont sub; + FT_UInt idx; + + + /* this is a CID-keyed font, we must now allocate a table of */ + /* sub-fonts, then load each of them separately */ + if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) + goto Exit; + + error = cff_index_init( &fd_index, stream, 0 ); + if ( error ) + goto Exit; + + if ( fd_index.count > CFF_MAX_CID_FONTS ) + { + FT_ERROR(( "cff_font_load: FD array too large in CID font\n" )); + goto Fail_CID; + } + + /* allocate & read each font dict independently */ + font->num_subfonts = fd_index.count; + if ( FT_NEW_ARRAY( sub, fd_index.count ) ) + goto Fail_CID; + + /* set up pointer table */ + for ( idx = 0; idx < fd_index.count; idx++ ) + font->subfonts[idx] = sub + idx; + + /* now load each subfont independently */ + for ( idx = 0; idx < fd_index.count; idx++ ) + { + sub = font->subfonts[idx]; + error = cff_subfont_load( sub, &fd_index, idx, + stream, base_offset ); + if ( error ) + goto Fail_CID; + } + + /* now load the FD Select array */ + error = CFF_Load_FD_Select( &font->fd_select, + font->charstrings_index.count, + stream, + base_offset + dict->cid_fd_select_offset ); + + Fail_CID: + cff_index_done( &fd_index ); + + if ( error ) + goto Exit; + } + else + font->num_subfonts = 0; + + /* read the charstrings index now */ + if ( dict->charstrings_offset == 0 ) + { + FT_ERROR(( "cff_font_load: no charstrings offset!\n" )); + error = CFF_Err_Unknown_File_Format; + goto Exit; + } + + /* explicit the global subrs */ + font->num_global_subrs = font->global_subrs_index.count; + font->num_glyphs = font->charstrings_index.count; + + error = cff_index_get_pointers( &font->global_subrs_index, + &font->global_subrs ) ; + + if ( error ) + goto Exit; + + /* read the Charset and Encoding tables if available */ + if ( font->num_glyphs > 0 ) + { + FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU ); + + + error = cff_charset_load( &font->charset, font->num_glyphs, stream, + base_offset, dict->charset_offset, invert ); + if ( error ) + goto Exit; + + /* CID-keyed CFFs don't have an encoding */ + if ( dict->cid_registry == 0xFFFFU ) + { + error = cff_encoding_load( &font->encoding, + &font->charset, + font->num_glyphs, + stream, + base_offset, + dict->encoding_offset ); + if ( error ) + goto Exit; + } + else + /* CID-keyed fonts only need CIDs */ + FT_FREE( font->charset.sids ); + } + + /* get the font name (/CIDFontName for CID-keyed fonts, */ + /* /FontName otherwise) */ + font->font_name = cff_index_get_name( &font->name_index, face_index ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_font_done( CFF_Font font ) + { + FT_Memory memory = font->memory; + FT_UInt idx; + + + cff_index_done( &font->global_subrs_index ); + cff_index_done( &font->string_index ); + cff_index_done( &font->font_dict_index ); + cff_index_done( &font->name_index ); + cff_index_done( &font->charstrings_index ); + + /* release font dictionaries, but only if working with */ + /* a CID keyed CFF font */ + if ( font->num_subfonts > 0 ) + { + for ( idx = 0; idx < font->num_subfonts; idx++ ) + cff_subfont_done( memory, font->subfonts[idx] ); + + /* the subfonts array has been allocated as a single block */ + FT_FREE( font->subfonts[0] ); + } + + cff_encoding_done( &font->encoding ); + cff_charset_done( &font->charset, font->stream ); + + cff_subfont_done( memory, &font->top_font ); + + CFF_Done_FD_Select( &font->fd_select, font->stream ); + + if (font->font_info != NULL) + { + FT_FREE( font->font_info->version ); + FT_FREE( font->font_info->notice ); + FT_FREE( font->font_info->full_name ); + FT_FREE( font->font_info->family_name ); + FT_FREE( font->font_info->weight ); + FT_FREE( font->font_info ); + } + + FT_FREE( font->global_subrs ); + FT_FREE( font->font_name ); + } + + +/* END */ diff --git a/src/freetype2/cff/cffload.h b/src/freetype2/cff/cffload.h new file mode 100644 index 0000000..068cbb5 --- /dev/null +++ b/src/freetype2/cff/cffload.h @@ -0,0 +1,79 @@ +/***************************************************************************/ +/* */ +/* cffload.h */ +/* */ +/* OpenType & CFF data/program tables loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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 __CFFLOAD_H__ +#define __CFFLOAD_H__ + + +#include +#include "cfftypes.h" +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ); + + + FT_LOCAL( FT_String* ) + cff_index_get_name( CFF_Index idx, + FT_UInt element ); + + FT_LOCAL( FT_String* ) + cff_index_get_sid_string( CFF_Index idx, + FT_UInt sid, + FT_Service_PsCMaps psnames ); + + + FT_LOCAL( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ); + + FT_LOCAL( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ); + + + FT_LOCAL( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ); + + + FT_LOCAL( FT_Error ) + cff_font_load( FT_Stream stream, + FT_Int face_index, + CFF_Font font ); + + FT_LOCAL( void ) + cff_font_done( CFF_Font font ); + + + FT_LOCAL( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ); + + +FT_END_HEADER + +#endif /* __CFFLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cffobjs.c b/src/freetype2/cff/cffobjs.c new file mode 100644 index 0000000..c02cf33 --- /dev/null +++ b/src/freetype2/cff/cffobjs.c @@ -0,0 +1,782 @@ +/***************************************************************************/ +/* */ +/* cffobjs.c */ +/* */ +/* OpenType objects manager (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_ERRORS_H +#include FT_TRUETYPE_IDS_H +#include FT_TRUETYPE_TAGS_H +#include FT_INTERNAL_SFNT_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include "cffobjs.h" +#include "cffload.h" +#include "cffcmap.h" +#include "cfferrs.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_cffobjs + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /* Note that we store the global hints in the size's `internal' root */ + /* field. */ + /* */ + /*************************************************************************/ + + + static PSH_Globals_Funcs + cff_size_get_globals_funcs( CFF_Size size ) + { + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_FontRec *)face->extra.data; + PSHinter_Service pshinter = (PSHinter_Service)font->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cff_size_done( FT_Size cffsize ) /* CFF_Size */ + { + CFF_Size size = (CFF_Size)cffsize; + + + if ( cffsize->internal ) + { + PSH_Globals_Funcs funcs; + + + funcs = cff_size_get_globals_funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)cffsize->internal ); + + cffsize->internal = 0; + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_size_init( FT_Size cffsize ) /* CFF_Size */ + { + CFF_Size size = (CFF_Size)cffsize; + FT_Error error = CFF_Err_Ok; + PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + CFF_Face face = (CFF_Face)cffsize->face; + CFF_Font font = (CFF_FontRec *)face->extra.data; + CFF_SubFont subfont = &font->top_font; + + CFF_Private cpriv = &subfont->private_dict; + PS_PrivateRec priv; + + + /* IMPORTANT: The CFF and Type1 private dictionaries have */ + /* slightly different structures; we need to */ + /* synthetize a type1 dictionary on the fly here. */ + + { + FT_UInt n, count; + + + FT_MEM_ZERO( &priv, sizeof ( priv ) ); + + count = priv.num_blue_values = cpriv->num_blue_values; + for ( n = 0; n < count; n++ ) + priv.blue_values[n] = (FT_Short)cpriv->blue_values[n]; + + count = priv.num_other_blues = cpriv->num_other_blues; + for ( n = 0; n < count; n++ ) + priv.other_blues[n] = (FT_Short)cpriv->other_blues[n]; + + count = priv.num_family_blues = cpriv->num_family_blues; + for ( n = 0; n < count; n++ ) + priv.family_blues[n] = (FT_Short)cpriv->family_blues[n]; + + count = priv.num_family_other_blues = cpriv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + priv.family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n]; + + priv.blue_scale = cpriv->blue_scale; + priv.blue_shift = (FT_Int)cpriv->blue_shift; + priv.blue_fuzz = (FT_Int)cpriv->blue_fuzz; + + priv.standard_width[0] = (FT_UShort)cpriv->standard_width; + priv.standard_height[0] = (FT_UShort)cpriv->standard_height; + + count = priv.num_snap_widths = cpriv->num_snap_widths; + for ( n = 0; n < count; n++ ) + priv.snap_widths[n] = (FT_Short)cpriv->snap_widths[n]; + + count = priv.num_snap_heights = cpriv->num_snap_heights; + for ( n = 0; n < count; n++ ) + priv.snap_heights[n] = (FT_Short)cpriv->snap_heights[n]; + + priv.force_bold = cpriv->force_bold; + priv.language_group = cpriv->language_group; + priv.lenIV = cpriv->lenIV; + } + + error = funcs->create( cffsize->face->memory, &priv, &globals ); + if ( !error ) + cffsize->internal = (FT_Size_Internal)(void*)globals; + } + + size->strike_index = 0xFFFFFFFFUL; + + return error; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + + cffsize->strike_index = strike_index; + + FT_Select_Metrics( size->face, strike_index ); + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + + return CFF_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + FT_LOCAL_DEF( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + CFF_Face cffface = (CFF_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + FT_ULong strike_index; + + + if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) ) + cffsize->strike_index = 0xFFFFFFFFUL; + else + return cff_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + FT_Request_Metrics( size->face, req ); + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + + return CFF_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* SLOT FUNCTIONS */ + /* */ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + cff_slot_done( FT_GlyphSlot slot ) + { + slot->internal->glyph_hints = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ) + { + CFF_Face face = (CFF_Face)slot->face; + CFF_Font font = (CFF_FontRec *)face->extra.data; + PSHinter_Service pshinter = (PSHinter_Service)font->pshinter; + + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->face->driver->root.library, + "pshinter" ); + if ( module ) + { + T2_Hints_Funcs funcs; + + + funcs = pshinter->get_t2_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + static FT_String* + cff_strcpy( FT_Memory memory, + const FT_String* source ) + { + FT_Error error; + FT_String* result; + + + result = ft_mem_strdup( memory, source, &error ); + + return result; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face cffface, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CFF_Face face = (CFF_Face)cffface; + FT_Error error; + SFNT_Service sfnt; + FT_Service_PsCMaps psnames; + PSHinter_Service pshinter; + FT_Bool pure_cff = 1; + FT_Bool sfnt_format = 0; + + +#if 0 + FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt, SFNT ); + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_NAMES ); + FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER ); + + if ( !sfnt ) + goto Bad_Format; +#else + sfnt = (SFNT_Service)FT_Get_Module_Interface( + cffface->driver->root.library, "sfnt" ); + if ( !sfnt ) + goto Bad_Format; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + + pshinter = (PSHinter_Service)FT_Get_Module_Interface( + cffface->driver->root.library, "pshinter" ); +#endif + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check whether we have a valid OpenType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( !error ) + { + if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */ + { + FT_TRACE2(( "[not a valid OpenType/CFF font]\n" )); + goto Bad_Format; + } + + /* if we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return CFF_Err_Ok; + + /* UNDOCUMENTED! A CFF in an SFNT can have only a single font. */ + if ( face_index > 0 ) + { + FT_ERROR(( "cff_face_init: invalid face index\n" )); + error = CFF_Err_Invalid_Argument; + goto Exit; + } + + sfnt_format = 1; + + /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ + /* font; in the latter case it doesn't have a `head' table */ + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( !error ) + { + pure_cff = 0; + + /* load font directory */ + error = sfnt->load_face( stream, face, + face_index, num_params, params ); + if ( error ) + goto Exit; + } + else + { + /* load the `cmap' table explicitly */ + error = sfnt->load_cmap( face, stream ); + if ( error ) + goto Exit; + + /* XXX: we don't load the GPOS table, as OpenType Layout */ + /* support will be added later to a layout library on top of */ + /* FreeType 2 */ + } + + /* now load the CFF part of the file */ + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + if ( error ) + goto Exit; + } + else + { + /* rewind to start of file; we are going to load a pure-CFF font */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + error = CFF_Err_Ok; + } + + /* now load and parse the CFF table in the file */ + { + CFF_Font cff; + CFF_FontRecDict dict; + FT_Memory memory = cffface->memory; + FT_Int32 flags; + FT_UInt i; + + + if ( FT_NEW( cff ) ) + goto Exit; + + face->extra.data = cff; + error = cff_font_load( stream, face_index, cff ); + if ( error ) + goto Exit; + + cff->pshinter = pshinter; + cff->psnames = (void*)psnames; + + /* Complement the root flags with some interesting information. */ + /* Note that this is only necessary for pure CFF and CEF fonts; */ + /* SFNT based fonts use the `name' table instead. */ + + cffface->num_glyphs = cff->num_glyphs; + + dict = &cff->top_font.font_dict; + + /* we need the `PSNames' module for CFF and CEF formats */ + /* which aren't CID-keyed */ + if ( dict->cid_registry == 0xFFFFU && !psnames ) + { + FT_ERROR(( "cff_face_init:" )); + FT_ERROR(( " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " )); + FT_ERROR(( " without the `PSNames' module\n" )); + goto Bad_Format; + } + + if ( pure_cff ) + { + char* style_name = NULL; + + + /* set up num_faces */ + cffface->num_faces = cff->num_faces; + + /* compute number of glyphs */ + if ( dict->cid_registry != 0xFFFFU ) + cffface->num_glyphs = dict->cid_count; + else + cffface->num_glyphs = cff->charstrings_index.count; + + /* set global bbox, as well as EM size */ + cffface->bbox.xMin = dict->font_bbox.xMin >> 16; + cffface->bbox.yMin = dict->font_bbox.yMin >> 16; + cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16; + cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16; + + if ( !dict->units_per_em ) + dict->units_per_em = 1000; + + cffface->units_per_EM = dict->units_per_em; + + cffface->ascender = (FT_Short)( cffface->bbox.yMax ); + cffface->descender = (FT_Short)( cffface->bbox.yMin ); + + cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); + if ( cffface->height < cffface->ascender - cffface->descender ) + cffface->height = (FT_Short)( cffface->ascender - cffface->descender ); + + cffface->underline_position = + (FT_Short)( dict->underline_position >> 16 ); + cffface->underline_thickness = + (FT_Short)( dict->underline_thickness >> 16 ); + + /* retrieve font family & style name */ + cffface->family_name = cff_index_get_name( &cff->name_index, + face_index ); + + if ( cffface->family_name ) + { + char* full = cff_index_get_sid_string( &cff->string_index, + dict->full_name, + psnames ); + char* fullp = full; + char* family = cffface->family_name; + char* family_name = 0; + + + if ( dict->family_name ) + { + family_name = cff_index_get_sid_string( &cff->string_index, + dict->family_name, + psnames); + if ( family_name ) + family = family_name; + } + + /* We try to extract the style name from the full name. */ + /* We need to ignore spaces and dashes during the search. */ + if ( full && family ) + { + while ( *fullp ) + { + /* skip common characters at the start of both strings */ + if ( *fullp == *family ) + { + family++; + fullp++; + continue; + } + + /* ignore spaces and dashes in full name during comparison */ + if ( *fullp == ' ' || *fullp == '-' ) + { + fullp++; + continue; + } + + /* ignore spaces and dashes in family name during comparison */ + if ( *family == ' ' || *family == '-' ) + { + family++; + continue; + } + + if ( !*family && *fullp ) + { + /* The full name begins with the same characters as the */ + /* family name, with spaces and dashes removed. In this */ + /* case, the remaining string in `fullp' will be used as */ + /* the style name. */ + style_name = cff_strcpy( memory, fullp ); + } + break; + } + + if ( family_name ) + FT_FREE( family_name ); + FT_FREE( full ); + } + } + else + { + char *cid_font_name = + cff_index_get_sid_string( &cff->string_index, + dict->cid_font_name, + psnames ); + + + /* do we have a `/FontName' for a CID-keyed font? */ + if ( cid_font_name ) + cffface->family_name = cid_font_name; + } + + if ( style_name ) + cffface->style_name = style_name; + else + /* assume "Regular" style if we don't know better */ + cffface->style_name = cff_strcpy( memory, (char *)"Regular" ); + + /*******************************************************************/ + /* */ + /* Compute face flags. */ + /* */ + flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( sfnt_format ) + flags |= FT_FACE_FLAG_SFNT; + + /* fixed width font? */ + if ( dict->is_fixed_pitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ +#if 0 + /* kerning available? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; +#endif + + cffface->face_flags = flags; + + /*******************************************************************/ + /* */ + /* Compute style flags. */ + /* */ + flags = 0; + + if ( dict->italic_angle ) + flags |= FT_STYLE_FLAG_ITALIC; + + { + char *weight = cff_index_get_sid_string( &cff->string_index, + dict->weight, + psnames ); + + + if ( weight ) + if ( !ft_strcmp( weight, "Bold" ) || + !ft_strcmp( weight, "Black" ) ) + flags |= FT_STYLE_FLAG_BOLD; + FT_FREE( weight ); + } + + /* double check */ + if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) + if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || + !ft_strncmp( cffface->style_name, "Black", 5 ) ) + flags |= FT_STYLE_FLAG_BOLD; + + cffface->style_flags = flags; + } + else + { + if ( !dict->units_per_em ) + dict->units_per_em = face->root.units_per_EM; + } + + /* handle font matrix settings in subfonts (if any) */ + for ( i = cff->num_subfonts; i > 0; i-- ) + { + CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; + CFF_FontRecDict top = &cff->top_font.font_dict; + + + if ( sub->units_per_em ) + { + FT_Matrix scale; + + + scale.xx = scale.yy = (FT_Fixed)FT_DivFix( top->units_per_em, + sub->units_per_em ); + scale.xy = scale.yx = 0; + + FT_Matrix_Multiply( &scale, &sub->font_matrix ); + FT_Vector_Transform( &sub->font_offset, &scale ); + } + else + { + sub->font_matrix = top->font_matrix; + sub->font_offset = top->font_offset; + } + } + +#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES + /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */ + /* has unset this flag because of the 3.0 `post' table */ + if ( dict->cid_registry == 0xFFFFU ) + cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + + /*******************************************************************/ + /* */ + /* Compute char maps. */ + /* */ + + /* Try to synthetize a Unicode charmap if there is none available */ + /* already. If an OpenType font contains a Unicode "cmap", we */ + /* will use it, whatever be in the CFF part of the file. */ + { + FT_CharMapRec cmaprec; + FT_CharMap cmap; + FT_UInt nn; + CFF_Encoding encoding = &cff->encoding; + + + for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) + { + cmap = cffface->charmaps[nn]; + + /* Windows Unicode (3,1)? */ + if ( cmap->platform_id == 3 && cmap->encoding_id == 1 ) + goto Skip_Unicode; + + /* Deprecated Unicode platform id? */ + if ( cmap->platform_id == 0 ) + goto Skip_Unicode; /* Standard Unicode (deprecated) */ + } + + /* since CID-keyed fonts don't contain glyph names, we can't */ + /* construct a cmap */ + if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) + goto Exit; + + /* we didn't find a Unicode charmap -- synthetize one */ + cmaprec.face = cffface; + cmaprec.platform_id = 3; + cmaprec.encoding_id = 1; + cmaprec.encoding = FT_ENCODING_UNICODE; + + nn = (FT_UInt)cffface->num_charmaps; + + FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL ); + + /* if no Unicode charmap was previously selected, select this one */ + if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) + cffface->charmap = cffface->charmaps[nn]; + + Skip_Unicode: + if ( encoding->count > 0 ) + { + FT_CMap_Class clazz; + + + cmaprec.face = cffface; + cmaprec.platform_id = 7; /* Adobe platform id */ + + if ( encoding->offset == 0 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; + cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; + clazz = &cff_cmap_encoding_class_rec; + } + else if ( encoding->offset == 1 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; + cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; + clazz = &cff_cmap_encoding_class_rec; + } + else + { + cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; + cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; + clazz = &cff_cmap_encoding_class_rec; + } + + FT_CMap_New( clazz, NULL, &cmaprec, NULL ); + } + } + } + + Exit: + return error; + + Bad_Format: + error = CFF_Err_Unknown_File_Format; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + cff_face_done( FT_Face cffface ) /* CFF_Face */ + { + CFF_Face face = (CFF_Face)cffface; + FT_Memory memory = cffface->memory; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + if ( sfnt ) + sfnt->done_face( face ); + + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + if ( cff ) + { + cff_font_done( cff ); + FT_FREE( face->extra.data ); + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_driver_init( FT_Module module ) + { + FT_UNUSED( module ); + + return CFF_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + cff_driver_done( FT_Module module ) + { + FT_UNUSED( module ); + } + + +/* END */ diff --git a/src/freetype2/cff/cffobjs.h b/src/freetype2/cff/cffobjs.h new file mode 100644 index 0000000..f18b5d9 --- /dev/null +++ b/src/freetype2/cff/cffobjs.h @@ -0,0 +1,165 @@ +/***************************************************************************/ +/* */ +/* cffobjs.h */ +/* */ +/* OpenType objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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 __CFFOBJS_H__ +#define __CFFOBJS_H__ + + +#include +#include FT_INTERNAL_OBJECTS_H +#include "cfftypes.h" +#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_Driver */ + /* */ + /* */ + /* A handle to an OpenType driver object. */ + /* */ + typedef struct CFF_DriverRec_* CFF_Driver; + + typedef TT_Face CFF_Face; + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_Size */ + /* */ + /* */ + /* A handle to an OpenType size object. */ + /* */ + typedef struct CFF_SizeRec_ + { + FT_SizeRec root; + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + + } CFF_SizeRec, *CFF_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_GlyphSlot */ + /* */ + /* */ + /* A handle to an OpenType glyph slot object. */ + /* */ + typedef struct CFF_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CFF_GlyphSlotRec, *CFF_GlyphSlot; + + + + /*************************************************************************/ + /* */ + /* Subglyph transformation record. */ + /* */ + typedef struct CFF_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } CFF_Transform; + + + /***********************************************************************/ + /* */ + /* TrueType driver class. */ + /* */ + typedef struct CFF_DriverRec_ + { + FT_DriverRec root; + void* extension_component; + + } CFF_DriverRec; + + + FT_LOCAL( FT_Error ) + cff_size_init( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( void ) + cff_size_done( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ); + +#endif + + FT_LOCAL( void ) + cff_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ); + + + /*************************************************************************/ + /* */ + /* Face functions */ + /* */ + FT_LOCAL( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face face, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cff_face_done( FT_Face face ); /* CFF_Face */ + + + /*************************************************************************/ + /* */ + /* Driver functions */ + /* */ + FT_LOCAL( FT_Error ) + cff_driver_init( FT_Module module ); + + FT_LOCAL( void ) + cff_driver_done( FT_Module module ); + + +FT_END_HEADER + +#endif /* __CFFOBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cffparse.c b/src/freetype2/cff/cffparse.c new file mode 100644 index 0000000..41af6a3 --- /dev/null +++ b/src/freetype2/cff/cffparse.c @@ -0,0 +1,688 @@ +/***************************************************************************/ +/* */ +/* cffparse.c */ +/* */ +/* CFF token stream parser (body) */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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 +#include "cffparse.h" +#include FT_INTERNAL_STREAM_H + +#include "cfferrs.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_cffparse + + + enum + { + cff_kind_none = 0, + cff_kind_num, + cff_kind_fixed, + cff_kind_fixed_thousand, + cff_kind_string, + cff_kind_bool, + cff_kind_delta, + cff_kind_callback, + + cff_kind_max /* do not remove */ + }; + + + /* now generate handlers for the most simple fields */ + typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser ); + + typedef struct CFF_Field_Handler_ + { + int kind; + int code; + FT_UInt offset; + FT_Byte size; + CFF_Field_Reader reader; + FT_UInt array_max; + FT_UInt count_offset; + + } CFF_Field_Handler; + + + FT_LOCAL_DEF( void ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object ) + { + FT_MEM_ZERO( parser, sizeof ( *parser ) ); + + parser->top = parser->stack; + parser->object_code = code; + parser->object = object; + } + + + /* read an integer */ + static FT_Long + cff_parse_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + + + if ( v == 28 ) + { + if ( p + 2 > limit ) + goto Bad; + + val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] ); + p += 2; + } + else if ( v == 29 ) + { + if ( p + 4 > limit ) + goto Bad; + + val = ( (FT_Long)p[0] << 24 ) | + ( (FT_Long)p[1] << 16 ) | + ( (FT_Long)p[2] << 8 ) | + p[3]; + p += 4; + } + else if ( v < 247 ) + { + val = v - 139; + } + else if ( v < 251 ) + { + if ( p + 1 > limit ) + goto Bad; + + val = ( v - 247 ) * 256 + p[0] + 108; + p++; + } + else + { + if ( p + 1 > limit ) + goto Bad; + + val = -( v - 251 ) * 256 - p[0] - 108; + p++; + } + + Exit: + return val; + + Bad: + val = 0; + goto Exit; + } + + + /* read a real */ + static FT_Fixed + cff_parse_real( FT_Byte* start, + FT_Byte* limit, + FT_Int power_ten ) + { + FT_Byte* p = start; + FT_Long num, divider, result, exponent; + FT_Int sign = 0, exponent_sign = 0; + FT_UInt nib; + FT_UInt phase; + + + result = 0; + num = 0; + divider = 1; + + /* first of all, read the integer part */ + phase = 4; + + for (;;) + { + /* If we entered this iteration with phase == 4, we need to */ + /* read a new byte. This also skips past the initial 0x1E. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + + if ( nib == 0xE ) + sign = 1; + else if ( nib > 9 ) + break; + else + result = result * 10 + nib; + } + + /* read decimal part, if any */ + if ( nib == 0xa ) + for (;;) + { + /* If we entered this iteration with phase == 4, we need */ + /* to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + if ( divider < 10000000L ) + { + num = num * 10 + nib; + divider *= 10; + } + } + + /* read exponent, if any */ + if ( nib == 12 ) + { + exponent_sign = 1; + nib = 11; + } + + if ( nib == 11 ) + { + exponent = 0; + + for (;;) + { + /* If we entered this iteration with phase == 4, we need */ + /* to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + exponent = exponent * 10 + nib; + } + + if ( exponent_sign ) + exponent = -exponent; + + power_ten += (FT_Int)exponent; + } + + /* raise to power of ten if needed */ + while ( power_ten > 0 ) + { + result = result * 10; + num = num * 10; + + power_ten--; + } + + while ( power_ten < 0 ) + { + result = result / 10; + divider = divider * 10; + + power_ten++; + } + + /* Move the integer part into the high 16 bits. */ + result <<= 16; + + /* Place the decimal part into the low 16 bits. */ + if ( num ) + result |= FT_DivFix( num, divider ); + + if ( sign ) + result = -result; + + Exit: + return result; + + Bad: + result = 0; + goto Exit; + } + + + /* read a number, either integer or real */ + static FT_Long + cff_parse_num( FT_Byte** d ) + { + return ( **d == 30 ? ( cff_parse_real ( d[0], d[1], 0 ) >> 16 ) + : cff_parse_integer( d[0], d[1] ) ); + } + + + /* read a floating point number, either integer or real */ + static FT_Fixed + cff_parse_fixed( FT_Byte** d ) + { + return ( **d == 30 ? cff_parse_real ( d[0], d[1], 0 ) + : cff_parse_integer( d[0], d[1] ) << 16 ); + } + + /* read a floating point number, either integer or real, */ + /* but return 1000 times the number read in. */ + static FT_Fixed + cff_parse_fixed_thousand( FT_Byte** d ) + { + return **d == + 30 ? cff_parse_real ( d[0], d[1], 3 ) + : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 ); + } + + static FT_Error + cff_parse_font_matrix( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_UShort* upm = &dict->units_per_em; + FT_Byte** data = parser->stack; + FT_Error error; + FT_Fixed temp; + + + error = CFF_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 6 ) + { + matrix->xx = cff_parse_fixed_thousand( data++ ); + matrix->yx = cff_parse_fixed_thousand( data++ ); + matrix->xy = cff_parse_fixed_thousand( data++ ); + matrix->yy = cff_parse_fixed_thousand( data++ ); + offset->x = cff_parse_fixed_thousand( data++ ); + offset->y = cff_parse_fixed_thousand( data ); + + temp = FT_ABS( matrix->yy ); + + *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) ); + + if ( temp != 0x10000L ) + { + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + + /* note that the offsets must be expressed in integer font units */ + offset->x >>= 16; + offset->y >>= 16; + + error = CFF_Err_Ok; + } + + return error; + } + + + static FT_Error + cff_parse_font_bbox( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = CFF_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 4 ) + { + bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) ); + error = CFF_Err_Ok; + } + + return error; + } + + + static FT_Error + cff_parse_private_dict( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = CFF_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 2 ) + { + dict->private_size = cff_parse_num( data++ ); + dict->private_offset = cff_parse_num( data ); + error = CFF_Err_Ok; + } + + return error; + } + + + static FT_Error + cff_parse_cid_ros( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = CFF_Err_Stack_Underflow; + + if ( parser->top >= parser->stack + 3 ) + { + dict->cid_registry = (FT_UInt)cff_parse_num ( data++ ); + dict->cid_ordering = (FT_UInt)cff_parse_num ( data++ ); + dict->cid_supplement = (FT_ULong)cff_parse_num( data ); + error = CFF_Err_Ok; + } + + return error; + } + + +#define CFF_FIELD_NUM( code, name ) \ + CFF_FIELD( code, name, cff_kind_num ) +#define CFF_FIELD_FIXED( code, name ) \ + CFF_FIELD( code, name, cff_kind_fixed ) +#define CFF_FIELD_FIXED_1000( code, name ) \ + CFF_FIELD( code, name, cff_kind_fixed_thousand ) +#define CFF_FIELD_STRING( code, name ) \ + CFF_FIELD( code, name, cff_kind_string ) +#define CFF_FIELD_BOOL( code, name ) \ + CFF_FIELD( code, name, cff_kind_bool ) +#define CFF_FIELD_DELTA( code, name, max ) \ + CFF_FIELD( code, name, cff_kind_delta ) + +#define CFF_FIELD_CALLBACK( code, name ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0 \ + }, + +#undef CFF_FIELD +#define CFF_FIELD( code, name, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + 0, 0, 0 \ + }, + +#undef CFF_FIELD_DELTA +#define CFF_FIELD_DELTA( code, name, max ) \ + { \ + cff_kind_delta, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + 0, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ + }, + +#define CFFCODE_TOPDICT 0x1000 +#define CFFCODE_PRIVATE 0x2000 + + static const CFF_Field_Handler cff_field_handlers[] = + { + +#include "cfftoken.h" + + { 0, 0, 0, 0, 0, 0, 0 } + }; + + + FT_LOCAL_DEF( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Error error = CFF_Err_Ok; + + + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + + while ( p < limit ) + { + FT_UInt v = *p; + + + if ( v >= 27 && v != 31 ) + { + /* it's a number; we will push its position on the stack */ + if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH ) + goto Stack_Overflow; + + *parser->top ++ = p; + + /* now, skip it */ + if ( v == 30 ) + { + /* skip real number */ + p++; + for (;;) + { + if ( p >= limit ) + goto Syntax_Error; + v = p[0] >> 4; + if ( v == 15 ) + break; + v = p[0] & 0xF; + if ( v == 15 ) + break; + p++; + } + } + else if ( v == 28 ) + p += 2; + else if ( v == 29 ) + p += 4; + else if ( v > 246 ) + p += 1; + } + else + { + /* This is not a number, hence it's an operator. Compute its code */ + /* and look for it in our current list. */ + + FT_UInt code; + FT_UInt num_args = (FT_UInt) + ( parser->top - parser->stack ); + const CFF_Field_Handler* field; + + + *parser->top = p; + code = v; + if ( v == 12 ) + { + /* two byte operator */ + p++; + if ( p >= limit ) + goto Syntax_Error; + + code = 0x100 | p[0]; + } + code = code | parser->object_code; + + for ( field = cff_field_handlers; field->kind; field++ ) + { + if ( field->code == (FT_Int)code ) + { + /* we found our field's handler; read it */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; + + + /* check that we have enough arguments -- except for */ + /* delta encoded arrays, which can be empty */ + if ( field->kind != cff_kind_delta && num_args < 1 ) + goto Stack_Underflow; + + switch ( field->kind ) + { + case cff_kind_bool: + case cff_kind_string: + case cff_kind_num: + val = cff_parse_num( parser->stack ); + goto Store_Number; + + case cff_kind_fixed: + val = cff_parse_fixed( parser->stack ); + goto Store_Number; + + case cff_kind_fixed_thousand: + val = cff_parse_fixed_thousand( parser->stack ); + + Store_Number: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case cff_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val += cff_parse_num( data++ ); + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + + q += field->size; + num_args--; + } + } + break; + + default: /* callback */ + error = field->reader( parser ); + if ( error ) + goto Exit; + } + goto Found; + } + } + + /* this is an unknown operator, or it is unsupported; */ + /* we will ignore it for now. */ + + Found: + /* clear stack */ + parser->top = parser->stack; + } + p++; + } + + Exit: + return error; + + Stack_Overflow: + error = CFF_Err_Invalid_Argument; + goto Exit; + + Stack_Underflow: + error = CFF_Err_Invalid_Argument; + goto Exit; + + Syntax_Error: + error = CFF_Err_Invalid_Argument; + goto Exit; + } + + +/* END */ diff --git a/src/freetype2/cff/cffparse.h b/src/freetype2/cff/cffparse.h new file mode 100644 index 0000000..8f3fa58 --- /dev/null +++ b/src/freetype2/cff/cffparse.h @@ -0,0 +1,69 @@ +/***************************************************************************/ +/* */ +/* cffparse.h */ +/* */ +/* CFF token stream parser (specification) */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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 __CFF_PARSE_H__ +#define __CFF_PARSE_H__ + + +#include +#include "cfftypes.h" +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + +#define CFF_MAX_STACK_DEPTH 96 + +#define CFF_CODE_TOPDICT 0x1000 +#define CFF_CODE_PRIVATE 0x2000 + + + typedef struct CFF_ParserRec_ + { + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + + FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1]; + FT_Byte** top; + + FT_UInt object_code; + void* object; + + } CFF_ParserRec, *CFF_Parser; + + + FT_LOCAL( void ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object ); + + FT_LOCAL( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ); + + +FT_END_HEADER + + +#endif /* __CFF_PARSE_H__ */ + + +/* END */ diff --git a/src/freetype2/cff/cfftoken.h b/src/freetype2/cff/cfftoken.h new file mode 100644 index 0000000..6bb27d5 --- /dev/null +++ b/src/freetype2/cff/cfftoken.h @@ -0,0 +1,97 @@ +/***************************************************************************/ +/* */ +/* cfftoken.h */ +/* */ +/* CFF token definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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. */ +/* */ +/***************************************************************************/ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec + +#undef CFFCODE +#define CFFCODE CFFCODE_TOPDICT + + CFF_FIELD_STRING ( 0, version ) + CFF_FIELD_STRING ( 1, notice ) + CFF_FIELD_STRING ( 0x100, copyright ) + CFF_FIELD_STRING ( 2, full_name ) + CFF_FIELD_STRING ( 3, family_name ) + CFF_FIELD_STRING ( 4, weight ) + CFF_FIELD_BOOL ( 0x101, is_fixed_pitch ) + CFF_FIELD_FIXED ( 0x102, italic_angle ) + CFF_FIELD_FIXED ( 0x103, underline_position ) + CFF_FIELD_FIXED ( 0x104, underline_thickness ) + CFF_FIELD_NUM ( 0x105, paint_type ) + CFF_FIELD_NUM ( 0x106, charstring_type ) + CFF_FIELD_CALLBACK( 0x107, font_matrix ) + CFF_FIELD_NUM ( 13, unique_id ) + CFF_FIELD_CALLBACK( 5, font_bbox ) + CFF_FIELD_NUM ( 0x108, stroke_width ) + CFF_FIELD_NUM ( 15, charset_offset ) + CFF_FIELD_NUM ( 16, encoding_offset ) + CFF_FIELD_NUM ( 17, charstrings_offset ) + CFF_FIELD_CALLBACK( 18, private_dict ) + CFF_FIELD_NUM ( 0x114, synthetic_base ) + CFF_FIELD_STRING ( 0x115, embedded_postscript ) + +#if 0 + CFF_FIELD_STRING ( 0x116, base_font_name ) + CFF_FIELD_DELTA ( 0x117, base_font_blend, 16 ) + CFF_FIELD_CALLBACK( 0x118, multiple_master ) + CFF_FIELD_CALLBACK( 0x119, blend_axis_types ) +#endif + + CFF_FIELD_CALLBACK( 0x11E, cid_ros ) + CFF_FIELD_NUM ( 0x11F, cid_font_version ) + CFF_FIELD_NUM ( 0x120, cid_font_revision ) + CFF_FIELD_NUM ( 0x121, cid_font_type ) + CFF_FIELD_NUM ( 0x122, cid_count ) + CFF_FIELD_NUM ( 0x123, cid_uid_base ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset ) + CFF_FIELD_STRING ( 0x126, cid_font_name ) + +#if 0 + CFF_FIELD_NUM ( 0x127, chameleon ) +#endif + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_PrivateRec +#undef CFFCODE +#define CFFCODE CFFCODE_PRIVATE + + CFF_FIELD_DELTA ( 6, blue_values, 14 ) + CFF_FIELD_DELTA ( 7, other_blues, 10 ) + CFF_FIELD_DELTA ( 8, family_blues, 14 ) + CFF_FIELD_DELTA ( 9, family_other_blues, 10 ) + CFF_FIELD_FIXED_1000( 0x109, blue_scale ) + CFF_FIELD_NUM ( 0x10A, blue_shift ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz ) + CFF_FIELD_NUM ( 10, standard_width ) + CFF_FIELD_NUM ( 11, standard_height ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13 ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13 ) + CFF_FIELD_BOOL ( 0x10E, force_bold ) + CFF_FIELD_FIXED ( 0x10F, force_bold_threshold ) + CFF_FIELD_NUM ( 0x110, lenIV ) + CFF_FIELD_NUM ( 0x111, language_group ) + CFF_FIELD_FIXED ( 0x112, expansion_factor ) + CFF_FIELD_NUM ( 0x113, initial_random_seed ) + CFF_FIELD_NUM ( 19, local_subrs_offset ) + CFF_FIELD_NUM ( 20, default_width ) + CFF_FIELD_NUM ( 21, nominal_width ) + + +/* END */ diff --git a/src/freetype2/cff/cfftypes.h b/src/freetype2/cff/cfftypes.h new file mode 100644 index 0000000..306e5aa --- /dev/null +++ b/src/freetype2/cff/cfftypes.h @@ -0,0 +1,270 @@ +/***************************************************************************/ +/* */ +/* cfftypes.h */ +/* */ +/* Basic OpenType/CFF type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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 __CFFTYPES_H__ +#define __CFFTYPES_H__ + + +#include +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* */ + /* CFF_IndexRec */ + /* */ + /* */ + /* A structure used to model a CFF Index table. */ + /* */ + /* */ + /* stream :: The source input stream. */ + /* */ + /* start :: The position of the first index byte in the */ + /* input stream. */ + /* */ + /* count :: The number of elements in the index. */ + /* */ + /* off_size :: The size in bytes of object offsets in index. */ + /* */ + /* data_offset :: The position of first data byte in the index's */ + /* bytes. */ + /* */ + /* data_size :: The size of the data table in this index. */ + /* */ + /* offsets :: A table of element offsets in the index. Must be */ + /* loaded explicitly. */ + /* */ + /* bytes :: If the index is loaded in memory, its bytes. */ + /* */ + typedef struct CFF_IndexRec_ + { + FT_Stream stream; + FT_ULong start; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + FT_ULong data_size; + + FT_ULong* offsets; + FT_Byte* bytes; + + } CFF_IndexRec, *CFF_Index; + + + typedef struct CFF_EncodingRec_ + { + FT_UInt format; + FT_ULong offset; + + FT_UInt count; + FT_UShort sids [256]; /* avoid dynamic allocations */ + FT_UShort codes[256]; + + } CFF_EncodingRec, *CFF_Encoding; + + + typedef struct CFF_CharsetRec_ + { + + FT_UInt format; + FT_ULong offset; + + FT_UShort* sids; + FT_UShort* cids; /* the inverse mapping of `sids'; only needed */ + /* for CID-keyed fonts */ + FT_UInt max_cid; + FT_UInt num_glyphs; + + } CFF_CharsetRec, *CFF_Charset; + + + typedef struct CFF_FontRecDictRec_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Fixed underline_position; + FT_Fixed underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_UShort units_per_em; + FT_Vector font_offset; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; + + /* these should only be used for the top-level font dictionary */ + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_ULong cid_supplement; + + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_ULong cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + + } CFF_FontRecDictRec, *CFF_FontRecDict; + + + typedef struct CFF_PrivateRec_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Pos blue_values[14]; + FT_Pos other_blues[10]; + FT_Pos family_blues[14]; + FT_Pos family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + + } CFF_PrivateRec, *CFF_Private; + + + typedef struct CFF_FDSelectRec_ + { + FT_Byte format; + FT_UInt range_count; + + /* that's the table, taken from the file `as is' */ + FT_Byte* data; + FT_UInt data_size; + + /* small cache for format 3 only */ + FT_UInt cache_first; + FT_UInt cache_count; + FT_Byte cache_fd; + + } CFF_FDSelectRec, *CFF_FDSelect; + + + /* A SubFont packs a font dict and a private dict together. They are */ + /* needed to support CID-keyed CFF fonts. */ + typedef struct CFF_SubFontRec_ + { + CFF_FontRecDictRec font_dict; + CFF_PrivateRec private_dict; + + CFF_IndexRec local_subrs_index; + FT_UInt num_local_subrs; + FT_Byte** local_subrs; + + } CFF_SubFontRec, *CFF_SubFont; + + + /* maximum number of sub-fonts in a CID-keyed file */ +#define CFF_MAX_CID_FONTS 32 + + + typedef struct CFF_FontRec_ + { + FT_Stream stream; + FT_Memory memory; + FT_UInt num_faces; + FT_UInt num_glyphs; + + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + FT_Byte absolute_offsize; + + + CFF_IndexRec name_index; + CFF_IndexRec top_dict_index; + CFF_IndexRec string_index; + CFF_IndexRec global_subrs_index; + + CFF_EncodingRec encoding; + CFF_CharsetRec charset; + + CFF_IndexRec charstrings_index; + CFF_IndexRec font_dict_index; + CFF_IndexRec private_index; + CFF_IndexRec local_subrs_index; + + FT_String* font_name; + FT_UInt num_global_subrs; + FT_Byte** global_subrs; + + CFF_SubFontRec top_font; + FT_UInt num_subfonts; + CFF_SubFont subfonts[CFF_MAX_CID_FONTS]; + + CFF_FDSelectRec fd_select; + + /* interface to PostScript hinter */ + void* pshinter; + + /* interface to Postscript Names service */ + void* psnames; + + /* since version 2.3.0 */ + PS_FontInfoRec* font_info; /* font info dictionary */ + + } CFF_FontRec, *CFF_Font; + + +FT_END_HEADER + +#endif /* __CFFTYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/ciderrs.h b/src/freetype2/cid/ciderrs.h new file mode 100644 index 0000000..01813e1 --- /dev/null +++ b/src/freetype2/cid/ciderrs.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* ciderrs.h */ +/* */ +/* CID error codes (specification only). */ +/* */ +/* Copyright 2001 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 CID error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __CIDERRS_H__ +#define __CIDERRS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX CID_Err_ +#define FT_ERR_BASE FT_Mod_Err_CID + +#include FT_ERRORS_H + +#endif /* __CIDERRS_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidgload.c b/src/freetype2/cid/cidgload.c new file mode 100644 index 0000000..8bec6e1 --- /dev/null +++ b/src/freetype2/cid/cidgload.c @@ -0,0 +1,433 @@ +/***************************************************************************/ +/* */ +/* cidgload.c */ +/* */ +/* CID-keyed Type1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include "cidload.h" +#include "cidgload.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_OUTLINE_H + +#include "ciderrs.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_cidgload + + + FT_CALLBACK_DEF( FT_Error ) + cid_load_glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + CID_Face face = (CID_Face)decoder->builder.face; + CID_FaceInfo cid = &face->cid; + FT_Byte* p; + FT_UInt fd_select; + FT_Stream stream = face->cid_stream; + FT_Error error = CID_Err_Ok; + FT_Byte* charstring = 0; + FT_Memory memory = face->root.memory; + FT_ULong glyph_length = 0; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using */ + /* the callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data glyph_data; + + + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, + &glyph_data ); + if ( error ) + goto Exit; + + p = (FT_Byte*)glyph_data.pointer; + fd_select = (FT_UInt)cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + + if ( glyph_data.length != 0 ) + { + glyph_length = glyph_data.length - cid->fd_bytes; + FT_ALLOC( charstring, glyph_length ); + if ( !error ) + ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length ); + } + + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + + if ( error ) + goto Exit; + } + + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* For ordinary fonts read the CID font dictionary index */ + /* and charstring offset from the CIDMap. */ + { + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + FT_ULong off1; + + + if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len ) || + FT_FRAME_ENTER( 2 * entry_len ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + fd_select = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + off1 = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); + p += cid->fd_bytes; + glyph_length = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ) - off1; + FT_FRAME_EXIT(); + + if ( fd_select >= (FT_UInt)cid->num_dicts ) + { + error = CID_Err_Invalid_Offset; + goto Exit; + } + if ( glyph_length == 0 ) + goto Exit; + if ( FT_ALLOC( charstring, glyph_length ) ) + goto Exit; + if ( FT_STREAM_READ_AT( cid->data_offset + off1, + charstring, glyph_length ) ) + goto Exit; + } + + /* Now set up the subrs array and parse the charstrings. */ + { + CID_FaceDict dict; + CID_Subrs cid_subrs = face->subrs + fd_select; + FT_Int cs_offset; + + + /* Set up subrs */ + decoder->num_subrs = cid_subrs->num_subrs; + decoder->subrs = cid_subrs->code; + decoder->subrs_len = 0; + + /* Set up font matrix */ + dict = cid->font_dicts + fd_select; + + decoder->font_matrix = dict->font_matrix; + decoder->font_offset = dict->font_offset; + decoder->lenIV = dict->private_dict.lenIV; + + /* Decode the charstring. */ + + /* Adjustment for seed bytes. */ + cs_offset = ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + + /* Decrypt only if lenIV >= 0. */ + if ( decoder->lenIV >= 0 ) + psaux->t1_decrypt( charstring, glyph_length, 4330 ); + + error = decoder->funcs.parse_charstrings( + decoder, charstring + cs_offset, + (FT_Int)glyph_length - cs_offset ); + } + + FT_FREE( charstring ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && + face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = decoder->builder.left_bearing.x; + metrics.bearing_y = decoder->builder.left_bearing.y; + metrics.advance = decoder->builder.advance.x; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + decoder->builder.left_bearing.x = metrics.bearing_x; + decoder->builder.left_bearing.y = metrics.bearing_y; + decoder->builder.advance.x = metrics.advance; + decoder->builder.advance.y = 0; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + Exit: + return error; + } + + +#if 0 + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + *max_advance = 0; + + /* Initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + 0, /* glyph names! XXX */ + 0, /* blend == 0 */ + 0, /* hinting == 0 */ + cid_load_glyph ); + if ( error ) + return error; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + /* now get load the unscaled outline */ + error = cid_load_glyph( &decoder, glyph_index ); + /* ignore the error if one occurred - skip to next glyph */ + } + + *max_advance = decoder.builder.advance.x; + + psaux->t1_decoder_funcs->done( &decoder ); + + return CID_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot cidglyph, /* CID_GlyphSlot */ + FT_Size cidsize, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + CID_GlyphSlot glyph = (CID_GlyphSlot)cidglyph; + CID_Size size = (CID_Size)cidsize; + FT_Error error; + T1_DecoderRec decoder; + CID_Face face = (CID_Face)cidglyph->face; + FT_Bool hinting; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Matrix font_matrix; + FT_Vector font_offset; + + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = CID_Err_Invalid_Argument; + goto Exit; + } + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = cidsize->metrics.x_scale; + glyph->y_scale = cidsize->metrics.y_scale; + + cidglyph->outline.n_points = 0; + cidglyph->outline.n_contours = 0; + + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + error = psaux->t1_decoder_funcs->init( &decoder, + cidglyph->face, + cidsize, + cidglyph, + 0, /* glyph names -- XXX */ + 0, /* blend == 0 */ + hinting, + FT_LOAD_TARGET_MODE( load_flags ), + cid_load_glyph ); + if ( error ) + goto Exit; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + /* set up the decoder */ + decoder.builder.no_recurse = FT_BOOL( + ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) ); + + error = cid_load_glyph( &decoder, glyph_index ); + if ( error ) + goto Exit; + + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + psaux->t1_decoder_funcs->done( &decoder ); + + /* now set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + cidglyph->outline.flags &= FT_OUTLINE_OWNER; + cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = cidglyph->internal; + + + cidglyph->metrics.horiBearingX = decoder.builder.left_bearing.x; + cidglyph->metrics.horiAdvance = decoder.builder.advance.x; + + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &cidglyph->metrics; + FT_Vector advance; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + cidglyph->linearHoriAdvance = decoder.builder.advance.x; + cidglyph->internal->glyph_transformed = 0; + + /* make up vertical ones */ + metrics->vertAdvance = ( face->cid.font_bbox.yMax - + face->cid.font_bbox.yMin ) >> 16; + cidglyph->linearVertAdvance = metrics->vertAdvance; + + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + if ( size && cidsize->metrics.y_ppem < 24 ) + cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + /* apply the font matrix */ + FT_Outline_Transform( &cidglyph->outline, &font_matrix ); + + FT_Outline_Translate( &cidglyph->outline, + font_offset.x, + font_offset.y ); + + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + font_offset.y; + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &cidglyph->outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype2/cid/cidgload.h b/src/freetype2/cid/cidgload.h new file mode 100644 index 0000000..a0a91bf --- /dev/null +++ b/src/freetype2/cid/cidgload.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* cidgload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CIDGLOAD_H__ +#define __CIDGLOAD_H__ + + +#include +#include "cidobjs.h" + + +FT_BEGIN_HEADER + + +#if 0 + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + FT_LOCAL( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot glyph, /* CID_Glyph_Slot */ + FT_Size size, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* __CIDGLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidload.c b/src/freetype2/cid/cidload.c new file mode 100644 index 0000000..9ed8cee --- /dev/null +++ b/src/freetype2/cid/cidload.c @@ -0,0 +1,644 @@ +/***************************************************************************/ +/* */ +/* cidload.c */ +/* */ +/* CID-keyed Type1 font loader (body). */ +/* */ +/* Copyright 1996-2001, 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 +#include FT_INTERNAL_DEBUG_H +#include FT_CONFIG_CONFIG_H +#include FT_MULTIPLE_MASTERS_H +#include FT_INTERNAL_TYPE1_TYPES_H + +#include "cidload.h" + +#include "ciderrs.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_cidload + + + /* read a single offset */ + FT_LOCAL_DEF( FT_Long ) + cid_get_offset( FT_Byte* *start, + FT_Byte offsize ) + { + FT_Long result; + FT_Byte* p = *start; + + + for ( result = 0; offsize > 0; offsize-- ) + { + result <<= 8; + result |= *p++; + } + + *start = p; + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + cid_load_keyword( CID_Face face, + CID_Loader* loader, + const T1_Field keyword ) + { + FT_Error error; + CID_Parser* parser = &loader->parser; + FT_Byte* object; + void* dummy_object; + CID_FaceInfo cid = &face->cid; + + + /* if the keyword has a dedicated callback, call it */ + if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) + { + keyword->reader( (FT_Face)face, parser ); + error = parser->root.error; + goto Exit; + } + + /* we must now compute the address of our target object */ + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_CID_INFO: + object = (FT_Byte*)cid; + break; + + case T1_FIELD_LOCATION_FONT_INFO: + object = (FT_Byte*)&cid->font_info; + break; + + case T1_FIELD_LOCATION_BBOX: + object = (FT_Byte*)&cid->font_bbox; + break; + + default: + { + CID_FaceDict dict; + + + if ( parser->num_dict < 0 ) + { + FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n", + keyword->ident )); + error = CID_Err_Syntax_Error; + goto Exit; + } + + dict = cid->font_dicts + parser->num_dict; + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_PRIVATE: + object = (FT_Byte*)&dict->private_dict; + break; + + default: + object = (FT_Byte*)dict; + } + } + } + + dummy_object = object; + + /* now, load the keyword data in the object's field(s) */ + if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || + keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = cid_parser_load_field_table( &loader->parser, keyword, + &dummy_object ); + else + error = cid_parser_load_field( &loader->parser, + keyword, &dummy_object ); + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + parse_font_matrix( CID_Face face, + CID_Parser* parser ) + { + FT_Matrix* matrix; + FT_Vector* offset; + CID_FaceDict dict; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + + + if ( parser->num_dict >= 0 ) + { + dict = face->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + offset = &dict->font_offset; + + (void)cid_parser_to_fixed_array( parser, 6, temp, 3 ); + + temp_scale = FT_ABS( temp[3] ); + + /* Set units per EM based on FontMatrix values. We set the value to */ + /* `1000/temp_scale', because temp_scale was already multiplied by */ + /* 1000 (in `t1_tofixed', from psobjs.c). */ + root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L, + FT_DivFix( temp_scale, 1000 ) ) ); + + /* we need to scale the values by 1.0/temp[3] */ + if ( temp_scale != 0x10000L ) + { + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + /* note that the font offsets are expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + return CID_Err_Ok; /* this is a callback function; */ + /* we must return an error code */ + } + + + FT_CALLBACK_DEF( FT_Error ) + parse_fd_array( CID_Face face, + CID_Parser* parser ) + { + CID_FaceInfo cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Error error = CID_Err_Ok; + FT_Long num_dicts; + + + num_dicts = cid_parser_to_int( parser ); + + if ( !cid->font_dicts ) + { + FT_Int n; + + + if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) + goto Exit; + + cid->num_dicts = (FT_UInt)num_dicts; + + /* don't forget to set a few defaults */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + + + /* default value for lenIV */ + dict->private_dict.lenIV = 4; + } + } + + Exit: + return error; + } + + + static + const T1_FieldRec cid_field_records[] = + { + +#include "cidtoken.h" + + T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) + T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix, 0 ) + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + + static FT_Error + cid_parse_dict( CID_Face face, + CID_Loader* loader, + FT_Byte* base, + FT_Long size ) + { + CID_Parser* parser = &loader->parser; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = CID_Err_Ok; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + + for (;;) + { + FT_Byte* newlimit; + + + parser->root.cursor = cur; + cid_parser_skip_spaces( parser ); + + if ( parser->root.cursor >= limit ) + newlimit = limit - 1 - 17; + else + newlimit = parser->root.cursor - 17; + + /* look for `%ADOBeginFontDict' */ + for ( ; cur < newlimit; cur++ ) + { + if ( *cur == '%' && + ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + parser->num_dict++; + } + } + + cur = parser->root.cursor; + /* no error can occur in cid_parser_skip_spaces */ + if ( cur >= limit ) + break; + + cid_parser_skip_PS_token( parser ); + if ( parser->root.cursor >= limit || parser->root.error ) + break; + + /* look for immediates */ + if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + + + cur++; + len = parser->root.cursor - cur; + + if ( len > 0 && len < 22 ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)cid_field_records; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == (FT_PtrDist)ft_strlen( (const char*)name ) ) + { + FT_PtrDist n; + + + for ( n = 1; n < len; n++ ) + if ( cur[n] != name[n] ) + break; + + if ( n >= len ) + { + /* we found it - run the parsing callback */ + parser->root.error = cid_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + } + keyword++; + } + } + } + + cur = parser->root.cursor; + } + } + return parser->root.error; + } + + + /* read the subrmap and the subrs of each font dict */ + static FT_Error + cid_read_subrs( CID_Face face ) + { + CID_FaceInfo cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->cid_stream; + FT_Error error; + FT_Int n; + CID_Subrs subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = 0; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) + goto Exit; + + subr = face->subrs; + for ( n = 0; n < cid->num_dicts; n++, subr++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + FT_Int lenIV = dict->private_dict.lenIV; + FT_UInt count, num_subrs = dict->num_subrs; + FT_ULong data_len; + FT_Byte* p; + + + /* reallocate offsets array if needed */ + if ( num_subrs + 1 > max_offsets ) + { + FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); + + + if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) + goto Fail; + + max_offsets = new_max; + } + + /* read the subrmap's offsets */ + if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || + FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) + goto Fail; + + p = (FT_Byte*)stream->cursor; + for ( count = 0; count <= num_subrs; count++ ) + offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); + + FT_FRAME_EXIT(); + + /* now, compute the size of subrs charstrings, */ + /* allocate, and read them */ + data_len = offsets[num_subrs] - offsets[0]; + + if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_ALLOC( subr->code[0], data_len ) ) + goto Fail; + + if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || + FT_STREAM_READ( subr->code[0], data_len ) ) + goto Fail; + + /* set up pointers */ + for ( count = 1; count <= num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count] - offsets[count - 1]; + subr->code[count] = subr->code[count - 1] + len; + } + + /* decrypt subroutines, but only if lenIV >= 0 */ + if ( lenIV >= 0 ) + { + for ( count = 0; count < num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count + 1] - offsets[count]; + psaux->t1_decrypt( subr->code[count], len, 4330 ); + } + } + + subr->num_subrs = num_subrs; + } + + Exit: + FT_FREE( offsets ); + return error; + + Fail: + if ( face->subrs ) + { + for ( n = 0; n < cid->num_dicts; n++ ) + { + if ( face->subrs[n].code ) + FT_FREE( face->subrs[n].code[0] ); + + FT_FREE( face->subrs[n].code ); + } + FT_FREE( face->subrs ); + } + goto Exit; + } + + + static void + t1_init_loader( CID_Loader* loader, + CID_Face face ) + { + FT_UNUSED( face ); + + FT_MEM_ZERO( loader, sizeof ( *loader ) ); + } + + + static void + t1_done_loader( CID_Loader* loader ) + { + CID_Parser* parser = &loader->parser; + + + /* finalize parser */ + cid_parser_done( parser ); + } + + + static FT_Error + cid_hex_to_binary( FT_Byte* data, + FT_Long data_len, + FT_ULong offset, + CID_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Error error; + + FT_Byte buffer[256]; + FT_Byte *p, *plimit; + FT_Byte *d, *dlimit; + FT_Byte val; + + FT_Bool upper_nibble, done; + + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + + d = data; + dlimit = d + data_len; + p = buffer; + plimit = p; + + upper_nibble = 1; + done = 0; + + while ( d < dlimit ) + { + if ( p >= plimit ) + { + FT_ULong oldpos = FT_STREAM_POS(); + FT_ULong size = stream->size - oldpos; + + + if ( size == 0 ) + { + error = CID_Err_Syntax_Error; + goto Exit; + } + + if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) + goto Exit; + p = buffer; + plimit = p + FT_STREAM_POS() - oldpos; + } + + if ( ft_isdigit( *p ) ) + val = (FT_Byte)( *p - '0' ); + else if ( *p >= 'a' && *p <= 'f' ) + val = (FT_Byte)( *p - 'a' ); + else if ( *p >= 'A' && *p <= 'F' ) + val = (FT_Byte)( *p - 'A' + 10 ); + else if ( *p == ' ' || + *p == '\t' || + *p == '\r' || + *p == '\n' || + *p == '\f' || + *p == '\0' ) + { + p++; + continue; + } + else if ( *p == '>' ) + { + val = 0; + done = 1; + } + else + { + error = CID_Err_Syntax_Error; + goto Exit; + } + + if ( upper_nibble ) + *d = (FT_Byte)( val << 4 ); + else + { + *d = (FT_Byte)( *d + val ); + d++; + } + + upper_nibble = (FT_Byte)( 1 - upper_nibble ); + + if ( done ) + break; + + p++; + } + + error = CID_Err_Ok; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ) + { + CID_Loader loader; + CID_Parser* parser; + FT_Memory memory = face->root.memory; + FT_Error error; + + + t1_init_loader( &loader, face ); + + parser = &loader.parser; + error = cid_parser_new( parser, face->root.stream, face->root.memory, + (PSAux_Service)face->psaux ); + if ( error ) + goto Exit; + + error = cid_parse_dict( face, &loader, + parser->postscript, + parser->postscript_len ); + if ( error ) + goto Exit; + + if ( face_index < 0 ) + goto Exit; + + if ( FT_NEW( face->cid_stream ) ) + goto Exit; + + if ( parser->binary_length ) + { + /* we must convert the data section from hexadecimal to binary */ + if ( FT_ALLOC( face->binary_data, parser->binary_length ) || + cid_hex_to_binary( face->binary_data, parser->binary_length, + parser->data_offset, face ) ) + goto Exit; + + FT_Stream_OpenMemory( face->cid_stream, + face->binary_data, parser->binary_length ); + face->cid.data_offset = 0; + } + else + { + *face->cid_stream = *face->root.stream; + face->cid.data_offset = loader.parser.data_offset; + } + + error = cid_read_subrs( face ); + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/src/freetype2/cid/cidload.h b/src/freetype2/cid/cidload.h new file mode 100644 index 0000000..8c172ff --- /dev/null +++ b/src/freetype2/cid/cidload.h @@ -0,0 +1,53 @@ +/***************************************************************************/ +/* */ +/* cidload.h */ +/* */ +/* CID-keyed Type1 font loader (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CIDLOAD_H__ +#define __CIDLOAD_H__ + + +#include +#include FT_INTERNAL_STREAM_H +#include "cidparse.h" + + +FT_BEGIN_HEADER + + + typedef struct CID_Loader_ + { + CID_Parser parser; /* parser used to read the stream */ + FT_Int num_chars; /* number of characters in encoding */ + + } CID_Loader; + + + FT_LOCAL( FT_Long ) + cid_get_offset( FT_Byte** start, + FT_Byte offsize ); + + FT_LOCAL( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ); + + +FT_END_HEADER + +#endif /* __CIDLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidobjs.c b/src/freetype2/cid/cidobjs.c new file mode 100644 index 0000000..1b3bfbf --- /dev/null +++ b/src/freetype2/cid/cidobjs.c @@ -0,0 +1,480 @@ +/***************************************************************************/ +/* */ +/* cidobjs.c */ +/* */ +/* CID objects manager (body). */ +/* */ +/* Copyright 1996-2001, 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 +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H + +#include "cidgload.h" +#include "cidload.h" + +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + +#include "ciderrs.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_cidobjs + + + /*************************************************************************/ + /* */ + /* SLOT FUNCTIONS */ + /* */ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + cid_slot_done( FT_GlyphSlot slot ) + { + slot->internal->glyph_hints = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ) + { + CID_Face face; + PSHinter_Service pshinter; + + + face = (CID_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->face->driver->root.library, + "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + + + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + static PSH_Globals_Funcs + cid_size_get_globals_funcs( CID_Size size ) + { + CID_Face face = (CID_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cid_size_done( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + + + if ( cidsize->internal ) + { + PSH_Globals_Funcs funcs; + + + funcs = cid_size_get_globals_funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)cidsize->internal ); + + cidsize->internal = 0; + } + } + + + FT_LOCAL_DEF( FT_Error ) + cid_size_init( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + FT_Error error = 0; + PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + CID_Face face = (CID_Face)cidsize->face; + CID_FaceDict dict = face->cid.font_dicts + face->root.face_index; + PS_Private priv = &dict->private_dict; + + + error = funcs->create( cidsize->face->memory, priv, &globals ); + if ( !error ) + cidsize->internal = (FT_Size_Internal)(void*)globals; + } + + return error; + } + + + FT_LOCAL( FT_Error ) + cid_size_request( FT_Size size, + FT_Size_Request req ) + { + PSH_Globals_Funcs funcs; + + + FT_Request_Metrics( size->face, req ); + + funcs = cid_size_get_globals_funcs( (CID_Size)size ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + + return CID_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* cid_face_done */ + /* */ + /* */ + /* Finalizes a given face object. */ + /* */ + /* */ + /* face :: A pointer to the face object to destroy. */ + /* */ + FT_LOCAL_DEF( void ) + cid_face_done( FT_Face cidface ) /* CID_Face */ + { + CID_Face face = (CID_Face)cidface; + FT_Memory memory; + + + if ( face ) + { + CID_FaceInfo cid = &face->cid; + PS_FontInfo info = &cid->font_info; + + + memory = cidface->memory; + + /* release subrs */ + if ( face->subrs ) + { + FT_Int n; + + + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_Subrs subr = face->subrs + n; + + + if ( subr->code ) + { + FT_FREE( subr->code[0] ); + FT_FREE( subr->code ); + } + } + + FT_FREE( face->subrs ); + } + + /* release FontInfo strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release font dictionaries */ + FT_FREE( cid->font_dicts ); + cid->num_dicts = 0; + + /* release other strings */ + FT_FREE( cid->cid_font_name ); + FT_FREE( cid->registry ); + FT_FREE( cid->ordering ); + + cidface->family_name = 0; + cidface->style_name = 0; + + FT_FREE( face->binary_data ); + FT_FREE( face->cid_stream ); + } + } + + + /*************************************************************************/ + /* */ + /* */ + /* cid_face_init */ + /* */ + /* */ + /* Initializes a given CID face object. */ + /* */ + /* */ + /* stream :: The source font stream. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* */ + /* face :: The newly built face object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face cidface, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CID_Face face = (CID_Face)cidface; + FT_Error error; + PSAux_Service psaux; + PSHinter_Service pshinter; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + cidface->num_faces = 1; + + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + psaux = (PSAux_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "psaux" ); + + face->psaux = psaux; + } + + pshinter = (PSHinter_Service)face->pshinter; + if ( !pshinter ) + { + pshinter = (PSHinter_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "pshinter" ); + + face->pshinter = pshinter; + } + + /* open the tokenizer; this will also check the font format */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = cid_face_open( face, face_index ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "cid_face_init: invalid face index\n" )); + error = CID_Err_Invalid_Argument; + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + CID_FaceInfo cid = &face->cid; + PS_FontInfo info = &cid->font_info; + + + cidface->num_glyphs = cid->cid_count; + cidface->num_charmaps = 0; + + cidface->face_index = face_index; + cidface->face_flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( info->is_fixed_pitch ) + cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: TODO: add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a /FontName dictionary entry! */ + cidface->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + cidface->style_name = (char *)"Regular"; + if ( cidface->family_name ) + { + char* full = info->full_name; + char* family = cidface->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + cidface->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( cid->cid_font_name ) + cidface->family_name = cid->cid_font_name; + } + + /* compute style flags */ + cidface->style_flags = 0; + if ( info->italic_angle ) + cidface->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + cidface->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + cidface->num_fixed_sizes = 0; + cidface->available_sizes = 0; + + cidface->bbox.xMin = cid->font_bbox.xMin >> 16; + cidface->bbox.yMin = cid->font_bbox.yMin >> 16; + cidface->bbox.xMax = ( cid->font_bbox.xMax + 0xFFFFU ) >> 16; + cidface->bbox.yMax = ( cid->font_bbox.yMax + 0xFFFFU ) >> 16; + + if ( !cidface->units_per_EM ) + cidface->units_per_EM = 1000; + + cidface->ascender = (FT_Short)( cidface->bbox.yMax ); + cidface->descender = (FT_Short)( cidface->bbox.yMin ); + + cidface->height = (FT_Short)( ( cidface->units_per_EM * 12 ) / 10 ); + if ( cidface->height < cidface->ascender - cidface->descender ) + cidface->height = (FT_Short)( cidface->ascender - cidface->descender ); + + cidface->underline_position = (FT_Short)info->underline_position; + cidface->underline_thickness = (FT_Short)info->underline_thickness; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cid_driver_init */ + /* */ + /* */ + /* Initializes a given CID driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + cid_driver_init( FT_Module driver ) + { + FT_UNUSED( driver ); + + return CID_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* */ + /* cid_driver_done */ + /* */ + /* */ + /* Finalizes a given CID driver. */ + /* */ + /* */ + /* driver :: A handle to the target CID driver. */ + /* */ + FT_LOCAL_DEF( void ) + cid_driver_done( FT_Module driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/src/freetype2/cid/cidobjs.h b/src/freetype2/cid/cidobjs.h new file mode 100644 index 0000000..aee346d --- /dev/null +++ b/src/freetype2/cid/cidobjs.h @@ -0,0 +1,154 @@ +/***************************************************************************/ +/* */ +/* cidobjs.h */ +/* */ +/* CID objects manager (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CIDOBJS_H__ +#define __CIDOBJS_H__ + + +#include +#include FT_INTERNAL_OBJECTS_H +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_TYPE1_TYPES_H + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct CID_Size_Hints_ CID_Size_Hints; + typedef struct CID_Glyph_Hints_ CID_Glyph_Hints; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct CID_DriverRec_* CID_Driver; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct CID_SizeRec_* CID_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct CID_GlyphSlotRec_* CID_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* */ + /* CID_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables. */ + /* */ + typedef struct CID_CharMapRec_* CID_CharMap; + + + /*************************************************************************/ + /* */ + /* HERE BEGINS THE TYPE 1 SPECIFIC STUFF */ + /* */ + /*************************************************************************/ + + + typedef struct CID_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + + } CID_SizeRec; + + + typedef struct CID_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CID_GlyphSlotRec; + + + FT_LOCAL( void ) + cid_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ); + + + FT_LOCAL( void ) + cid_size_done( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_init( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_request( FT_Size size, /* CID_Size */ + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face face, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cid_face_done( FT_Face face ); /* CID_Face */ + + + FT_LOCAL( FT_Error ) + cid_driver_init( FT_Module driver ); + + FT_LOCAL( void ) + cid_driver_done( FT_Module driver ); + + +FT_END_HEADER + +#endif /* __CIDOBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidparse.c b/src/freetype2/cid/cidparse.c new file mode 100644 index 0000000..bb87afc --- /dev/null +++ b/src/freetype2/cid/cidparse.c @@ -0,0 +1,226 @@ +/***************************************************************************/ +/* */ +/* cidparse.c */ +/* */ +/* CID-keyed Type1 parser (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_STREAM_H + +#include "cidparse.h" + +#include "ciderrs.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_cidparse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_ULong base_offset, offset, ps_len; + FT_Byte *cur, *limit; + FT_Byte *arg1, *arg2; + + + FT_MEM_ZERO( parser, sizeof ( *parser ) ); + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + + parser->stream = stream; + + base_offset = FT_STREAM_POS(); + + /* first of all, check the font format in the header */ + if ( FT_FRAME_ENTER( 31 ) ) + goto Exit; + + if ( ft_strncmp( (char *)stream->cursor, + "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_TRACE2(( "[not a valid CID-keyed font]\n" )); + error = CID_Err_Unknown_File_Format; + } + + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + + Again: + /* now, read the rest of the file until we find */ + /* `StartData' or `/sfnts' */ + { + FT_Byte buffer[256 + 10]; + FT_Int read_len = 256 + 10; + FT_Byte* p = buffer; + + + for ( offset = (FT_ULong)FT_STREAM_POS(); ; offset += 256 ) + { + FT_Int stream_len; + + + stream_len = stream->size - FT_STREAM_POS(); + if ( stream_len == 0 ) + { + FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); + error = CID_Err_Unknown_File_Format; + goto Exit; + } + + read_len = FT_MIN( read_len, stream_len ); + if ( FT_STREAM_READ( p, read_len ) ) + goto Exit; + + if ( read_len < 256 ) + p[read_len] = '\0'; + + limit = p + read_len - 10; + + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 ) + { + /* save offset of binary data after `StartData' */ + offset += p - buffer + 10; + goto Found; + } + else if ( p[1] == 's' && ft_strncmp( (char*)p, "/sfnts", 6 ) == 0 ) + { + offset += p - buffer + 7; + goto Found; + } + } + + FT_MEM_MOVE( buffer, p, 10 ); + read_len = 256; + p = buffer + 10; + } + } + + Found: + /* We have found the start of the binary data or the `/sfnts' token. */ + /* Now rewind and extract the frame corresponding to this PostScript */ + /* section. */ + + ps_len = offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + parser->num_dict = -1; + + /* Finally, we check whether `StartData' or `/sfnts' was real -- */ + /* it could be in a comment or string. We also get the arguments */ + /* of `StartData' to find out whether the data is represented in */ + /* binary or hex format. */ + + arg1 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg2 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + + limit = parser->root.limit; + cur = parser->root.cursor; + + while ( cur < limit ) + { + if ( parser->root.error ) + { + error = parser->root.error; + goto Exit; + } + + if ( cur[0] == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 ) + { + if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) + parser->binary_length = ft_atol( (const char *)arg2 ); + + limit = parser->root.limit; + cur = parser->root.cursor; + goto Exit; + } + else if ( cur[1] == 's' && ft_strncmp( (char*)cur, "/sfnts", 6 ) == 0 ) + { + FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); + error = CID_Err_Unknown_File_Format; + goto Exit; + } + + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg1 = arg2; + arg2 = cur; + cur = parser->root.cursor; + } + + /* we haven't found the correct `StartData'; go back and continue */ + /* searching */ + FT_FRAME_RELEASE( parser->postscript ); + if ( !FT_STREAM_SEEK( offset ) ) + goto Again; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cid_parser_done( CID_Parser* parser ) + { + /* always free the private dictionary */ + if ( parser->postscript ) + { + FT_Stream stream = parser->stream; + + + FT_FRAME_RELEASE( parser->postscript ); + } + parser->root.funcs.done( &parser->root ); + } + + +/* END */ diff --git a/src/freetype2/cid/cidparse.h b/src/freetype2/cid/cidparse.h new file mode 100644 index 0000000..ca37dea --- /dev/null +++ b/src/freetype2/cid/cidparse.h @@ -0,0 +1,123 @@ +/***************************************************************************/ +/* */ +/* cidparse.h */ +/* */ +/* CID-keyed Type1 parser (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CIDPARSE_H__ +#define __CIDPARSE_H__ + + +#include +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* */ + /* CID_Parser */ + /* */ + /* */ + /* A CID_Parser is an object used to parse a Type 1 fonts very */ + /* quickly. */ + /* */ + /* */ + /* root :: The root PS_ParserRec fields. */ + /* */ + /* stream :: The current input stream. */ + /* */ + /* postscript :: A pointer to the data to be parsed. */ + /* */ + /* postscript_len :: The length of the data to be parsed. */ + /* */ + /* data_offset :: The start position of the binary data (i.e., the */ + /* end of the data to be parsed. */ + /* */ + /* binary_length :: The length of the data after the `StartData' */ + /* command if the data format is hexadecimal. */ + /* */ + /* cid :: A structure which holds the information about */ + /* the current font. */ + /* */ + /* num_dict :: The number of font dictionaries. */ + /* */ + typedef struct CID_Parser_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* postscript; + FT_Long postscript_len; + + FT_ULong data_offset; + + FT_Long binary_length; + + CID_FaceInfo cid; + FT_Int num_dict; + + } CID_Parser; + + + FT_LOCAL( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + cid_parser_done( CID_Parser* parser ); + + + /*************************************************************************/ + /* */ + /* PARSING ROUTINES */ + /* */ + /*************************************************************************/ + +#define cid_parser_skip_spaces( p ) \ + (p)->root.funcs.skip_spaces( &(p)->root ) +#define cid_parser_skip_PS_token( p ) \ + (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root ) +#define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define cid_parser_to_coord_array( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define cid_parser_to_fixed_array( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define cid_parser_to_token( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define cid_parser_to_token_array( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define cid_parser_load_field( p, f, o ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 ) +#define cid_parser_load_field_table( p, f, o ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 ) + + +FT_END_HEADER + +#endif /* __CIDPARSE_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidriver.c b/src/freetype2/cid/cidriver.c new file mode 100644 index 0000000..5c5a729 --- /dev/null +++ b/src/freetype2/cid/cidriver.c @@ -0,0 +1,163 @@ +/***************************************************************************/ +/* */ +/* cidriver.c */ +/* */ +/* CID driver interface (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include +#include "cidriver.h" +#include "cidgload.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H + +#include "ciderrs.h" + +#include FT_SERVICE_POSTSCRIPT_NAME_H +#include FT_SERVICE_XFREE86_NAME_H +#include FT_SERVICE_POSTSCRIPT_INFO_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_ciddriver + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + cid_get_postscript_name( CID_Face face ) + { + const char* result = face->cid.cid_font_name; + + + if ( result && result[0] == '/' ) + result++; + + return result; + } + + + static const FT_Service_PsFontNameRec cid_service_ps_name = + { + (FT_PsName_GetFunc) cid_get_postscript_name + }; + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Error + cid_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((CID_Face)face)->cid.font_info; + return 0; + } + + + static const FT_Service_PsInfoRec cid_service_ps_info = + { + (PS_GetFontInfoFunc) cid_ps_get_font_info, + (PS_HasGlyphNamesFunc) NULL, /* unsupported with CID fonts */ + (PS_GetFontPrivateFunc)NULL /* unsupported */ + }; + + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec cid_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cid_service_ps_name }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_CID }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &cid_service_ps_info }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cid_get_interface( FT_Module module, + const char* cid_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( cid_services, cid_interface ); + } + + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1cid_driver_class = + { + /* first of all, the FT_Module_Class fields */ + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + + sizeof( FT_DriverRec ), + "t1cid", /* module name */ + 0x10000L, /* version 1.0 of driver */ + 0x20000L, /* requires FreeType 2.0 */ + + 0, + + cid_driver_init, + cid_driver_done, + cid_get_interface + }, + + /* then the other font drivers fields */ + sizeof( CID_FaceRec ), + sizeof( CID_SizeRec ), + sizeof( CID_GlyphSlotRec ), + + cid_face_init, + cid_face_done, + + cid_size_init, + cid_size_done, + cid_slot_init, + cid_slot_done, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + + cid_slot_load_glyph, + + 0, /* FT_Face_GetKerningFunc */ + 0, /* FT_Face_AttachFunc */ + + 0, /* FT_Face_GetAdvancesFunc */ + + cid_size_request, + 0 /* FT_Size_SelectFunc */ + }; + + +/* END */ diff --git a/src/freetype2/cid/cidriver.h b/src/freetype2/cid/cidriver.h new file mode 100644 index 0000000..d5a80f6 --- /dev/null +++ b/src/freetype2/cid/cidriver.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* cidriver.h */ +/* */ +/* High-level CID driver interface (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __CIDRIVER_H__ +#define __CIDRIVER_H__ + + +#include +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const FT_Driver_ClassRec t1cid_driver_class; + + +FT_END_HEADER + +#endif /* __CIDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/cid/cidtoken.h b/src/freetype2/cid/cidtoken.h new file mode 100644 index 0000000..ad5bbb2 --- /dev/null +++ b/src/freetype2/cid/cidtoken.h @@ -0,0 +1,103 @@ +/***************************************************************************/ +/* */ +/* cidtoken.h */ +/* */ +/* CID token definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_CID_INFO + + T1_FIELD_KEY ( "CIDFontName", cid_font_name, 0 ) + T1_FIELD_NUM ( "CIDFontVersion", cid_version, 0 ) + T1_FIELD_NUM ( "CIDFontType", cid_font_type, 0 ) + T1_FIELD_STRING( "Registry", registry, 0 ) + T1_FIELD_STRING( "Ordering", ordering, 0 ) + T1_FIELD_NUM ( "Supplement", supplement, 0 ) + T1_FIELD_NUM ( "UIDBase", uid_base, 0 ) + T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset, 0 ) + T1_FIELD_NUM ( "FDBytes", fd_bytes, 0 ) + T1_FIELD_NUM ( "GDBytes", gd_bytes, 0 ) + T1_FIELD_NUM ( "CIDCount", cid_count, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceDictRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset, 0 ) + T1_FIELD_NUM ( "SDBytes", sd_bytes, 0 ) + T1_FIELD_NUM ( "SubrCount", num_subrs, 0 ) + T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar, 0 ) + T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold, 0 ) + T1_FIELD_FIXED( "ExpansionFactor", expansion_factor, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, 0 ) + T1_FIELD_NUM ( "lenIV", lenIV, 0 ) + T1_FIELD_NUM ( "LanguageGroup", language_group, 0 ) + T1_FIELD_NUM ( "password", password, 0 ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, 0 ) + T1_FIELD_NUM ( "BlueShift", blue_shift, 0 ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, 0 ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, 0 ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, 0 ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, 0 ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, 0 ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, 0 ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, 0 ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, 0 ) + + +/* END */ diff --git a/src/freetype2/cid/type1cid.c b/src/freetype2/cid/type1cid.c new file mode 100644 index 0000000..0b866e9 --- /dev/null +++ b/src/freetype2/cid/type1cid.c @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* type1cid.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-2001 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 +#include "cidparse.c" +#include "cidload.c" +#include "cidobjs.c" +#include "cidriver.c" +#include "cidgload.c" + + +/* END */ diff --git a/src/freetype2/freetype/config/ftconfig.h b/src/freetype2/freetype/config/ftconfig.h new file mode 100644 index 0000000..3b33a65 --- /dev/null +++ b/src/freetype2/freetype/config/ftconfig.h @@ -0,0 +1,363 @@ +/***************************************************************************/ +/* */ +/* ftconfig.h */ +/* */ +/* ANSI-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This header file contains a number of macro definitions that are used */ + /* by the rest of the engine. Most of the macros here are automatically */ + /* determined at compile time, and you should not need to change it to */ + /* port FreeType, except to compile the library with a non-ANSI */ + /* compiler. */ + /* */ + /* Note however that if some specific modifications are needed, we */ + /* advise you to place a modified copy in your build directory. */ + /* */ + /* The build directory is usually `freetype/builds/', and */ + /* contains system-specific files that are always included first when */ + /* building the library. */ + /* */ + /* This ANSI version should stay in `include/freetype/config'. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCONFIG_H__ +#define __FTCONFIG_H__ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* PLATFORM-SPECIFIC CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled to suit a specific system. The current */ + /* ones are defaults used to compile FreeType in an ANSI C environment */ + /* (16bit compilers are also supported). Copy this file to your own */ + /* `freetype/builds/' directory, and edit it to port the engine. */ + /* */ + /*************************************************************************/ + + + /* There are systems (like the Texas Instruments 'C54x) where a `char' */ + /* has 16 bits. ANSI C says that sizeof(char) is always 1. Since an */ + /* `int' has 16 bits also for this system, sizeof(int) gives 1 which */ + /* is probably unexpected. */ + /* */ + /* `CHAR_BIT' (defined in limits.h) gives the number of bits in a */ + /* `char' type. */ + +#ifndef FT_CHAR_BIT +#define FT_CHAR_BIT CHAR_BIT +#endif + + + /* The size of an `int' type. */ +#if FT_UINT_MAX == 0xFFFFUL +#define FT_SIZEOF_INT (16 / FT_CHAR_BIT) +#elif FT_UINT_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_INT (32 / FT_CHAR_BIT) +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_INT (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `int' type!" +#endif + + /* The size of a `long' type. A five-byte `long' (as used e.g. on the */ + /* DM642) is recognized but avoided. */ +#if FT_ULONG_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_LONG (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `long' type!" +#endif + + + /* Preferred alignment of data */ +#define FT_ALIGNMENT 8 + + + /* FT_UNUSED is a macro used to indicate that a given parameter is not */ + /* used -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* AUTOMATIC CONFIGURATION MACROS */ + /* */ + /* These macros are computed from the ones defined above. Don't touch */ + /* their definition, unless you know precisely what you are doing. No */ + /* porter should need to mess with them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Mac support */ + /* */ + /* This is the only necessary change, so it is defined here instead */ + /* providing a new configuration file. */ + /* */ +#if ( defined( __APPLE__ ) && !defined( DARWIN_NO_CARBON ) ) || \ + ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* no Carbon frameworks for 64bit 10.4.x */ +#include "AvailabilityMacros.h" +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#define DARWIN_NO_CARBON 1 +#else +/* #define FT_MACINTOSH 1 CDLIB */ +#endif +#endif + + + /*************************************************************************/ + /* */ + /* IntN types */ + /* */ + /* Used to guarantee the size of some specific integers. */ + /* */ + typedef signed short FT_Int16; + typedef unsigned short FT_UInt16; + +#if FT_SIZEOF_INT == (32 / FT_CHAR_BIT) + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == (32 / FT_CHAR_BIT) + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + + /* look up an integer type that is at least 32 bits */ +#if FT_SIZEOF_INT >= (32 / FT_CHAR_BIT) + + typedef int FT_Fast; + typedef unsigned int FT_UFast; + +#elif FT_SIZEOF_LONG >= (32 / FT_CHAR_BIT) + + typedef long FT_Fast; + typedef unsigned long FT_UFast; + +#endif + + + /* determine whether we have a 64-bit int type for platforms without */ + /* Autoconf */ +#if FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) + + /* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long + +#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __BORLANDC__ ) /* Borland C++ */ + + /* XXXX: We should probably check the value of __BORLANDC__ in order */ + /* to test the compiler version. */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __WATCOMC__ ) /* Watcom C++ */ + + /* Watcom doesn't provide 64-bit data types */ + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_LONG64 +#define FT_INT64 long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long' type */ +#define FT_LONG64 +#define FT_INT64 long long int + +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ + + +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + + + /*************************************************************************/ + /* */ + /* A 64-bit data type will create compilation problems if you compile */ + /* in strict ANSI mode. To avoid them, we disable their use if */ + /* __STDC__ is defined. You can however ignore this rule by */ + /* defining the FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ + /* */ +#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#ifdef __STDC__ + + /* undefine the 64-bit macros in strict ANSI compilation mode */ +#undef FT_LONG64 +#undef FT_INT64 + +#endif /* __STDC__ */ + +#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */ + + +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#ifdef __cplusplus +#define FT_LOCAL( x ) extern "C" x +#define FT_LOCAL_DEF( x ) extern "C" x +#else +#define FT_LOCAL( x ) extern x +#define FT_LOCAL_DEF( x ) x +#endif + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + +#ifndef FT_BASE + +#ifdef __cplusplus +#define FT_BASE( x ) extern "C" x +#else +#define FT_BASE( x ) extern x +#endif + +#endif /* !FT_BASE */ + + +#ifndef FT_BASE_DEF + +#ifdef __cplusplus +#define FT_BASE_DEF( x ) x +#else +#define FT_BASE_DEF( x ) x +#endif + +#endif /* !FT_BASE_DEF */ + + +#ifndef FT_EXPORT + +#ifdef __cplusplus +#define FT_EXPORT( x ) extern "C" x +#else +#define FT_EXPORT( x ) extern x +#endif + +#endif /* !FT_EXPORT */ + + +#ifndef FT_EXPORT_DEF + +#ifdef __cplusplus +#define FT_EXPORT_DEF( x ) extern "C" x +#else +#define FT_EXPORT_DEF( x ) extern x +#endif + +#endif /* !FT_EXPORT_DEF */ + + +#ifndef FT_EXPORT_VAR + +#ifdef __cplusplus +#define FT_EXPORT_VAR( x ) extern "C" x +#else +#define FT_EXPORT_VAR( x ) extern x +#endif + +#endif /* !FT_EXPORT_VAR */ + + /* The following macros are needed to compile the library with a */ + /* C++ compiler and with 16bit compilers. */ + /* */ + + /* This is special. Within C++, you must specify `extern "C"' for */ + /* functions which are used via function pointers, and you also */ + /* must do that for structures which contain function pointers to */ + /* assure C linkage -- it's not possible to have (local) anonymous */ + /* functions which are accessed by (global) function pointers. */ + /* */ + /* */ + /* FT_CALLBACK_DEF is used to _define_ a callback function. */ + /* */ + /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */ + /* contains pointers to callback functions. */ + /* */ + /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */ + /* that contains pointers to callback functions. */ + /* */ + /* */ + /* Some 16bit compilers have to redefine these macros to insert */ + /* the infamous `_cdecl' or `__fastcall' declarations. */ + /* */ +#ifndef FT_CALLBACK_DEF +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif +#endif /* FT_CALLBACK_DEF */ + +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +#define FT_CALLBACK_TABLE_DEF /* nothing */ +#endif +#endif /* FT_CALLBACK_TABLE */ + + +FT_END_HEADER + + +#endif /* __FTCONFIG_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/config/ftheader.h b/src/freetype2/freetype/config/ftheader.h new file mode 100644 index 0000000..b957d05 --- /dev/null +++ b/src/freetype2/freetype/config/ftheader.h @@ -0,0 +1,729 @@ +/***************************************************************************/ +/* */ +/* ftheader.h */ +/* */ +/* Build macros of the FreeType 2 library. */ +/* */ +/* Copyright 1996-2001, 2002, 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 __FT_HEADER_H__ +#define __FT_HEADER_H__ + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_BEGIN_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_END_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* nothing */ +#endif + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_END_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_BEGIN_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* nothing */ +#endif + + + /*************************************************************************/ + /* */ + /* Aliases for the FreeType 2 public and configuration files. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /*
*/ + /* header_file_macros */ + /* */ + /* */ + /* Header File Macros */ + /* */ + /* <Abstract> */ + /* Macro definitions used to #include specific header files. */ + /* */ + /* <Description> */ + /* The following macros are defined to the name of specific */ + /* FreeType 2 header files. They can be used directly in #include */ + /* statements as in: */ + /* */ + /* { */ + /* #include FT_FREETYPE_H */ + /* #include FT_MULTIPLE_MASTERS_H */ + /* #include FT_GLYPH_H */ + /* } */ + /* */ + /* There are several reasons why we are now using macros to name */ + /* public header files. The first one is that such macros are not */ + /* limited to the infamous 8.3 naming rule required by DOS (and */ + /* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */ + /* */ + /* The second reason is that it allows for more flexibility in the */ + /* way FreeType 2 is installed on a given system. */ + /* */ + /*************************************************************************/ + + + /* configuration files */ + + /************************************************************************* + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h> +#endif + + + /* public headers */ + + /************************************************************************* + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * base FreeType 2 API. + * + */ +#define FT_FREETYPE_H <freetype/freetype.h> + + + /************************************************************************* + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H <freetype/fterrors.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h> + + + /************************************************************************* + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H <freetype/ftsystem.h> + + + /************************************************************************* + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H <freetype/ftimage.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * basic data types defined by FreeType 2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H <freetype/fttypes.h> + + + /************************************************************************* + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list management API of FreeType 2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H <freetype/ftlist.h> + + + /************************************************************************* + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * scalable outline management API of FreeType 2. + * + */ +#define FT_OUTLINE_H <freetype/ftoutln.h> + + + /************************************************************************* + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H <freetype/ftsizes.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * module management API of FreeType 2. + * + */ +#define FT_MODULE_H <freetype/ftmodapi.h> + + + /************************************************************************* + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * renderer module management API of FreeType 2. + * + */ +#define FT_RENDER_H <freetype/ftrender.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the Type 1 format. + * + */ +#define FT_TYPE1_TABLES_H <freetype/t1tables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H <freetype/tttables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of TrueType four-byte `tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H <freetype/tttags.h> + + + /************************************************************************* + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a + * face. + * + */ +#define FT_BDF_H <freetype/ftbdf.h> + + + /************************************************************************* + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H <freetype/ftgzip.h> + + + /************************************************************************* + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H <freetype/ftlzw.h> + + + /************************************************************************* + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H <freetype/ftwinfnt.h> + + + /************************************************************************* + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H <freetype/ftglyph.h> + + + /************************************************************************* + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H <freetype/ftbitmap.h> + + + /************************************************************************* + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H <freetype/ftbbox.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional FreeType 2 cache sub-system. + * + */ +#define FT_CACHE_H <freetype/ftcache.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `glyph image' API of the FreeType 2 cache sub-system. + * + * It is used to define a cache for @FT_Glyph elements. You can also + * use the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need to + * store small glyph bitmaps, as it will use less memory. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * glyph image-related cache declarations. + * + */ +#define FT_CACHE_IMAGE_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_SMALL_BITMAPS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `small bitmaps' API of the FreeType 2 cache sub-system. + * + * It is used to define a cache for small glyph bitmaps in a relatively + * memory-efficient way. You can also use the API defined in + * @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, + * including scalable outlines. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * small bitmaps-related cache declarations. + * + */ +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_CHARMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `charmap' API of the FreeType 2 cache sub-system. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * charmap-based cache declarations. + * + */ +#define FT_CACHE_CHARMAP_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in #include statements to name the file containing the + * Macintosh-specific FreeType 2 API. The latter is used to access + * fonts embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H <freetype/ftmac.h> + + + /************************************************************************* + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional multiple-masters management API of FreeType 2. + * + */ +#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h> + + + /************************************************************************* + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which accesses embedded `name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H <freetype/ftsnames.h> + + + /************************************************************************* + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which validates OpenType tables (BASE, GDEF, + * GPOS, GSUB, JSTF). + * + */ +#define FT_OPENTYPE_VALIDATE_H <freetype/ftotval.h> + + + /************************************************************************* + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which validates TrueTypeGX/AAT tables (feat, + * mort, morx, bsln, just, kern, opbd, trak, prop). + * + */ +#define FT_GX_VALIDATE_H <freetype/ftgxval.h> + + + /************************************************************************* + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H <freetype/ftpfr.h> + + + /************************************************************************* + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H <freetype/ftstroke.h> + + + /************************************************************************* + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H <freetype/ftsynth.h> + + + /************************************************************************* + * + * @macro: + * FT_XFREE86_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which provides functions specific to the XFree86 and + * X.Org X11 servers. + */ +#define FT_XFREE86_H <freetype/ftxf86.h> + + + /************************************************************************* + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H <freetype/fttrigon.h> + + + /************************************************************************* + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H <freetype/ftlcdfil.h> + + + /************************************************************************* + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H <freetype/ftgasp.h> + + + /* */ + +#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h> + + + /* The internals of the cache sub-system are no longer exposed. We */ + /* default to FT_CACHE_H at the moment just in case, but we know of */ + /* no rogue client that uses them. */ + /* */ +#define FT_CACHE_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MRU_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_CACHE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_GLYPH_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_IMAGE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_SBITS_H <freetype/ftcache.h> + + +#define FT_INCREMENTAL_H <freetype/ftincrem.h> + +#define FT_TRUETYPE_UNPATENTED_H <freetype/ttunpat.h> + + + /* + * Include internal headers definitions from <freetype/internal/...> + * only when building the library. + */ +#ifdef FT2_BUILD_LIBRARY +#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h> +#include FT_INTERNAL_INTERNAL_H +#endif /* FT2_BUILD_LIBRARY */ + + +#endif /* __FT2_BUILD_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/config/ftmodule.h b/src/freetype2/freetype/config/ftmodule.h new file mode 100644 index 0000000..bc42a92 --- /dev/null +++ b/src/freetype2/freetype/config/ftmodule.h @@ -0,0 +1,32 @@ +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `<topdir>/objs/') based on information + * from `<topdir>/modules.cfg'. + * + * Please read `docs/INSTALL.ANY' and `docs/CUSTOMIZE' how to compile + * FreeType without GNU make. + * + */ + +FT_USE_MODULE(autofit_module_class) +FT_USE_MODULE(tt_driver_class) +FT_USE_MODULE(t1_driver_class) +FT_USE_MODULE(cff_driver_class) +FT_USE_MODULE(t1cid_driver_class) +FT_USE_MODULE(pfr_driver_class) +FT_USE_MODULE(t42_driver_class) +FT_USE_MODULE(winfnt_driver_class) +FT_USE_MODULE(pcf_driver_class) +FT_USE_MODULE(psaux_module_class) +FT_USE_MODULE(psnames_module_class) +FT_USE_MODULE(pshinter_module_class) +FT_USE_MODULE(ft_raster1_renderer_class) +FT_USE_MODULE(sfnt_module_class) +FT_USE_MODULE(ft_smooth_renderer_class) +FT_USE_MODULE(ft_smooth_lcd_renderer_class) +FT_USE_MODULE(ft_smooth_lcdv_renderer_class) +FT_USE_MODULE(bdf_driver_class) + +/* EOF */ diff --git a/src/freetype2/freetype/config/ftoption.h b/src/freetype2/freetype/config/ftoption.h new file mode 100644 index 0000000..5323975 --- /dev/null +++ b/src/freetype2/freetype/config/ftoption.h @@ -0,0 +1,669 @@ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __FTOPTION_H__ +#define __FTOPTION_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* USER-SELECTABLE CONFIGURATION MACROS */ + /* */ + /* This file contains the default configuration macro definitions for */ + /* a standard build of the FreeType library. There are three ways to */ + /* use this file to build project-specific versions of the library: */ + /* */ + /* - You can modify this file by hand, but this is not recommended in */ + /* cases where you would like to build several versions of the */ + /* library from a single source directory. */ + /* */ + /* - You can put a copy of this file in your build directory, more */ + /* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */ + /* is the name of a directory that is included _before_ the FreeType */ + /* include path during compilation. */ + /* */ + /* The default FreeType Makefiles and Jamfiles use the build */ + /* directory `builds/<system>' by default, but you can easily change */ + /* that for your own projects. */ + /* */ + /* - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it */ + /* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */ + /* locate this file during the build. For example, */ + /* */ + /* #define FT_CONFIG_OPTIONS_H <myftoptions.h> */ + /* #include <freetype/config/ftheader.h> */ + /* */ + /* will use `$BUILD/myftoptions.h' instead of this file for macro */ + /* definitions. */ + /* */ + /* Note also that you can similarly pre-define the macro */ + /* FT_CONFIG_MODULES_H used to locate the file listing of the modules */ + /* that are statically linked to the library at compile time. By */ + /* default, this file is <freetype/config/ftmodule.h>. */ + /* */ + /* We highly recommend using the third method whenever possible. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Uncomment the line below if you want to activate sub-pixel rendering */ + /* (a.k.a. LCD rendering, or ClearType) in this build of the library. */ + /* */ + /* Note that this feature is covered by several Microsoft patents */ + /* and should not be activated in any default build of the library. */ + /* */ + /* This macro has no impact on the FreeType API, only on its */ + /* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */ + /* FT_Render_Glyph still generates a bitmap that is 3 times larger than */ + /* the original size; the difference will be that each triplet of */ + /* subpixels has R=G=B. */ + /* */ + /* This is done to allow FreeType clients to run unmodified, forcing */ + /* them to display normal gray-level anti-aliased glyphs. */ + /* */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /*************************************************************************/ + /* */ + /* Many compilers provide a non-ANSI 64-bit data type that can be used */ + /* by FreeType to speed up some computations. However, this will create */ + /* some problems when compiling the library in strict ANSI mode. */ + /* */ + /* For this reason, the use of 64-bit integers is normally disabled when */ + /* the __STDC__ macro is defined. You can however disable this by */ + /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */ + /* */ + /* For most compilers, this will only create compilation warnings when */ + /* building the library. */ + /* */ + /* ObNote: The compiler-specific 64-bit integers are detected in the */ + /* file `ftconfig.h' either statically or through the */ + /* `configure' script on supported platforms. */ + /* */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /*************************************************************************/ + /* */ + /* LZW-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `compress' program. This is mostly used to parse many of the PCF */ + /* files that come with various X11 distributions. The implementation */ + /* uses NetBSD's `zopen' to partially uncompress the file on the fly */ + /* (see src/lzw/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +#define FT_CONFIG_OPTION_USE_LZW + + + /*************************************************************************/ + /* */ + /* Gzip-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `gzip' program. This is mostly used to parse many of the PCF files */ + /* that come with XFree86. The implementation uses `zlib' to */ + /* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. See also */ + /* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */ + /* */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /*************************************************************************/ + /* */ + /* ZLib library selection */ + /* */ + /* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */ + /* It allows FreeType's `ftgzip' component to link to the system's */ + /* installation of the ZLib library. This is useful on systems like */ + /* Unix or VMS where it generally is already available. */ + /* */ + /* If you let it undefined, the component will use its own copy */ + /* of the zlib sources instead. These have been modified to be */ + /* included directly within the component and *not* export external */ + /* function names. This allows you to link any program with FreeType */ + /* _and_ ZLib without linking conflicts. */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /*************************************************************************/ + /* */ + /* DLL export compilation */ + /* */ + /* When compiling FreeType as a DLL, some systems/compilers need a */ + /* special keyword in front OR after the return type of function */ + /* declarations. */ + /* */ + /* Two macros are used within the FreeType source code to define */ + /* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */ + /* */ + /* FT_EXPORT( return_type ) */ + /* */ + /* is used in a function declaration, as in */ + /* */ + /* FT_EXPORT( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ); */ + /* */ + /* */ + /* FT_EXPORT_DEF( return_type ) */ + /* */ + /* is used in a function definition, as in */ + /* */ + /* FT_EXPORT_DEF( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ) */ + /* { */ + /* ... some code ... */ + /* return FT_Err_Ok; */ + /* } */ + /* */ + /* You can provide your own implementation of FT_EXPORT and */ + /* FT_EXPORT_DEF here if you want. If you leave them undefined, they */ + /* will be later automatically defined as `extern return_type' to */ + /* allow normal compilation. */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_EXPORT(x) extern x */ +/* #define FT_EXPORT_DEF(x) x */ + + + /*************************************************************************/ + /* */ + /* Glyph Postscript Names handling */ + /* */ + /* By default, FreeType 2 is compiled with the `PSNames' module. This */ + /* module is in charge of converting a glyph name string into a */ + /* Unicode value, or return a Macintosh standard glyph name for the */ + /* use with the TrueType `post' table. */ + /* */ + /* Undefine this macro if you do not want `PSNames' compiled in your */ + /* build of FreeType. This has the following effects: */ + /* */ + /* - The TrueType driver will provide its own set of glyph names, */ + /* if you build it to support postscript names in the TrueType */ + /* `post' table. */ + /* */ + /* - The Type 1 driver will not be able to synthetize a Unicode */ + /* charmap out of the glyphs found in the fonts. */ + /* */ + /* You would normally undefine this configuration macro when building */ + /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ + /* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Postscript Names to Unicode Values support */ + /* */ + /* By default, FreeType 2 is built with the `PSNames' module compiled */ + /* in. Among other things, the module is used to convert a glyph name */ + /* into a Unicode value. This is especially useful in order to */ + /* synthetize on the fly a Unicode charmap from the CFF/Type 1 driver */ + /* through a big table named the `Adobe Glyph List' (AGL). */ + /* */ + /* Undefine this macro if you do not want the Adobe Glyph List */ + /* compiled in your `PSNames' module. The Type 1 driver will not be */ + /* able to synthetize a Unicode charmap out of the glyphs found in the */ + /* fonts. */ + /* */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /*************************************************************************/ + /* */ + /* Support for Mac fonts */ + /* */ + /* Define this macro if you want support for outline fonts in Mac */ + /* format (mac dfont, mac resource, macbinary containing a mac */ + /* resource) on non-Mac platforms. */ + /* */ + /* Note that the `FOND' resource isn't checked. */ + /* */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /*************************************************************************/ + /* */ + /* Guessing methods to access embedded resource forks */ + /* */ + /* Enable extra Mac fonts support on non-Mac platforms (e.g. */ + /* GNU/Linux). */ + /* */ + /* Resource forks which include fonts data are stored sometimes in */ + /* locations which users or developers don't expected. In some cases, */ + /* resource forks start with some offset from the head of a file. In */ + /* other cases, the actual resource fork is stored in file different */ + /* from what the user specifies. If this option is activated, */ + /* FreeType tries to guess whether such offsets or different file */ + /* names must be used. */ + /* */ + /* Note that normal, direct access of resource forks is controlled via */ + /* the FT_CONFIG_OPTION_MAC_FONTS option. */ + /* */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /*************************************************************************/ + /* */ + /* Allow the use of FT_Incremental_Interface to load typefaces that */ + /* contain no glyph data, but supply it via a callback function. */ + /* This allows FreeType to be used with the PostScript language, using */ + /* the GhostScript interpreter. */ + /* */ +/* #define FT_CONFIG_OPTION_INCREMENTAL */ + + + /*************************************************************************/ + /* */ + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ + /* */ + /* This must be greater than 4KByte if you use FreeType to rasterize */ + /* glyphs; otherwise, you may set it to zero to avoid unnecessary */ + /* allocation of the render pool. */ + /* */ +#define FT_RENDER_POOL_SIZE 16384L + + + /*************************************************************************/ + /* */ + /* FT_MAX_MODULES */ + /* */ + /* The maximum number of modules that can be registered in a single */ + /* FreeType library object. 32 is the default. */ + /* */ +#define FT_MAX_MODULES 32 + + + /*************************************************************************/ + /* */ + /* Debug level */ + /* */ + /* FreeType can be compiled in debug or trace mode. In debug mode, */ + /* errors are reported through the `ftdebug' component. In trace */ + /* mode, additional messages are sent to the standard output during */ + /* execution. */ + /* */ + /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ + /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ + /* */ + /* Don't define any of these macros to compile in `release' mode! */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Memory Debugging */ + /* */ + /* FreeType now comes with an integrated memory debugger that is */ + /* capable of detecting simple errors like memory leaks or double */ + /* deletes. To compile it within your build of the library, you */ + /* should define FT_DEBUG_MEMORY here. */ + /* */ + /* Note that the memory debugger is only activated at runtime when */ + /* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_DEBUG_MEMORY */ + + + /*************************************************************************/ + /* */ + /* Module errors */ + /* */ + /* If this macro is set (which is _not_ the default), the higher byte */ + /* of an error code gives the module in which the error has occurred, */ + /* while the lower byte is the real error code. */ + /* */ + /* Setting this macro makes sense for debugging purposes only, since */ + /* it would break source compatibility of certain programs that use */ + /* FreeType 2. */ + /* */ + /* More details can be found in the files ftmoderr.h and fterrors.h. */ + /* */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ + /* embedded bitmaps in all formats using the SFNT module (namely */ + /* TrueType & OpenType). */ + /* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ + /* load and enumerate the glyph Postscript names in a TrueType or */ + /* OpenType file. */ + /* */ + /* Note that when you do not compile the `PSNames' module by undefining */ + /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ + /* contain additional code used to read the PS Names table from a font. */ + /* */ + /* (By default, the module uses `PSNames' to extract glyph names.) */ + /* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ + /* access the internal name table in a SFNT-based format like TrueType */ + /* or OpenType. The name table contains various strings used to */ + /* describe the font, like family name, copyright, version, etc. It */ + /* does not contain any glyph name though. */ + /* */ + /* Accessing SFNT names is done through the functions declared in */ + /* `freetype/ftnames.h'. */ + /* */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /*************************************************************************/ + /* */ + /* TrueType CMap support */ + /* */ + /* Here you can fine-tune which TrueType CMap table format shall be */ + /* supported. */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. Note that there are */ + /* important patent issues related to the use of the interpreter. */ + /* */ + /* By undefining this, you will only compile the code necessary to load */ + /* TrueType glyphs without hinting. */ + /* */ + /* Do not #undef this macro here, since the build system might */ + /* define it for certain configurations only. */ + /* */ +/* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */ + /* of the TrueType bytecode interpreter is used that doesn't implement */ + /* any of the patented opcodes and algorithms. Note that the */ + /* the TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored* if you */ + /* define TT_CONFIG_OPTION_BYTECODE_INTERPRETER; with other words, */ + /* either define TT_CONFIG_OPTION_BYTECODE_INTERPRETER or */ + /* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time. */ + /* */ + /* This macro is only useful for a small number of font files (mostly */ + /* for Asian scripts) that require bytecode interpretation to properly */ + /* load glyphs. For all other fonts, this produces unpleasant results, */ + /* thus the unpatented interpreter is never used to load glyphs from */ + /* TrueType fonts unless one of the following two options is used. */ + /* */ + /* - The unpatented interpreter is explicitly activated by the user */ + /* through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag */ + /* when opening the FT_Face. */ + /* */ + /* - FreeType detects that the FT_Face corresponds to one of the */ + /* `trick' fonts (e.g., `Mingliu') it knows about. The font engine */ + /* contains a hard-coded list of font names and other matching */ + /* parameters (see function `tt_face_init' in file */ + /* `src/truetype/ttobjs.c'). */ + /* */ + /* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */ + /* */ + /* { */ + /* FT_Parameter parameter; */ + /* FT_Open_Args open_args; */ + /* */ + /* */ + /* parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING; */ + /* */ + /* open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; */ + /* open_args.pathname = my_font_pathname; */ + /* open_args.num_params = 1; */ + /* open_args.params = ¶meter; */ + /* */ + /* error = FT_Open_Face( library, &open_args, index, &face ); */ + /* ... */ + /* } */ + /* */ +#define TT_CONFIG_OPTION_UNPATENTED_HINTING + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ + /* bytecode interpreter with a huge switch statement, rather than a call */ + /* table. This results in smaller and faster code for a number of */ + /* architectures. */ + /* */ + /* Note however that on some compiler/processor combinations, undefining */ + /* this macro will generate faster, though larger, code. */ + /* */ +#define TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */ + /* TrueType glyph loader to use Apple's definition of how to handle */ + /* component offsets in composite glyphs. */ + /* */ + /* Apple and MS disagree on the default behavior of component offsets */ + /* in composites. Apple says that they should be scaled by the scaling */ + /* factors in the transformation matrix (roughly, it's more complex) */ + /* while MS says they should not. OpenType defines two bits in the */ + /* composite flags array which can be used to disambiguate, but old */ + /* fonts will not have them. */ + /* */ + /* http://partners.adobe.com/asn/developer/opentype/glyf.html */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */ + /* */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */ + /* support for Apple's distortable font technology (fvar, gvar, cvar, */ + /* and avar tables). This has many similarities to Type 1 Multiple */ + /* Masters support. */ + /* */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BDF if you want to include support for */ + /* an embedded `BDF ' table within SFNT-based bitmap formats. */ + /* */ +#define TT_CONFIG_OPTION_BDF + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ + /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ + /* required. */ + /* */ +#define T1_MAX_DICT_DEPTH 5 + + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 16 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ + /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of `t1afm', which is in charge of reading Type 1 AFM */ + /* files into an existing face. Note that if set, the T1 driver will be */ + /* unable to produce kerning distances. */ + /* */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of the Multiple Masters font support in the Type 1 */ + /* driver. */ + /* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Compile autofit module with CJK script support. */ + /* */ +#define AF_CONFIG_OPTION_CJK + + /*************************************************************************/ + /* */ + /* Compile autofit module with Indic script support. */ + /* */ +#define AF_CONFIG_OPTION_INDIC + + /* */ + + + /* + * Define this variable if you want to keep the layout of internal + * structures that was used prior to FreeType 2.2. This also compiles in + * a few obsolete functions to avoid linking problems on typical Unix + * distributions. + * + * For embedded systems or building a new distribution from scratch, it + * is recommended to disable the macro since it reduces the library's code + * size and activates a few memory-saving optimizations as well. + */ +#define FT_CONFIG_OPTION_OLD_INTERNALS + + + /* + * This variable is defined if either unpatented or native TrueType + * hinting is requested by the definitions above. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#elif defined TT_CONFIG_OPTION_UNPATENTED_HINTING +#define TT_USE_BYTECODE_INTERPRETER +#endif + +FT_END_HEADER + + +#endif /* __FTOPTION_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/config/ftstdlib.h b/src/freetype2/freetype/config/ftstdlib.h new file mode 100644 index 0000000..f923f3e --- /dev/null +++ b/src/freetype2/freetype/config/ftstdlib.h @@ -0,0 +1,180 @@ +/***************************************************************************/ +/* */ +/* ftstdlib.h */ +/* */ +/* ANSI-specific library and header configuration file (specification */ +/* only). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to group all #includes to the ANSI C library that */ + /* FreeType normally requires. It also defines macros to rename the */ + /* standard functions within the FreeType source code. */ + /* */ + /* Load a file which defines __FTSTDLIB_H__ before this one to override */ + /* it. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSTDLIB_H__ +#define __FTSTDLIB_H__ + + +#include <stddef.h> + +#define ft_ptrdiff_t ptrdiff_t + + + /**********************************************************************/ + /* */ + /* integer limits */ + /* */ + /* UINT_MAX and ULONG_MAX are used to automatically compute the size */ + /* of `int' and `long' in bytes at compile-time. So far, this works */ + /* for all platforms the library has been tested on. */ + /* */ + /* Note that on the extremely rare platforms that do not provide */ + /* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */ + /* old Crays where `int' is 36 bits), we do not make any guarantee */ + /* about the correct behaviour of FT2 with all fonts. */ + /* */ + /* In these case, `ftconfig.h' will refuse to compile anyway with a */ + /* message like `couldn't find 32-bit type' or something similar. */ + /* */ + /* IMPORTANT NOTE: We do not define aliases for heap management and */ + /* i/o routines (i.e. malloc/free/fopen/fread/...) */ + /* since these functions should all be encapsulated */ + /* by platform-specific implementations of */ + /* `ftsystem.c'. */ + /* */ + /**********************************************************************/ + + +#include <limits.h> + +#define FT_CHAR_BIT CHAR_BIT +#define FT_INT_MAX INT_MAX +#define FT_UINT_MAX UINT_MAX +#define FT_ULONG_MAX ULONG_MAX + + + /**********************************************************************/ + /* */ + /* character and string processing */ + /* */ + /**********************************************************************/ + + +#include <string.h> + +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr + + + /**********************************************************************/ + /* */ + /* file handling */ + /* */ + /**********************************************************************/ + + +#include <stdio.h> + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_sprintf sprintf + + + /**********************************************************************/ + /* */ + /* sorting */ + /* */ + /**********************************************************************/ + + +#include <stdlib.h> + +#define ft_qsort qsort + +#define ft_exit exit /* only used to exit from unhandled exceptions */ + + + /**********************************************************************/ + /* */ + /* memory allocation */ + /* */ + /**********************************************************************/ + + +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc + + + /**********************************************************************/ + /* */ + /* miscellaneous */ + /* */ + /**********************************************************************/ + + +#define ft_atol atol +#define ft_labs labs + + + /**********************************************************************/ + /* */ + /* execution control */ + /* */ + /**********************************************************************/ + + +#include <setjmp.h> + +#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */ + /* jmp_buf is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp longjmp +#define ft_setjmp( b ) setjmp( *(jmp_buf*) &(b) ) /* same thing here */ + + + /* the following is only used for debugging purposes, i.e., if */ + /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */ + +#include <stdarg.h> + + +#endif /* __FTSTDLIB_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/freetype.h b/src/freetype2/freetype/freetype.h new file mode 100644 index 0000000..dbca087 --- /dev/null +++ b/src/freetype2/freetype/freetype.h @@ -0,0 +1,3434 @@ +/***************************************************************************/ +/* */ +/* freetype.h */ +/* */ +/* FreeType high-level API and common types (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 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 FT_FREETYPE_H +#error "`ft2build.h' hasn't been included yet!" +#error "Please always use macros to include FreeType header files." +#error "Example:" +#error " #include <ft2build.h>" +#error " #include FT_FREETYPE_H" +#endif + + + /*************************************************************************/ + /* */ + /* The `raster' component duplicates some of the declarations in */ + /* freetype.h for stand-alone use if _FREETYPE_ isn't defined. */ + /* */ + /*************************************************************************/ + + +#ifndef __FREETYPE_H__ +#define __FREETYPE_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_ERRORS_H +#include FT_TYPES_H + + +FT_BEGIN_HEADER + + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* user_allocation */ + /* */ + /* <Title> */ + /* User allocation */ + /* */ + /* <Abstract> */ + /* How client applications should allocate FreeType data structures. */ + /* */ + /* <Description> */ + /* FreeType assumes that structures allocated by the user and passed */ + /* as arguments are zeroed out except for the actual data. With */ + /* other words, it is recommended to use `calloc' (or variants of it) */ + /* instead of `malloc' for allocation. */ + /* */ + /*************************************************************************/ + + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* base_interface */ + /* */ + /* <Title> */ + /* Base Interface */ + /* */ + /* <Abstract> */ + /* The FreeType 2 base font interface. */ + /* */ + /* <Description> */ + /* This section describes the public high-level API of FreeType 2. */ + /* */ + /* <Order> */ + /* FT_Library */ + /* FT_Face */ + /* FT_Size */ + /* FT_GlyphSlot */ + /* FT_CharMap */ + /* FT_Encoding */ + /* */ + /* FT_FaceRec */ + /* */ + /* FT_FACE_FLAG_SCALABLE */ + /* FT_FACE_FLAG_FIXED_SIZES */ + /* FT_FACE_FLAG_FIXED_WIDTH */ + /* FT_FACE_FLAG_HORIZONTAL */ + /* FT_FACE_FLAG_VERTICAL */ + /* FT_FACE_FLAG_SFNT */ + /* FT_FACE_FLAG_KERNING */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS */ + /* FT_FACE_FLAG_GLYPH_NAMES */ + /* FT_FACE_FLAG_EXTERNAL_STREAM */ + /* FT_FACE_FLAG_FAST_GLYPHS */ + /* FT_FACE_FLAG_HINTER */ + /* */ + /* FT_STYLE_FLAG_BOLD */ + /* FT_STYLE_FLAG_ITALIC */ + /* */ + /* FT_SizeRec */ + /* FT_Size_Metrics */ + /* */ + /* FT_GlyphSlotRec */ + /* FT_Glyph_Metrics */ + /* FT_SubGlyph */ + /* */ + /* FT_Bitmap_Size */ + /* */ + /* FT_Init_FreeType */ + /* FT_Done_FreeType */ + /* */ + /* FT_New_Face */ + /* FT_Done_Face */ + /* FT_New_Memory_Face */ + /* FT_Open_Face */ + /* FT_Open_Args */ + /* FT_Parameter */ + /* FT_Attach_File */ + /* FT_Attach_Stream */ + /* */ + /* FT_Set_Char_Size */ + /* FT_Set_Pixel_Sizes */ + /* FT_Request_Size */ + /* FT_Select_Size */ + /* FT_Size_Request_Type */ + /* FT_Size_Request */ + /* FT_Set_Transform */ + /* FT_Load_Glyph */ + /* FT_Get_Char_Index */ + /* FT_Get_Name_Index */ + /* FT_Load_Char */ + /* */ + /* FT_OPEN_MEMORY */ + /* FT_OPEN_STREAM */ + /* FT_OPEN_PATHNAME */ + /* FT_OPEN_DRIVER */ + /* FT_OPEN_PARAMS */ + /* */ + /* FT_LOAD_DEFAULT */ + /* FT_LOAD_RENDER */ + /* FT_LOAD_MONOCHROME */ + /* FT_LOAD_LINEAR_DESIGN */ + /* FT_LOAD_NO_SCALE */ + /* FT_LOAD_NO_HINTING */ + /* FT_LOAD_NO_BITMAP */ + /* FT_LOAD_CROP_BITMAP */ + /* */ + /* FT_LOAD_VERTICAL_LAYOUT */ + /* FT_LOAD_IGNORE_TRANSFORM */ + /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ + /* FT_LOAD_FORCE_AUTOHINT */ + /* FT_LOAD_NO_RECURSE */ + /* FT_LOAD_PEDANTIC */ + /* */ + /* FT_LOAD_TARGET_NORMAL */ + /* FT_LOAD_TARGET_LIGHT */ + /* FT_LOAD_TARGET_MONO */ + /* FT_LOAD_TARGET_LCD */ + /* FT_LOAD_TARGET_LCD_V */ + /* */ + /* FT_Render_Glyph */ + /* FT_Render_Mode */ + /* FT_Get_Kerning */ + /* FT_Kerning_Mode */ + /* FT_Get_Track_Kerning */ + /* FT_Get_Glyph_Name */ + /* FT_Get_Postscript_Name */ + /* */ + /* FT_CharMapRec */ + /* FT_Select_Charmap */ + /* FT_Set_Charmap */ + /* FT_Get_Charmap_Index */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Glyph_Metrics */ + /* */ + /* <Description> */ + /* A structure used to model the metrics of a single glyph. The */ + /* values are expressed in 26.6 fractional pixel format; if the flag */ + /* @FT_LOAD_NO_SCALE has been used while loading the glyph, values */ + /* are expressed in font units instead. */ + /* */ + /* <Fields> */ + /* width :: */ + /* The glyph's width. */ + /* */ + /* height :: */ + /* The glyph's height. */ + /* */ + /* horiBearingX :: */ + /* Left side bearing for horizontal layout. */ + /* */ + /* horiBearingY :: */ + /* Top side bearing for horizontal layout. */ + /* */ + /* horiAdvance :: */ + /* Advance width for horizontal layout. */ + /* */ + /* vertBearingX :: */ + /* Left side bearing for vertical layout. */ + /* */ + /* vertBearingY :: */ + /* Top side bearing for vertical layout. */ + /* */ + /* vertAdvance :: */ + /* Advance height for vertical layout. */ + /* */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + + } FT_Glyph_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap_Size */ + /* */ + /* <Description> */ + /* This structure models the metrics of a bitmap strike (i.e., a set */ + /* of glyphs for a given point size and resolution) in a bitmap font. */ + /* It is used for the `available_sizes' field of @FT_Face. */ + /* */ + /* <Fields> */ + /* height :: The vertical distance, in pixels, between two */ + /* consecutive baselines. It is always positive. */ + /* */ + /* width :: The average width, in pixels, of all glyphs in the */ + /* strike. */ + /* */ + /* size :: The nominal size of the strike in 26.6 fractional */ + /* points. This field is not very useful. */ + /* */ + /* x_ppem :: The horizontal ppem (nominal width) in 26.6 fractional */ + /* pixels. */ + /* */ + /* y_ppem :: The vertical ppem (nominal height) in 26.6 fractional */ + /* pixels. */ + /* */ + /* <Note> */ + /* Windows FNT: */ + /* The nominal size given in a FNT font is not reliable. Thus when */ + /* the driver finds it incorrect, it sets `size' to some calculated */ + /* values and sets `x_ppem' and `y_ppem' to the pixel width and */ + /* height given in the font, respectively. */ + /* */ + /* TrueType embedded bitmaps: */ + /* `size', `width', and `height' values are not contained in the */ + /* bitmap strike itself. They are computed from the global font */ + /* parameters. */ + /* */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Library */ + /* */ + /* <Description> */ + /* A handle to a FreeType library instance. Each `library' is */ + /* completely independent from the others; it is the `root' of a set */ + /* of objects like fonts, faces, sizes, etc. */ + /* */ + /* It also embeds a memory manager (see @FT_Memory), as well as a */ + /* scan-line converter object (see @FT_Raster). */ + /* */ + /* For multi-threading applications each thread should have its own */ + /* FT_Library object. */ + /* */ + /* <Note> */ + /* Library objects are normally created by @FT_Init_FreeType, and */ + /* destroyed with @FT_Done_FreeType. */ + /* */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Module */ + /* */ + /* <Description> */ + /* A handle to a given FreeType module object. Each module can be a */ + /* font driver, a renderer, or anything else that provides services */ + /* to the formers. */ + /* */ + typedef struct FT_ModuleRec_* FT_Module; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Driver */ + /* */ + /* <Description> */ + /* A handle to a given FreeType font driver object. Each font driver */ + /* is a special module capable of creating faces from font files. */ + /* */ + typedef struct FT_DriverRec_* FT_Driver; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Renderer */ + /* */ + /* <Description> */ + /* A handle to a given FreeType renderer. A renderer is a special */ + /* module in charge of converting a glyph image to a bitmap, when */ + /* necessary. Each renderer supports a given glyph image format, and */ + /* one or more target surface depths. */ + /* */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face */ + /* */ + /* <Description> */ + /* A handle to a given typographic face object. A face object models */ + /* a given typeface, in a given style. */ + /* */ + /* <Note> */ + /* Each face object also owns a single @FT_GlyphSlot object, as well */ + /* as one or more @FT_Size objects. */ + /* */ + /* Use @FT_New_Face or @FT_Open_Face to create a new face object from */ + /* a given filepathname or a custom input stream. */ + /* */ + /* Use @FT_Done_Face to destroy it (along with its slot and sizes). */ + /* */ + /* <Also> */ + /* The @FT_FaceRec details the publicly accessible fields of a given */ + /* face object. */ + /* */ + typedef struct FT_FaceRec_* FT_Face; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size */ + /* */ + /* <Description> */ + /* A handle to an object used to model a face scaled to a given */ + /* character size. */ + /* */ + /* <Note> */ + /* Each @FT_Face has an _active_ @FT_Size object that is used by */ + /* functions like @FT_Load_Glyph to determine the scaling */ + /* transformation which is used to load and hint glyphs and metrics. */ + /* */ + /* You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, */ + /* @FT_Request_Size or even @FT_Select_Size to change the content */ + /* (i.e., the scaling values) of the active @FT_Size. */ + /* */ + /* You can use @FT_New_Size to create additional size objects for a */ + /* given @FT_Face, but they won't be used by other functions until */ + /* you activate it through @FT_Activate_Size. Only one size can be */ + /* activated at any given time per face. */ + /* */ + /* <Also> */ + /* The @FT_SizeRec structure details the publicly accessible fields */ + /* of a given size object. */ + /* */ + typedef struct FT_SizeRec_* FT_Size; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_GlyphSlot */ + /* */ + /* <Description> */ + /* A handle to a given `glyph slot'. A slot is a container where it */ + /* is possible to load any one of the glyphs contained in its parent */ + /* face. */ + /* */ + /* In other words, each time you call @FT_Load_Glyph or */ + /* @FT_Load_Char, the slot's content is erased by the new glyph data, */ + /* i.e., the glyph's metrics, its image (bitmap or outline), and */ + /* other control information. */ + /* */ + /* <Also> */ + /* @FT_GlyphSlotRec details the publicly accessible glyph fields. */ + /* */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_CharMap */ + /* */ + /* <Description> */ + /* A handle to a given character map. A charmap is used to translate */ + /* character codes in a given encoding into glyph indexes for its */ + /* parent's face. Some font formats may provide several charmaps per */ + /* font. */ + /* */ + /* Each face object owns zero or more charmaps, but only one of them */ + /* can be `active' and used by @FT_Get_Char_Index or @FT_Load_Char. */ + /* */ + /* The list of available charmaps in a face is available through the */ + /* `face->num_charmaps' and `face->charmaps' fields of @FT_FaceRec. */ + /* */ + /* The currently active charmap is available as `face->charmap'. */ + /* You should call @FT_Set_Charmap to change it. */ + /* */ + /* <Note> */ + /* When a new face is created (either through @FT_New_Face or */ + /* @FT_Open_Face), the library looks for a Unicode charmap within */ + /* the list and automatically activates it. */ + /* */ + /* <Also> */ + /* The @FT_CharMapRec details the publicly accessible fields of a */ + /* given character map. */ + /* */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_ENC_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags into an unsigned long. It is */ + /* used to define `encoding' identifiers (see @FT_Encoding). */ + /* */ + /* <Note> */ + /* Since many 16bit compilers don't like 32bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_ENC_TAG( value, a, b, c, d ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ + +#ifndef FT_ENC_TAG +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( (FT_UInt32)(a) << 24 ) | \ + ( (FT_UInt32)(b) << 16 ) | \ + ( (FT_UInt32)(c) << 8 ) | \ + (FT_UInt32)(d) ) + +#endif /* FT_ENC_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Encoding */ + /* */ + /* <Description> */ + /* An enumeration used to specify character sets supported by */ + /* charmaps. Used in the @FT_Select_Charmap API function. */ + /* */ + /* <Note> */ + /* Despite the name, this enumeration lists specific character */ + /* repertories (i.e., charsets), and not text encoding methods (e.g., */ + /* UTF-8, UTF-16, GB2312_EUC, etc.). */ + /* */ + /* Because of 32-bit charcodes defined in Unicode (i.e., surrogates), */ + /* all character codes must be expressed as FT_Longs. */ + /* */ + /* Other encodings might be defined in the future. */ + /* */ + /* <Values> */ + /* FT_ENCODING_NONE :: */ + /* The encoding value 0 is reserved. */ + /* */ + /* FT_ENCODING_UNICODE :: */ + /* Corresponds to the Unicode character set. This value covers */ + /* all versions of the Unicode repertoire, including ASCII and */ + /* Latin-1. Most fonts include a Unicode charmap, but not all */ + /* of them. */ + /* */ + /* FT_ENCODING_MS_SYMBOL :: */ + /* Corresponds to the Microsoft Symbol encoding, used to encode */ + /* mathematical symbols in the 32..255 character code range. For */ + /* more information, see `http://www.ceviz.net/symbol.htm'. */ + /* */ + /* FT_ENCODING_SJIS :: */ + /* Corresponds to Japanese SJIS encoding. More info at */ + /* at `http://langsupport.japanreference.com/encoding.shtml'. */ + /* See note on multi-byte encodings below. */ + /* */ + /* FT_ENCODING_GB2312 :: */ + /* Corresponds to an encoding system for Simplified Chinese as used */ + /* used in mainland China. */ + /* */ + /* FT_ENCODING_BIG5 :: */ + /* Corresponds to an encoding system for Traditional Chinese as used */ + /* in Taiwan and Hong Kong. */ + /* */ + /* FT_ENCODING_WANSUNG :: */ + /* Corresponds to the Korean encoding system known as Wansung. */ + /* For more information see */ + /* `http://www.microsoft.com/typography/unicode/949.txt'. */ + /* */ + /* FT_ENCODING_JOHAB :: */ + /* The Korean standard character set (KS C-5601-1992), which */ + /* corresponds to MS Windows code page 1361. This character set */ + /* includes all possible Hangeul character combinations. */ + /* */ + /* FT_ENCODING_ADOBE_LATIN_1 :: */ + /* Corresponds to a Latin-1 encoding as defined in a Type 1 */ + /* Postscript font. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_ADOBE_STANDARD :: */ + /* Corresponds to the Adobe Standard encoding, as found in Type 1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_EXPERT :: */ + /* Corresponds to the Adobe Expert encoding, as found in Type 1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_CUSTOM :: */ + /* Corresponds to a custom encoding, as found in Type 1, CFF, and */ + /* OpenType/CFF fonts. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_APPLE_ROMAN :: */ + /* Corresponds to the 8-bit Apple roman encoding. Many TrueType and */ + /* OpenType fonts contain a charmap for this encoding, since older */ + /* versions of Mac OS are able to use it. */ + /* */ + /* FT_ENCODING_OLD_LATIN_2 :: */ + /* This value is deprecated and was never used nor reported by */ + /* FreeType. Don't use or test for it. */ + /* */ + /* FT_ENCODING_MS_SJIS :: */ + /* Same as FT_ENCODING_SJIS. Deprecated. */ + /* */ + /* FT_ENCODING_MS_GB2312 :: */ + /* Same as FT_ENCODING_GB2312. Deprecated. */ + /* */ + /* FT_ENCODING_MS_BIG5 :: */ + /* Same as FT_ENCODING_BIG5. Deprecated. */ + /* */ + /* FT_ENCODING_MS_WANSUNG :: */ + /* Same as FT_ENCODING_WANSUNG. Deprecated. */ + /* */ + /* FT_ENCODING_MS_JOHAB :: */ + /* Same as FT_ENCODING_JOHAB. Deprecated. */ + /* */ + /* <Note> */ + /* By default, FreeType automatically synthetizes a Unicode charmap */ + /* for Postscript fonts, using their glyph names dictionaries. */ + /* However, it also reports the encodings defined explicitly in the */ + /* font file, for the cases when they are needed, with the Adobe */ + /* values as well. */ + /* */ + /* FT_ENCODING_NONE is set by the BDF and PCF drivers if the charmap */ + /* is neither Unicode nor ISO-8859-1 (otherwise it is set to */ + /* FT_ENCODING_UNICODE). Use @FT_Get_BDF_Charset_ID to find out which */ + /* encoding is really present. If, for example, the `cs_registry' */ + /* field is `KOI8' and the `cs_encoding' field is `R', the font is */ + /* encoded in KOI8-R. */ + /* */ + /* FT_ENCODING_NONE is always set (with a single exception) by the */ + /* winfonts driver. Use @FT_Get_WinFNT_Header and examine the */ + /* `charset' field of the @FT_WinFNT_HeaderRec structure to find out */ + /* which encoding is really present. For example, */ + /* @FT_WinFNT_ID_CP1251 (204) means Windows code page 1251 (for */ + /* Russian). */ + /* */ + /* FT_ENCODING_NONE is set if `platform_id' is @TT_PLATFORM_MACINTOSH */ + /* and `encoding_id' is not @TT_MAC_ID_ROMAN (otherwise it is set to */ + /* FT_ENCODING_APPLE_ROMAN). */ + /* */ + /* If `platform_id' is @TT_PLATFORM_MACINTOSH, use the function c */ + /* @FT_Get_CMap_Language_ID to query the Mac language ID which may be */ + /* needed to be able to distinguish Apple encoding variants. See */ + /* */ + /* http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/README.TXT */ + /* */ + /* to get an idea how to do that. Basically, if the language ID is 0, */ + /* don't use it, otherwise subtract 1 from the language ID. Then */ + /* examine `encoding_id'. If, for example, `encoding_id' is */ + /* @TT_MAC_ID_ROMAN and the language ID (minus 1) is */ + /* `TT_MAC_LANGID_GREEK', it is the Greek encoding, not Roman. */ + /* @TT_MAC_ID_ARABIC with `TT_MAC_LANGID_FARSI' means the Farsi */ + /* variant the Arabic encoding. */ + /* */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backwards compatibility */ + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + + } FT_Encoding; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_encoding_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated; use the corresponding @FT_Encoding */ + /* values instead. */ + /* */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_GB2312 +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_CharMapRec */ + /* */ + /* <Description> */ + /* The base charmap structure. */ + /* */ + /* <Fields> */ + /* face :: A handle to the parent face object. */ + /* */ + /* encoding :: An @FT_Encoding tag identifying the charmap. Use */ + /* this with @FT_Select_Charmap. */ + /* */ + /* platform_id :: An ID number describing the platform for the */ + /* following encoding ID. This comes directly from */ + /* the TrueType specification and should be emulated */ + /* for other formats. */ + /* */ + /* encoding_id :: A platform specific encoding number. This also */ + /* comes from the TrueType specification and should be */ + /* emulated similarly. */ + /* */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Face_InternalRec' structure, used to */ + /* model private data of a given @FT_Face object. */ + /* */ + /* This structure might change between releases of FreeType 2 and is */ + /* not generally available to client applications. */ + /* */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_FaceRec */ + /* */ + /* <Description> */ + /* FreeType root face class structure. A face object models a */ + /* typeface in a font file. */ + /* */ + /* <Fields> */ + /* num_faces :: The number of faces in the font file. Some */ + /* font formats can have multiple faces in */ + /* a font file. */ + /* */ + /* face_index :: The index of the face in the font file. It */ + /* is set to 0 if there is only one face in */ + /* the font file. */ + /* */ + /* face_flags :: A set of bit flags that give important */ + /* information about the face; see */ + /* @FT_FACE_FLAG_XXX for the details. */ + /* */ + /* style_flags :: A set of bit flags indicating the style of */ + /* the face; see @FT_STYLE_FLAG_XXX for the */ + /* details. */ + /* */ + /* num_glyphs :: The number of glyphs in the face. If the */ + /* face is scalable and has sbits (see */ + /* `num_fixed_sizes'), it is set to the number */ + /* of outline glyphs. */ + /* */ + /* family_name :: The face's family name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's family (like `Times New */ + /* Roman', `Bodoni', `Garamond', etc). This */ + /* is a least common denominator used to list */ + /* fonts. Some formats (TrueType & OpenType) */ + /* provide localized and Unicode versions of */ + /* this string. Applications should use the */ + /* format specific interface to access them. */ + /* */ + /* style_name :: The face's style name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's style (like `Italic', */ + /* `Bold', `Condensed', etc). Not all font */ + /* formats provide a style name, so this field */ + /* is optional, and can be set to NULL. As */ + /* for `family_name', some formats provide */ + /* localized and Unicode versions of this */ + /* string. Applications should use the format */ + /* specific interface to access them. */ + /* */ + /* num_fixed_sizes :: The number of bitmap strikes in the face. */ + /* Even if the face is scalable, there might */ + /* still be bitmap strikes, which are called */ + /* `sbits' in that case. */ + /* */ + /* available_sizes :: An array of @FT_Bitmap_Size for all bitmap */ + /* strikes in the face. It is set to NULL if */ + /* there is no bitmap strike. */ + /* */ + /* num_charmaps :: The number of charmaps in the face. */ + /* */ + /* charmaps :: An array of the charmaps of the face. */ + /* */ + /* generic :: A field reserved for client uses. See the */ + /* @FT_Generic type description. */ + /* */ + /* bbox :: The font bounding box. Coordinates are */ + /* expressed in font units (see */ + /* `units_per_EM'). The box is large enough */ + /* to contain any glyph from the font. Thus, */ + /* `bbox.yMax' can be seen as the `maximal */ + /* ascender', and `bbox.yMin' as the `minimal */ + /* descender'. Only relevant for scalable */ + /* formats. */ + /* */ + /* units_per_EM :: The number of font units per EM square for */ + /* this face. This is typically 2048 for */ + /* TrueType fonts, and 1000 for Type 1 fonts. */ + /* Only relevant for scalable formats. */ + /* */ + /* ascender :: The typographic ascender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMax'. Only relevant for scalable */ + /* formats. */ + /* */ + /* descender :: The typographic descender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMin'. Note that this field is */ + /* usually negative. Only relevant for */ + /* scalable formats. */ + /* */ + /* height :: The height is the vertical distance */ + /* between two consecutive baselines, */ + /* expressed in font units. It is always */ + /* positive. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_width :: The maximal advance width, in font units, */ + /* for all glyphs in this face. This can be */ + /* used to make word wrapping computations */ + /* faster. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_height :: The maximal advance height, in font units, */ + /* for all glyphs in this face. This is only */ + /* relevant for vertical layouts, and is set */ + /* to `height' for fonts that do not provide */ + /* vertical metrics. Only relevant for */ + /* scalable formats. */ + /* */ + /* underline_position :: The position, in font units, of the */ + /* underline line for this face. It's the */ + /* center of the underlining stem. Only */ + /* relevant for scalable formats. */ + /* */ + /* underline_thickness :: The thickness, in font units, of the */ + /* underline for this face. Only relevant for */ + /* scalable formats. */ + /* */ + /* glyph :: The face's associated glyph slot(s). */ + /* */ + /* size :: The current active size for this face. */ + /* */ + /* charmap :: The current active charmap for this face. */ + /* */ + /* <Note> */ + /* Fields may be changed after a call to @FT_Attach_File or */ + /* @FT_Attach_Stream. */ + /* */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /*# The following member variables (down to `underline_thickness') */ + /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /*# for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /*@private begin */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; + void* extensions; + + FT_Face_Internal internal; + + /*@private end */ + + } FT_FaceRec; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_FACE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flags used in the `face_flags' field of the */ + /* @FT_FaceRec structure. They inform client applications of */ + /* properties of the corresponding face. */ + /* */ + /* <Values> */ + /* FT_FACE_FLAG_SCALABLE :: */ + /* Indicates that the face contains outline glyphs. This doesn't */ + /* prevent bitmap strikes, i.e., a face can have both this and */ + /* and @FT_FACE_FLAG_FIXED_SIZES set. */ + /* */ + /* FT_FACE_FLAG_FIXED_SIZES :: */ + /* Indicates that the face contains bitmap strikes. See also the */ + /* `num_fixed_sizes' and `available_sizes' fields of @FT_FaceRec. */ + /* */ + /* FT_FACE_FLAG_FIXED_WIDTH :: */ + /* Indicates that the face contains fixed-width characters (like */ + /* Courier, Lucido, MonoType, etc.). */ + /* */ + /* FT_FACE_FLAG_SFNT :: */ + /* Indicates that the face uses the `sfnt' storage scheme. For */ + /* now, this means TrueType and OpenType. */ + /* */ + /* FT_FACE_FLAG_HORIZONTAL :: */ + /* Indicates that the face contains horizontal glyph metrics. This */ + /* should be set for all common formats. */ + /* */ + /* FT_FACE_FLAG_VERTICAL :: */ + /* Indicates that the face contains vertical glyph metrics. This */ + /* is only available in some formats, not all of them. */ + /* */ + /* FT_FACE_FLAG_KERNING :: */ + /* Indicates that the face contains kerning information. If set, */ + /* the kerning distance can be retrieved through the function */ + /* @FT_Get_Kerning. Otherwise the function always return the */ + /* vector (0,0). Note that FreeType doesn't handle kerning data */ + /* from the `GPOS' table (as present in some OpenType fonts). */ + /* */ + /* FT_FACE_FLAG_FAST_GLYPHS :: */ + /* THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. */ + /* */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS :: */ + /* Indicates that the font contains multiple masters and is capable */ + /* of interpolating between them. See the multiple-masters */ + /* specific API for details. */ + /* */ + /* FT_FACE_FLAG_GLYPH_NAMES :: */ + /* Indicates that the font contains glyph names that can be */ + /* retrieved through @FT_Get_Glyph_Name. Note that some TrueType */ + /* fonts contain broken glyph name tables. Use the function */ + /* @FT_Has_PS_Glyph_Names when needed. */ + /* */ + /* FT_FACE_FLAG_EXTERNAL_STREAM :: */ + /* Used internally by FreeType to indicate that a face's stream was */ + /* provided by the client application and should not be destroyed */ + /* when @FT_Done_Face is called. Don't read or test this flag. */ + /* */ + /* FT_FACE_FLAG_HINTER :: */ + /* Set if the font driver has a hinting machine of its own. For */ + /* example, with TrueType fonts, it makes sense to use data from */ + /* the SFNT `gasp' table only if the native TrueType hinting engine */ + /* (with the bytecode interpreter) is available and active. */ + /* */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) + + /* */ + + + /************************************************************************* + * + * @macro: + * FT_HAS_HORIZONTAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains + * horizontal metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_HORIZONTAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_VERTICAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains vertical + * metrics. + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_VERTICAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_KERNING( face ) + * + * @description: + * A macro that returns true whenever a face object contains kerning + * data that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( face->face_flags & FT_FACE_FLAG_KERNING ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SCALABLE( face ) + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type 1, Type 42, CID, OpenType/CFF, + * and PFR font formats. + * + */ +#define FT_IS_SCALABLE( face ) \ + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SFNT( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font + * whose format is based on the SFNT storage scheme. This usually + * means: TrueType fonts, OpenType fonts, as well as SFNT-based embedded + * bitmap fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( face->face_flags & FT_FACE_FLAG_SFNT ) + + + /************************************************************************* + * + * @macro: + * FT_IS_FIXED_WIDTH( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or `monospace', `fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_FIXED_SIZES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes' field of the + * @FT_FaceRec structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) + + /* */ + + + /************************************************************************* + * + * @macro: + * FT_HAS_FAST_GLYPHS( face ) + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 + + + /************************************************************************* + * + * @macro: + * FT_HAS_GLYPH_NAMES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) + + + /*************************************************************************/ + /* */ + /* <Constant> */ + /* FT_STYLE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit-flags used to indicate the style of a given face. */ + /* These are used in the `style_flags' field of @FT_FaceRec. */ + /* */ + /* <Values> */ + /* FT_STYLE_FLAG_ITALIC :: */ + /* Indicates that a given face is italicized. */ + /* */ + /* FT_STYLE_FLAG_BOLD :: */ + /* Indicates that a given face is bold. */ + /* */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Size_InternalRec' structure, used to */ + /* model private data of a given FT_Size object. */ + /* */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_Metrics */ + /* */ + /* <Description> */ + /* The size metrics structure gives the metrics of a size object. */ + /* */ + /* <Fields> */ + /* x_ppem :: The width of the scaled EM square in pixels, hence */ + /* the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal width'. */ + /* */ + /* y_ppem :: The height of the scaled EM square in pixels, */ + /* hence the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal height'. */ + /* */ + /* x_scale :: A 16.16 fractional scaling value used to convert */ + /* horizontal metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* y_scale :: A 16.16 fractional scaling value used to convert */ + /* vertical metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* ascender :: The ascender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* descender :: The descender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* height :: The height in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* max_advance :: The maximal advance width in 26.6 fractional */ + /* pixels. See @FT_FaceRec for the details. */ + /* */ + /* <Note> */ + /* The scaling values, if relevant, are determined first during a */ + /* size changing operation. The remaining fields are then set by the */ + /* driver. For scalable formats, they are usually set to scaled */ + /* values of the corresponding fields in @FT_FaceRec. */ + /* */ + /* Note that due to glyph hinting, these values might not be exact */ + /* for certain fonts. Thus they must be treated as unreliable */ + /* with an error margin of at least one pixel! */ + /* */ + /* Indeed, the only way to get the exact metrics is to render _all_ */ + /* glyphs. As this would be a definite performance hit, it is up to */ + /* client applications to perform such computations. */ + /* */ + /* The FT_Size_Metrics structure is valid for bitmap fonts also. */ + /* */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SizeRec */ + /* */ + /* <Description> */ + /* FreeType root size class structure. A size object models a face */ + /* object at a given size. */ + /* */ + /* <Fields> */ + /* face :: Handle to the parent face object. */ + /* */ + /* generic :: A typeless pointer, which is unused by the FreeType */ + /* library or any of its drivers. It can be used by */ + /* client applications to link their own data to each size */ + /* object. */ + /* */ + /* metrics :: Metrics for this size object. This field is read-only. */ + /* */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; + + } FT_SizeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SubGlyph */ + /* */ + /* <Description> */ + /* The subglyph structure is an internal object used to describe */ + /* subglyphs (for example, in the case of composites). */ + /* */ + /* <Note> */ + /* The subglyph implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + /* You can however retrieve subglyph information with */ + /* @FT_Get_SubGlyph_Info. */ + /* */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Slot_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Slot_InternalRec' structure, used to */ + /* model private data of a given FT_GlyphSlot object. */ + /* */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphSlotRec */ + /* */ + /* <Description> */ + /* FreeType root glyph slot class structure. A glyph slot is a */ + /* container where individual glyphs can be loaded, be they in */ + /* outline or bitmap format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library instance */ + /* this slot belongs to. */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* next :: In some cases (like some font tools), several */ + /* glyph slots per face object can be a good */ + /* thing. As this is rare, the glyph slots are */ + /* listed through a direct, single-linked list */ + /* using its `next' field. */ + /* */ + /* generic :: A typeless pointer which is unused by the */ + /* FreeType library or any of its drivers. It */ + /* can be used by client applications to link */ + /* their own data to each glyph slot object. */ + /* */ + /* metrics :: The metrics of the last loaded glyph in the */ + /* slot. The returned values depend on the last */ + /* load flags (see the @FT_Load_Glyph API */ + /* function) and can be expressed either in 26.6 */ + /* fractional pixels or font units. */ + /* */ + /* Note that even when the glyph image is */ + /* transformed, the metrics are not. */ + /* */ + /* linearHoriAdvance :: The advance width of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* linearVertAdvance :: The advance height of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* advance :: This is the transformed advance width for the */ + /* glyph. */ + /* */ + /* format :: This field indicates the format of the image */ + /* contained in the glyph slot. Typically */ + /* @FT_GLYPH_FORMAT_BITMAP, */ + /* @FT_GLYPH_FORMAT_OUTLINE, or */ + /* @FT_GLYPH_FORMAT_COMPOSITE, but others are */ + /* possible. */ + /* */ + /* bitmap :: This field is used as a bitmap descriptor */ + /* when the slot format is */ + /* @FT_GLYPH_FORMAT_BITMAP. Note that the */ + /* address and content of the bitmap buffer can */ + /* change between calls of @FT_Load_Glyph and a */ + /* few other functions. */ + /* */ + /* bitmap_left :: This is the bitmap's left bearing expressed */ + /* in integer pixels. Of course, this is only */ + /* valid if the format is */ + /* @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* bitmap_top :: This is the bitmap's top bearing expressed in */ + /* integer pixels. Remember that this is the */ + /* distance from the baseline to the top-most */ + /* glyph scanline, upwards y-coordinates being */ + /* *positive*. */ + /* */ + /* outline :: The outline descriptor for the current glyph */ + /* image if its format is */ + /* @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is */ + /* loaded, `outline' can be transformed, */ + /* distorted, embolded, etc. However, it must */ + /* not be freed. */ + /* */ + /* num_subglyphs :: The number of subglyphs in a composite glyph. */ + /* This field is only valid for the composite */ + /* glyph format that should normally only be */ + /* loaded with the @FT_LOAD_NO_RECURSE flag. */ + /* For now this is internal to FreeType. */ + /* */ + /* subglyphs :: An array of subglyph descriptors for */ + /* composite glyphs. There are `num_subglyphs' */ + /* elements in there. Currently internal to */ + /* FreeType. */ + /* */ + /* control_data :: Certain font drivers can also return the */ + /* control data for a given glyph image (e.g. */ + /* TrueType bytecode, Type 1 charstrings, etc.). */ + /* This field is a pointer to such data. */ + /* */ + /* control_len :: This is the length in bytes of the control */ + /* data. */ + /* */ + /* other :: Really wicked formats can use this pointer to */ + /* present their own glyph image to client */ + /* applications. Note that the application */ + /* needs to know about the image format. */ + /* */ + /* lsb_delta :: The difference between hinted and unhinted */ + /* left side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* rsb_delta :: The difference between hinted and unhinted */ + /* right side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* <Note> */ + /* If @FT_Load_Glyph is called with default flags (see */ + /* @FT_LOAD_DEFAULT) the glyph image is loaded in the glyph slot in */ + /* its native format (e.g., an outline glyph for TrueType and Type 1 */ + /* formats). */ + /* */ + /* This image can later be converted into a bitmap by calling */ + /* @FT_Render_Glyph. This function finds the current renderer for */ + /* the native image's format then invokes it. */ + /* */ + /* The renderer is in charge of transforming the native image through */ + /* the slot's face transformation fields, then convert it into a */ + /* bitmap that is returned in `slot->bitmap'. */ + /* */ + /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */ + /* to specify the position of the bitmap relative to the current pen */ + /* position (e.g., coordinates (0,0) on the baseline). Of course, */ + /* `slot->format' is also changed to @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* <Note> */ + /* Here a small pseudo code fragment which shows how to use */ + /* `lsb_delta' and `rsb_delta': */ + /* */ + /* { */ + /* FT_Pos origin_x = 0; */ + /* FT_Pos prev_rsb_delta = 0; */ + /* */ + /* */ + /* for all glyphs do */ + /* <compute kern between current and previous glyph and add it to */ + /* `origin_x'> */ + /* */ + /* <load glyph with `FT_Load_Glyph'> */ + /* */ + /* if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 ) */ + /* origin_x -= 64; */ + /* else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 ) */ + /* origin_x += 64; */ + /* */ + /* prev_rsb_delta = face->glyph->rsb_delta; */ + /* */ + /* <save glyph image, or render glyph, or ...> */ + /* */ + /* origin_x += face->glyph->advance.x; */ + /* endfor */ + /* } */ + /* */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt reserved; /* retained for binary compatibility */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Init_FreeType */ + /* */ + /* <Description> */ + /* Initialize a new FreeType library object. The set of modules */ + /* that are registered by this function is determined at build time. */ + /* */ + /* <Output> */ + /* alibrary :: A handle to a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_FreeType */ + /* */ + /* <Description> */ + /* Destroy a given FreeType library object and all of its children, */ + /* including resources, drivers, faces, sizes, etc. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OPEN_XXX */ + /* */ + /* <Description> */ + /* A list of bit-field constants used within the `flags' field of the */ + /* @FT_Open_Args structure. */ + /* */ + /* <Values> */ + /* FT_OPEN_MEMORY :: This is a memory-based stream. */ + /* */ + /* FT_OPEN_STREAM :: Copy the stream from the `stream' field. */ + /* */ + /* FT_OPEN_PATHNAME :: Create a new input stream from a C */ + /* path name. */ + /* */ + /* FT_OPEN_DRIVER :: Use the `driver' field. */ + /* */ + /* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */ + /* */ + /* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */ + /* */ + /* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */ + /* */ + /* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */ + /* */ + /* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */ + /* */ + /* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */ + /* */ + /* <Note> */ + /* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */ + /* flags are mutually exclusive. */ + /* */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + +#define ft_open_memory FT_OPEN_MEMORY /* deprecated */ +#define ft_open_stream FT_OPEN_STREAM /* deprecated */ +#define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */ +#define ft_open_driver FT_OPEN_DRIVER /* deprecated */ +#define ft_open_params FT_OPEN_PARAMS /* deprecated */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Parameter */ + /* */ + /* <Description> */ + /* A simple structure used to pass more or less generic parameters */ + /* to @FT_Open_Face. */ + /* */ + /* <Fields> */ + /* tag :: A four-byte identification tag. */ + /* */ + /* data :: A pointer to the parameter data. */ + /* */ + /* <Note> */ + /* The ID and function of parameters are driver-specific. */ + /* */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Open_Args */ + /* */ + /* <Description> */ + /* A structure used to indicate how to open a new font file or */ + /* stream. A pointer to such a structure can be used as a parameter */ + /* for the functions @FT_Open_Face and @FT_Attach_Stream. */ + /* */ + /* <Fields> */ + /* flags :: A set of bit flags indicating how to use the */ + /* structure. */ + /* */ + /* memory_base :: The first byte of the file in memory. */ + /* */ + /* memory_size :: The size in bytes of the file in memory. */ + /* */ + /* pathname :: A pointer to an 8-bit file pathname. */ + /* */ + /* stream :: A handle to a source stream object. */ + /* */ + /* driver :: This field is exclusively used by @FT_Open_Face; */ + /* it simply specifies the font driver to use to open */ + /* the face. If set to 0, FreeType tries to load the */ + /* face with each one of the drivers in its list. */ + /* */ + /* num_params :: The number of extra parameters. */ + /* */ + /* params :: Extra parameters passed to the font driver when */ + /* opening a new face. */ + /* */ + /* <Note> */ + /* The stream type is determined by the contents of `flags' which */ + /* are tested in the following order by @FT_Open_Face: */ + /* */ + /* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */ + /* memory file of `memory_size' bytes, located at `memory_address'. */ + /* The data are are not copied, and the client is responsible for */ + /* releasing and destroying them _after_ the corresponding call to */ + /* @FT_Done_Face. */ + /* */ + /* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */ + /* custom input stream `stream' is used. */ + /* */ + /* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */ + /* is a normal file and use `pathname' to open it. */ + /* */ + /* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */ + /* open the file with the driver whose handler is in `driver'. */ + /* */ + /* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */ + /* `num_params' and `params' is used. They are ignored otherwise. */ + /* */ + /* Ideally, both the `pathname' and `params' fields should be tagged */ + /* as `const'; this is missing for API backwards compatibility. With */ + /* other words, applications should treat them as read-only. */ + /* */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font by its pathname. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* pathname :: A path to the font file. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Memory_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font which has been */ + /* loaded into memory. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* file_base :: A pointer to the beginning of the font data. */ + /* */ + /* file_size :: The size of the memory chunk used by the font data. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You must not deallocate the memory before calling @FT_Done_Face. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Open_Face */ + /* */ + /* <Description> */ + /* Create a face object from a given resource described by */ + /* @FT_Open_Args. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* args :: A pointer to an `FT_Open_Args' structure which must */ + /* be filled by the caller. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See note below. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* FT_Open_Face can be used to quickly check whether the font */ + /* format of a given font resource is supported by FreeType. If the */ + /* `face_index' field is negative, the function's return value is 0 */ + /* if the font format is recognized, or non-zero otherwise; */ + /* the function returns a more or less empty face handle in `*aface' */ + /* (if `aface' isn't NULL). The only useful field in this special */ + /* case is `face->num_faces' which gives the number of faces within */ + /* the font file. After examination, the returned @FT_Face structure */ + /* should be deallocated with a call to @FT_Done_Face. */ + /* */ + /* Each new face object created with this function also owns a */ + /* default @FT_Size object, accessible as `face->size'. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_File */ + /* */ + /* <Description> */ + /* This function calls @FT_Attach_Stream to attach a file. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* filepathname :: The pathname. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_Stream */ + /* */ + /* <Description> */ + /* `Attach' data to a face object. Normally, this is used to read */ + /* additional information for the face object. For example, you can */ + /* attach an AFM file that comes with a Type 1 font to get the */ + /* kerning values and other metrics. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* parameters :: A pointer to @FT_Open_Args which must be filled by */ + /* the caller. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The meaning of the `attach' (i.e., what really happens when the */ + /* new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Face */ + /* */ + /* <Description> */ + /* Discard a given face object, as well as all of its child slots and */ + /* sizes. */ + /* */ + /* <Input> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Size */ + /* */ + /* <Description> */ + /* Select a bitmap strike. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* strike_index :: The index of the bitmap strike in the */ + /* `available_sizes' field of @FT_FaceRec structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Size_Request_Type */ + /* */ + /* <Description> */ + /* An enumeration type that lists the supported size request types. */ + /* */ + /* <Values> */ + /* FT_SIZE_REQUEST_TYPE_NOMINAL :: */ + /* The nominal size. The `units_per_EM' field of @FT_FaceRec is */ + /* used to determine both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_REAL_DIM :: */ + /* The real dimension. The sum of the the `Ascender' and (minus */ + /* of) the `Descender' fields of @FT_FaceRec are used to determine */ + /* both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_BBOX :: */ + /* The font bounding box. The width and height of the `bbox' field */ + /* of @FT_FaceRec are used to determine the horizontal and vertical */ + /* scaling value, respectively. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_CELL :: */ + /* The `max_advance_width' field of @FT_FaceRec is used to */ + /* determine the horizontal scaling value; the vertical scaling */ + /* value is determined the same way as */ + /* @FT_SIZE_REQUEST_TYPE_REAL_DIM does. Finally, both scaling */ + /* values are set to the smaller one. This type is useful if you */ + /* want to specify the font size for, say, a window of a given */ + /* dimension and 80x24 cells. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_SCALES :: */ + /* Specify the scaling values directly. */ + /* */ + /* <Note> */ + /* The above descriptions only apply to scalable formats. For bitmap */ + /* formats, the behaviour is up to the driver. */ + /* */ + /* See the note section of @FT_Size_Metrics if you wonder how size */ + /* requesting relates to scaling values. */ + /* */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + + } FT_Size_Request_Type; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_RequestRec */ + /* */ + /* <Description> */ + /* A structure used to model a size request. */ + /* */ + /* <Fields> */ + /* type :: See @FT_Size_Request_Type. */ + /* */ + /* width :: The desired width. */ + /* */ + /* height :: The desired height. */ + /* */ + /* horiResolution :: The horizontal resolution. If set to zero, */ + /* `width' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* vertResolution :: The vertical resolution. If set to zero, */ + /* `height' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* <Note> */ + /* If `width' is zero, then the horizontal scaling value is set */ + /* equal to the vertical scaling value, and vice versa. */ + /* */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + + } FT_Size_RequestRec, *FT_Size_Request; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Request_Size */ + /* */ + /* <Description> */ + /* Resize the scale of the active @FT_Size object in a face. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* req :: A pointer to a @FT_Size_RequestRec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Although drivers may select the bitmap strike matching the */ + /* request, you should not rely on this if you intend to select a */ + /* particular bitmap strike. Use @FT_Select_Size instead in that */ + /* case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Char_Size */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in points). */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* char_width :: The nominal width, in 26.6 fractional points. */ + /* */ + /* char_height :: The nominal height, in 26.6 fractional points. */ + /* */ + /* horz_resolution :: The horizontal resolution in dpi. */ + /* */ + /* vert_resolution :: The vertical resolution in dpi. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If either the character width or height is zero, it is set equal */ + /* to the other value. */ + /* */ + /* If either the horizontal or vertical resolution is zero, it is set */ + /* equal to the other value. */ + /* */ + /* A character width or height smaller than 1pt is set to 1pt; if */ + /* both resolution values are zero, they are set to 72dpi. */ + /* */ + + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Pixel_Sizes */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in pixels). */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* pixel_width :: The nominal width, in pixels. */ + /* */ + /* pixel_height :: The nominal height, in pixels. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Glyph */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* glyph_index :: The index of the glyph in the font file. For */ + /* CID-keyed fonts (either in PS or in CFF format) */ + /* this argument specifies the CID value. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The loaded glyph may be transformed. See @FT_Set_Transform for */ + /* the details. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Char */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object, according to its character code. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* char_code :: The glyph's character code, according to the */ + /* current charmap used in the face. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); + + + /************************************************************************* + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit-field constants used with @FT_Load_Glyph to indicate + * what kind of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to 0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. + * The bitmap data can be accessed from the glyph slot (see note + * below). + * + * 2. If no embedded bitmap is searched or found, FreeType looks for a + * scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then `hinted' to the pixel grid + * in order to optimize it. The outline data can be accessed from + * the glyph slot (see note below). + * + * Note that by default, the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the outline glyph loaded, but keep it in font units. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates `blurrier' bitmap glyph + * when the glyph is rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. _Don't_ use it as it is + * problematic currently. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Indicates that the auto-hinter is preferred over the font's native + * hinter. See also the note below. + * + * FT_LOAD_CROP_BITMAP :: + * Indicates that the font driver should crop the loaded bitmap glyph + * (i.e., remove all space around its black bits). Not all drivers + * implement this. + * + * FT_LOAD_PEDANTIC :: + * Indicates that the font driver should perform pedantic verifications + * during glyph loading. This is mostly used to detect broken glyphs + * in fonts. By default, FreeType tries to handle broken fonts also. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Indicates that the font driver should ignore the global advance + * width defined in the font. By default, that value is used as the + * advance width for all glyphs when the face has + * @FT_FACE_FLAG_FIXED_WIDTH set. + * + * This flag exists for historical reasons (to support buggy CJK + * fonts). + * + * FT_LOAD_NO_RECURSE :: + * This flag is only used internally. It merely indicates that the + * font driver should not load composite glyphs recursively. Instead, + * it should set the `num_subglyph' and `subglyphs' values of the + * glyph slot accordingly, and set `glyph->format' to + * @FT_GLYPH_FORMAT_COMPOSITE. + * + * The description of sub-glyphs is not available to client + * applications for now. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Indicates that the transform matrix set by @FT_Set_Transform should + * be ignored. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8 pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should use @FT_LOAD_TARGET_MONO instead so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Indicates that the `linearHoriAdvance' and `linearVertAdvance' + * fields of @FT_GlyphSlotRec should be kept in font units. See + * @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable auto-hinter. See also the note below. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be + * used at all. + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE 0x1 +#define FT_LOAD_NO_HINTING 0x2 +#define FT_LOAD_RENDER 0x4 +#define FT_LOAD_NO_BITMAP 0x8 +#define FT_LOAD_VERTICAL_LAYOUT 0x10 +#define FT_LOAD_FORCE_AUTOHINT 0x20 +#define FT_LOAD_CROP_BITMAP 0x40 +#define FT_LOAD_PEDANTIC 0x80 +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +#define FT_LOAD_NO_RECURSE 0x400 +#define FT_LOAD_IGNORE_TRANSFORM 0x800 +#define FT_LOAD_MONOCHROME 0x1000 +#define FT_LOAD_LINEAR_DESIGN 0x2000 + + /* temporary hack! */ +#define FT_LOAD_SBITS_ONLY 0x4000 +#define FT_LOAD_NO_AUTOHINT 0x8000U + + /* */ + + + /************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values that are used to select a specific hinting algorithm + * to use by the hinter. You should OR one of these values to your + * `load_flags' when calling @FT_Load_Glyph. + * + * Note that font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it + * always implies @FT_LOAD_FORCE_AUTOHINT. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * This corresponds to the default hinting algorithm, optimized for + * standard gray-level rendering. For monochrome output, use + * @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for non-monochrome modes. Many + * generated glyphs are more fuzzy but better resemble its original + * shape. A bit like rendering on Mac OS X. + * + * As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT. + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the FT_LOAD_TARGET_XXX values in your + * `load_flags'. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode which matches the used algorithm + * best) unless @FT_LOAD_MONOCHROME is set. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the `light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * { + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * } + */ + +#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + + + /* + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + */ + +#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Transform */ + /* */ + /* <Description> */ + /* A function used to set the transformation that is applied to glyph */ + /* images when they are loaded into a glyph slot through */ + /* @FT_Load_Glyph. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation's 2x2 matrix. Use 0 for */ + /* the identity matrix. */ + /* delta :: A pointer to the translation vector. Use 0 for the null */ + /* vector. */ + /* */ + /* <Note> */ + /* The transformation is only applied to scalable image formats after */ + /* the glyph has been loaded. It means that hinting is unaltered by */ + /* the transformation and is performed on the character size given in */ + /* the last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Render_Mode */ + /* */ + /* <Description> */ + /* An enumeration type that lists the render modes supported by */ + /* FreeType 2. Each mode corresponds to a specific type of scanline */ + /* conversion performed on the outline. */ + /* */ + /* For bitmap fonts the `bitmap->pixel_mode' field in the */ + /* @FT_GlyphSlotRec structure gives the format of the returned */ + /* bitmap. */ + /* */ + /* <Values> */ + /* FT_RENDER_MODE_NORMAL :: */ + /* This is the default render mode; it corresponds to 8-bit */ + /* anti-aliased bitmaps, using 256 levels of opacity. */ + /* */ + /* FT_RENDER_MODE_LIGHT :: */ + /* This is equivalent to @FT_RENDER_MODE_NORMAL. It is only */ + /* defined as a separate value because render modes are also used */ + /* indirectly to define hinting algorithm selectors. See */ + /* @FT_LOAD_TARGET_XXX for details. */ + /* */ + /* FT_RENDER_MODE_MONO :: */ + /* This mode corresponds to 1-bit bitmaps. */ + /* */ + /* FT_RENDER_MODE_LCD :: */ + /* This mode corresponds to horizontal RGB and BGR sub-pixel */ + /* displays, like LCD-screens. It produces 8-bit bitmaps that are */ + /* 3 times the width of the original glyph outline in pixels, and */ + /* which use the @FT_PIXEL_MODE_LCD mode. */ + /* */ + /* FT_RENDER_MODE_LCD_V :: */ + /* This mode corresponds to vertical RGB and BGR sub-pixel displays */ + /* (like PDA screens, rotated LCD displays, etc.). It produces */ + /* 8-bit bitmaps that are 3 times the height of the original */ + /* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */ + /* */ + /* <Note> */ + /* The LCD-optimized glyph bitmaps produced by FT_Render_Glyph are */ + /* _not_ _filtered_ to reduce color-fringes. It is up to the caller */ + /* to perform this pass. */ + /* */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + + FT_RENDER_MODE_MAX + + } FT_Render_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_render_mode_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Render_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */ + /* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */ + /* */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Render_Glyph */ + /* */ + /* <Description> */ + /* Convert a given glyph image to a bitmap. It does so by inspecting */ + /* the glyph image format, finding the relevant renderer, and */ + /* invoking it. */ + /* */ + /* <InOut> */ + /* slot :: A handle to the glyph slot containing the image to */ + /* convert. */ + /* */ + /* <Input> */ + /* render_mode :: This is the render mode used to render the glyph */ + /* image into a bitmap. See @FT_Render_Mode for a */ + /* list of possible values. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Kerning_Mode */ + /* */ + /* <Description> */ + /* An enumeration used to specify which kerning values to return in */ + /* @FT_Get_Kerning. */ + /* */ + /* <Values> */ + /* FT_KERNING_DEFAULT :: Return scaled and grid-fitted kerning */ + /* distances (value is 0). */ + /* */ + /* FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning */ + /* distances. */ + /* */ + /* FT_KERNING_UNSCALED :: Return the kerning vector in original font */ + /* units. */ + /* */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + + } FT_Kerning_Mode; + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_default */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_DEFAULT */ + /* instead. */ + /* */ +#define ft_kerning_default FT_KERNING_DEFAULT + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unfitted */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNFITTED */ + /* instead. */ + /* */ +#define ft_kerning_unfitted FT_KERNING_UNFITTED + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unscaled */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNSCALED */ + /* instead. */ + /* */ +#define ft_kerning_unscaled FT_KERNING_UNSCALED + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Kerning */ + /* */ + /* <Description> */ + /* Return the kerning vector between two glyphs of a same face. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* kern_mode :: See @FT_Kerning_Mode for more information. */ + /* Determines the scale and dimension of the returned */ + /* kerning vector. */ + /* */ + /* <Output> */ + /* akerning :: The kerning vector. This is either in font units */ + /* or in pixels (26.6 format) for scalable formats, */ + /* and in pixels for fixed-sizes formats. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this method. Other layouts, or more sophisticated */ + /* kernings, are out of the scope of this API function -- they can be */ + /* implemented through format-specific interfaces. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Track_Kerning */ + /* */ + /* <Description> */ + /* Return the track kerning for a given face object at a given size. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* point_size :: The point size in 16.16 fractional points. */ + /* */ + /* degree :: The degree of tightness. */ + /* */ + /* <Output> */ + /* akerning :: The kerning in 16.16 fractional points. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII name of a given glyph in a face. This only */ + /* works for those faces where @FT_HAS_GLYPH_NAMES(face) returns 1. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* buffer_max :: The maximal number of bytes available in the */ + /* buffer. */ + /* */ + /* <Output> */ + /* buffer :: A pointer to a target buffer where the name is */ + /* copied to. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* An error is returned if the face doesn't provide glyph names or if */ + /* the glyph index is invalid. In all cases of failure, the first */ + /* byte of `buffer' is set to 0 to indicate an empty name. */ + /* */ + /* The glyph name is truncated to fit within the buffer if it is too */ + /* long. The returned string is always zero-terminated. */ + /* */ + /* This function is not compiled within the library if the config */ + /* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */ + /* `include/freetype/config/ftoptions.h'. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Postscript_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII Postscript name of a given face, if available. */ + /* This only works with Postscript and TrueType fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Return> */ + /* A pointer to the face's Postscript name. NULL if unavailable. */ + /* */ + /* <Note> */ + /* The returned pointer is owned by the face and is destroyed with */ + /* it. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap by its encoding tag (as listed in */ + /* `freetype.h'). */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* encoding :: A handle to the selected encoding. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function returns an error if no charmap in the face */ + /* corresponds to the encoding queried here. */ + /* */ + /* Because many fonts contain more than a single cmap for Unicode */ + /* encoding, this function has some special code to select the one */ + /* which covers Unicode best. It is thus preferable to */ + /* @FT_Set_Charmap in this case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap for character code to glyph index mapping. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* charmap :: A handle to the selected charmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function returns an error if the charmap is not part of */ + /* the face (i.e., if it is not listed in the `face->charmaps' */ + /* table). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /************************************************************************* + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap' belongs. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Char_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given character code. This function */ + /* uses a charmap object to do the mapping. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* <Return> */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + /* <Note> */ + /* If you use FreeType to manipulate the contents of font files */ + /* directly, be aware that the glyph index returned by this function */ + /* doesn't always correspond to the internal indices used within */ + /* the file. This is done to ensure that value 0 always corresponds */ + /* to the `missing glyph'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_First_Char */ + /* */ + /* <Description> */ + /* This function is used to return the first character code in the */ + /* current charmap of a given face. It also returns the */ + /* corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of first character code. 0 if charmap is */ + /* empty. */ + /* */ + /* <Return> */ + /* The charmap's first character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_Next_Char to be able to */ + /* parse all character codes available in a given charmap. The code */ + /* should look like this: */ + /* */ + /* { */ + /* FT_ULong charcode; */ + /* FT_UInt gindex; */ + /* */ + /* */ + /* charcode = FT_Get_First_Char( face, &gindex ); */ + /* while ( gindex != 0 ) */ + /* { */ + /* ... do something with (charcode,gindex) pair ... */ + /* */ + /* charcode = FT_Get_Next_Char( face, charcode, &gindex ); */ + /* } */ + /* } */ + /* */ + /* Note that `*agindex' is set to 0 if the charmap is empty. The */ + /* result itself can be 0 in two cases: if the charmap is empty or */ + /* when the value 0 is the first valid character code. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Next_Char */ + /* */ + /* <Description> */ + /* This function is used to return the next character code in the */ + /* current charmap of a given face following the value `char_code', */ + /* as well as the corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* char_code :: The starting character code. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of first character code. 0 if charmap */ + /* is empty. */ + /* */ + /* <Return> */ + /* The charmap's next character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_First_Char to walk */ + /* over all character codes available in a given charmap. See the */ + /* note for this function for a simple code example. */ + /* */ + /* Note that `*agindex' is set to 0 when there are no more codes in */ + /* the charmap. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Name_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given glyph name. This function uses */ + /* driver specific objects to do the translation. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* glyph_name :: The glyph name. */ + /* */ + /* <Return> */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ); + + + /************************************************************************* + * + * @macro: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants used to describe subglyphs. Please refer to the + * TrueType specification for the meaning of the various flags. + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + /************************************************************************* + * + * @func: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format' is @FT_GLYPH_FORMAT_COMPOSITE, or an error is + * returned. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of subglyph. Must be less than `glyph->num_subglyphs'. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The values of `*p_arg1', `*p_arg2', and `*p_transform' must be + * interpreted depending on the flags returned in `*p_flags'. See the + * TrueType specification for details. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /* <Title> */ + /* Computations */ + /* */ + /* <Abstract> */ + /* Crunching fixed numbers and vectors. */ + /* */ + /* <Description> */ + /* This section contains various functions used to perform */ + /* computations on 16.16 fixed-float numbers or 2d vectors. */ + /* */ + /* <Order> */ + /* FT_MulDiv */ + /* FT_MulFix */ + /* FT_DivFix */ + /* FT_RoundFix */ + /* FT_CeilFix */ + /* FT_FloorFix */ + /* FT_Vector_Transform */ + /* FT_Matrix_Multiply */ + /* FT_Matrix_Invert */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulDiv */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* <Return> */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* <Note> */ + /* This function has been optimized for the case where the absolute */ + /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ + /* As this happens mainly when scaling from notional units to */ + /* fractional pixels in FreeType, it resulted in noticeable speed */ + /* improvements between versions 2.x and 1.x. */ + /* */ + /* As a conclusion, always try to place a 16.16 factor as the */ + /* _second_ argument of this function; this can make a great */ + /* difference. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_DivFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* <Note> */ + /* The optimization for FT_DivFix() is simple: If (a << 16) fits in */ + /* 32 bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of @FT_MulDiv. */ + /* */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_RoundFix */ + /* */ + /* <Description> */ + /* A very simple function used to round a 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number to be rounded. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x8000) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_CeilFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the ceiling function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the ceiling function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x10000 - 1) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_FloorFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the floor function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the floor function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `a & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Vector_Transform */ + /* */ + /* <Description> */ + /* Transform a single vector through a 2x2 matrix. */ + /* */ + /* <InOut> */ + /* vector :: The target vector to transform. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* <Note> */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vec, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* version */ + /* */ + /* <Title> */ + /* FreeType Version */ + /* */ + /* <Abstract> */ + /* Functions and macros related to FreeType versions. */ + /* */ + /* <Description> */ + /* Note that those functions and macros are of limited use because */ + /* even a new release of FreeType with only documentation changes */ + /* increases the version number. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. + * Use @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: The major version number. + * FREETYPE_MINOR :: The minor version number. + * FREETYPE_PATCH :: The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library + * with the `libtool' package is _not_ controlled by these three + * macros. + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 3 +#define FREETYPE_PATCH 5 + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Library_Version */ + /* */ + /* <Description> */ + /* Return the version of the FreeType library being used. This is */ + /* useful when dynamically linking to the library, since one cannot */ + /* use the macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and */ + /* @FREETYPE_PATCH. */ + /* */ + /* <Input> */ + /* library :: A source library handle. */ + /* */ + /* <Output> */ + /* amajor :: The major version number. */ + /* */ + /* aminor :: The minor version number. */ + /* */ + /* apatch :: The patch version number. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' argument is because */ + /* certain programs implement library initialization in a custom way */ + /* that doesn't use @FT_Init_FreeType. */ + /* */ + /* In such cases, the library version might not be available before */ + /* the library object has been created. */ + /* */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_CheckTrueTypePatents */ + /* */ + /* <Description> */ + /* Parse all bytecode instructions of a TrueType font file to check */ + /* whether any of the patented opcodes are used. This is only useful */ + /* if you want to be able to use the unpatented hinter with */ + /* fonts that do *not* use these opcodes. */ + /* */ + /* Note that this function parses *all* glyph instructions in the */ + /* font file, which may be slow. */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* <Return> */ + /* 1 if this is a TrueType font that uses one of the patented */ + /* opcodes, 0 otherwise. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_SetUnpatentedHinting */ + /* */ + /* <Description> */ + /* Enable or disable the unpatented hinter for a given face. */ + /* Only enable it if you have determined that the face doesn't */ + /* use any patented opcodes (see @FT_Face_CheckTrueTypePatents). */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* value :: New boolean setting. */ + /* */ + /* <Return> */ + /* The old setting value. This will always be false if this is not */ + /* a SFNT font, or if the unpatented hinter is not compiled in this */ + /* instance of the library. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); + + /* */ + + +FT_END_HEADER + +#endif /* __FREETYPE_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftbbox.h b/src/freetype2/freetype/ftbbox.h new file mode 100644 index 0000000..5f79c32 --- /dev/null +++ b/src/freetype2/freetype/ftbbox.h @@ -0,0 +1,94 @@ +/***************************************************************************/ +/* */ +/* ftbbox.h */ +/* */ +/* FreeType exact bbox computation (specification). */ +/* */ +/* Copyright 1996-2001, 2003 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. */ + /* */ + /* It is separated from the rest of the engine for various technical */ + /* reasons. It may well be integrated in `ftoutln' later. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTBBOX_H__ +#define __FTBBOX_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_BBox */ + /* */ + /* <Description> */ + /* Computes the exact bounding box of an outline. This is slower */ + /* than computing the control box. However, it uses an advanced */ + /* algorithm which returns _very_ quickly when the two boxes */ + /* coincide. Otherwise, the outline Bézier arcs are walked over to */ + /* extract their extrema. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline. */ + /* */ + /* <Output> */ + /* abbox :: The outline's exact bounding box. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBBOX_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftbdf.h b/src/freetype2/freetype/ftbdf.h new file mode 100644 index 0000000..9555694 --- /dev/null +++ b/src/freetype2/freetype/ftbdf.h @@ -0,0 +1,200 @@ +/***************************************************************************/ +/* */ +/* ftbdf.h */ +/* */ +/* FreeType API for accessing BDF-specific strings (specification). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBDF_H__ +#define __FTBDF_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bdf_fonts */ + /* */ + /* <Title> */ + /* BDF Files */ + /* */ + /* <Abstract> */ + /* BDF specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of BDF specific functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value 0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + + } BDF_PropertyType; + + + /********************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given + * BDF/PCF property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; + + + /********************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + + } u; + + } BDF_PropertyRec; + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieves a BDF font character set identity, according to + * the BDF specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C string, owned by the face. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieves a BDF property from a BDF or PCF font file. + * + * @input: + * face :: A handle to the input face. + * + * name :: The property name. + * + * @output: + * aproperty :: The property. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * In case of error, `aproperty->type' is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + /* */ + +FT_END_HEADER + +#endif /* __FTBDF_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftbitmap.h b/src/freetype2/freetype/ftbitmap.h new file mode 100644 index 0000000..337d888 --- /dev/null +++ b/src/freetype2/freetype/ftbitmap.h @@ -0,0 +1,206 @@ +/***************************************************************************/ +/* */ +/* ftbitmap.h */ +/* */ +/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ +/* bitmaps into 8bpp format (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBITMAP_H__ +#define __FTBITMAP_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bitmap_handling */ + /* */ + /* <Title> */ + /* Bitmap Handling */ + /* */ + /* <Abstract> */ + /* Handling FT_Bitmap objects. */ + /* */ + /* <Description> */ + /* This section contains functions for converting FT_Bitmap objects. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_New */ + /* */ + /* <Description> */ + /* Initialize a pointer to an @FT_Bitmap structure. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the bitmap structure. */ + /* */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Copy */ + /* */ + /* <Description> */ + /* Copies an bitmap into another one. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: A handle to the source bitmap. */ + /* */ + /* <Output> */ + /* target :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Embolden */ + /* */ + /* <Description> */ + /* Embolden a bitmap. The new bitmap will be about `xStrength' */ + /* pixels wider and `yStrength' pixels higher. The left and bottom */ + /* borders are kept unchanged. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* xStrength :: How strong the glyph is emboldened horizontally. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* yStrength :: How strong the glyph is emboldened vertically. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* <InOut> */ + /* bitmap :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The current implementation restricts `xStrength' to be less than */ + /* or equal to 8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ + /* */ + /* If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, */ + /* you should call `FT_GlyphSlot_Own_Bitmap' on the slot first. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Convert */ + /* */ + /* <Description> */ + /* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ + /* bitmap object with depth 8bpp, making the number of used bytes per */ + /* line (a.k.a. the `pitch') a multiple of `alignment'. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: The source bitmap. */ + /* */ + /* alignment :: The pitch of the bitmap is a multiple of this */ + /* parameter. Common values are 1, 2, or 4. */ + /* */ + /* <Output> */ + /* target :: The target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* It is possible to call @FT_Bitmap_Convert multiple times without */ + /* calling @FT_Bitmap_Done (the memory is simply reallocated). */ + /* */ + /* Use @FT_Bitmap_Done to finally remove the bitmap object. */ + /* */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Done */ + /* */ + /* <Description> */ + /* Destroy a bitmap object created with @FT_Bitmap_New. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* bitmap :: The bitmap object to be freed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBITMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftcache.h b/src/freetype2/freetype/ftcache.h new file mode 100644 index 0000000..721aa16 --- /dev/null +++ b/src/freetype2/freetype/ftcache.h @@ -0,0 +1,1110 @@ +/***************************************************************************/ +/* */ +/* ftcache.h */ +/* */ +/* FreeType Cache subsystem (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __FTCACHE_H__ +#define __FTCACHE_H__ + + +#include <ft2build.h> +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************* + * + * <Section> + * cache_subsystem + * + * <Title> + * Cache Sub-System + * + * <Abstract> + * How to cache face, size, and glyph data with FreeType 2. + * + * <Description> + * This section describes the FreeType 2 cache sub-system, which is used + * to limit the number of concurrently opened @FT_Face and @FT_Size + * objects, as well as caching information like character maps and glyph + * images while limiting their maximum memory usage. + * + * Note that all types and functions begin with the `FTC_' prefix. + * + * The cache is highly portable and thus doesn't know anything about the + * fonts installed on your system, or how to access them. This implies + * the following scheme: + * + * First, available or installed font faces are uniquely identified by + * @FTC_FaceID values, provided to the cache by the client. Note that + * the cache only stores and compares these values, and doesn't try to + * interpret them in any way. + * + * Second, the cache calls, only when needed, a client-provided function + * to convert a @FTC_FaceID into a new @FT_Face object. The latter is + * then completely managed by the cache, including its termination + * through @FT_Done_Face. + * + * Clients are free to map face IDs to anything else. The most simple + * usage is to associate them to a (pathname,face_index) pair that is + * used to call @FT_New_Face. However, more complex schemes are also + * possible. + * + * Note that for the cache to work correctly, the face ID values must be + * *persistent*, which means that the contents they point to should not + * change at runtime, or that their value should not become invalid. + * + * If this is unavoidable (e.g., when a font is uninstalled at runtime), + * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let + * the cache get rid of any references to the old @FTC_FaceID it may + * keep internally. Failure to do so will lead to incorrect behaviour + * or even crashes. + * + * To use the cache, start with calling @FTC_Manager_New to create a new + * @FTC_Manager object, which models a single cache instance. You can + * then look up @FT_Face and @FT_Size objects with + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively. + * + * If you want to use the charmap caching, call @FTC_CMapCache_New, then + * later use @FTC_CMapCache_Lookup to perform the equivalent of + * @FT_Get_Char_Index, only much faster. + * + * If you want to use the @FT_Glyph caching, call @FTC_ImageCache, then + * later use @FTC_ImageCache_Lookup to retrieve the corresponding + * @FT_Glyph objects from the cache. + * + * If you need lots of small bitmaps, it is much more memory efficient + * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This + * returns @FTC_SBitRec structures, which are used to store small + * bitmaps directly. (A small bitmap is one whose metrics and + * dimensions all fit into 8-bit integers). + * + * We hope to also provide a kerning cache in the near future. + * + * + * <Order> + * FTC_Manager + * FTC_FaceID + * FTC_Face_Requester + * + * FTC_Manager_New + * FTC_Manager_Reset + * FTC_Manager_Done + * FTC_Manager_LookupFace + * FTC_Manager_LookupSize + * FTC_Manager_RemoveFaceID + * + * FTC_Node + * FTC_Node_Unref + * + * FTC_ImageCache + * FTC_ImageCache_New + * FTC_ImageCache_Lookup + * + * FTC_SBit + * FTC_SBitCache + * FTC_SBitCache_New + * FTC_SBitCache_Lookup + * + * FTC_CMapCache + * FTC_CMapCache_New + * FTC_CMapCache_Lookup + * + *************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: FTC_FaceID + * + * @description: + * An opaque pointer type that is used to identity face objects. The + * contents of such objects is application-dependent. + * + * These pointers are typically used to point to a user-defined + * structure containing a font file path, and face index. + * + * @note: + * Never use NULL as a valid @FTC_FaceID. + * + * Face IDs are passed by the client to the cache manager, which calls, + * when needed, the @FTC_Face_Requester to translate them into new + * @FT_Face objects. + * + * If the content of a given face ID changes at runtime, or if the value + * becomes invalid (e.g., when uninstalling a font), you should + * immediately call @FTC_Manager_RemoveFaceID before any other cache + * function. + * + * Failure to do so will result in incorrect behaviour or even + * memory leaks and crashes. + */ + typedef struct FTC_FaceIDRec_* FTC_FaceID; + + + /************************************************************************ + * + * @functype: + * FTC_Face_Requester + * + * @description: + * A callback function provided by client applications. It is used by + * the cache manager to translate a given @FTC_FaceID into a new valid + * @FT_Face object, on demand. + * + * <Input> + * face_id :: + * The face ID to resolve. + * + * library :: + * A handle to a FreeType library object. + * + * req_data :: + * Application-provided request data (see note below). + * + * <Output> + * aface :: + * A new @FT_Face handle. + * + * <Return> + * FreeType error code. 0 means success. + * + * <Note> + * The third parameter `req_data' is the same as the one passed by the + * client when @FTC_Manager_New is called. + * + * The face requester should not perform funny things on the returned + * face object, like creating a new @FT_Size for it, or setting a + * transformation through @FT_Set_Transform! + */ + typedef FT_Error + (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface ); + + /* */ + +#define FT_POINTER_TO_ULONG( p ) ( (FT_ULong)(FT_Pointer)(p) ) + +#define FTC_FACE_ID_HASH( i ) \ + ((FT_UInt32)(( FT_POINTER_TO_ULONG( i ) >> 3 ) ^ \ + ( FT_POINTER_TO_ULONG( i ) << 7 ) ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Manager */ + /* */ + /* <Description> */ + /* This object corresponds to one instance of the cache-subsystem. */ + /* It is used to cache one or more @FT_Face objects, along with */ + /* corresponding @FT_Size objects. */ + /* */ + /* The manager intentionally limits the total number of opened */ + /* @FT_Face and @FT_Size objects to control memory usage. See the */ + /* `max_faces' and `max_sizes' parameters of @FTC_Manager_New. */ + /* */ + /* The manager is also used to cache `nodes' of various types while */ + /* limiting their total memory usage. */ + /* */ + /* All limitations are enforced by keeping lists of managed objects */ + /* in most-recently-used order, and flushing old nodes to make room */ + /* for new ones. */ + /* */ + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Node */ + /* */ + /* <Description> */ + /* An opaque handle to a cache node object. Each cache node is */ + /* reference-counted. A node with a count of 0 might be flushed */ + /* out of a full cache whenever a lookup request is performed. */ + /* */ + /* If you lookup nodes, you have the ability to `acquire' them, i.e., */ + /* to increment their reference count. This will prevent the node */ + /* from being flushed out of the cache until you explicitly `release' */ + /* it (see @FTC_Node_Unref). */ + /* */ + /* See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. */ + /* */ + typedef struct FTC_NodeRec_* FTC_Node; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_New */ + /* */ + /* <Description> */ + /* Creates a new cache manager. */ + /* */ + /* <Input> */ + /* library :: The parent FreeType library handle to use. */ + /* */ + /* max_faces :: Maximum number of opened @FT_Face objects managed by */ + /* this cache instance. Use 0 for defaults. */ + /* */ + /* max_sizes :: Maximum number of opened @FT_Size objects managed by */ + /* this cache instance. Use 0 for defaults. */ + /* */ + /* max_bytes :: Maximum number of bytes to use for cached data nodes. */ + /* Use 0 for defaults. Note that this value does not */ + /* account for managed @FT_Face and @FT_Size objects. */ + /* */ + /* requester :: An application-provided callback used to translate */ + /* face IDs into real @FT_Face objects. */ + /* */ + /* req_data :: A generic pointer that is passed to the requester */ + /* each time it is called (see @FTC_Face_Requester). */ + /* */ + /* <Output> */ + /* amanager :: A handle to a new manager object. 0 in case of */ + /* failure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Reset */ + /* */ + /* <Description> */ + /* Empties a given cache manager. This simply gets rid of all the */ + /* currently cached @FT_Face and @FT_Size objects within the manager. */ + /* */ + /* <InOut> */ + /* manager :: A handle to the manager. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Reset( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Done */ + /* */ + /* <Description> */ + /* Destroys a given manager after emptying it. */ + /* */ + /* <Input> */ + /* manager :: A handle to the target cache manager object. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Done( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupFace */ + /* */ + /* <Description> */ + /* Retrieves the @FT_Face object that corresponds to a given face ID */ + /* through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* face_id :: The ID of the face object. */ + /* */ + /* <Output> */ + /* aface :: A handle to the face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Face object is always owned by the manager. You */ + /* should never try to discard it yourself. */ + /* */ + /* The @FT_Face object doesn't necessarily have a current size object */ + /* (i.e., face->size can be 0). If you need a specific `font size', */ + /* use @FTC_Manager_LookupSize instead. */ + /* */ + /* Never change the face's transformation matrix (i.e., never call */ + /* the @FT_Set_Transform function) on a returned face! If you need */ + /* to transform glyphs, do it yourself after glyph loading. */ + /* */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory was available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_ScalerRec */ + /* */ + /* <Description> */ + /* A structure used to describe a given character size in either */ + /* pixels or points to the cache manager. See */ + /* @FTC_Manager_LookupSize. */ + /* */ + /* <Fields> */ + /* face_id :: The source face ID. */ + /* */ + /* width :: The character width. */ + /* */ + /* height :: The character height. */ + /* */ + /* pixel :: A Boolean. If 1, the `width' and `height' fields are */ + /* interpreted as integer pixel character sizes. */ + /* Otherwise, they are expressed as 1/64th of points. */ + /* */ + /* x_res :: Only used when `pixel' is value 0 to indicate the */ + /* horizontal resolution in dpi. */ + /* */ + /* y_res :: Only used when `pixel' is value 0 to indicate the */ + /* vertical resolution in dpi. */ + /* */ + /* <Note> */ + /* This type is mainly used to retrieve @FT_Size objects through the */ + /* cache manager. */ + /* */ + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec, *FTC_Scaler; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupSize */ + /* */ + /* <Description> */ + /* Retrieve the @FT_Size object that corresponds to a given */ + /* @FTC_ScalerRec pointer through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* scaler :: A scaler handle. */ + /* */ + /* <Output> */ + /* asize :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Size object is always owned by the manager. You */ + /* should never try to discard it by yourself. */ + /* */ + /* You can access the parent @FT_Face object simply as `size->face' */ + /* if you need it. Note that this object is also owned by the */ + /* manager. */ + /* */ + /* <Note> */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory is available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Node_Unref */ + /* */ + /* <Description> */ + /* Decrement a cache node's internal reference count. When the count */ + /* reaches 0, it is not destroyed but becomes eligible for subsequent */ + /* cache flushes. */ + /* */ + /* <Input> */ + /* node :: The cache node handle. */ + /* */ + /* manager :: The cache manager handle. */ + /* */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /************************************************************************* + * + * @function: + * FTC_Manager_RemoveFaceID + * + * @description: + * A special function used to indicate to the cache manager that + * a given @FTC_FaceID is no longer valid, either because its + * content changed, or because it was deallocated or uninstalled. + * + * @input: + * manager :: + * The cache manager handle. + * + * face_id :: + * The @FTC_FaceID to be removed. + * + * @note: + * This function flushes all nodes from the cache corresponding to this + * `face_id', with the exception of nodes with a non-null reference + * count. + * + * Such nodes are however modified internally so as to never appear + * in later lookups with the same `face_id' value, and to be immediately + * destroyed when released by all their users. + * + */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to model a charmap cache. This cache is to + * hold character codes -> glyph indices mappings. + * + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /************************************************************************* + * + * @function: + * FTC_CMapCache_New + * + * @description: + * Create a new charmap cache. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * @output: + * acache :: + * A new cache handle. NULL in case of error. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * Like all other caches, this one will be destroyed with the cache + * manager. + * + */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /************************************************************************ + * + * @function: + * FTC_CMapCache_Lookup + * + * @description: + * Translate a character code into a glyph index, using the charmap + * cache. + * + * @input: + * cache :: + * A charmap cache handle. + * + * face_id :: + * The source face ID. + * + * cmap_index :: + * The index of the charmap in the source face. + * + * char_code :: + * The character code (in the corresponding charmap). + * + * @return: + * Glyph index. 0 means `no glyph'. + * + */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @struct: + * FTC_ImageTypeRec + * + * @description: + * A structure used to model the type of images in a glyph cache. + * + * @fields: + * face_id :: + * The face ID. + * + * width :: + * The width in pixels. + * + * height :: + * The height in pixels. + * + * flags :: + * The load flags, as in @FT_Load_Glyph. + * + */ + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_Int width; + FT_Int height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + + /************************************************************************* + * + * @type: + * FTC_ImageType + * + * @description: + * A handle to an @FTC_ImageTypeRec structure. + * + */ + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + + /* */ + + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( (d1)->face_id == (d2)->face_id && \ + (d1)->width == (d2)->width && \ + (d1)->flags == (d2)->flags ) + +#define FTC_IMAGE_TYPE_HASH( d ) \ + (FT_UFast)( FTC_FACE_ID_HASH( (d)->face_id ) ^ \ + ( (d)->width << 8 ) ^ (d)->height ^ \ + ( (d)->flags << 4 ) ) + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_ImageCache */ + /* */ + /* <Description> */ + /* A handle to an glyph image cache object. They are designed to */ + /* hold many distinct glyph images while not exceeding a certain */ + /* memory threshold. */ + /* */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_New */ + /* */ + /* <Description> */ + /* Creates a new glyph image cache. */ + /* */ + /* <Input> */ + /* manager :: The parent manager for the image cache. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new glyph image cache object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_Lookup */ + /* */ + /* <Description> */ + /* Retrieves a given glyph image from a glyph image cache. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* type :: A pointer to a glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* scaler :: A pointer to a scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBit */ + /* */ + /* <Description> */ + /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */ + /* structure for details. */ + /* */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_SBitRec */ + /* */ + /* <Description> */ + /* A very compact structure used to describe a small glyph bitmap. */ + /* */ + /* <Fields> */ + /* width :: The bitmap width in pixels. */ + /* */ + /* height :: The bitmap height in pixels. */ + /* */ + /* left :: The horizontal distance from the pen position to the */ + /* left bitmap border (a.k.a. `left side bearing', or */ + /* `lsb'). */ + /* */ + /* top :: The vertical distance from the pen position (on the */ + /* baseline) to the upper bitmap border (a.k.a. `top */ + /* side bearing'). The distance is positive for upwards */ + /* Y coordinates. */ + /* */ + /* format :: The format of the glyph bitmap (monochrome or gray). */ + /* */ + /* max_grays :: Maximum gray level value (in the range 1 to 255). */ + /* */ + /* pitch :: The number of bytes per bitmap line. May be positive */ + /* or negative. */ + /* */ + /* xadvance :: The horizontal advance width in pixels. */ + /* */ + /* yadvance :: The vertical advance height in pixels. */ + /* */ + /* buffer :: A pointer to the bitmap pixels. */ + /* */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBitCache */ + /* */ + /* <Description> */ + /* A handle to a small bitmap cache. These are special cache objects */ + /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */ + /* much more efficient way than the traditional glyph image cache */ + /* implemented by @FTC_ImageCache. */ + /* */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_New */ + /* */ + /* <Description> */ + /* Creates a new cache to store small glyph bitmaps. */ + /* */ + /* <Input> */ + /* manager :: A handle to the source cache manager. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new sbit cache. NULL in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_Lookup */ + /* */ + /* <Description> */ + /* Looks up a given small glyph bitmap in a given sbit cache and */ + /* `lock' it to prevent its flushing from the cache until needed. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* type :: A pointer to the glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to 0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* scaler :: A pointer to the scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to 0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /* */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*@***********************************************************************/ + /* */ + /* <Struct> */ + /* FTC_FontRec */ + /* */ + /* <Description> */ + /* A simple structure used to describe a given `font' to the cache */ + /* manager. Note that a `font' is the combination of a given face */ + /* with a given character size. */ + /* */ + /* <Fields> */ + /* face_id :: The ID of the face to use. */ + /* */ + /* pix_width :: The character width in integer pixels. */ + /* */ + /* pix_height :: The character height in integer pixels. */ + /* */ + typedef struct FTC_FontRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_FontRec; + + + /* */ + + +#define FTC_FONT_COMPARE( f1, f2 ) \ + ( (f1)->face_id == (f2)->face_id && \ + (f1)->pix_width == (f2)->pix_width && \ + (f1)->pix_height == (f2)->pix_height ) + +#define FTC_FONT_HASH( f ) \ + (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^ \ + ((f)->pix_width << 8) ^ \ + ((f)->pix_height) ) + + typedef FTC_FontRec* FTC_Font; + + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_Font font, + FT_Face *aface, + FT_Size *asize ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* */ + +FT_END_HEADER + +#endif /* __FTCACHE_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftchapters.h b/src/freetype2/freetype/ftchapters.h new file mode 100644 index 0000000..bd812c8 --- /dev/null +++ b/src/freetype2/freetype/ftchapters.h @@ -0,0 +1,100 @@ +/***************************************************************************/ +/* */ +/* This file defines the structure of the FreeType reference. */ +/* It is used by the python script which generates the HTML files. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* general_remarks */ +/* */ +/* <Title> */ +/* General Remarks */ +/* */ +/* <Sections> */ +/* user_allocation */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* core_api */ +/* */ +/* <Title> */ +/* Core API */ +/* */ +/* <Sections> */ +/* version */ +/* basic_types */ +/* base_interface */ +/* glyph_management */ +/* mac_specific */ +/* sizes_management */ +/* header_file_macros */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* format_specific */ +/* */ +/* <Title> */ +/* Format-Specific API */ +/* */ +/* <Sections> */ +/* multiple_masters */ +/* truetype_tables */ +/* type1_tables */ +/* sfnt_names */ +/* bdf_fonts */ +/* pfr_fonts */ +/* winfnt_fonts */ +/* font_formats */ +/* gasp_table */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* cache_subsystem */ +/* */ +/* <Title> */ +/* Cache Sub-System */ +/* */ +/* <Sections> */ +/* cache_subsystem */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* support_api */ +/* */ +/* <Title> */ +/* Support API */ +/* */ +/* <Sections> */ +/* computations */ +/* list_processing */ +/* outline_processing */ +/* bitmap_handling */ +/* raster */ +/* glyph_stroker */ +/* system_interface */ +/* module_management */ +/* gzip */ +/* lzw */ +/* lcd_filtering */ +/* */ +/***************************************************************************/ diff --git a/src/freetype2/freetype/fterrdef.h b/src/freetype2/freetype/fterrdef.h new file mode 100644 index 0000000..d7ad256 --- /dev/null +++ b/src/freetype2/freetype/fterrdef.h @@ -0,0 +1,239 @@ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 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. */ +/* */ +/***************************************************************************/ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST OF ERROR CODES/MESSAGES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + + /* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ + /* including this file. */ + + + /* generic errors */ + + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + + /* glyph/character errors */ + + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) + + /* handle errors */ + + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) + + /* driver errors */ + + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) + + /* memory errors */ + + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) + + /* stream errors */ + + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) + + /* raster errors */ + + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) + + /* cache errors */ + + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) + + /* TrueType and SFNT errors */ + + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) + + /* CFF, CID, and Type 1 errors */ + + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + + /* BDF errors */ + + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB3, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB4, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB5, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB6, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB7, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB8, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xB9, \ + "Font glyphs corrupted or missing fields" ) + + +/* END */ diff --git a/src/freetype2/freetype/fterrors.h b/src/freetype2/freetype/fterrors.h new file mode 100644 index 0000000..6600dad --- /dev/null +++ b/src/freetype2/freetype/fterrors.h @@ -0,0 +1,206 @@ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This special header file is used to define the handling of FT2 */ + /* enumeration constants. It can also be used to generate error message */ + /* strings with a small macro trick explained below. */ + /* */ + /* I - Error Formats */ + /* ----------------- */ + /* */ + /* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ + /* defined in ftoption.h in order to make the higher byte indicate */ + /* the module where the error has happened (this is not compatible */ + /* with standard builds of FreeType 2). You can then use the macro */ + /* FT_ERROR_BASE macro to extract the generic error code from an */ + /* FT_Error value. */ + /* */ + /* */ + /* II - Error Message strings */ + /* -------------------------- */ + /* */ + /* The error definitions below are made through special macros that */ + /* allow client applications to build a table of error message strings */ + /* if they need it. The strings are not included in a normal build of */ + /* FreeType 2 to save space (most client applications do not use */ + /* them). */ + /* */ + /* To do so, you have to define the following macros before including */ + /* this file: */ + /* */ + /* FT_ERROR_START_LIST :: */ + /* This macro is called before anything else to define the start of */ + /* the error list. It is followed by several FT_ERROR_DEF calls */ + /* (see below). */ + /* */ + /* FT_ERROR_DEF( e, v, s ) :: */ + /* This macro is called to define one single error. */ + /* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ + /* `v' is the error numerical value. */ + /* `s' is the corresponding error string. */ + /* */ + /* FT_ERROR_END_LIST :: */ + /* This macro ends the list. */ + /* */ + /* Additionally, you have to undefine __FTERRORS_H__ before #including */ + /* this file. */ + /* */ + /* Here is a simple example: */ + /* */ + /* { */ + /* #undef __FTERRORS_H__ */ + /* #define FT_ERRORDEF( e, v, s ) { e, s }, */ + /* #define FT_ERROR_START_LIST { */ + /* #define FT_ERROR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int err_code; */ + /* const char* err_msg; */ + /* } ft_errors[] = */ + /* */ + /* #include FT_ERRORS_H */ + /* } */ + /* */ + /*************************************************************************/ + + +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ + + + /* include module base error codes */ +#include FT_MODULE_ERRORS_H + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#undef FT_ERR_XCAT +#undef FT_ERR_CAT + +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + + /* FT_ERR_PREFIX is used as a prefix for error identifiers. */ + /* By default, we use `FT_Err_'. */ + /* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif + + + /* FT_ERR_BASE is used as the base for module-specific errors. */ + /* */ +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +#ifndef FT_ERR_BASE +#define FT_ERR_BASE FT_Mod_Err_Base +#endif + +#else + +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 + +#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */ + + + /* If FT_ERRORDEF is not defined, we need to define a simple */ + /* enumeration type. */ + /* */ +#ifndef FT_ERRORDEF + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_ERRORDEF */ + + + /* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) + + /* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + + /* now include the error codes */ +#include FT_ERROR_DEFINITIONS_H + + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SIMPLE CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ + +#undef FT_NEED_EXTERN_C +#undef FT_ERR_CONCAT +#undef FT_ERR_BASE + + /* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#endif + +#endif /* __FTERRORS_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftgasp.h b/src/freetype2/freetype/ftgasp.h new file mode 100644 index 0000000..97cd330 --- /dev/null +++ b/src/freetype2/freetype/ftgasp.h @@ -0,0 +1,113 @@ +/***************************************************************************/ +/* */ +/* ftgasp.h */ +/* */ +/* Access of TrueType's `gasp' table (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef _FT_GASP_H_ +#define _FT_GASP_H_ + +#include <ft2build.h> +#include FT_FREETYPE_H + + /*************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType `gasp' table entries + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in their `gasp' table, if any. This is + * mainly useful when implementing native TrueType hinting with the + * bytecode interpreter to duplicate the Windows text rendering results. + */ + + /************************************************************************* + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This *really* means TrueType bytecode interpretation. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * Smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * `ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x10 + + + /************************************************************************* + * + * @func: + * FT_Get_Gasp + * + * @description: + * Read the `gasp' table from a TrueType or OpenType font file and + * return the entry corresponding to a given character pixel size. + * + * @input: + * face :: The source face handle. + * ppem :: The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE is there is no + * `gasp' table in the face. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); + +/* */ + +#endif /* _FT_GASP_H_ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftglyph.h b/src/freetype2/freetype/ftglyph.h new file mode 100644 index 0000000..08058da --- /dev/null +++ b/src/freetype2/freetype/ftglyph.h @@ -0,0 +1,575 @@ +/***************************************************************************/ +/* */ +/* ftglyph.h */ +/* */ +/* FreeType convenience functions to handle glyphs (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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 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. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTGLYPH_H__ +#define __FTGLYPH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* glyph_management */ + /* */ + /* <Title> */ + /* Glyph Management */ + /* */ + /* <Abstract> */ + /* Generic interface to manage individual glyph data. */ + /* */ + /* <Description> */ + /* This section contains definitions used to manage glyph data */ + /* through generic FT_Glyph objects. Each of them can contain a */ + /* bitmap, a vector outline, or even images in other formats. */ + /* */ + /*************************************************************************/ + + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Glyph */ + /* */ + /* <Description> */ + /* Handle to an object used to model generic glyph images. It is a */ + /* pointer to the @FT_GlyphRec structure and can contain a glyph */ + /* bitmap or pointer. */ + /* */ + /* <Note> */ + /* Glyph objects are not owned by the library. You must thus release */ + /* them manually (through @FT_Done_Glyph) _before_ calling */ + /* @FT_Done_FreeType. */ + /* */ + typedef struct FT_GlyphRec_* FT_Glyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphRec */ + /* */ + /* <Description> */ + /* The root glyph structure contains a given glyph image plus its */ + /* advance width in 16.16 fixed float format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library object. */ + /* */ + /* clazz :: A pointer to the glyph's class. Private. */ + /* */ + /* format :: The format of the glyph's image. */ + /* */ + /* advance :: A 16.16 vector that gives the glyph's advance width. */ + /* */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_BitmapGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model a bitmap glyph image. This is */ + /* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ + /* */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BitmapGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for bitmap glyph images. This really is a */ + /* `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* left :: The left-side bearing, i.e., the horizontal distance */ + /* from the current pen position to the left border of the */ + /* glyph bitmap. */ + /* */ + /* top :: The top-side bearing, i.e., the vertical distance from */ + /* the current pen position to the top border of the glyph */ + /* bitmap. This distance is positive for upwards-y! */ + /* */ + /* bitmap :: A descriptor for the bitmap. */ + /* */ + /* <Note> */ + /* You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_BITMAP'. This lets you access */ + /* the bitmap's contents easily. */ + /* */ + /* The corresponding pixel buffer is always owned by @FT_BitmapGlyph */ + /* and is thus created and destroyed with it. */ + /* */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_OutlineGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model an outline glyph image. This */ + /* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ + /* */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_OutlineGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for outline (vectorial) glyph images. This */ + /* really is a `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* outline :: A descriptor for the outline. */ + /* */ + /* <Note> */ + /* You can typecast a @FT_Glyph to @FT_OutlineGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_OUTLINE'. This lets you access */ + /* the outline's content easily. */ + /* */ + /* As the outline is extracted from a glyph slot, its coordinates are */ + /* expressed normally in 26.6 pixels, unless the flag */ + /* @FT_LOAD_NO_SCALE was used in @FT_Load_Glyph() or @FT_Load_Char(). */ + /* */ + /* The outline's tables are always owned by the object and are */ + /* destroyed with it. */ + /* */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph */ + /* */ + /* <Description> */ + /* A function used to extract a glyph image from a slot. */ + /* */ + /* <Input> */ + /* slot :: A handle to the source glyph slot. */ + /* */ + /* <Output> */ + /* aglyph :: A handle to the glyph object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Copy */ + /* */ + /* <Description> */ + /* A function used to copy a glyph image. Note that the created */ + /* @FT_Glyph object must be released with @FT_Done_Glyph. */ + /* */ + /* <Input> */ + /* source :: A handle to the source glyph object. */ + /* */ + /* <Output> */ + /* target :: A handle to the target glyph object. 0 in case of */ + /* error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Transform */ + /* */ + /* <Description> */ + /* Transforms a glyph image if its format is scalable. */ + /* */ + /* <InOut> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to a 2x2 matrix to apply. */ + /* */ + /* delta :: A pointer to a 2d vector to apply. Coordinates are */ + /* expressed in 1/64th of a pixel. */ + /* */ + /* <Return> */ + /* FreeType error code (if not 0, the glyph format is not scalable). */ + /* */ + /* <Note> */ + /* The 2x2 transformation matrix is also applied to the glyph's */ + /* advance vector. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_BBox_Mode */ + /* */ + /* <Description> */ + /* The mode how the values of @FT_Glyph_Get_CBox are returned. */ + /* */ + /* <Values> */ + /* FT_GLYPH_BBOX_UNSCALED :: */ + /* Return unscaled font units. */ + /* */ + /* FT_GLYPH_BBOX_SUBPIXELS :: */ + /* Return unfitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_GRIDFIT :: */ + /* Return grid-fitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_TRUNCATE :: */ + /* Return coordinates in integer pixels. */ + /* */ + /* FT_GLYPH_BBOX_PIXELS :: */ + /* Return grid-fitted pixel coordinates. */ + /* */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + + } FT_Glyph_BBox_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_bbox_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Glyph_BBox_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */ + /* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */ + /* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */ + /* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */ + /* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */ + /* */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Get_CBox */ + /* */ + /* <Description> */ + /* Return a glyph's `control box'. The control box encloses all the */ + /* outline's points, including Bézier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bézier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the source glyph object. */ + /* */ + /* mode :: The mode which indicates how to interpret the returned */ + /* bounding box values. */ + /* */ + /* <Output> */ + /* acbox :: The glyph coordinate bounding box. Coordinates are */ + /* expressed in 1/64th of pixels if it is grid-fitted. */ + /* */ + /* <Note> */ + /* Coordinates are relative to the glyph origin, using the Y-upwards */ + /* convention. */ + /* */ + /* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' */ + /* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font */ + /* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS */ + /* is another name for this constant. */ + /* */ + /* Note that the maximum coordinates are exclusive, which means that */ + /* one can compute the width and height of the glyph image (be it in */ + /* integer or 26.6 pixels) as: */ + /* */ + /* { */ + /* width = bbox.xMax - bbox.xMin; */ + /* height = bbox.yMax - bbox.yMin; */ + /* } */ + /* */ + /* Note also that for 26.6 coordinates, if `bbox_mode' is set to */ + /* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, */ + /* which corresponds to: */ + /* */ + /* { */ + /* bbox.xMin = FLOOR(bbox.xMin); */ + /* bbox.yMin = FLOOR(bbox.yMin); */ + /* bbox.xMax = CEILING(bbox.xMax); */ + /* bbox.yMax = CEILING(bbox.yMax); */ + /* } */ + /* */ + /* To get the bbox in pixel coordinates, set `bbox_mode' to */ + /* @FT_GLYPH_BBOX_TRUNCATE. */ + /* */ + /* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */ + /* to @FT_GLYPH_BBOX_PIXELS. */ + /* */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_To_Bitmap */ + /* */ + /* <Description> */ + /* Converts a given glyph object to a bitmap glyph object. */ + /* */ + /* <InOut> */ + /* the_glyph :: A pointer to a handle to the target glyph. */ + /* */ + /* <Input> */ + /* render_mode :: An enumeration that describe how the data is */ + /* rendered. */ + /* */ + /* origin :: A pointer to a vector used to translate the glyph */ + /* image before rendering. Can be 0 (if no */ + /* translation). The origin is expressed in */ + /* 26.6 pixels. */ + /* */ + /* destroy :: A boolean that indicates that the original glyph */ + /* image should be destroyed by this function. It is */ + /* never destroyed in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The glyph image is translated with the `origin' vector before */ + /* rendering. */ + /* */ + /* The first parameter is a pointer to an @FT_Glyph handle, that will */ + /* be replaced by this function. Typically, you would use (omitting */ + /* error handling): */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyph; */ + /* FT_BitmapGlyph glyph_bitmap; */ + /* */ + /* */ + /* // load glyph */ + /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ + /* */ + /* // extract glyph image */ + /* error = FT_Get_Glyph( face->glyph, &glyph ); */ + /* */ + /* // convert to a bitmap (default render mode + destroy old) */ + /* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) */ + /* { */ + /* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_DEFAULT, */ + /* 0, 1 ); */ + /* if ( error ) // glyph unchanged */ + /* ... */ + /* } */ + /* */ + /* // access bitmap content by typecasting */ + /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ + /* */ + /* // do funny stuff with it, like blitting/drawing */ + /* ... */ + /* */ + /* // discard glyph image (bitmap or not) */ + /* FT_Done_Glyph( glyph ); */ + /* } */ + /* */ + /* */ + /* This function does nothing if the glyph format isn't scalable. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + FT_Vector* origin, + FT_Bool destroy ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Glyph */ + /* */ + /* <Description> */ + /* Destroys a given glyph. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); + + /* */ + + + /* other helpful functions */ + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Multiply */ + /* */ + /* <Description> */ + /* Performs the matrix operation `b = a*b'. */ + /* */ + /* <Input> */ + /* a :: A pointer to matrix `a'. */ + /* */ + /* <InOut> */ + /* b :: A pointer to matrix `b'. */ + /* */ + /* <Note> */ + /* The result is undefined if either `a' or `b' is zero. */ + /* */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Invert */ + /* */ + /* <Description> */ + /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */ + /* */ + /* <InOut> */ + /* matrix :: A pointer to the target matrix. Remains untouched in */ + /* case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGLYPH_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftgxval.h b/src/freetype2/freetype/ftgxval.h new file mode 100644 index 0000000..c7ea861 --- /dev/null +++ b/src/freetype2/freetype/ftgxval.h @@ -0,0 +1,358 @@ +/***************************************************************************/ +/* */ +/* ftgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGXVAL_H__ +#define __FTGXVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gx_validation */ + /* */ + /* <Title> */ + /* TrueTypeGX/AAT Validation */ + /* */ + /* <Abstract> */ + /* An API to validate TrueTypeGX/AAT tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, */ + /* trak, prop, lcar). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Warning: Use FT_VALIDATE_XXX to validate a table. */ + /* Following definitions are for gxvalid developers. */ + /* */ + /* */ + /*************************************************************************/ + +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX + + + /************************************************************************* + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length' argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH (FT_VALIDATE_GX_LAST_INDEX + 1) + + /* */ + + /* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate `feat' table. + * + * FT_VALIDATE_mort :: + * Validate `mort' table. + * + * FT_VALIDATE_morx :: + * Validate `morx' table. + * + * FT_VALIDATE_bsln :: + * Validate `bsln' table. + * + * FT_VALIDATE_just :: + * Validate `just' table. + * + * FT_VALIDATE_kern :: + * Validate `kern' table. + * + * FT_VALIDATE_opbd :: + * Validate `opbd' table. + * + * FT_VALIDATE_trak :: + * Validate `trak' table. + * + * FT_VALIDATE_prop :: + * Validate `prop' table. + * + * FT_VALIDATE_lcar :: + * Validate `lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ + +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) + +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables' array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. + * The array itself must be allocated by a client. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables' element, by calling @FT_TrueTypeGX_Free. A NULL value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by + * @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate + * to indicate the classic kern dialect or dialects. If the selected + * type doesn't fit, @FT_ClassicKern_Validate regards the table as + * invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the `kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the `kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the `kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) + +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16bit format) kern table to assure that the offsets + * and indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * The `kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32bit format and the classic 16bit format, while + * FT_ClassicKern_Validate only supports the classic 16bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table', by calling @FT_ClassicKern_Free. A NULL value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGXVAL_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftgzip.h b/src/freetype2/freetype/ftgzip.h new file mode 100644 index 0000000..9893437 --- /dev/null +++ b/src/freetype2/freetype/ftgzip.h @@ -0,0 +1,102 @@ +/***************************************************************************/ +/* */ +/* ftgzip.h */ +/* */ +/* Gzip-compressed stream support. */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGZIP_H__ +#define __FTGZIP_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gzip */ + /* */ + /* <Title> */ + /* GZIP Streams */ + /* */ + /* <Abstract> */ + /* Using gzip-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Gzip-specific functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************ + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is + * mainly used to support the compressed `*.pcf.gz' fonts that come + * with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream. + * + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from + * it and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTGZIP_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftimage.h b/src/freetype2/freetype/ftimage.h new file mode 100644 index 0000000..1c428f1 --- /dev/null +++ b/src/freetype2/freetype/ftimage.h @@ -0,0 +1,1237 @@ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Note: A `raster' is simply a scan-line converter, used to render */ + /* FT_Outlines into FT_Bitmaps. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTIMAGE_H__ +#define __FTIMAGE_H__ + + +/* _STANDALONE_ is from ftgrays.c */ +#ifndef _STANDALONE_ +#include <ft2build.h> +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pos */ + /* */ + /* <Description> */ + /* The type FT_Pos is a 32-bit integer used to store vectorial */ + /* coordinates. Depending on the context, these can represent */ + /* distances in integer font units, or 16,16, or 26.6 fixed float */ + /* pixel coordinates. */ + /* */ + typedef signed long FT_Pos; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Vector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector; coordinates are of */ + /* the FT_Pos type. */ + /* */ + /* <Fields> */ + /* x :: The horizontal coordinate. */ + /* y :: The vertical coordinate. */ + /* */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BBox */ + /* */ + /* <Description> */ + /* A structure used to hold an outline's bounding box, i.e., the */ + /* coordinates of its extrema in the horizontal and vertical */ + /* directions. */ + /* */ + /* <Fields> */ + /* xMin :: The horizontal minimum (left-most). */ + /* */ + /* yMin :: The vertical minimum (bottom-most). */ + /* */ + /* xMax :: The horizontal maximum (right-most). */ + /* */ + /* yMax :: The vertical maximum (top-most). */ + /* */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Pixel_Mode */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of pixels in a */ + /* given bitmap. Note that additional formats may be added in the */ + /* future. */ + /* */ + /* <Values> */ + /* FT_PIXEL_MODE_NONE :: */ + /* Value 0 is reserved. */ + /* */ + /* FT_PIXEL_MODE_MONO :: */ + /* A monochrome bitmap, using 1 bit per pixel. Note that pixels */ + /* are stored in most-significant order (MSB), which means that */ + /* the left-most pixel in a byte has value 128. */ + /* */ + /* FT_PIXEL_MODE_GRAY :: */ + /* An 8-bit bitmap, generally used to represent anti-aliased glyph */ + /* images. Each pixel is stored in one byte. Note that the number */ + /* of value `gray' levels is stored in the `num_bytes' field of */ + /* the @FT_Bitmap structure (it generally is 256). */ + /* */ + /* FT_PIXEL_MODE_GRAY2 :: */ + /* A 2-bit/pixel bitmap, used to represent embedded anti-aliased */ + /* bitmaps in font files according to the OpenType specification. */ + /* We haven't found a single font using this format, however. */ + /* */ + /* FT_PIXEL_MODE_GRAY4 :: */ + /* A 4-bit/pixel bitmap, used to represent embedded anti-aliased */ + /* bitmaps in font files according to the OpenType specification. */ + /* We haven't found a single font using this format, however. */ + /* */ + /* FT_PIXEL_MODE_LCD :: */ + /* An 8-bit bitmap, used to represent RGB or BGR decimated glyph */ + /* images used for display on LCD displays; the bitmap is three */ + /* times wider than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD. */ + /* */ + /* FT_PIXEL_MODE_LCD_V :: */ + /* An 8-bit bitmap, used to represent RGB or BGR decimated glyph */ + /* images used for display on rotated LCD displays; the bitmap */ + /* is three times taller than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD_V. */ + /* */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + + FT_PIXEL_MODE_MAX /* do not remove */ + + } FT_Pixel_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_pixel_mode_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Pixel_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */ + /* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */ + /* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */ + /* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */ + /* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */ + /* */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + + /* */ + +#if 0 + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Palette_Mode */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT! */ + /* */ + /* An enumeration type to describe the format of a bitmap palette, */ + /* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ + /* */ + /* <Fields> */ + /* ft_palette_mode_rgb :: The palette is an array of 3-bytes RGB */ + /* records. */ + /* */ + /* ft_palette_mode_rgba :: The palette is an array of 4-bytes RGBA */ + /* records. */ + /* */ + /* <Note> */ + /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ + /* FreeType, these types are not handled by the library itself. */ + /* */ + typedef enum FT_Palette_Mode_ + { + ft_palette_mode_rgb = 0, + ft_palette_mode_rgba, + + ft_palettte_mode_max /* do not remove */ + + } FT_Palette_Mode; + + /* */ + +#endif + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap */ + /* */ + /* <Description> */ + /* A structure used to describe a bitmap or pixmap to the raster. */ + /* Note that we now manage pixmaps of various depths through the */ + /* `pixel_mode' field. */ + /* */ + /* <Fields> */ + /* rows :: The number of bitmap rows. */ + /* */ + /* width :: The number of pixels in bitmap row. */ + /* */ + /* pitch :: The pitch's absolute value is the number of bytes */ + /* taken by one bitmap row, including padding. */ + /* However, the pitch is positive when the bitmap has */ + /* a `down' flow, and negative when it has an `up' */ + /* flow. In all cases, the pitch is an offset to add */ + /* to a bitmap pointer in order to go down one row. */ + /* */ + /* buffer :: A typeless pointer to the bitmap buffer. This */ + /* value should be aligned on 32-bit boundaries in */ + /* most cases. */ + /* */ + /* num_grays :: This field is only used with */ + /* @FT_PIXEL_MODE_GRAY; it gives the number of gray */ + /* levels used in the bitmap. */ + /* */ + /* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. */ + /* See @FT_Pixel_Mode for possible values. */ + /* */ + /* palette_mode :: This field is intended for paletted pixel modes; */ + /* it indicates how the palette is stored. Not */ + /* used currently. */ + /* */ + /* palette :: A typeless pointer to the bitmap palette; this */ + /* field is intended for paletted pixel modes. Not */ + /* used currently. */ + /* */ + /* <Note> */ + /* For now, the only pixel modes supported by FreeType are mono and */ + /* grays. However, drivers might be added in the future to support */ + /* more `colorful' options. */ + /* */ + typedef struct FT_Bitmap_ + { + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; + + } FT_Bitmap; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline */ + /* */ + /* <Description> */ + /* This structure is used to describe an outline to the scan-line */ + /* converter. */ + /* */ + /* <Fields> */ + /* n_contours :: The number of contours in the outline. */ + /* */ + /* n_points :: The number of points in the outline. */ + /* */ + /* points :: A pointer to an array of `n_points' @FT_Vector */ + /* elements, giving the outline's point coordinates. */ + /* */ + /* tags :: A pointer to an array of `n_points' chars, giving */ + /* each outline point's type. If bit 0 is unset, the */ + /* point is `off' the curve, i.e., a Bézier control */ + /* point, while it is `on' when set. */ + /* */ + /* Bit 1 is meaningful for `off' points only. If set, */ + /* it indicates a third-order Bézier arc control point; */ + /* and a second-order control point if unset. */ + /* */ + /* contours :: An array of `n_contours' shorts, giving the end */ + /* point of each contour within the outline. For */ + /* example, the first contour is defined by the points */ + /* `0' to `contours[0]', the second one is defined by */ + /* the points `contours[0]+1' to `contours[1]', etc. */ + /* */ + /* flags :: A set of bit flags used to characterize the outline */ + /* and give hints to the scan-converter and hinter on */ + /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ + /* */ + typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OUTLINE_FLAGS */ + /* */ + /* <Description> */ + /* A list of bit-field constants use for the flags in an outline's */ + /* `flags' field. */ + /* */ + /* <Values> */ + /* FT_OUTLINE_NONE :: Value 0 is reserved. */ + /* */ + /* FT_OUTLINE_OWNER :: If set, this flag indicates that the */ + /* outline's field arrays (i.e., */ + /* `points', `flags' & `contours') are */ + /* `owned' by the outline object, and */ + /* should thus be freed when it is */ + /* destroyed. */ + /* */ + /* FT_OUTLINE_EVEN_ODD_FILL :: By default, outlines are filled using */ + /* the non-zero winding rule. If set to */ + /* 1, the outline will be filled using */ + /* the even-odd fill rule (only works */ + /* with the smooth raster). */ + /* */ + /* FT_OUTLINE_REVERSE_FILL :: By default, outside contours of an */ + /* outline are oriented in clock-wise */ + /* direction, as defined in the TrueType */ + /* specification. This flag is set if */ + /* the outline uses the opposite */ + /* direction (typically for Type 1 */ + /* fonts). This flag is ignored by the */ + /* scan-converter. */ + /* */ + /* FT_OUTLINE_IGNORE_DROPOUTS :: By default, the scan converter will */ + /* try to detect drop-outs in an outline */ + /* and correct the glyph bitmap to */ + /* ensure consistent shape continuity. */ + /* If set, this flag hints the scan-line */ + /* converter to ignore such cases. */ + /* */ + /* FT_OUTLINE_HIGH_PRECISION :: This flag indicates that the */ + /* scan-line converter should try to */ + /* convert this outline to bitmaps with */ + /* the highest possible quality. It is */ + /* typically set for small character */ + /* sizes. Note that this is only a */ + /* hint, that might be completely */ + /* ignored by a given scan-converter. */ + /* */ + /* FT_OUTLINE_SINGLE_PASS :: This flag is set to force a given */ + /* scan-converter to only use a single */ + /* pass over the outline to render a */ + /* bitmap glyph image. Normally, it is */ + /* set for very large character sizes. */ + /* It is only a hint, that might be */ + /* completely ignored by a given */ + /* scan-converter. */ + /* */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + + + /************************************************************************* + * + * @enum: + * ft_outline_flags + * + * @description: + * These constants are deprecated. Please use the corresponding + * @FT_OUTLINE_FLAGS values. + * + * @values: + * ft_outline_none :: See @FT_OUTLINE_NONE. + * ft_outline_owner :: See @FT_OUTLINE_OWNER. + * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL. + * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL. + * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS. + * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION. + * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS. + */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + + /* */ + +#define FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define FT_CURVE_TAG_ON 1 +#define FT_CURVE_TAG_CONIC 0 +#define FT_CURVE_TAG_CUBIC 2 + +#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_MoveToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `move */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `move to' is emitted to start a new contour in an outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `move to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_LineToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `line */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `line to' is emitted to indicate a segment in the outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `line to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_ConicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type use to describe the signature of a `conic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `conic to' is emitted to indicate a second-order Bézier arc in */ + /* the outline. */ + /* */ + /* <Input> */ + /* control :: An intermediate control point between the last position */ + /* and the new target in `to'. */ + /* */ + /* to :: A pointer to the target end point of the conic arc. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); + +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_CubicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `cubic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `cubic to' is emitted to indicate a third-order Bézier arc. */ + /* */ + /* <Input> */ + /* control1 :: A pointer to the first Bézier control point. */ + /* */ + /* control2 :: A pointer to the second Bézier control point. */ + /* */ + /* to :: A pointer to the target end point. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); + +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline_Funcs */ + /* */ + /* <Description> */ + /* A structure to hold various function pointers used during outline */ + /* decomposition in order to emit segments, conic, and cubic Béziers, */ + /* as well as `move to' and `close to' operations. */ + /* */ + /* <Fields> */ + /* move_to :: The `move to' emitter. */ + /* */ + /* line_to :: The segment emitter. */ + /* */ + /* conic_to :: The second-order Bézier arc emitter. */ + /* */ + /* cubic_to :: The third-order Bézier arc emitter. */ + /* */ + /* shift :: The shift that is applied to coordinates before they */ + /* are sent to the emitter. */ + /* */ + /* delta :: The delta that is applied to coordinates before they */ + /* are sent to the emitter, but after the shift. */ + /* */ + /* <Note> */ + /* The point coordinates sent to the emitters are the transformed */ + /* version of the original coordinates (this is important for high */ + /* accuracy during scan-conversion). The transformation is simple: */ + /* */ + /* { */ + /* x' = (x << shift) - delta */ + /* y' = (x << shift) - delta */ + /* } */ + /* */ + /* Set the value of `shift' and `delta' to 0 to get the original */ + /* point coordinates. */ + /* */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_IMAGE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags to an unsigned long type. */ + /* */ + /* <Note> */ + /* Since many 16bit compilers don't like 32bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) +#endif /* FT_IMAGE_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_Format */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of a given glyph */ + /* image. Note that this version of FreeType only supports two image */ + /* formats, even though future font drivers will be able to register */ + /* their own format. */ + /* */ + /* <Values> */ + /* FT_GLYPH_FORMAT_NONE :: */ + /* The value 0 is reserved. */ + /* */ + /* FT_GLYPH_FORMAT_COMPOSITE :: */ + /* The glyph image is a composite of several other images. This */ + /* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to */ + /* report compound glyphs (like accented characters). */ + /* */ + /* FT_GLYPH_FORMAT_BITMAP :: */ + /* The glyph image is a bitmap, and can be described as an */ + /* @FT_Bitmap. You generally need to access the `bitmap' field of */ + /* the @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_OUTLINE :: */ + /* The glyph image is a vectorial outline made of line segments */ + /* and Bézier arcs; it can be described as an @FT_Outline; you */ + /* generally want to access the `outline' field of the */ + /* @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_PLOTTER :: */ + /* The glyph image is a vectorial path with no inside and outside */ + /* contours. Some Type 1 fonts, like those in the Hershey family, */ + /* contain glyphs in this format. These are described as */ + /* @FT_Outline, but FreeType isn't currently capable of rendering */ + /* them correctly. */ + /* */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) + + } FT_Glyph_Format; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_format_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Glyph_Format values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */ + /* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */ + /* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */ + /* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */ + /* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */ + /* */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* A raster is a scan converter, in charge of rendering an outline into */ + /* a a bitmap. This section contains the public API for rasters. */ + /* */ + /* Note that in FreeType 2, all rasters are now encapsulated within */ + /* specific modules called `renderers'. See `freetype/ftrender.h' for */ + /* more details on renderers. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* raster */ + /* */ + /* <Title> */ + /* Scanline Converter */ + /* */ + /* <Abstract> */ + /* How vectorial outlines are converted into bitmaps and pixmaps. */ + /* */ + /* <Description> */ + /* This section contains technical definitions. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Raster */ + /* */ + /* <Description> */ + /* A handle (pointer) to a raster object. Each object can be used */ + /* independently to convert an outline into a bitmap or pixmap. */ + /* */ + typedef struct FT_RasterRec_* FT_Raster; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Span */ + /* */ + /* <Description> */ + /* A structure used to model a single span of gray (or black) pixels */ + /* when rendering a monochrome or anti-aliased bitmap. */ + /* */ + /* <Fields> */ + /* x :: The span's horizontal start position. */ + /* */ + /* len :: The span's length in pixels. */ + /* */ + /* coverage :: The span color/coverage, ranging from 0 (background) */ + /* to 255 (foreground). Only used for anti-aliased */ + /* rendering. */ + /* */ + /* <Note> */ + /* This structure is used by the span drawing callback type named */ + /* @FT_SpanFunc which takes the y-coordinate of the span as a */ + /* a parameter. */ + /* */ + /* The coverage value is always between 0 and 255. */ + /* */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_SpanFunc */ + /* */ + /* <Description> */ + /* A function used as a call-back by the anti-aliased renderer in */ + /* order to let client applications draw themselves the gray pixel */ + /* spans on each scan line. */ + /* */ + /* <Input> */ + /* y :: The scanline's y-coordinate. */ + /* */ + /* count :: The number of spans to draw on this scanline. */ + /* */ + /* spans :: A table of `count' spans to draw on the scanline. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Note> */ + /* This callback allows client applications to directly render the */ + /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ + /* */ + /* This can be used to write anti-aliased outlines directly to a */ + /* given background bitmap, and even perform translucency. */ + /* */ + /* Note that the `count' field cannot be greater than a fixed value */ + /* defined by the `FT_MAX_GRAY_SPANS' configuration macro in */ + /* `ftoption.h'. By default, this value is set to 32, which means */ + /* that if there are more than 32 spans on a given scanline, the */ + /* callback is called several times with the same `y' parameter in */ + /* order to draw all callbacks. */ + /* */ + /* Otherwise, the callback is only called once per scan-line, and */ + /* only for those scanlines that do have `gray' pixels on them. */ + /* */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); + +#define FT_Raster_Span_Func FT_SpanFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitTest_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to test whether a given target pixel is already set to the drawing */ + /* `color'. These tests are crucial to implement drop-out control */ + /* per-se the TrueType spec. */ + /* */ + /* <Input> */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitSet_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to set an individual target pixel. This is crucial to implement */ + /* drop-out control according to the TrueType specification. */ + /* */ + /* <Input> */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_RASTER_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flag constants as used in the `flags' field of a */ + /* @FT_Raster_Params structure. */ + /* */ + /* <Values> */ + /* FT_RASTER_FLAG_DEFAULT :: This value is 0. */ + /* */ + /* FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ + /* anti-aliased glyph image should be */ + /* generated. Otherwise, it will be */ + /* monochrome (1-bit). */ + /* */ + /* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ + /* rendering. In this mode, client */ + /* applications must provide their own span */ + /* callback. This lets them directly */ + /* draw or compose over an existing bitmap. */ + /* If this bit is not set, the target */ + /* pixmap's buffer _must_ be zeroed before */ + /* rendering. */ + /* */ + /* Note that for now, direct rendering is */ + /* only possible with anti-aliased glyphs. */ + /* */ + /* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ + /* rendering mode. If set, the output will */ + /* be clipped to a box specified in the */ + /* `clip_box' field of the */ + /* @FT_Raster_Params structure. */ + /* */ + /* Note that by default, the glyph bitmap */ + /* is clipped to the target pixmap, except */ + /* in direct rendering mode where all spans */ + /* are generated if no clipping box is set. */ + /* */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 + + /* deprecated */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Params */ + /* */ + /* <Description> */ + /* A structure to hold the arguments used by a raster's render */ + /* function. */ + /* */ + /* <Fields> */ + /* target :: The target bitmap. */ + /* */ + /* source :: A pointer to the source glyph image (e.g., an */ + /* @FT_Outline). */ + /* */ + /* flags :: The rendering flags. */ + /* */ + /* gray_spans :: The gray span drawing callback. */ + /* */ + /* black_spans :: The black span drawing callback. */ + /* */ + /* bit_test :: The bit test callback. UNIMPLEMENTED! */ + /* */ + /* bit_set :: The bit set callback. UNIMPLEMENTED! */ + /* */ + /* user :: User-supplied data that is passed to each drawing */ + /* callback. */ + /* */ + /* clip_box :: An optional clipping box. It is only used in */ + /* direct rendering mode. Note that coordinates here */ + /* should be expressed in _integer_ pixels (and not in */ + /* 26.6 fixed-point units). */ + /* */ + /* <Note> */ + /* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA */ + /* bit flag is set in the `flags' field, otherwise a monochrome */ + /* bitmap is generated. */ + /* */ + /* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ + /* raster will call the `gray_spans' callback to draw gray pixel */ + /* spans, in the case of an aa glyph bitmap, it will call */ + /* `black_spans', and `bit_test' and `bit_set' in the case of a */ + /* monochrome bitmap. This allows direct composition over a */ + /* pre-existing bitmap through user-provided callbacks to perform the */ + /* span drawing/composition. */ + /* */ + /* Note that the `bit_test' and `bit_set' callbacks are required when */ + /* rendering a monochrome bitmap, as they are crucial to implement */ + /* correct drop-out control as defined in the TrueType specification. */ + /* */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; + FT_SpanFunc black_spans; + FT_Raster_BitTest_Func bit_test; /* doesn't work! */ + FT_Raster_BitSet_Func bit_set; /* doesn't work! */ + void* user; + FT_BBox clip_box; + + } FT_Raster_Params; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_NewFunc */ + /* */ + /* <Description> */ + /* A function used to create a new raster object. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory allocator. */ + /* */ + /* <Output> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `memory' parameter is a typeless pointer in order to avoid */ + /* un-wanted dependencies on the rest of the FreeType code. In */ + /* practice, it is an @FT_Memory object, i.e., a handle to the */ + /* standard FreeType memory allocator. However, this field can be */ + /* completely ignored by a given raster implementation. */ + /* */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); + +#define FT_Raster_New_Func FT_Raster_NewFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_DoneFunc */ + /* */ + /* <Description> */ + /* A function used to destroy a given raster object. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); + +#define FT_Raster_Done_Func FT_Raster_DoneFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_ResetFunc */ + /* */ + /* <Description> */ + /* FreeType provides an area of memory called the `render pool', */ + /* available to all registered rasters. This pool can be freely used */ + /* during a given scan-conversion but is shared by all rasters. Its */ + /* content is thus transient. */ + /* */ + /* This function is called each time the render pool changes, or just */ + /* after a new raster object is created. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* pool_base :: The address in memory of the render pool. */ + /* */ + /* pool_size :: The size in bytes of the render pool. */ + /* */ + /* <Note> */ + /* Rasters can ignore the render pool and rely on dynamic memory */ + /* allocation if they want to (a handle to the memory allocator is */ + /* passed to the raster constructor). However, this is not */ + /* recommended for efficiency purposes. */ + /* */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define FT_Raster_Reset_Func FT_Raster_ResetFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_SetModeFunc */ + /* */ + /* <Description> */ + /* This function is a generic facility to change modes or attributes */ + /* in a given raster. This can be used for debugging purposes, or */ + /* simply to allow implementation-specific `features' in a given */ + /* raster module. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* mode :: A 4-byte tag used to name the mode or property. */ + /* */ + /* args :: A pointer to the new mode/property to use. */ + /* */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); + +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_RenderFunc */ + /* */ + /* <Description> */ + /* Invokes a given raster to scan-convert a given glyph image into a */ + /* target bitmap. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* store the rendering parameters. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + /* <Note> */ + /* The exact format of the source image depends on the raster's glyph */ + /* format defined in its @FT_Raster_Funcs structure. It can be an */ + /* @FT_Outline or anything else in order to support a large array of */ + /* glyph formats. */ + /* */ + /* Note also that the render function can fail and return a */ + /* `FT_Err_Unimplemented_Feature' error code if the raster used does */ + /* not support direct composition. */ + /* */ + /* XXX: For now, the standard raster doesn't support direct */ + /* composition but this should change for the final release (see */ + /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ + /* for examples of distinct implementations which support direct */ + /* composition). */ + /* */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); + +#define FT_Raster_Render_Func FT_Raster_RenderFunc + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Funcs */ + /* */ + /* <Description> */ + /* A structure used to describe a given raster class to the library. */ + /* */ + /* <Fields> */ + /* glyph_format :: The supported glyph format for this raster. */ + /* */ + /* raster_new :: The raster constructor. */ + /* */ + /* raster_reset :: Used to reset the render pool within the raster. */ + /* */ + /* raster_render :: A function to render a glyph into a given bitmap. */ + /* */ + /* raster_done :: The raster destructor. */ + /* */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + + } FT_Raster_Funcs; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTIMAGE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftincrem.h b/src/freetype2/freetype/ftincrem.h new file mode 100644 index 0000000..46bc8bd --- /dev/null +++ b/src/freetype2/freetype/ftincrem.h @@ -0,0 +1,331 @@ +/***************************************************************************/ +/* */ +/* ftincrem.h */ +/* */ +/* FreeType incremental loading (specification). */ +/* */ +/* Copyright 2002, 2003, 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 __FTINCREM_H__ +#define __FTINCREM_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * `incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application, + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a Postscript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ + + + /*************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * `incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., Postscript interpreters), + * where the glyph data isn't in the font file, or must be overridden by + * different values. + * + * @note: + * It is up to client applications to create and implement @FT_Incremental + * objects, as long as they provide implementations for the methods + * @FT_Incremental_GetGlyphDataFunc, @FT_Incremental_FreeGlyphDataFunc + * and @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + */ + typedef struct FT_IncrementalRec_* FT_Incremental; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A small structure used to contain the basic glyph metrics returned + * by the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical' argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; + + } FT_Incremental_MetricsRec, *FT_Incremental_Metrics; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the `glyf' table. For Postscript formats, it must correspond to the + * *unencrypted* charstring bytes, without any `lenIV' header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release + * the data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This is necessary because, in certain + * formats like TrueType, the metrics are stored in a different place from + * the glyph images proper. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. + * The original glyph metrics, if any, in font units. If metrics are + * not available all the values must be set to zero. + * + * @output: + * ametrics :: + * The replacement glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data + * incrementally. Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does + * not provide overriding glyph metrics. + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + + } FT_Incremental_FuncsRec; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * { + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * } + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + + } FT_Incremental_InterfaceRec; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * A constant used as the tag of @FT_Parameter structures to indicate + * an incremental loading object to be used by FreeType. + * + */ +#define FT_PARAM_TAG_INCREMENTAL FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + + /* */ + +FT_END_HEADER + +#endif /* __FTINCREM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftlcdfil.h b/src/freetype2/freetype/ftlcdfil.h new file mode 100644 index 0000000..9a61377 --- /dev/null +++ b/src/freetype2/freetype/ftlcdfil.h @@ -0,0 +1,166 @@ +/***************************************************************************/ +/* */ +/* ftlcdfil.h */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs */ +/* (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 __FT_LCD_FILTER_H__ +#define __FT_LCD_FILTER_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * lcd_filtering + * + * @title: + * LCD Filtering + * + * @abstract: + * Reduce color fringes of LCD-optimized bitmaps. + * + * @description: + * The @FT_Library_SetLcdFilter API can be used to specify a low-pass + * filter which is then applied to LCD-optimized bitmaps generated + * through @FT_Render_Glyph. This is useful to reduce color fringes + * which would occur with unfiltered rendering. + * + * Note that no filter is active by default, and that this function is + * *not* implemented in default builds of the library. You need to + * #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file + * in order to activate it. + */ + + + /**************************************************************************** + * + * @func: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * The default filter reduces color fringes considerably, at the cost + * of a slight blurriness in the output. + * + * FT_LCD_FILTER_LIGHT :: + * The light filter is a variant that produces less blurriness at the + * cost of slightly more color fringes than the default one. It might + * be better, depending on taste, your monitor, or your personal vision. + * + * FT_LCD_FILTER_LEGACY :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * In other words, it only works well if the TrueType bytecode + * interpreter is enabled *and* high-quality hinted fonts are used. + * + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. + * + * @since: + * 2.3.0 + */ + typedef enum + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY = 16, + + FT_LCD_FILTER_MAX /* do not remove */ + + } FT_LcdFilter; + + + /************************************************************************** + * + * @func: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to apply color filtering to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work + * well on most LCD screens. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This feature is always disabled by default. Clients must make an + * explicit call to this function with a `filter' value other than + * @FT_LCD_FILTER_NONE in order to enable it. + * + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * The filter affects glyph bitmaps rendered through @FT_Render_Glyph, + * @FT_Outline_Get_Bitmap, @FT_Load_Glyph, and @FT_Load_Char. + * + * It does _not_ affect the output of @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * If this feature is activated, the dimensions of LCD glyph bitmaps are + * either larger or taller than the dimensions of the corresponding + * outline with regards to the pixel grid. For example, for + * @FT_RENDER_MODE_LCD, the filter adds up to 3 pixels to the left, and + * up to 3 pixels to the right. + * + * The bitmap offset values are adjusted correctly, so clients shouldn't + * need to modify their layout and glyph positioning code when enabling + * the filter. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); + + /* */ + + +FT_END_HEADER + +#endif /* __FT_LCD_FILTER_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftlist.h b/src/freetype2/freetype/ftlist.h new file mode 100644 index 0000000..f3223ee --- /dev/null +++ b/src/freetype2/freetype/ftlist.h @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* ftlist.h */ +/* */ +/* Generic list support for FreeType (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file implements functions relative to list processing. Its */ + /* data structures are defined in `freetype.h'. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTLIST_H__ +#define __FTLIST_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /* <Title> */ + /* List Processing */ + /* */ + /* <Abstract> */ + /* Simple management of lists. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to list */ + /* processing using doubly-linked nodes. */ + /* */ + /* <Order> */ + /* FT_List */ + /* FT_ListNode */ + /* FT_ListRec */ + /* FT_ListNodeRec */ + /* */ + /* FT_List_Add */ + /* FT_List_Insert */ + /* FT_List_Find */ + /* FT_List_Remove */ + /* FT_List_Up */ + /* FT_List_Iterate */ + /* FT_List_Iterator */ + /* FT_List_Finalize */ + /* FT_List_Destructor */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Find */ + /* */ + /* <Description> */ + /* Finds the list node for a given listed object. */ + /* */ + /* <Input> */ + /* list :: A pointer to the parent list. */ + /* data :: The address of the listed object. */ + /* */ + /* <Return> */ + /* List node. NULL if it wasn't found. */ + /* */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Add */ + /* */ + /* <Description> */ + /* Appends an element to the end of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to append. */ + /* */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Insert */ + /* */ + /* <Description> */ + /* Inserts an element at the head of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to parent list. */ + /* node :: The node to insert. */ + /* */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Remove */ + /* */ + /* <Description> */ + /* Removes a node from a list. This function doesn't check whether */ + /* the node is in the list! */ + /* */ + /* <Input> */ + /* node :: The node to remove. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Up */ + /* */ + /* <Description> */ + /* Moves a node to the head/top of a list. Used to maintain LRU */ + /* lists. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to move. */ + /* */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Iterator */ + /* */ + /* <Description> */ + /* An FT_List iterator function which is called during a list parse */ + /* by @FT_List_Iterate. */ + /* */ + /* <Input> */ + /* node :: The current iteration list node. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. */ + /* Can be used to point to the iteration's state. */ + /* */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Iterate */ + /* */ + /* <Description> */ + /* Parses a list and calls a given iterator function on each element. */ + /* Note that parsing is stopped as soon as one of the iterator calls */ + /* returns a non-zero value. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* iterator :: An iterator function, called on each node of the list. */ + /* user :: A user-supplied field which is passed as the second */ + /* argument to the iterator. */ + /* */ + /* <Return> */ + /* The result (a FreeType error code) of the last iterator call. */ + /* */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Destructor */ + /* */ + /* <Description> */ + /* An @FT_List iterator function which is called during a list */ + /* finalization by @FT_List_Finalize to destroy all elements in a */ + /* given list. */ + /* */ + /* <Input> */ + /* system :: The current system object. */ + /* */ + /* data :: The current object to destroy. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. It can */ + /* be used to point to the iteration's state. */ + /* */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Finalize */ + /* */ + /* <Description> */ + /* Destroys all elements in the list as well as the list itself. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* */ + /* destroy :: A list destructor that will be applied to each element */ + /* of the list. */ + /* */ + /* memory :: The current memory object which handles deallocation. */ + /* */ + /* user :: A user-supplied field which is passed as the last */ + /* argument to the destructor. */ + /* */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTLIST_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftlzw.h b/src/freetype2/freetype/ftlzw.h new file mode 100644 index 0000000..d950653 --- /dev/null +++ b/src/freetype2/freetype/ftlzw.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* ftlzw.h */ +/* */ +/* LZW-compressed stream support. */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTLZW_H__ +#define __FTLZW_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* lzw */ + /* */ + /* <Title> */ + /* LZW Streams */ + /* */ + /* <Abstract> */ + /* Using LZW-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of LZW-specific functions. */ + /* */ + /*************************************************************************/ + + /************************************************************************ + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is + * mainly used to support the compressed `*.pcf.Z' fonts that come + * with XFree86. + * + * @input: + * stream :: The target embedding stream. + * + * source :: The source stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream + * + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it + * and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTLZW_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftmac.h b/src/freetype2/freetype/ftmac.h new file mode 100644 index 0000000..3c6fafe --- /dev/null +++ b/src/freetype2/freetype/ftmac.h @@ -0,0 +1,272 @@ +/***************************************************************************/ +/* */ +/* ftmac.h */ +/* */ +/* Additional Mac-specific API. */ +/* */ +/* Copyright 1996-2001, 2004, 2006, 2007 by */ +/* Just van Rossum, 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. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* NOTE: Include this file after <freetype/freetype.h> and after the */ +/* Mac-specific <Types.h> header (or any other Mac header that */ +/* includes <Types.h>); we use Handle type. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMAC_H__ +#define __FTMAC_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + +/* gcc-3.4.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined(__GNUC__) && \ + ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +#define FT_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* mac_specific */ + /* */ + /* <Title> */ + /* Mac Specific Interface */ + /* */ + /* <Abstract> */ + /* Only available on the Macintosh. */ + /* */ + /* <Description> */ + /* The following definitions are only available if FreeType is */ + /* compiled on a Macintosh. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FOND */ + /* */ + /* <Description> */ + /* Create a new face object from a FOND resource. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* fond :: A FOND resource. */ + /* */ + /* face_index :: Only supported for the -1 `sanity check' special */ + /* case. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Notes> */ + /* This function can be used to create @FT_Face objects from fonts */ + /* that are installed in the system as follows. */ + /* */ + /* { */ + /* fond = GetResource( 'FOND', fontName ); */ + /* error = FT_New_Face_From_FOND( library, fond, 0, &face ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font (e.g., Times New Roman */ + /* Bold). */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFilePath_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return a pathname of the disk file and face index for given font */ + /* name which is handled by ATS framework. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* path :: Buffer to store pathname of the file. For passing */ + /* to @FT_New_Face. The client must allocate this */ + /* buffer before calling this function. */ + /* */ + /* maxPathSize :: Lengths of the buffer `path' that client allocated. */ + /* */ + /* face_index :: Index of the face. For passing to @FT_New_Face. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSSpec */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSSpec to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSSpec to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSSpec is identical to @FT_New_Face except */ + /* it accepts an FSSpec instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSRef */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSRef to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSRef to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSRef is identical to @FT_New_Face except */ + /* it accepts an FSRef instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + /* */ + + +FT_END_HEADER + + +#endif /* __FTMAC_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftmm.h b/src/freetype2/freetype/ftmm.h new file mode 100644 index 0000000..a9ccfe7 --- /dev/null +++ b/src/freetype2/freetype/ftmm.h @@ -0,0 +1,378 @@ +/***************************************************************************/ +/* */ +/* ftmm.h */ +/* */ +/* FreeType Multiple Master font interface (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMM_H__ +#define __FTMM_H__ + + +#include <ft2build.h> +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* multiple_masters */ + /* */ + /* <Title> */ + /* Multiple Masters */ + /* */ + /* <Abstract> */ + /* How to manage Multiple Masters fonts. */ + /* */ + /* <Description> */ + /* The following types and functions are used to manage Multiple */ + /* Master fonts, i.e., the selection of specific design instances by */ + /* setting design axis coordinates. */ + /* */ + /* George Williams has extended this interface to make it work with */ + /* both Type 1 Multiple Masters fonts and GX distortable (var) */ + /* fonts. Some of these routines only work with MM fonts, others */ + /* will work with both types. They are similar enough that a */ + /* consistent interface makes sense. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters fonts. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Multi_Master */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* font. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* num_axis :: Number of axes. Cannot exceed 4. */ + /* */ + /* num_designs :: Number of designs; should be normally 2^num_axis */ + /* even though the Type 1 specification strangely */ + /* allows for intermediate designs to be present. This */ + /* number cannot exceed 16. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters and GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* Not always meaningful for GX. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* def :: The axis's default design coordinate. */ + /* FreeType computes meaningful default values for MM; it */ + /* is then an integer value, not in 16.16 format. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + /* tag :: The axis's tag (the GX equivalent to `name'). */ + /* FreeType provides default values for MM if possible. */ + /* */ + /* strid :: The entry in `name' table (another GX version of */ + /* `name'). */ + /* Not meaningful for MM. */ + /* */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + + FT_ULong tag; + FT_UInt strid; + + } FT_Var_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Named_Style */ + /* */ + /* <Description> */ + /* A simple structure used to model a named style in a GX var font. */ + /* */ + /* This structure can't be used for MM fonts. */ + /* */ + /* <Fields> */ + /* coords :: The design coordinates for this style. */ + /* This is an array with one entry for each axis. */ + /* */ + /* strid :: The entry in `name' table identifying this style. */ + /* */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + + } FT_Var_Named_Style; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Var */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* or GX var distortable font. */ + /* */ + /* Some fields are specific to one format and not to the other. */ + /* */ + /* <Fields> */ + /* num_axis :: The number of axes. The maximum value is 4 for */ + /* MM; no limit in GX. */ + /* */ + /* num_designs :: The number of designs; should be normally */ + /* 2^num_axis for MM fonts. Not meaningful for GX */ + /* (where every glyph could have a different */ + /* number of designs). */ + /* */ + /* num_namedstyles :: The number of named styles; only meaningful for */ + /* GX which allows certain design coordinates to */ + /* have a string ID (in the `name' table) */ + /* associated with them. The font can tell the */ + /* user that, for example, Weight=1.5 is `Bold'. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* GX fonts contain slightly more data than MM. */ + /* */ + /* namedstyles :: A table of named styles. */ + /* Only meaningful with GX. */ + /* */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + + } FT_MM_Var; + + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Multi_Master */ + /* */ + /* <Description> */ + /* Retrieves the Multiple Master descriptor of a given font. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_MM_Var */ + /* */ + /* <Description> */ + /* Retrieves the Multiple Master/GX var descriptor of a given font. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters descriptor. */ + /* Allocates a data structure, which the user must free */ + /* (a single call to FT_FREE will do it). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through design coordinates. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Master or GX Var fonts, choose an interpolated font */ + /* design through design coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Blend_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters and GX var fonts, choose an interpolated font */ + /* design through normalized blend coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates array (each element must be */ + /* between 0 and 1.0). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Blend_Coordinates */ + /* */ + /* <Description> */ + /* This is another name of @FT_Set_MM_Blend_Coordinates. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftmodapi.h b/src/freetype2/freetype/ftmodapi.h new file mode 100644 index 0000000..9cc32af --- /dev/null +++ b/src/freetype2/freetype/ftmodapi.h @@ -0,0 +1,406 @@ +/***************************************************************************/ +/* */ +/* ftmodapi.h */ +/* */ +/* FreeType modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMODAPI_H__ +#define __FTMODAPI_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /* <Title> */ + /* Module Management */ + /* */ + /* <Abstract> */ + /* How to add, upgrade, and remove modules from FreeType. */ + /* */ + /* <Description> */ + /* The definitions below are used to manage modules within FreeType. */ + /* Modules can be added, upgraded, and removed at runtime. */ + /* */ + /*************************************************************************/ + + + /* module bit flags */ +#define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ +#define FT_MODULE_RENDERER 2 /* this module is a renderer */ +#define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ +#define FT_MODULE_STYLER 8 /* this module is a styler */ + +#define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ + /* scalable fonts */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ + /* support vector outlines */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ + /* own hinter */ + + + /* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER + +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER + + + typedef FT_Pointer FT_Module_Interface; + + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); + + typedef void + (*FT_Module_Destructor)( FT_Module module ); + + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Module_Class */ + /* */ + /* <Description> */ + /* The module class descriptor. */ + /* */ + /* <Fields> */ + /* module_flags :: Bit flags describing the module. */ + /* */ + /* module_size :: The size of one module object/instance in */ + /* bytes. */ + /* */ + /* module_name :: The name of the module. */ + /* */ + /* module_version :: The version, as a 16.16 fixed number */ + /* (major.minor). */ + /* */ + /* module_requires :: The version of FreeType this module requires, */ + /* as a 16.16 fixed number (major.minor). Starts */ + /* at version 2.0, i.e., 0x20000. */ + /* */ + /* module_init :: A function used to initialize (not create) a */ + /* new module object. */ + /* */ + /* module_done :: A function used to finalize (not destroy) a */ + /* given module object */ + /* */ + /* get_interface :: Queries a given module for a specific */ + /* interface by name. */ + /* */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Module */ + /* */ + /* <Description> */ + /* Adds a new module to a given library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* clazz :: A pointer to class descriptor for the module. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Module */ + /* */ + /* <Description> */ + /* Finds a module by its name. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* <Return> */ + /* A module handle. 0 if none was found. */ + /* */ + /* <Note> */ + /* FreeType's internal modules aren't documented very well, and you */ + /* should look up the source code for details. */ + /* */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Remove_Module */ + /* */ + /* <Description> */ + /* Removes a given module from a library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to a library object. */ + /* */ + /* <Input> */ + /* module :: A handle to a module object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The module object is destroyed by the function in case of success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Library */ + /* */ + /* <Description> */ + /* This function is used to create a new FreeType library instance */ + /* from a given memory object. It is thus possible to use libraries */ + /* with distinct memory allocators within the same program. */ + /* */ + /* <Input> */ + /* memory :: A handle to the original memory object. */ + /* */ + /* <Output> */ + /* alibrary :: A pointer to handle of a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Library */ + /* */ + /* <Description> */ + /* Discards a given library object. This closes all drivers and */ + /* discards all resource objects. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); + +/* */ + + typedef void + (*FT_DebugHook_Func)( void* arg ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Debug_Hook */ + /* */ + /* <Description> */ + /* Sets a debug hook function for debugging the interpreter of a font */ + /* format. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* hook_index :: The index of the debug hook. You should use the */ + /* values defined in `ftobjs.h', e.g., */ + /* `FT_DEBUG_HOOK_TRUETYPE'. */ + /* */ + /* debug_hook :: The function used to debug the interpreter. */ + /* */ + /* <Note> */ + /* Currently, four debug hook slots are available, but only two (for */ + /* the TrueType and the Type 1 interpreter) are defined. */ + /* */ + /* Since the internal headers of FreeType are no longer installed, */ + /* the symbol `FT_DEBUG_HOOK_TRUETYPE' isn't available publicly. */ + /* This is a bug and will be fixed in a forthcoming release. */ + /* */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Default_Modules */ + /* */ + /* <Description> */ + /* Adds the set of default drivers to a given library object. */ + /* This is only useful when you create a library object with */ + /* @FT_New_Library (usually to plug a custom memory manager). */ + /* */ + /* <InOut> */ + /* library :: A handle to a new library object. */ + /* */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); + + + + /************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode + * engine is implemented in a given FT_Library instance. It is used + * by the @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * The library implements a bytecode interpreter that doesn't + * support the patented operations of the TrueType virtual machine. + * + * Its main use is to load certain Asian fonts which position and + * scale glyph components with bytecode instructions. It produces + * bad output for most other fonts. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers + * the full instruction set of the TrueType virtual machine. + * See the file `docs/PATENTS' for legal aspects. + * + * @since: + * 2.2 + * + */ + typedef enum + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + + } FT_TrueTypeEngineType; + + + /************************************************************************** + * + * @func: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return a @FT_TrueTypeEngineType value to indicate which level of + * the TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMODAPI_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftmoderr.h b/src/freetype2/freetype/ftmoderr.h new file mode 100644 index 0000000..b0115dd --- /dev/null +++ b/src/freetype2/freetype/ftmoderr.h @@ -0,0 +1,155 @@ +/***************************************************************************/ +/* */ +/* ftmoderr.h */ +/* */ +/* FreeType module error offsets (specification). */ +/* */ +/* Copyright 2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the FreeType module error offsets. */ + /* */ + /* The lower byte gives the error code, the higher byte gives the */ + /* module. The base module has error offset 0. For example, the error */ + /* `FT_Err_Invalid_File_Format' has value 0x003, the error */ + /* `TT_Err_Invalid_File_Format' has value 0x1103, the error */ + /* `T1_Err_Invalid_File_Format' has value 0x1203, etc. */ + /* */ + /* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */ + /* to make the higher byte always zero (disabling the module error */ + /* mechanism). */ + /* */ + /* It can also be used to create a module error message table easily */ + /* with something like */ + /* */ + /* { */ + /* #undef __FTMODERR_H__ */ + /* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */ + /* #define FT_MODERR_START_LIST { */ + /* #define FT_MODERR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int mod_err_offset; */ + /* const char* mod_err_msg */ + /* } ft_mod_errors[] = */ + /* */ + /* #include FT_MODULE_ERRORS_H */ + /* } */ + /* */ + /* To use such a table, all errors must be ANDed with 0xFF00 to remove */ + /* the error code. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTMODERR_H__ +#define __FTMODERR_H__ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#ifndef FT_MODERRDEF + +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v, +#else +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#endif + +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_MODERRDEF */ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST MODULE ERROR BASES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + + + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Cache, 0x300, "cache module" ) + FT_MODERRDEF( CFF, 0x400, "CFF module" ) + FT_MODERRDEF( CID, 0x500, "CID module" ) + FT_MODERRDEF( Gzip, 0x600, "Gzip module" ) + FT_MODERRDEF( LZW, 0x700, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x800, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0x900, "PCF module" ) + FT_MODERRDEF( PFR, 0xA00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xB00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xC00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xD00, "PS names module" ) + FT_MODERRDEF( Raster, 0xE00, "raster module" ) + FT_MODERRDEF( SFNT, 0xF00, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1000, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1100, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1200, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1300, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1400, "Windows FON/FNT module" ) + + +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C + + +#endif /* __FTMODERR_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftotval.h b/src/freetype2/freetype/ftotval.h new file mode 100644 index 0000000..7c488fd --- /dev/null +++ b/src/freetype2/freetype/ftotval.h @@ -0,0 +1,198 @@ +/***************************************************************************/ +/* */ +/* ftotval.h */ +/* */ +/* FreeType API for validating OpenType tables (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* */ +/* Warning: This module might be moved to a different library in the */ +/* future to avoid a tight dependency between FreeType and the */ +/* OpenType specification. */ +/* */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOTVAL_H__ +#define __FTOTVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* ot_validation */ + /* */ + /* <Title> */ + /* OpenType Validation */ + /* */ + /* <Abstract> */ + /* An API to validate OpenType tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 + +#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A NULL value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOTVAL_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftoutln.h b/src/freetype2/freetype/ftoutln.h new file mode 100644 index 0000000..786ae13 --- /dev/null +++ b/src/freetype2/freetype/ftoutln.h @@ -0,0 +1,526 @@ +/***************************************************************************/ +/* */ +/* ftoutln.h */ +/* */ +/* Support for the FT_Outline type used to store glyph shapes of */ +/* most scalable font formats (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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 __FTOUTLN_H__ +#define __FTOUTLN_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /* <Title> */ + /* Outline Processing */ + /* */ + /* <Abstract> */ + /* Functions to create, transform, and render vectorial glyph images. */ + /* */ + /* <Description> */ + /* This section contains routines used to create and destroy scalable */ + /* glyph images known as `outlines'. These can also be measured, */ + /* transformed, and converted into bitmaps and pixmaps. */ + /* */ + /* <Order> */ + /* FT_Outline */ + /* FT_OUTLINE_FLAGS */ + /* FT_Outline_New */ + /* FT_Outline_Done */ + /* FT_Outline_Copy */ + /* FT_Outline_Translate */ + /* FT_Outline_Transform */ + /* FT_Outline_Embolden */ + /* FT_Outline_Reverse */ + /* FT_Outline_Check */ + /* */ + /* FT_Outline_Get_CBox */ + /* FT_Outline_Get_BBox */ + /* */ + /* FT_Outline_Get_Bitmap */ + /* FT_Outline_Render */ + /* */ + /* FT_Outline_Decompose */ + /* FT_Outline_Funcs */ + /* FT_Outline_MoveTo_Func */ + /* FT_Outline_LineTo_Func */ + /* FT_Outline_ConicTo_Func */ + /* FT_Outline_CubicTo_Func */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Decompose */ + /* */ + /* <Description> */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bézier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source target. */ + /* */ + /* func_interface :: A table of `emitters', i.e,. function pointers */ + /* called during decomposition to indicate path */ + /* operations. */ + /* */ + /* <InOut> */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_New */ + /* */ + /* <Description> */ + /* Creates a new outline of a given size. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object from where the */ + /* outline is allocated. Note however that the new */ + /* outline will *not* necessarily be *freed*, when */ + /* destroying the library, by @FT_Done_FreeType. */ + /* */ + /* numPoints :: The maximal number of points within the outline. */ + /* */ + /* numContours :: The maximal number of contours within the outline. */ + /* */ + /* <Output> */ + /* anoutline :: A handle to the new outline. NULL in case of */ + /* error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' parameter is simply */ + /* to use the library's memory allocator. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Done */ + /* */ + /* <Description> */ + /* Destroys an outline created with @FT_Outline_New. */ + /* */ + /* <Input> */ + /* library :: A handle of the library object used to allocate the */ + /* outline. */ + /* */ + /* outline :: A pointer to the outline object to be discarded. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If the outline's `owner' field is not set, only the outline */ + /* descriptor will be released. */ + /* */ + /* The reason why this function takes an `library' parameter is */ + /* simply to use ft_mem_free(). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Check */ + /* */ + /* <Description> */ + /* Check the contents of an outline descriptor. */ + /* */ + /* <Input> */ + /* outline :: A handle to a source outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_CBox */ + /* */ + /* <Description> */ + /* Returns an outline's `control box'. The control box encloses all */ + /* the outline's points, including Bézier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bézier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <Output> */ + /* acbox :: The outline's control box. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Translate */ + /* */ + /* <Description> */ + /* Applies a simple translation to the points of an outline. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* xOffset :: The horizontal offset. */ + /* */ + /* yOffset :: The vertical offset. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Copy */ + /* */ + /* <Description> */ + /* Copies an outline into another one. Both objects must have the */ + /* same sizes (number of points & number of contours) when this */ + /* function is called. */ + /* */ + /* <Input> */ + /* source :: A handle to the source outline. */ + /* */ + /* <Output> */ + /* target :: A handle to the target outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Transform */ + /* */ + /* <Description> */ + /* Applies a simple 2x2 matrix to all of an outline's points. Useful */ + /* for applying rotations, slanting, flipping, etc. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation matrix. */ + /* */ + /* <Note> */ + /* You can use @FT_Outline_Translate if you need to translate the */ + /* outline's points. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Embolden */ + /* */ + /* <Description> */ + /* Emboldens an outline. The new outline will be at most 4 times */ + /* `strength' pixels wider and higher. You may think of the left and */ + /* bottom borders as unchanged. */ + /* */ + /* Negative `strength' values to reduce the outline thickness are */ + /* possible also. */ + /* */ + /* <InOut> */ + /* outline :: A handle to the target outline. */ + /* */ + /* <Input> */ + /* strength :: How strong the glyph is emboldened. Expressed in */ + /* 26.6 pixel format. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The used algorithm to increase or decrease the thickness of the */ + /* glyph doesn't change the number of points; this means that certain */ + /* situations like acute angles or intersections are sometimes */ + /* handled incorrectly. */ + /* */ + /* Example call: */ + /* */ + /* { */ + /* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); */ + /* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) */ + /* FT_Outline_Embolden( &face->slot->outline, strength ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Reverse */ + /* */ + /* <Description> */ + /* Reverses the drawing direction of an outline. This is used to */ + /* ensure consistent fill conventions for mirrored glyphs. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Note> */ + /* This functions toggles the bit flag @FT_OUTLINE_REVERSE_FILL in */ + /* the outline's `flags' field. */ + /* */ + /* It shouldn't be used by a normal client application, unless it */ + /* knows what it is doing. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_Bitmap */ + /* */ + /* <Description> */ + /* Renders an outline within a bitmap. The outline's image is simply */ + /* OR-ed to the target bitmap. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the target bitmap descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function does NOT CREATE the bitmap, it only renders an */ + /* outline image within the one you pass to it! */ + /* */ + /* It will use the raster corresponding to the default glyph format. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Render */ + /* */ + /* <Description> */ + /* Renders an outline within a bitmap using the current scan-convert. */ + /* This functions uses an @FT_Raster_Params structure as an argument, */ + /* allowing advanced features like direct composition, translucency, */ + /* etc. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* describe the rendering operation. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You should know what you are doing and how @FT_Raster_Params works */ + /* to use this function. */ + /* */ + /* The field `params.source' will be set to `outline' before the scan */ + /* converter is called, which means that the value you give to it is */ + /* actually ignored. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + + /************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and Postscript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must + * be filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the Postscript specification, counter-clockwise contours + * must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in Postscript, everything that is to the left of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + + } FT_Orientation; + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its + * fill orientation (see @FT_Orientation). This is done by computing + * the direction of each global horizontal and/or vertical extrema + * within the outline. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOUTLN_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftpfr.h b/src/freetype2/freetype/ftpfr.h new file mode 100644 index 0000000..e2801fd --- /dev/null +++ b/src/freetype2/freetype/ftpfr.h @@ -0,0 +1,172 @@ +/***************************************************************************/ +/* */ +/* ftpfr.h */ +/* */ +/* FreeType API for accessing PFR-specific data (specification only). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTPFR_H__ +#define __FTPFR_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* pfr_fonts */ + /* */ + /* <Title> */ + /* PFR Fonts */ + /* */ + /* <Abstract> */ + /* PFR/TrueDoc specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of PFR-specific functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM'. + * Optional (parameter can be NULL). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed + * in metrics units to device sub-pixels. This is equivalent to + * `face->size->x_scale', but for metrics only. Optional (parameter + * can be NULL) + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale' but for the vertical direction. + * optional (parameter can be NULL) + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: A handle to the input face. + * + * left :: Index of the left glyph. + * + * right :: Index of the right glyph. + * + * @output: + * avector :: A kerning vector. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function always return distances in original PFR metrics + * units. This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED + * mode, which always returns distances converted to outline units. + * + * You can use the value of the `x_scale' and `y_scale' parameters + * returned by @FT_Get_PFR_Metrics to scale these to device sub-pixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: A handle to the input face. + * + * gindex :: The glyph index. + * + * @output: + * aadvance :: The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You can use the `x_scale' or `y_scale' results of @FT_Get_PFR_Metrics + * to convert the advance to device sub-pixels (i.e., 1/64th of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTPFR_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftrender.h b/src/freetype2/freetype/ftrender.h new file mode 100644 index 0000000..5b07f08 --- /dev/null +++ b/src/freetype2/freetype/ftrender.h @@ -0,0 +1,229 @@ +/***************************************************************************/ +/* */ +/* ftrender.h */ +/* */ +/* FreeType renderer modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTRENDER_H__ +#define __FTRENDER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /*************************************************************************/ + + + /* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + + + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + + + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_UInt mode, + const FT_Vector* origin ); + + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Renderer_Class */ + /* */ + /* <Description> */ + /* The renderer module class descriptor. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Module_Class fields. */ + /* */ + /* glyph_format :: The glyph image format this renderer handles. */ + /* */ + /* render_glyph :: A method used to render the image that is in a */ + /* given glyph slot into a bitmap. */ + /* */ + /* set_mode :: A method used to pass additional parameters. */ + /* */ + /* raster_class :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. This */ + /* is a pointer to its raster's class. */ + /* */ + /* raster :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. This */ + /* is a pointer to the corresponding raster object, */ + /* if any. */ + /* */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + + FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Renderer */ + /* */ + /* <Description> */ + /* Retrieves the current renderer for a given glyph format. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* format :: The glyph format. */ + /* */ + /* <Return> */ + /* A renderer handle. 0 if none found. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + /* To add a new renderer, simply use @FT_Add_Module. To retrieve a */ + /* renderer by its name, use @FT_Get_Module. */ + /* */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Renderer */ + /* */ + /* <Description> */ + /* Sets the current renderer to use, and set additional mode. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* renderer :: A handle to the renderer object. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* parameters :: Additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* In case of success, the renderer will be used to convert glyph */ + /* images in the renderer's known format into bitmaps. */ + /* */ + /* This doesn't change the current renderer for other formats. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTRENDER_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftsizes.h b/src/freetype2/freetype/ftsizes.h new file mode 100644 index 0000000..622df16 --- /dev/null +++ b/src/freetype2/freetype/ftsizes.h @@ -0,0 +1,159 @@ +/***************************************************************************/ +/* */ +/* ftsizes.h */ +/* */ +/* FreeType size objects management (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Typical application would normally not need to use these functions. */ + /* However, they have been placed in a public API for the rare cases */ + /* where they are needed. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSIZES_H__ +#define __FTSIZES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sizes_management */ + /* */ + /* <Title> */ + /* Size Management */ + /* */ + /* <Abstract> */ + /* Managing multiple sizes per face. */ + /* */ + /* <Description> */ + /* When creating a new face object (e.g., with @FT_New_Face), an */ + /* @FT_Size object is automatically created and used to store all */ + /* pixel-size dependent information, available in the `face->size' */ + /* field. */ + /* */ + /* It is however possible to create more sizes for a given face, */ + /* mostly in order to manage several character pixel sizes of the */ + /* same font family and style. See @FT_New_Size and @FT_Done_Size. */ + /* */ + /* Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only */ + /* modify the contents of the current `active' size; you thus need */ + /* to use @FT_Activate_Size to change it. */ + /* */ + /* 99% of applications won't need the functions provided here, */ + /* especially if they use the caching sub-system, so be cautious */ + /* when using these. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Size */ + /* */ + /* <Description> */ + /* Create a new size object from a given face object. */ + /* */ + /* <Input> */ + /* face :: A handle to a parent face object. */ + /* */ + /* <Output> */ + /* asize :: A handle to a new size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You need to call @FT_Activate_Size in order to select the new size */ + /* for upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, */ + /* @FT_Load_Glyph, @FT_Load_Char, etc. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Size */ + /* */ + /* <Description> */ + /* Discard a given size object. Note that @FT_Done_Face */ + /* automatically discards all size objects allocated with */ + /* @FT_New_Size. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Activate_Size */ + /* */ + /* <Description> */ + /* Even though it is possible to create several size objects for a */ + /* given face (see @FT_New_Size for details), functions like */ + /* @FT_Load_Glyph or @FT_Load_Char only use the last-created one to */ + /* determine the `current character pixel size'. */ + /* */ + /* This function can be used to `activate' a previously created size */ + /* object. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If `face' is the size's parent face object, this function changes */ + /* the value of `face->size' to the input size handle. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTSIZES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftsnames.h b/src/freetype2/freetype/ftsnames.h new file mode 100644 index 0000000..003cbcd --- /dev/null +++ b/src/freetype2/freetype/ftsnames.h @@ -0,0 +1,170 @@ +/***************************************************************************/ +/* */ +/* ftsnames.h */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (specification). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_SFNT_NAMES_H__ +#define __FT_SFNT_NAMES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sfnt_names */ + /* */ + /* <Title> */ + /* SFNT Names */ + /* */ + /* <Abstract> */ + /* Access the names embedded in TrueType and OpenType files. */ + /* */ + /* <Description> */ + /* The TrueType and OpenType specification allow the inclusion of */ + /* a special `names table' in font files. This table contains */ + /* textual (and internationalized) information regarding the font, */ + /* like family name, copyright, version, etc. */ + /* */ + /* The definitions below are used to access them if available. */ + /* */ + /* Note that this has nothing to do with glyph names! */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SfntName */ + /* */ + /* <Description> */ + /* A structure used to model an SFNT `name' table entry. */ + /* */ + /* <Fields> */ + /* platform_id :: The platform ID for `string'. */ + /* */ + /* encoding_id :: The encoding ID for `string'. */ + /* */ + /* language_id :: The language ID for `string'. */ + /* */ + /* name_id :: An identifier for `string'. */ + /* */ + /* string :: The `name' string. Note that its format differs */ + /* depending on the (platform,encoding) pair. It can */ + /* be a Pascal String, a UTF-16 one, etc. */ + /* */ + /* Generally speaking, the string is not */ + /* zero-terminated. Please refer to the TrueType */ + /* specification for details. */ + /* */ + /* string_len :: The length of `string' in bytes. */ + /* */ + /* <Note> */ + /* Possible values for `platform_id', `encoding_id', `language_id', */ + /* and `name_id' are given in the file `ttnameid.h'. For details */ + /* please refer to the TrueType or OpenType specification. */ + /* */ + /* See also @TT_PLATFORM_XXX, @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, */ + /* @TT_ISO_ID_XXX, and @TT_MS_ID_XXX. */ + /* */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name_Count */ + /* */ + /* <Description> */ + /* Retrieves the number of name strings in the SFNT `name' table. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Return> */ + /* The number of strings in the `name' table. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name */ + /* */ + /* <Description> */ + /* Retrieves a string of the SFNT `name' table for a given index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* idx :: The index of the `name' string. */ + /* */ + /* <Output> */ + /* aname :: The indexed @FT_SfntName structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `string' array returned in the `aname' structure is not */ + /* null-terminated. */ + /* */ + /* Use @FT_Get_Sfnt_Name_Count to get the total number of available */ + /* `name' table entries, then do a loop until you get the right */ + /* platform, encoding, and name ID. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FT_SFNT_NAMES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftstroke.h b/src/freetype2/freetype/ftstroke.h new file mode 100644 index 0000000..738b43c --- /dev/null +++ b/src/freetype2/freetype/ftstroke.h @@ -0,0 +1,716 @@ +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_STROKE_H__ +#define __FT_STROKE_H__ + +#include <ft2build.h> +#include FT_OUTLINE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************ + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial + * glyph. It also allows you to retrieve the `outside' and/or the + * `inside' borders of the stroke. + * + * This can be useful to generate `bordered' glyph, i.e., glyphs + * displayed with a coloured (and anti-aliased) border around their + * shape. + */ + + + /************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins; i.e., the two joining lines + * are extended until they intersect. + * + * FT_STROKER_LINEJOIN_MITER :: + * Same as beveled rendering, except that an additional line + * break is added if the angle between the two joining lines + * is too closed (this is useful to avoid unpleasant spikes + * in beveled rendering). + */ + typedef enum + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL, + FT_STROKER_LINEJOIN_MITER + + } FT_Stroker_LineJoin; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ + typedef enum + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + + } FT_Stroker_LineCap; + + + /************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + + /************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `inside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `outside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the FT_STROKER_LINEJOIN_MITER style, + * expressed as 16.16 fixed point value. + * + * @note: + * The radius is expressed in the same units that the outline + * coordinates. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. + * You should call this function before beginning a new + * series of calls to @FT_Stroker_BeginSubPath or + * @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If 1, the outline is treated as an open path instead + * of a closed one. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If `opened' is 0 (the default), the outline is treated as a closed + * path, and the stroker will generate two distinct `border' outlines. + * + * If `opened' is 1, the outline is processed as an open path, and the + * stroker will generate a single `stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); + + + /************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If 1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function is useful when you need to stroke a path that is + * not stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); + + + /************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. + * If the subpath was not `opened', this function will `draw' a + * single line segment to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * `Draw' a single line segment in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * `Draw' a single quadratic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * `Draw' a single cubic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first Bézier control point. + * + * control2 :: + * A pointer to second Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It will return the number of points and + * contours necessary to export one of the `border' or `stroke' + * outlines generated by the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right'. + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to + * retrieve the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * Note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right' + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the all borders to your own @FT_Outline structure. + * + * Note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If 1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); + + + /************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but + * only return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If 1, return the inside border, otherwise + * the outside border. + * + * destroy :: + * A Boolean. If 1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); + + /* */ + +FT_END_HEADER + +#endif /* __FT_STROKE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftsynth.h b/src/freetype2/freetype/ftsynth.h new file mode 100644 index 0000000..36984bf --- /dev/null +++ b/src/freetype2/freetype/ftsynth.h @@ -0,0 +1,73 @@ +/***************************************************************************/ +/* */ +/* ftsynth.h */ +/* */ +/* FreeType synthesizing code for emboldening and slanting */ +/* (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE, THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTSYNTH_H__ +#define __FTSYNTH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /* Make sure slot owns slot->bitmap. */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); + + /* Do not use this function directly! Copy the code to */ + /* your application and modify it to suit your need. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); + + + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + + /* */ + +FT_END_HEADER + +#endif /* __FTSYNTH_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftsystem.h b/src/freetype2/freetype/ftsystem.h new file mode 100644 index 0000000..59cd019 --- /dev/null +++ b/src/freetype2/freetype/ftsystem.h @@ -0,0 +1,346 @@ +/***************************************************************************/ +/* */ +/* ftsystem.h */ +/* */ +/* FreeType low-level system interface definition (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __FTSYSTEM_H__ +#define __FTSYSTEM_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* system_interface */ + /* */ + /* <Title> */ + /* System Interface */ + /* */ + /* <Abstract> */ + /* How FreeType manages memory and i/o. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to memory */ + /* management and i/o access. You need to understand this */ + /* information if you want to use a custom memory manager or you own */ + /* i/o streams. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* M E M O R Y M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; + + + /************************************************************************* + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size' bytes from `memory'. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0 in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + + /************************************************************************* + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); + + + /************************************************************************* + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0 in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + /************************************************************************* + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType 2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /*************************************************************************/ + /* */ + /* I / O M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + */ + typedef struct FT_StreamRec_* FT_Stream; + + + /************************************************************************* + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*' in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + /************************************************************************* + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset of read in stream (always from start). + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * The number of bytes effectively read by the stream. + * + * @note: + * This function might be called to perform a seek or skip operation + * with a `count' of 0. + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + + /************************************************************************* + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); + + + /************************************************************************* + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to NULL for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*' + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream;s close function. + * + * memory :: + * The memory manager to use to preload frames. This is set + * internally by FreeType and shouldn't be touched by stream + * implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + + } FT_StreamRec; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTSYSTEM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/fttrigon.h b/src/freetype2/freetype/fttrigon.h new file mode 100644 index 0000000..6b77d2e --- /dev/null +++ b/src/freetype2/freetype/fttrigon.h @@ -0,0 +1,350 @@ +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 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 __FTTRIGON_H__ +#define __FTTRIGON_H__ + +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed float value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) + + + /************************************************************************* + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************* + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTTRIGON_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/fttypes.h b/src/freetype2/freetype/fttypes.h new file mode 100644 index 0000000..2340bac --- /dev/null +++ b/src/freetype2/freetype/fttypes.h @@ -0,0 +1,583 @@ +/***************************************************************************/ +/* */ +/* fttypes.h */ +/* */ +/* FreeType simple types definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 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 __FTTYPES_H__ +#define __FTTYPES_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_SYSTEM_H +#include FT_IMAGE_H + +#include <stddef.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /* <Title> */ + /* Basic Data Types */ + /* */ + /* <Abstract> */ + /* The basic data types defined by the library. */ + /* */ + /* <Description> */ + /* This section contains the basic data types defined by FreeType 2, */ + /* ranging from simple scalar types to bitmap descriptors. More */ + /* font-specific structures are defined in a different section. */ + /* */ + /* <Order> */ + /* FT_Byte */ + /* FT_Bytes */ + /* FT_Char */ + /* FT_Int */ + /* FT_UInt */ + /* FT_Short */ + /* FT_UShort */ + /* FT_Long */ + /* FT_ULong */ + /* FT_Bool */ + /* FT_Offset */ + /* FT_PtrDist */ + /* FT_String */ + /* FT_Tag */ + /* FT_Error */ + /* FT_Fixed */ + /* FT_Pointer */ + /* FT_Pos */ + /* FT_Vector */ + /* FT_BBox */ + /* FT_Matrix */ + /* FT_FWord */ + /* FT_UFWord */ + /* FT_F2Dot14 */ + /* FT_UnitVector */ + /* FT_F26Dot6 */ + /* */ + /* */ + /* FT_Generic */ + /* FT_Generic_Finalizer */ + /* */ + /* FT_Bitmap */ + /* FT_Pixel_Mode */ + /* FT_Palette_Mode */ + /* FT_Glyph_Format */ + /* FT_IMAGE_TAG */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bool */ + /* */ + /* <Description> */ + /* A typedef of unsigned char, used for simple booleans. As usual, */ + /* values 1 and 0 represent true and false, respectively. */ + /* */ + typedef unsigned char FT_Bool; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_FWord */ + /* */ + /* <Description> */ + /* A signed 16-bit integer used to store a distance in original font */ + /* units. */ + /* */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UFWord */ + /* */ + /* <Description> */ + /* An unsigned 16-bit integer used to store a distance in original */ + /* font units. */ + /* */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Char */ + /* */ + /* <Description> */ + /* A simple typedef for the _signed_ char type. */ + /* */ + typedef signed char FT_Char; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Byte */ + /* */ + /* <Description> */ + /* A simple typedef for the _unsigned_ char type. */ + /* */ + typedef unsigned char FT_Byte; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bytes */ + /* */ + /* <Description> */ + /* A typedef for constant memory areas. */ + /* */ + typedef const FT_Byte* FT_Bytes; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Tag */ + /* */ + /* <Description> */ + /* A typedef for 32bit tags (as used in the SFNT format). */ + /* */ + typedef FT_UInt32 FT_Tag; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_String */ + /* */ + /* <Description> */ + /* A simple typedef for the char type, usually used for strings. */ + /* */ + typedef char FT_String; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Short */ + /* */ + /* <Description> */ + /* A typedef for signed short. */ + /* */ + typedef signed short FT_Short; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UShort */ + /* */ + /* <Description> */ + /* A typedef for unsigned short. */ + /* */ + typedef unsigned short FT_UShort; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Int */ + /* */ + /* <Description> */ + /* A typedef for the int type. */ + /* */ + typedef signed int FT_Int; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UInt */ + /* */ + /* <Description> */ + /* A typedef for the unsigned int type. */ + /* */ + typedef unsigned int FT_UInt; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Long */ + /* */ + /* <Description> */ + /* A typedef for signed long. */ + /* */ + typedef signed long FT_Long; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ULong */ + /* */ + /* <Description> */ + /* A typedef for unsigned long. */ + /* */ + typedef unsigned long FT_ULong; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F2Dot14 */ + /* */ + /* <Description> */ + /* A signed 2.14 fixed float type used for unit vectors. */ + /* */ + typedef signed short FT_F2Dot14; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F26Dot6 */ + /* */ + /* <Description> */ + /* A signed 26.6 fixed float type used for vectorial pixel */ + /* coordinates. */ + /* */ + typedef signed long FT_F26Dot6; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Fixed */ + /* */ + /* <Description> */ + /* This type is used to store 16.16 fixed float values, like scaling */ + /* values or matrix coefficients. */ + /* */ + typedef signed long FT_Fixed; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Error */ + /* */ + /* <Description> */ + /* The FreeType error code type. A value of 0 is always interpreted */ + /* as a successful operation. */ + /* */ + typedef int FT_Error; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pointer */ + /* */ + /* <Description> */ + /* A simple typedef for a typeless pointer. */ + /* */ + typedef void* FT_Pointer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Offset */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI C `size_t' type, i.e., the largest */ + /* _unsigned_ integer type used to express a file size or position, */ + /* or a memory block size. */ + /* */ + typedef size_t FT_Offset; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_PtrDist */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI C `ptrdiff_t' type, i.e., the */ + /* largest _signed_ integer type used to express the distance */ + /* between two pointers. */ + /* */ + typedef ft_ptrdiff_t FT_PtrDist; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_UnitVector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector unit vector. Uses */ + /* FT_F2Dot14 types. */ + /* */ + /* <Fields> */ + /* x :: Horizontal coordinate. */ + /* */ + /* y :: Vertical coordinate. */ + /* */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Matrix */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2x2 matrix. Coefficients are */ + /* in 16.16 fixed float format. The computation performed is: */ + /* */ + /* { */ + /* x' = x*xx + y*xy */ + /* y' = x*yx + y*yy */ + /* } */ + /* */ + /* <Fields> */ + /* xx :: Matrix coefficient. */ + /* */ + /* xy :: Matrix coefficient. */ + /* */ + /* yx :: Matrix coefficient. */ + /* */ + /* yy :: Matrix coefficient. */ + /* */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Data */ + /* */ + /* <Description> */ + /* Read-only binary data represented as a pointer and a length. */ + /* */ + /* <Fields> */ + /* pointer :: The data. */ + /* */ + /* length :: The length of the data in bytes. */ + /* */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_Int length; + + } FT_Data; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Generic_Finalizer */ + /* */ + /* <Description> */ + /* Describes a function used to destroy the `client' data of any */ + /* FreeType object. See the description of the @FT_Generic type for */ + /* details of usage. */ + /* */ + /* <Input> */ + /* The address of the FreeType object which is under finalization. */ + /* Its client data is accessed through its `generic' field. */ + /* */ + typedef void (*FT_Generic_Finalizer)(void* object); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Generic */ + /* */ + /* <Description> */ + /* Client applications often need to associate their own data to a */ + /* variety of FreeType core objects. For example, a text layout API */ + /* might want to associate a glyph cache to a given size object. */ + /* */ + /* Most FreeType object contains a `generic' field, of type */ + /* FT_Generic, which usage is left to client applications and font */ + /* servers. */ + /* */ + /* It can be used to store a pointer to client-specific data, as well */ + /* as the address of a `finalizer' function, which will be called by */ + /* FreeType when the object is destroyed (for example, the previous */ + /* client example would put the address of the glyph cache destructor */ + /* in the `finalizer' field). */ + /* */ + /* <Fields> */ + /* data :: A typeless pointer to any client-specified data. This */ + /* field is completely ignored by the FreeType library. */ + /* */ + /* finalizer :: A pointer to a `generic finalizer' function, which */ + /* will be called when the object is destroyed. If this */ + /* field is set to NULL, no code will be called. */ + /* */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_MAKE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags which are used to label */ + /* TrueType tables into an unsigned long to be used within FreeType. */ + /* */ + /* <Note> */ + /* The produced values *must* be 32bit integers. Don't redefine this */ + /* macro. */ + /* */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ListNode */ + /* */ + /* <Description> */ + /* Many elements and objects in FreeType are listed through an */ + /* @FT_List record (see @FT_ListRec). As its name suggests, an */ + /* FT_ListNode is a handle to a single list element. */ + /* */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_List */ + /* */ + /* <Description> */ + /* A handle to a list record (see @FT_ListRec). */ + /* */ + typedef struct FT_ListRec_* FT_List; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListNodeRec */ + /* */ + /* <Description> */ + /* A structure used to hold a single list element. */ + /* */ + /* <Fields> */ + /* prev :: The previous element in the list. NULL if first. */ + /* */ + /* next :: The next element in the list. NULL if last. */ + /* */ + /* data :: A typeless pointer to the listed object. */ + /* */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListRec */ + /* */ + /* <Description> */ + /* A structure used to hold a simple doubly-linked list. These are */ + /* used in many parts of FreeType. */ + /* */ + /* <Fields> */ + /* head :: The head (first element) of doubly-linked list. */ + /* */ + /* tail :: The tail (last element) of doubly-linked list. */ + /* */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + + /* */ + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) + + /* return base error code (without module-specific prefix) */ +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) + + /* return module error code */ +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) + +#define FT_BOOL( x ) ( (FT_Bool)( x ) ) + +FT_END_HEADER + +#endif /* __FTTYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ftwinfnt.h b/src/freetype2/freetype/ftwinfnt.h new file mode 100644 index 0000000..a0063cc --- /dev/null +++ b/src/freetype2/freetype/ftwinfnt.h @@ -0,0 +1,263 @@ +/***************************************************************************/ +/* */ +/* ftwinfnt.h */ +/* */ +/* FreeType API for accessing Windows fnt-specific data. */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTWINFNT_H__ +#define __FTWINFNT_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* winfnt_fonts */ + /* */ + /* <Title> */ + /* Window FNT Files */ + /* */ + /* <Abstract> */ + /* Windows FNT specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Windows FNT specific */ + /* functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset' byte in + * @FT_WinFNT_HeaderRec. Exact mapping tables for the various cpXXXX + * encodings (except for cp1361) can be found at ftp://ftp.unicode.org + * in the MAPPINGS/VENDORS/MICSFT/WINDOWS subdirectory. cp1361 is + * roughly a superset of MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a + * `don't care' value. Valid font files don't contain this value. + * When querying for information about the character set of the font + * that is currently selected into a specified device context, this + * return value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Pöttgen <michael@poettgen.de>: + * + * The `Windows Font Mapping' article says that FT_WinFNT_ID_OEM + * is used for the charset of vector fonts, like `modern.fon', + * `roman.fon', and `script.fon' on Windows. + * + * The `CreateFont' documentation says: The FT_WinFNT_ID_OEM value + * specifies a character set that is operating-system dependent. + * + * The `IFIMETRICS' documentation from the `Windows Driver + * Development Kit' says: This font supports an OEM-specific + * character set. The OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., cp1252), denotes the + * second default codepage that most international versions of + * Windows have. It is one of the OEM codepages from + * + * http://www.microsoft.com/globaldev/reference/cphome.mspx, + * + * and is used for the `DOS boxes', to support legacy applications. + * A German Windows version for example usually uses ANSI codepage + * 1252 and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS C 5601-1987 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big 5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ + +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_WinFNT_HeaderRec */ + /* */ + /* <Description> */ + /* Windows FNT Header info. */ + /* */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + + } FT_WinFNT_HeaderRec, *FT_WinFNT_Header; + + + /********************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: A handle to the input face. + * + * @output: + * aheader :: The WinFNT header. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + /* */ + +FT_END_HEADER + +#endif /* __FTWINFNT_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/src/freetype2/freetype/ftxf86.h b/src/freetype2/freetype/ftxf86.h new file mode 100644 index 0000000..ea82abb --- /dev/null +++ b/src/freetype2/freetype/ftxf86.h @@ -0,0 +1,80 @@ +/***************************************************************************/ +/* */ +/* ftxf86.h */ +/* */ +/* Support functions for X11. */ +/* */ +/* Copyright 2002, 2003, 2004, 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 __FTXF86_H__ +#define __FTXF86_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* font_formats */ + /* */ + /* <Title> */ + /* Font Formats */ + /* */ + /* <Abstract> */ + /* Getting the font format. */ + /* */ + /* <Description> */ + /* The single function in this section can be used to get the font */ + /* format. Note that this information is not needed normally; */ + /* however, there are special cases (like in PDF devices) where it is */ + /* important to differentiate, in spite of FreeType's uniform API. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_X11_Font_Format */ + /* */ + /* <Description> */ + /* Return a string describing the format of a given face, using values */ + /* which can be used as an X11 FONT_PROPERTY. Possible values are */ + /* `TrueType', `Type 1', `BDF', `PCF', `Type 42', `CID Type 1', `CFF', */ + /* `PFR', and `Windows FNT'. */ + /* */ + /* <Input> */ + /* face :: */ + /* Input face handle. */ + /* */ + /* <Return> */ + /* Font format string. NULL in case of error. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); + + /* */ + +FT_END_HEADER + +#endif /* __FTXF86_H__ */ diff --git a/src/freetype2/freetype/internal/autohint.h b/src/freetype2/freetype/internal/autohint.h new file mode 100644 index 0000000..ee00402 --- /dev/null +++ b/src/freetype2/freetype/internal/autohint.h @@ -0,0 +1,205 @@ +/***************************************************************************/ +/* */ +/* autohint.h */ +/* */ +/* High-level `autohint' module-specific interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The auto-hinter is used to load and automatically hint glyphs if a */ + /* format-specific hinter isn't available. */ + /* */ + /*************************************************************************/ + + +#ifndef __AUTOHINT_H__ +#define __AUTOHINT_H__ + + + /*************************************************************************/ + /* */ + /* A small technical note regarding automatic hinting in order to */ + /* clarify this module interface. */ + /* */ + /* An automatic hinter might compute two kinds of data for a given face: */ + /* */ + /* - global hints: Usually some metrics that describe global properties */ + /* of the face. It is computed by scanning more or less */ + /* aggressively the glyphs in the face, and thus can be */ + /* very slow to compute (even if the size of global */ + /* hints is really small). */ + /* */ + /* - glyph hints: These describe some important features of the glyph */ + /* outline, as well as how to align them. They are */ + /* generally much faster to compute than global hints. */ + /* */ + /* The current FreeType auto-hinter does a pretty good job while */ + /* performing fast computations for both global and glyph hints. */ + /* However, we might be interested in introducing more complex and */ + /* powerful algorithms in the future, like the one described in the John */ + /* D. Hobby paper, which unfortunately requires a lot more horsepower. */ + /* */ + /* Because a sufficiently sophisticated font management system would */ + /* typically implement an LRU cache of opened face objects to reduce */ + /* memory usage, it is a good idea to be able to avoid recomputing */ + /* global hints every time the same face is re-opened. */ + /* */ + /* We thus provide the ability to cache global hints outside of the face */ + /* object, in order to speed up font re-opening time. Of course, this */ + /* feature is purely optional, so most client programs won't even notice */ + /* it. */ + /* */ + /* I initially thought that it would be a good idea to cache the glyph */ + /* hints too. However, my general idea now is that if you really need */ + /* to cache these too, you are simply in need of a new font format, */ + /* where all this information could be stored within the font file and */ + /* decoded on the fly. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalGetFunc */ + /* */ + /* <Description> */ + /* Retrieves the global hints computed for a given face object the */ + /* resulting data is dissociated from the face and will survive a */ + /* call to FT_Done_Face(). It must be discarded through the API */ + /* FT_AutoHinter_GlobalDoneFunc(). */ + /* */ + /* <Input> */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* <Output> */ + /* global_hints :: A typeless pointer to the global hints. */ + /* */ + /* global_len :: The size in bytes of the global hints. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalDoneFunc */ + /* */ + /* <Description> */ + /* Discards the global hints retrieved through */ + /* FT_AutoHinter_GlobalGetFunc(). This is the only way these hints */ + /* are freed from memory. */ + /* */ + /* <Input> */ + /* hinter :: A handle to the auto-hinter module. */ + /* */ + /* global :: A pointer to retrieved global hints to discard. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, + void* global ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalResetFunc */ + /* */ + /* <Description> */ + /* This function is used to recompute the global metrics in a given */ + /* font. This is useful when global font data changes (e.g. Multiple */ + /* Masters fonts where blend coordinates change). */ + /* */ + /* <Input> */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the face. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, + FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlyphLoadFunc */ + /* */ + /* <Description> */ + /* This function is used to load, scale, and automatically hint a */ + /* glyph from a given face. */ + /* */ + /* <Input> */ + /* face :: A handle to the face. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* load_flags :: The load flags. */ + /* */ + /* <Note> */ + /* This function is capable of loading composite glyphs by hinting */ + /* each sub-glyph independently (which improves quality). */ + /* */ + /* It will call the font driver with FT_Load_Glyph(), with */ + /* FT_LOAD_NO_SCALE set. */ + /* */ + typedef FT_Error + (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_AutoHinter_ServiceRec */ + /* */ + /* <Description> */ + /* The auto-hinter module's interface. */ + /* */ + typedef struct FT_AutoHinter_ServiceRec_ + { + FT_AutoHinter_GlobalResetFunc reset_face; + FT_AutoHinter_GlobalGetFunc get_global_hints; + FT_AutoHinter_GlobalDoneFunc done_global_hints; + FT_AutoHinter_GlyphLoadFunc load_glyph; + + } FT_AutoHinter_ServiceRec, *FT_AutoHinter_Service; + + +FT_END_HEADER + +#endif /* __AUTOHINT_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftcalc.h b/src/freetype2/freetype/internal/ftcalc.h new file mode 100644 index 0000000..c7e9901 --- /dev/null +++ b/src/freetype2/freetype/internal/ftcalc.h @@ -0,0 +1,153 @@ +/***************************************************************************/ +/* */ +/* ftcalc.h */ +/* */ +/* Arithmetic computations (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCALC_H__ +#define __FTCALC_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_FixedSqrt */ + /* */ + /* <Description> */ + /* Computes the square root of a 16.16 fixed point value. */ + /* */ + /* <Input> */ + /* x :: The value to compute the root for. */ + /* */ + /* <Return> */ + /* The result of `sqrt(x)'. */ + /* */ + /* <Note> */ + /* This function is not very fast. */ + /* */ + FT_BASE( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Sqrt32 */ + /* */ + /* <Description> */ + /* Computes the square root of an Int32 integer (which will be */ + /* handled as an unsigned long value). */ + /* */ + /* <Input> */ + /* x :: The value to compute the root for. */ + /* */ + /* <Return> */ + /* The result of `sqrt(x)'. */ + /* */ + FT_EXPORT( FT_Int32 ) + FT_Sqrt32( FT_Int32 x ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulDiv_No_Round */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* (without rounding) with maximal accuracy (it uses a 64-bit */ + /* intermediate integer whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* <Return> */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_BASE( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* + * Return -1, 0, or +1, depending on the orientation of a given corner. + * We use the Cartesian coordinate system, with positive vertical values + * going upwards. The function returns +1 if the corner turns to the + * left, -1 to the right, and 0 for undecidable cases. + */ + FT_BASE( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + /* + * Return TRUE if a corner is flat or nearly flat. This is equivalent to + * saying that the angle difference between the `in' and `out' vectors is + * very small. + */ + FT_BASE( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) +#define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 ) +#define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) ) + +#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ + : ( -( ( 32 - (x) ) & -64 ) ) ) + + +FT_END_HEADER + +#endif /* __FTCALC_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftdebug.h b/src/freetype2/freetype/internal/ftdebug.h new file mode 100644 index 0000000..1562714 --- /dev/null +++ b/src/freetype2/freetype/internal/ftdebug.h @@ -0,0 +1,244 @@ +/***************************************************************************/ +/* */ +/* ftdebug.h */ +/* */ +/* Debugging and logging component (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 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. */ +/* */ +/* */ +/* IMPORTANT: A description of FreeType's debugging support can be */ +/* found in `docs/DEBUG.TXT'. Read it if you need to use or */ +/* understand this code. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTDEBUG_H__ +#define __FTDEBUG_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ + /* is already defined; this simplifies the following #ifdefs */ + /* */ +#ifdef FT_DEBUG_LEVEL_TRACE +#undef FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_ERROR +#endif + + + /*************************************************************************/ + /* */ + /* Define the trace enums as well as the trace levels array when they */ + /* are needed. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE_DEF( x ) trace_ ## x , + + /* defining the enumeration */ + typedef enum + { +#include FT_INTERNAL_TRACE_H + trace_count + + } FT_Trace; + + + /* defining the array of trace levels, provided by `src/base/ftdebug.c' */ + extern int ft_trace_levels[trace_count]; + +#undef FT_TRACE_DEF + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Define the FT_TRACE macro */ + /* */ + /* IMPORTANT! */ + /* */ + /* Each component must define the macro FT_COMPONENT to a valid FT_Trace */ + /* value before using any TRACE macro. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_COMPONENT] >= level ) \ + FT_Message varformat; \ + } while ( 0 ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE( level, varformat ) do ; while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Trace_Get_Count */ + /* */ + /* <Description> */ + /* Return the number of available trace components. */ + /* */ + /* <Return> */ + /* The number of trace components. 0 if FreeType 2 is not built with */ + /* FT_DEBUG_LEVEL_TRACE definition. */ + /* */ + /* <Note> */ + /* This function may be useful if you want to access elements of */ + /* the internal `ft_trace_levels' array by an index. */ + /* */ + FT_BASE( FT_Int ) + FT_Trace_Get_Count( void ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Trace_Get_Name */ + /* */ + /* <Description> */ + /* Return the name of a trace component. */ + /* */ + /* <Input> */ + /* The index of the trace component. */ + /* */ + /* <Return> */ + /* The name of the trace component. This is a statically allocated */ + /* C string, so do not free it after use. NULL if FreeType 2 is not */ + /* built with FT_DEBUG_LEVEL_TRACE definition. */ + /* */ + /* <Note> */ + /* Use @FT_Trace_Get_Count to get the number of available trace */ + /* components. */ + /* */ + /* This function may be useful if you want to control FreeType 2's */ + /* debug level in your application. */ + /* */ + FT_BASE( const char * ) + FT_Trace_Get_Name( FT_Int idx ); + + + /*************************************************************************/ + /* */ + /* You need two opening resp. closing parentheses! */ + /* */ + /* Example: FT_TRACE0(( "Value is %i", foo )) */ + /* */ + /*************************************************************************/ + +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) + + + /*************************************************************************/ + /* */ + /* Define the FT_ERROR macro */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ERROR( varformat ) FT_Message varformat + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ERROR( varformat ) do ; while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* Define the FT_ASSERT macro */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ASSERT( condition ) \ + do \ + { \ + if ( !( condition ) ) \ + FT_Panic( "assertion failed on line %d of file %s\n", \ + __LINE__, __FILE__ ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ASSERT( condition ) do ; while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* Define `FT_Message' and `FT_Panic' when needed */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#include "stdio.h" /* for vprintf() */ + + /* print a message */ + FT_BASE( void ) + FT_Message( const char* fmt, ... ); + + /* print a message and exit */ + FT_BASE( void ) + FT_Panic( const char* fmt, ... ); + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + + FT_BASE( void ) + ft_debug_init( void ); + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* we disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ + + +FT_END_HEADER + +#endif /* __FTDEBUG_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftdriver.h b/src/freetype2/freetype/internal/ftdriver.h new file mode 100644 index 0000000..97f3fd0 --- /dev/null +++ b/src/freetype2/freetype/internal/ftdriver.h @@ -0,0 +1,252 @@ +/***************************************************************************/ +/* */ +/* ftdriver.h */ +/* */ +/* FreeType font driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTDRIVER_H__ +#define __FTDRIVER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + typedef FT_Error + (*FT_Face_InitFunc)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + + typedef void + (*FT_Face_DoneFunc)( FT_Face face ); + + + typedef FT_Error + (*FT_Size_InitFunc)( FT_Size size ); + + typedef void + (*FT_Size_DoneFunc)( FT_Size size ); + + + typedef FT_Error + (*FT_Slot_InitFunc)( FT_GlyphSlot slot ); + + typedef void + (*FT_Slot_DoneFunc)( FT_GlyphSlot slot ); + + + typedef FT_Error + (*FT_Size_RequestFunc)( FT_Size size, + FT_Size_Request req ); + + typedef FT_Error + (*FT_Size_SelectFunc)( FT_Size size, + FT_ULong size_index ); + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + typedef FT_Error + (*FT_Size_ResetPointsFunc)( FT_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + typedef FT_Error + (*FT_Size_ResetPixelsFunc)( FT_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + typedef FT_Error + (*FT_Slot_LoadFunc)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + typedef FT_UInt + (*FT_CharMap_CharIndexFunc)( FT_CharMap charmap, + FT_Long charcode ); + + typedef FT_Long + (*FT_CharMap_CharNextFunc)( FT_CharMap charmap, + FT_Long charcode ); + + typedef FT_Error + (*FT_Face_GetKerningFunc)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + + + typedef FT_Error + (*FT_Face_AttachFunc)( FT_Face face, + FT_Stream stream ); + + + typedef FT_Error + (*FT_Face_GetAdvancesFunc)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Bool vertical, + FT_UShort* advances ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Driver_ClassRec */ + /* */ + /* <Description> */ + /* The font driver class. This structure mostly contains pointers to */ + /* driver methods. */ + /* */ + /* <Fields> */ + /* root :: The parent module. */ + /* */ + /* face_object_size :: The size of a face object in bytes. */ + /* */ + /* size_object_size :: The size of a size object in bytes. */ + /* */ + /* slot_object_size :: The size of a glyph object in bytes. */ + /* */ + /* init_face :: The format-specific face constructor. */ + /* */ + /* done_face :: The format-specific face destructor. */ + /* */ + /* init_size :: The format-specific size constructor. */ + /* */ + /* done_size :: The format-specific size destructor. */ + /* */ + /* init_slot :: The format-specific slot constructor. */ + /* */ + /* done_slot :: The format-specific slot destructor. */ + /* */ + /* */ + /* load_glyph :: A function handle to load a glyph to a slot. */ + /* This field is mandatory! */ + /* */ + /* get_char_index :: A function handle to return the glyph index of */ + /* a given character for a given charmap. This */ + /* field is mandatory! */ + /* */ + /* get_kerning :: A function handle to return the unscaled */ + /* kerning for a given pair of glyphs. Can be */ + /* set to 0 if the format doesn't support */ + /* kerning. */ + /* */ + /* attach_file :: This function handle is used to read */ + /* additional data for a face from another */ + /* file/stream. For example, this can be used to */ + /* add data from AFM or PFM files on a Type 1 */ + /* face, or a CIDMap on a CID-keyed face. */ + /* */ + /* get_advances :: A function handle used to return advance */ + /* widths of `count' glyphs (in font units), */ + /* starting at `first'. The `vertical' flag must */ + /* be set to get vertical advance heights. The */ + /* `advances' buffer is caller-allocated. */ + /* Currently not implemented. The idea of this */ + /* function is to be able to perform */ + /* device-independent text layout without loading */ + /* a single glyph image. */ + /* */ + /* request_size :: A handle to a function used to request the new */ + /* character size. Can be set to 0 if the */ + /* scaling done in the base layer suffices. */ + /* */ + /* select_size :: A handle to a function used to select a new */ + /* fixed size. It is used only if */ + /* @FT_FACE_FLAG_FIXED_SIZES is set. Can be set */ + /* to 0 if the scaling done in the base layer */ + /* suffices. */ + /* <Note> */ + /* Most function pointers, with the exception of `load_glyph' and */ + /* `get_char_index' can be set to 0 to indicate a default behaviour. */ + /* */ + typedef struct FT_Driver_ClassRec_ + { + FT_Module_Class root; + + FT_Long face_object_size; + FT_Long size_object_size; + FT_Long slot_object_size; + + FT_Face_InitFunc init_face; + FT_Face_DoneFunc done_face; + + FT_Size_InitFunc init_size; + FT_Size_DoneFunc done_size; + + FT_Slot_InitFunc init_slot; + FT_Slot_DoneFunc done_slot; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_Size_ResetPointsFunc set_char_sizes; + FT_Size_ResetPixelsFunc set_pixel_sizes; + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + FT_Slot_LoadFunc load_glyph; + + FT_Face_GetKerningFunc get_kerning; + FT_Face_AttachFunc attach_file; + FT_Face_GetAdvancesFunc get_advances; + + /* since version 2.2 */ + FT_Size_RequestFunc request_size; + FT_Size_SelectFunc select_size; + + } FT_Driver_ClassRec, *FT_Driver_Class; + + + /* + * The following functions are used as stubs for `set_char_sizes' and + * `set_pixel_sizes'; the code uses `request_size' and `select_size' + * functions instead. + * + * Implementation is in `src/base/ftobjs.c'. + */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE( FT_Error ) + ft_stub_set_char_sizes( FT_Size size, + FT_F26Dot6 width, + FT_F26Dot6 height, + FT_UInt horz_res, + FT_UInt vert_res ); + + FT_BASE( FT_Error ) + ft_stub_set_pixel_sizes( FT_Size size, + FT_UInt width, + FT_UInt height ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + +FT_END_HEADER + +#endif /* __FTDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftgloadr.h b/src/freetype2/freetype/internal/ftgloadr.h new file mode 100644 index 0000000..9f47c0b --- /dev/null +++ b/src/freetype2/freetype/internal/ftgloadr.h @@ -0,0 +1,168 @@ +/***************************************************************************/ +/* */ +/* ftgloadr.h */ +/* */ +/* The FreeType glyph loader (specification). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGLOADR_H__ +#define __FTGLOADR_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphLoader */ + /* */ + /* <Description> */ + /* The glyph loader is an internal object used to load several glyphs */ + /* together (for example, in the case of composites). */ + /* */ + /* <Note> */ + /* The glyph loader implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + typedef struct FT_GlyphLoaderRec_* FT_GlyphLoader ; + + +#if 0 /* moved to freetype.h in version 2.2 */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 +#endif + + + typedef struct FT_SubGlyphRec_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + + } FT_SubGlyphRec; + + + typedef struct FT_GlyphLoadRec_ + { + FT_Outline outline; /* outline */ + FT_Vector* extra_points; /* extra points table */ + FT_Vector* extra_points2; /* second extra points table */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph subglyphs; /* subglyphs */ + + } FT_GlyphLoadRec, *FT_GlyphLoad; + + + typedef struct FT_GlyphLoaderRec_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + FT_GlyphLoadRec base; + FT_GlyphLoadRec current; + + void* other; /* for possible future extension? */ + + } FT_GlyphLoaderRec; + + + /* create new empty glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ); + + /* add an extra points table to a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ); + + /* destroy a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ); + + /* reset a glyph loader (frees everything int it) */ + FT_BASE( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ); + + /* rewind a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ); + + /* check that there is enough space to add `n_points' and `n_contours' */ + /* to the glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ); + + +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || (int)((_loader)->base.outline.n_points + \ + (_loader)->current.outline.n_points + \ + (_count)) <= (int)(_loader)->max_points ) + +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || (int)((_loader)->base.outline.n_contours + \ + (_loader)->current.outline.n_contours + \ + (_count)) <= (int)(_loader)->max_contours ) + +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points,_contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ + : FT_GlyphLoader_CheckPoints( (_loader), (_points), (_contours) ) ) + + + /* check that there is enough space to add `n_subs' sub-glyphs to */ + /* a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ); + + /* prepare a glyph loader, i.e. empty the current glyph */ + FT_BASE( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ); + + /* add the current glyph to the base glyph */ + FT_BASE( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ); + + /* copy points from one glyph loader to another */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, + FT_GlyphLoader source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTGLOADR_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftmemory.h b/src/freetype2/freetype/internal/ftmemory.h new file mode 100644 index 0000000..c6ddc42 --- /dev/null +++ b/src/freetype2/freetype/internal/ftmemory.h @@ -0,0 +1,368 @@ +/***************************************************************************/ +/* */ +/* ftmemory.h */ +/* */ +/* The FreeType memory management macros (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __FTMEMORY_H__ +#define __FTMEMORY_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_TYPES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_SET_ERROR */ + /* */ + /* <Description> */ + /* This macro is used to set an implicit `error' variable to a given */ + /* expression's value (usually a function call), and convert it to a */ + /* boolean which is set whenever the value is != 0. */ + /* */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * C++ refuses to handle statements like p = (void*)anything; where `p' + * is a typed pointer. Since we don't have a `typeof' operator in + * standard C++, we have to use ugly casts. + */ + +#ifdef __cplusplus +#define FT_ASSIGNP( p, val ) *((void**)&(p)) = (val) +#else +#define FT_ASSIGNP( p, val ) (p) = (val) +#endif + + + +#ifdef FT_DEBUG_MEMORY + + FT_BASE( const char* ) _ft_debug_file; + FT_BASE( long ) _ft_debug_lineno; + +#define FT_DEBUG_INNER( exp ) ( _ft_debug_file = __FILE__, \ + _ft_debug_lineno = __LINE__, \ + (exp) ) + +#define FT_ASSIGNP_INNER( p, exp ) ( _ft_debug_file = __FILE__, \ + _ft_debug_lineno = __LINE__, \ + FT_ASSIGNP( p, exp ) ) + +#else /* !FT_DEBUG_MEMORY */ + +#define FT_DEBUG_INNER( exp ) (exp) +#define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) + +#endif /* !FT_DEBUG_MEMORY */ + + + /* + * The allocation functions return a pointer, and the error code + * is written to through the `p_error' parameter. See below for + * for documentation. + */ + + FT_BASE( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( void ) + ft_mem_free( FT_Memory memory, + const void* P ); + + +#define FT_MEM_ALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, (size), &error ) ) + +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + ft_mem_free( memory, (ptr) ); \ + (ptr) = NULL; \ + FT_END_STMNT + +#define FT_MEM_NEW( ptr ) \ + FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_REALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, (size), &error ) ) + +#define FT_MEM_QNEW( ptr ) \ + FT_MEM_QALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) + +#define FT_MEM_QALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) + + +#define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) + + +#define FT_MEM_SET( dest, byte, count ) ft_memset( dest, byte, count ) + +#define FT_MEM_COPY( dest, source, count ) ft_memcpy( dest, source, count ) + +#define FT_MEM_MOVE( dest, source, count ) ft_memmove( dest, source, count ) + + +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) + +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) + + +#define FT_ARRAY_ZERO( dest, count ) \ + FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_COPY( dest, source, count ) \ + FT_MEM_COPY( dest, source, (count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_MOVE( dest, source, count ) \ + FT_MEM_MOVE( dest, source, (count) * sizeof ( *(dest) ) ) + + + /* + * Return the maximum number of addressable elements in an array. + * We limit ourselves to INT_MAX, rather than UINT_MAX, to avoid + * any problems. + */ +#define FT_ARRAY_MAX( ptr ) ( FT_INT_MAX / sizeof ( *(ptr) ) ) + +#define FT_ARRAY_CHECK( ptr, count ) ( (count) <= FT_ARRAY_MAX( ptr ) ) + + + /*************************************************************************/ + /* */ + /* The following functions macros expect that their pointer argument is */ + /* _typed_ in order to automatically compute array element sizes. */ + /* */ + +#define FT_MEM_NEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QNEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + + +#define FT_ALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) + +#define FT_REALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) + +#define FT_ALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) + +#define FT_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_QALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) + +#define FT_QREALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) + +#define FT_QALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT( ptr, count, item_size ) ) + +#define FT_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_FREE( ptr ) FT_MEM_FREE( ptr ) + +#define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) + +#define FT_NEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + +#define FT_QNEW( ptr ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) + +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE( FT_Error ) + FT_Alloc( FT_Memory memory, + FT_Long size, + void* *P ); + + FT_BASE( FT_Error ) + FT_QAlloc( FT_Memory memory, + FT_Long size, + void* *p ); + + FT_BASE( FT_Error ) + FT_Realloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *P ); + + FT_BASE( FT_Error ) + FT_QRealloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *p ); + + FT_BASE( void ) + FT_Free( FT_Memory memory, + void* *P ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + FT_BASE( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ); + +#define FT_MEM_STRDUP( dst, str ) \ + (dst) = ft_mem_strdup( memory, (const char*)(str), &error ) + +#define FT_STRDUP( dst, str ) \ + FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) + +#define FT_MEM_DUP( dst, address, size ) \ + (dst) = ft_mem_dup( memory, (address), (FT_ULong)(size), &error ) + +#define FT_DUP( dst, address, size ) \ + FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) + + + /* Return >= 1 if a truncation occurs. */ + /* Return 0 if the source string fits the buffer. */ + /* This is *not* the same as strlcpy(). */ + FT_BASE( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ); + +#define FT_STRCPYN( dst, src, size ) \ + ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) + + /* */ + + +FT_END_HEADER + +#endif /* __FTMEMORY_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftobjs.h b/src/freetype2/freetype/internal/ftobjs.h new file mode 100644 index 0000000..15b68d6 --- /dev/null +++ b/src/freetype2/freetype/internal/ftobjs.h @@ -0,0 +1,820 @@ +/***************************************************************************/ +/* */ +/* ftobjs.h */ +/* */ +/* The FreeType private base classes (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of all internal FreeType classes. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTOBJS_H__ +#define __FTOBJS_H__ + +#include <ft2build.h> +#include FT_RENDER_H +#include FT_SIZES_H +#include FT_LCD_FILTER_H +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_GLYPH_LOADER_H +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_AUTOHINT_H +#include FT_INTERNAL_SERVICE_H + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#include FT_INCREMENTAL_H +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* Some generic definitions. */ + /* */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + + + /*************************************************************************/ + /* */ + /* The min and max functions missing in C. As usual, be careful not to */ + /* write things like FT_MIN( a++, b++ ) to avoid side effects. */ + /* */ +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + +#define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ((n)-1), n ) + +#define FT_PIX_FLOOR( x ) ( (x) & ~63 ) +#define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) +#define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) + + + /* + * Return the highest power of 2 that is <= value; this correspond to + * the highest bit in a given 32-bit value. + */ + FT_BASE( FT_UInt32 ) + ft_highpow2( FT_UInt32 value ); + + + /* + * character classification functions -- since these are used to parse + * font files, we must not use those in <ctypes.h> which are + * locale-dependent + */ +#define ft_isdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U ) + +#define ft_isxdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U || \ + ( (unsigned)(x) - 'a' ) < 6U || \ + ( (unsigned)(x) - 'A' ) < 6U ) + + /* the next two macros assume ASCII representation */ +#define ft_isupper( x ) ( ( (unsigned)(x) - 'A' ) < 26U ) +#define ft_islower( x ) ( ( (unsigned)(x) - 'a' ) < 26U ) + +#define ft_isalpha( x ) ( ft_isupper( x ) || ft_islower( x ) ) +#define ft_isalnum( x ) ( ft_isdigit( x ) || ft_isalpha( x ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R M A P S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to internal charmap object */ + typedef struct FT_CMapRec_* FT_CMap; + + /* handle to charmap class structure */ + typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; + + /* internal charmap object structure */ + typedef struct FT_CMapRec_ + { + FT_CharMapRec charmap; + FT_CMap_Class clazz; + + } FT_CMapRec; + + /* typecase any pointer to a charmap handle */ +#define FT_CMAP( x ) ((FT_CMap)( x )) + + /* obvious macros */ +#define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id +#define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id +#define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding +#define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face + + + /* class method definitions */ + typedef FT_Error + (*FT_CMap_InitFunc)( FT_CMap cmap, + FT_Pointer init_data ); + + typedef void + (*FT_CMap_DoneFunc)( FT_CMap cmap ); + + typedef FT_UInt + (*FT_CMap_CharIndexFunc)( FT_CMap cmap, + FT_UInt32 char_code ); + + typedef FT_UInt + (*FT_CMap_CharNextFunc)( FT_CMap cmap, + FT_UInt32 *achar_code ); + + + typedef struct FT_CMap_ClassRec_ + { + FT_ULong size; + FT_CMap_InitFunc init; + FT_CMap_DoneFunc done; + FT_CMap_CharIndexFunc char_index; + FT_CMap_CharNextFunc char_next; + + } FT_CMap_ClassRec; + + + /* create a new charmap and add it to charmap->face */ + FT_BASE( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ); + + /* destroy a charmap and remove it from face's list */ + FT_BASE( void ) + FT_CMap_Done( FT_CMap cmap ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Face_InternalRec */ + /* */ + /* <Description> */ + /* This structure contains the internal fields of each FT_Face */ + /* object. These fields may change between different releases of */ + /* FreeType. */ + /* */ + /* <Fields> */ + /* max_points :: */ + /* The maximal number of points used to store the vectorial outline */ + /* of any glyph in this face. If this value cannot be known in */ + /* advance, or if the face isn't scalable, this should be set to 0. */ + /* Only relevant for scalable formats. */ + /* */ + /* max_contours :: */ + /* The maximal number of contours used to store the vectorial */ + /* outline of any glyph in this face. If this value cannot be */ + /* known in advance, or if the face isn't scalable, this should be */ + /* set to 0. Only relevant for scalable formats. */ + /* */ + /* transform_matrix :: */ + /* A 2x2 matrix of 16.16 coefficients used to transform glyph */ + /* outlines after they are loaded from the font. Only used by the */ + /* convenience functions. */ + /* */ + /* transform_delta :: */ + /* A translation vector used to transform glyph outlines after they */ + /* are loaded from the font. Only used by the convenience */ + /* functions. */ + /* */ + /* transform_flags :: */ + /* Some flags used to classify the transform. Only used by the */ + /* convenience functions. */ + /* */ + /* services :: */ + /* A cache for frequently used services. It should be only */ + /* accessed with the macro `FT_FACE_LOOKUP_SERVICE'. */ + /* */ + /* incremental_interface :: */ + /* If non-null, the interface through which glyph data and metrics */ + /* are loaded incrementally for faces that do not provide all of */ + /* this data when first opened. This field exists only if */ + /* @FT_CONFIG_OPTION_INCREMENTAL is defined. */ + /* */ + /* ignore_unpatented_hinter :: */ + /* This boolean flag instructs the glyph loader to ignore the */ + /* native font hinter, if one is found. This is exclusively used */ + /* in the case when the unpatented hinter is compiled within the */ + /* library. */ + /* */ + typedef struct FT_Face_InternalRec_ + { +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_UShort reserved1; + FT_Short reserved2; +#endif + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + + FT_ServiceCacheRec services; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec* incremental_interface; +#endif + + FT_Bool ignore_unpatented_hinter; + + } FT_Face_InternalRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Slot_InternalRec */ + /* */ + /* <Description> */ + /* This structure contains the internal fields of each FT_GlyphSlot */ + /* object. These fields may change between different releases of */ + /* FreeType. */ + /* */ + /* <Fields> */ + /* loader :: The glyph loader object used to load outlines */ + /* into the glyph slot. */ + /* */ + /* flags :: Possible values are zero or */ + /* FT_GLYPH_OWN_BITMAP. The latter indicates */ + /* that the FT_GlyphSlot structure owns the */ + /* bitmap buffer. */ + /* */ + /* glyph_transformed :: Boolean. Set to TRUE when the loaded glyph */ + /* must be transformed through a specific */ + /* font transformation. This is _not_ the same */ + /* as the face transform set through */ + /* FT_Set_Transform(). */ + /* */ + /* glyph_matrix :: The 2x2 matrix corresponding to the glyph */ + /* transformation, if necessary. */ + /* */ + /* glyph_delta :: The 2d translation vector corresponding to */ + /* the glyph transformation, if necessary. */ + /* */ + /* glyph_hints :: Format-specific glyph hints management. */ + /* */ + +#define FT_GLYPH_OWN_BITMAP 0x1 + + typedef struct FT_Slot_InternalRec_ + { + FT_GlyphLoader loader; + FT_UInt flags; + FT_Bool glyph_transformed; + FT_Matrix glyph_matrix; + FT_Vector glyph_delta; + void* glyph_hints; + + } FT_GlyphSlot_InternalRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ModuleRec */ + /* */ + /* <Description> */ + /* A module object instance. */ + /* */ + /* <Fields> */ + /* clazz :: A pointer to the module's class. */ + /* */ + /* library :: A handle to the parent library object. */ + /* */ + /* memory :: A handle to the memory manager. */ + /* */ + /* generic :: A generic structure for user-level extensibility (?). */ + /* */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + FT_Generic generic; + + } FT_ModuleRec; + + + /* typecast an object to a FT_Module */ +#define FT_MODULE( x ) ((FT_Module)( x )) +#define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library +#define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory + + +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_FONT_DRIVER ) + +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_RENDERER ) + +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_HINTER ) + +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_STYLER ) + +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_SCALABLE ) + +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_NO_OUTLINES ) + +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HAS_HINTER ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Module_Interface */ + /* */ + /* <Description> */ + /* Finds a module and returns its specific interface as a typeless */ + /* pointer. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* <Return> */ + /* A module-specific interface if available, 0 otherwise. */ + /* */ + /* <Note> */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for, and what its interface is :-) */ + /* */ + FT_BASE( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + + FT_BASE( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id ); + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* a few macros used to perform easy typecasts with minimal brain damage */ + +#define FT_FACE( x ) ((FT_Face)(x)) +#define FT_SIZE( x ) ((FT_Size)(x)) +#define FT_SLOT( x ) ((FT_GlyphSlot)(x)) + +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory +#define FT_FACE_STREAM( x ) FT_FACE( x )->stream + +#define FT_SIZE_FACE( x ) FT_SIZE( x )->face +#define FT_SLOT_FACE( x ) FT_SLOT( x )->face + +#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph +#define FT_FACE_SIZE( x ) FT_FACE( x )->size + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_GlyphSlot */ + /* */ + /* <Description> */ + /* It is sometimes useful to have more than one glyph slot for a */ + /* given face object. This function is used to create additional */ + /* slots. All of them are automatically discarded when the face is */ + /* destroyed. */ + /* */ + /* <Input> */ + /* face :: A handle to a parent face object. */ + /* */ + /* <Output> */ + /* aslot :: A handle to a new glyph slot object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_BASE( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_GlyphSlot */ + /* */ + /* <Description> */ + /* Destroys a given glyph slot. Remember however that all slots are */ + /* automatically destroyed with its parent. Using this function is */ + /* not always mandatory. */ + /* */ + /* <Input> */ + /* slot :: A handle to a target glyph slot. */ + /* */ + FT_BASE( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ); + + /* */ + +#define FT_REQUEST_WIDTH( req ) \ + ( (req)->horiResolution \ + ? (FT_Pos)( (req)->width * (req)->horiResolution + 36 ) / 72 \ + : (req)->width ) + +#define FT_REQUEST_HEIGHT( req ) \ + ( (req)->vertResolution \ + ? (FT_Pos)( (req)->height * (req)->vertResolution + 36 ) / 72 \ + : (req)->height ) + + + /* Set the metrics according to a bitmap strike. */ + FT_BASE( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ); + + + /* Set the metrics according to a size request. */ + FT_BASE( void ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ); + + + /* Match a size request against `available_sizes'. */ + FT_BASE( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ); + + + /* Use the horizontal metrics to synthesize the vertical metrics. */ + /* If `advance' is zero, it is also synthesized. */ + FT_BASE( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ); + + + /* Free the bitmap of a given glyphslot when needed (i.e., only when it */ + /* was allocated with ft_glyphslot_alloc_bitmap). */ + FT_BASE( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ); + + + /* Allocate a new bitmap buffer in a glyph slot. */ + FT_BASE( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ); + + + /* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */ + /* will not be freed by a later call to ft_glyphslot_free_bitmap. */ + FT_BASE( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_RENDERER( x ) ((FT_Renderer)( x )) +#define FT_GLYPH( x ) ((FT_Glyph)( x )) +#define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x )) +#define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x )) + + + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + FT_Glyph_Class glyph_class; + + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FT_Renderer_RenderFunc render; + + } FT_RendererRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F O N T D R I V E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ((FT_Driver)(x)) + + /* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_DriverRec */ + /* */ + /* <Description> */ + /* The root font driver class. A font driver is responsible for */ + /* managing and loading font files of a given format. */ + /* */ + /* <Fields> */ + /* root :: Contains the fields of the root module class. */ + /* */ + /* clazz :: A pointer to the font driver's class. Note that */ + /* this is NOT root.clazz. `class' wasn't used */ + /* as it is a reserved word in C++. */ + /* */ + /* faces_list :: The list of faces currently opened by this */ + /* driver. */ + /* */ + /* extensions :: A typeless pointer to the driver's extensions */ + /* registry, if they are supported through the */ + /* configuration macro FT_CONFIG_OPTION_EXTENSIONS. */ + /* */ + /* glyph_loader :: The glyph loader for all faces managed by this */ + /* driver. This object isn't defined for unscalable */ + /* formats. */ + /* */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class clazz; + + FT_ListRec faces_list; + void* extensions; + + FT_GlyphLoader glyph_loader; + + } FT_DriverRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R I E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* This hook is used by the TrueType debugger. It must be set to an */ + /* alternate truetype bytecode interpreter function. */ +#define FT_DEBUG_HOOK_TRUETYPE 0 + + + /* Set this debug hook to a non-null pointer to force unpatented hinting */ + /* for all faces when both TT_USE_BYTECODE_INTERPRETER and */ + /* TT_CONFIG_OPTION_UNPATENTED_HINTING are defined. This is only used */ + /* during debugging. */ +#define FT_DEBUG_HOOK_UNPATENTED_HINTING 1 + + + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_LibraryRec */ + /* */ + /* <Description> */ + /* The FreeType library class. This is the root of all FreeType */ + /* data. Use FT_New_Library() to create a library object, and */ + /* FT_Done_Library() to discard it and all child objects. */ + /* */ + /* <Fields> */ + /* memory :: The library's memory object. Manages memory */ + /* allocation. */ + /* */ + /* generic :: Client data variable. Used to extend the */ + /* Library class by higher levels and clients. */ + /* */ + /* version_major :: The major version number of the library. */ + /* */ + /* version_minor :: The minor version number of the library. */ + /* */ + /* version_patch :: The current patch level of the library. */ + /* */ + /* num_modules :: The number of modules currently registered */ + /* within this library. This is set to 0 for new */ + /* libraries. New modules are added through the */ + /* FT_Add_Module() API function. */ + /* */ + /* modules :: A table used to store handles to the currently */ + /* registered modules. Note that each font driver */ + /* contains a list of its opened faces. */ + /* */ + /* renderers :: The list of renderers currently registered */ + /* within the library. */ + /* */ + /* cur_renderer :: The current outline renderer. This is a */ + /* shortcut used to avoid parsing the list on */ + /* each call to FT_Outline_Render(). It is a */ + /* handle to the current renderer for the */ + /* FT_GLYPH_FORMAT_OUTLINE format. */ + /* */ + /* auto_hinter :: XXX */ + /* */ + /* raster_pool :: The raster object's render pool. This can */ + /* ideally be changed dynamically at run-time. */ + /* */ + /* raster_pool_size :: The size of the render pool in bytes. */ + /* */ + /* debug_hooks :: XXX */ + /* */ + typedef struct FT_LibraryRec_ + { + FT_Memory memory; /* library's memory manager */ + + FT_Generic generic; + + FT_Int version_major; + FT_Int version_minor; + FT_Int version_patch; + + FT_UInt num_modules; + FT_Module modules[FT_MAX_MODULES]; /* module objects */ + + FT_ListRec renderers; /* list of renderers */ + FT_Renderer cur_renderer; /* current outline renderer */ + FT_Module auto_hinter; + + FT_Byte* raster_pool; /* scan-line conversion */ + /* render pool */ + FT_ULong raster_pool_size; /* size of render pool in bytes */ + + FT_DebugHook_Func debug_hooks[4]; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFilter lcd_filter; + FT_Int lcd_extra; /* number of extra pixels */ + FT_Byte lcd_weights[7]; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#endif + + } FT_LibraryRec; + + + FT_BASE( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + + FT_BASE( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + typedef const char* + (*FT_Face_GetPostscriptNameFunc)( FT_Face face ); + + typedef FT_Error + (*FT_Face_GetGlyphNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_Face_GetGlyphNameIndexFunc)( FT_Face face, + FT_String* glyph_name ); + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Memory */ + /* */ + /* <Description> */ + /* Creates a new memory object. */ + /* */ + /* <Return> */ + /* A pointer to the new memory object. 0 in case of error. */ + /* */ + FT_BASE( FT_Memory ) + FT_New_Memory( void ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Memory */ + /* */ + /* <Description> */ + /* Discards memory manager. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory manager. */ + /* */ + FT_BASE( void ) + FT_Done_Memory( FT_Memory memory ); + +#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* Define default raster's interface. The default raster is located in */ + /* `src/base/ftraster.c'. */ + /* */ + /* Client applications can register new rasters through the */ + /* FT_Set_Raster() API. */ + +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif + + +FT_END_HEADER + +#endif /* __FTOBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftrfork.h b/src/freetype2/freetype/internal/ftrfork.h new file mode 100644 index 0000000..94402bc --- /dev/null +++ b/src/freetype2/freetype/internal/ftrfork.h @@ -0,0 +1,184 @@ +/***************************************************************************/ +/* */ +/* ftrfork.h */ +/* */ +/* Embedded resource forks accessor (specification). */ +/* */ +/* Copyright 2004, 2006 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* Development of the code in this file is support of */ +/* Information-technology Promotion Agency, Japan. */ +/***************************************************************************/ + + +#ifndef __FTRFORK_H__ +#define __FTRFORK_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + + /* Number of guessing rules supported in `FT_Raccess_Guess'. */ + /* Don't forget to increment the number if you add a new guessing rule. */ +#define FT_RACCESS_N_RULES 8 + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Guess */ + /* */ + /* <Description> */ + /* Guess a file name and offset where the actual resource fork is */ + /* stored. The macro FT_RACCESS_N_RULES holds the number of */ + /* guessing rules; the guessed result for the Nth rule is */ + /* represented as a triplet: a new file name (new_names[N]), a file */ + /* offset (offsets[N]), and an error code (errors[N]). */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* base_name :: */ + /* The (base) file name of the resource fork used for some */ + /* guessing rules. */ + /* */ + /* <Output> */ + /* new_names :: */ + /* An array of guessed file names in which the resource forks may */ + /* exist. If `new_names[N]' is NULL, the guessed file name is */ + /* equal to `base_name'. */ + /* */ + /* offsets :: */ + /* An array of guessed file offsets. `offsets[N]' holds the file */ + /* offset of the possible start of the resource fork in file */ + /* `new_names[N]'. */ + /* */ + /* errors :: */ + /* An array of FreeType error codes. `errors[N]' is the error */ + /* code of Nth guessing rule function. If `errors[N]' is not */ + /* FT_Err_Ok, `new_names[N]' and `offsets[N]' are meaningless. */ + /* */ + FT_BASE( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char** new_names, + FT_Long* offsets, + FT_Error* errors ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Get_HeaderInfo */ + /* */ + /* <Description> */ + /* Get the information from the header of resource fork. The */ + /* information includes the file offset where the resource map */ + /* starts, and the file offset where the resource data starts. */ + /* `FT_Raccess_Get_DataOffsets' requires these two data. */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* rfork_offset :: */ + /* The file offset where the resource fork starts. */ + /* */ + /* <Output> */ + /* map_offset :: */ + /* The file offset where the resource map starts. */ + /* */ + /* rdata_pos :: */ + /* The file offset where the resource data starts. */ + /* */ + /* <Return> */ + /* FreeType error code. FT_Err_Ok means success. */ + /* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Get_DataOffsets */ + /* */ + /* <Description> */ + /* Get the data offsets for a tag in a resource fork. Offsets are */ + /* stored in an array because, in some cases, resources in a resource */ + /* fork have the same tag. */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* map_offset :: */ + /* The file offset where the resource map starts. */ + /* */ + /* rdata_pos :: */ + /* The file offset where the resource data starts. */ + /* */ + /* tag :: */ + /* The resource tag. */ + /* */ + /* <Output> */ + /* offsets :: */ + /* The stream offsets for the resource data specified by `tag'. */ + /* This array is allocated by the function, so you have to call */ + /* @ft_mem_free after use. */ + /* */ + /* count :: */ + /* The length of offsets array. */ + /* */ + /* <Return> */ + /* FreeType error code. FT_Err_Ok means success. */ + /* */ + /* <Note> */ + /* Normally you should use `FT_Raccess_Get_HeaderInfo' to get the */ + /* value for `map_offset' and `rdata_pos'. */ + /* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Long **offsets, + FT_Long *count ); + + +FT_END_HEADER + +#endif /* __FTRFORK_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftserv.h b/src/freetype2/freetype/internal/ftserv.h new file mode 100644 index 0000000..45d2fa9 --- /dev/null +++ b/src/freetype2/freetype/internal/ftserv.h @@ -0,0 +1,327 @@ +/***************************************************************************/ +/* */ +/* ftserv.h */ +/* */ +/* The FreeType services (specification only). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Each module can export one or more `services'. Each service is */ + /* identified by a constant string and modeled by a pointer; the latter */ + /* generally corresponds to a structure containing function pointers. */ + /* */ + /* Note that a service's data cannot be a mere function pointer because */ + /* in C it is possible that function pointers might be implemented */ + /* differently than data pointers (e.g. 48 bits instead of 32). */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSERV_H__ +#define __FTSERV_H__ + + +FT_BEGIN_HEADER + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* we disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ + + /* + * @macro: + * FT_FACE_FIND_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * @macro: + * FT_FACE_FIND_GLOBAL_SERVICE + * + * @description: + * This macro is used to look up a service from all modules. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E D E S C R I P T O R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The following structure is used to _describe_ a given service + * to the library. This is useful to build simple static service lists. + */ + typedef struct FT_ServiceDescRec_ + { + const char* serv_id; /* service name */ + const void* serv_data; /* service pointer/data */ + + } FT_ServiceDescRec; + + typedef const FT_ServiceDescRec* FT_ServiceDesc; + + + /* + * Parse a list of FT_ServiceDescRec descriptors and look for + * a specific service by ID. Note that the last element in the + * array must be { NULL, NULL }, and that the function should + * return NULL if the service isn't available. + * + * This function can be used by modules to implement their + * `get_service' method. + */ + FT_BASE( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E S C A C H E *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * This structure is used to store a cache for several frequently used + * services. It is the type of `face->internal->services'. You + * should only use FT_FACE_LOOKUP_SERVICE to access it. + * + * All fields should have the type FT_Pointer to relax compilation + * dependencies. We assume the developer isn't completely stupid. + * + * Each field must be named `service_XXXX' where `XXX' corresponds to + * the correct FT_SERVICE_ID_XXXX macro. See the definition of + * FT_FACE_LOOKUP_SERVICE below how this is implemented. + * + */ + typedef struct FT_ServiceCacheRec_ + { + FT_Pointer service_POSTSCRIPT_FONT_NAME; + FT_Pointer service_MULTI_MASTERS; + FT_Pointer service_GLYPH_DICT; + FT_Pointer service_PFR_METRICS; + FT_Pointer service_WINFNT; + + } FT_ServiceCacheRec, *FT_ServiceCache; + + + /* + * A magic number used within the services cache. + */ +#define FT_SERVICE_UNAVAILABLE ((FT_Pointer)-2) /* magic number */ + + + /* + * @macro: + * FT_FACE_LOOKUP_SERVICE + * + * @description: + * This macro is used to lookup a service from a face's driver module + * using its cache. + * + * @input: + * face:: + * The source face handle containing the cache. + * + * field :: + * The field name in the cache. + * + * id :: + * The service ID. + * + * @output: + * ptr :: + * A variable receiving the service data. NULL if not available. + */ +#ifdef __cplusplus + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + *Pptr = svc; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + ptr = svc; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * A macro used to define new service structure types. + */ + +#define FT_DEFINE_SERVICE( name ) \ + typedef struct FT_Service_ ## name ## Rec_ \ + FT_Service_ ## name ## Rec ; \ + typedef struct FT_Service_ ## name ## Rec_ \ + const * FT_Service_ ## name ; \ + struct FT_Service_ ## name ## Rec_ + + /* */ + + /* + * The header files containing the services. + */ + +#define FT_SERVICE_BDF_H <freetype/internal/services/svbdf.h> +#define FT_SERVICE_GLYPH_DICT_H <freetype/internal/services/svgldict.h> +#define FT_SERVICE_GX_VALIDATE_H <freetype/internal/services/svgxval.h> +#define FT_SERVICE_KERNING_H <freetype/internal/services/svkern.h> +#define FT_SERVICE_MULTIPLE_MASTERS_H <freetype/internal/services/svmm.h> +#define FT_SERVICE_OPENTYPE_VALIDATE_H <freetype/internal/services/svotval.h> +#define FT_SERVICE_PFR_H <freetype/internal/services/svpfr.h> +#define FT_SERVICE_POSTSCRIPT_CMAPS_H <freetype/internal/services/svpscmap.h> +#define FT_SERVICE_POSTSCRIPT_INFO_H <freetype/internal/services/svpsinfo.h> +#define FT_SERVICE_POSTSCRIPT_NAME_H <freetype/internal/services/svpostnm.h> +#define FT_SERVICE_SFNT_H <freetype/internal/services/svsfnt.h> +#define FT_SERVICE_TRUETYPE_ENGINE_H <freetype/internal/services/svtteng.h> +#define FT_SERVICE_TT_CMAP_H <freetype/internal/services/svttcmap.h> +#define FT_SERVICE_WINFNT_H <freetype/internal/services/svwinfnt.h> +#define FT_SERVICE_XFREE86_NAME_H <freetype/internal/services/svxf86nm.h> +#define FT_SERVICE_TRUETYPE_GLYF_H <freetype/internal/services/svttglyf.h> + + /* */ + +FT_END_HEADER + +#endif /* __FTSERV_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftstream.h b/src/freetype2/freetype/internal/ftstream.h new file mode 100644 index 0000000..a91eb72 --- /dev/null +++ b/src/freetype2/freetype/internal/ftstream.h @@ -0,0 +1,539 @@ +/***************************************************************************/ +/* */ +/* ftstream.h */ +/* */ +/* Stream handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTSTREAM_H__ +#define __FTSTREAM_H__ + + +#include <ft2build.h> +#include FT_SYSTEM_H +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + + /* format of an 8-bit frame_op value: */ + /* */ + /* bit 76543210 */ + /* xxxxxxes */ + /* */ + /* s is set to 1 if the value is signed. */ + /* e is set to 1 if the value is little-endian. */ + /* xxx is a command. */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ +#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ + + + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + + } FT_Frame_Op; + + + typedef struct FT_Frame_Field_ + { + FT_Byte value; + FT_Byte size; + FT_UShort offset; + + } FT_Frame_Field; + + + /* Construct an FT_Frame_Field out of a structure type and a field name. */ + /* The structure type must be set in the FT_STRUCTURE macro before */ + /* calling the FT_FRAME_START() macro. */ + /* */ +#define FT_FIELD_SIZE( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) + +#define FT_FIELD_SIZE_DELTA( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) + +#define FT_FIELD_OFFSET( f ) \ + (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) + +#define FT_FRAME_FIELD( frame_op, field ) \ + { \ + frame_op, \ + FT_FIELD_SIZE( field ), \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_START( size ) { ft_frame_start, 0, size } +#define FT_FRAME_END { ft_frame_end, 0, 0 } + +#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) +#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) +#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) +#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) +#define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) +#define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) +#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) +#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) + +#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) +#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) +#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) +#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) +#define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) +#define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) + +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } + +#define FT_FRAME_BYTES( field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } + + + /*************************************************************************/ + /* */ + /* Integer extraction macros -- the `buffer' parameter must ALWAYS be of */ + /* type `char*' or equivalent (1-byte elements). */ + /* */ + +#define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) +#define FT_INT8_( p, i ) ( ((const FT_Char*)(p))[(i)] ) + +#define FT_INT16( x ) ( (FT_Int16)(x) ) +#define FT_UINT16( x ) ( (FT_UInt16)(x) ) +#define FT_INT32( x ) ( (FT_Int32)(x) ) +#define FT_UINT32( x ) ( (FT_UInt32)(x) ) + +#define FT_BYTE_I16( p, i, s ) ( FT_INT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_I32( p, i, s ) ( FT_INT32( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) + +#define FT_INT8_I16( p, i, s ) ( FT_INT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U16( p, i, s ) ( FT_UINT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_I32( p, i, s ) ( FT_INT32( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U32( p, i, s ) ( FT_UINT32( FT_INT8_( p, i ) ) << (s) ) + + +#define FT_PEEK_SHORT( p ) FT_INT16( FT_INT8_I16( p, 0, 8) | \ + FT_BYTE_I16( p, 1, 0) ) + +#define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_LONG( p ) FT_INT32( FT_INT8_I32( p, 0, 24 ) | \ + FT_BYTE_I32( p, 1, 16 ) | \ + FT_BYTE_I32( p, 2, 8 ) | \ + FT_BYTE_I32( p, 3, 0 ) ) + +#define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_OFF3( p ) FT_INT32( FT_INT8_I32( p, 0, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 2, 0 ) ) + +#define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 2, 0 ) ) + +#define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_INT8_I16( p, 1, 8 ) | \ + FT_BYTE_I16( p, 0, 0 ) ) + +#define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_LONG_LE( p ) FT_INT32( FT_INT8_I32( p, 3, 24 ) | \ + FT_BYTE_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) + +#define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_INT8_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) + +#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + + +#define FT_NEXT_CHAR( buffer ) \ + ( (signed char)*buffer++ ) + +#define FT_NEXT_BYTE( buffer ) \ + ( (unsigned char)*buffer++ ) + +#define FT_NEXT_SHORT( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) + +#define FT_NEXT_USHORT( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) + +#define FT_NEXT_OFF3( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) ) + +#define FT_NEXT_UOFF3( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) ) + +#define FT_NEXT_LONG( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) + +#define FT_NEXT_ULONG( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) + + +#define FT_NEXT_SHORT_LE( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) ) + +#define FT_NEXT_USHORT_LE( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) ) + +#define FT_NEXT_OFF3_LE( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) ) + +#define FT_NEXT_UOFF3_LE( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) ) + +#define FT_NEXT_LONG_LE( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) ) + +#define FT_NEXT_ULONG_LE( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) ) + + + /*************************************************************************/ + /* */ + /* Each GET_xxxx() macro uses an implicit `stream' variable. */ + /* */ +#if 0 +#define FT_GET_MACRO( type ) FT_NEXT_ ## type ( stream->cursor ) + +#define FT_GET_CHAR() FT_GET_MACRO( CHAR ) +#define FT_GET_BYTE() FT_GET_MACRO( BYTE ) +#define FT_GET_SHORT() FT_GET_MACRO( SHORT ) +#define FT_GET_USHORT() FT_GET_MACRO( USHORT ) +#define FT_GET_OFF3() FT_GET_MACRO( OFF3 ) +#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 ) +#define FT_GET_LONG() FT_GET_MACRO( LONG ) +#define FT_GET_ULONG() FT_GET_MACRO( ULONG ) +#define FT_GET_TAG4() FT_GET_MACRO( ULONG ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE ) +#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE ) + +#else +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) + +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetChar, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetShort, FT_Short ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetShort, FT_UShort ) +#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetOffset, FT_Long ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetOffset, FT_ULong ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetLong, FT_Long ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetLong, FT_ULong ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetLong, FT_ULong ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetShortLE, FT_Short ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetShortLE, FT_UShort ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetLongLE, FT_Long ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetLongLE, FT_ULong ) +#endif + +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) + +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadShort, FT_Short, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadShort, FT_UShort, var ) +#define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadOffset, FT_Long, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadOffset, FT_ULong, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadLong, FT_Long, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadLong, FT_ULong, var ) + +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadShortLE, FT_Short, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadShortLE, FT_UShort, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadLongLE, FT_Long, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadLongLE, FT_ULong, var ) + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /* initialize a stream for reading a regular system stream */ + FT_BASE( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ); + +#endif /* FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* create a new (input) stream from an FT_Open_Args structure */ + FT_BASE( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ); + + /* free a stream */ + FT_BASE( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ); + + /* initialize a stream for reading in-memory data */ + FT_BASE( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ); + + /* close a stream (does not destroy the stream structure) */ + FT_BASE( void ) + FT_Stream_Close( FT_Stream stream ); + + + /* seek within a stream. position is relative to start of stream */ + FT_BASE( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ); + + /* skip bytes in a stream */ + FT_BASE( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ); + + /* return current stream position */ + FT_BASE( FT_Long ) + FT_Stream_Pos( FT_Stream stream ); + + /* read bytes from a stream into a user-allocated buffer, returns an */ + /* error if not all bytes could be read. */ + FT_BASE( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* read bytes from a stream at a given position */ + FT_BASE( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); + + /* try to read bytes at the end of a stream; return number of bytes */ + /* really available */ + FT_BASE( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* Enter a frame of `count' consecutive bytes in a stream. Returns an */ + /* error if the frame could not be read/accessed. The caller can use */ + /* the FT_Stream_Get_XXX functions to retrieve frame data without */ + /* error checks. */ + /* */ + /* You must _always_ call FT_Stream_ExitFrame() once you have entered */ + /* a stream frame! */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ); + + /* exit a stream frame */ + FT_BASE( void ) + FT_Stream_ExitFrame( FT_Stream stream ); + + /* Extract a stream frame. If the stream is disk-based, a heap block */ + /* is allocated and the frame bytes are read into it. If the stream */ + /* is memory-based, this function simply set a pointer to the data. */ + /* */ + /* Useful to optimize access to memory-based streams transparently. */ + /* */ + /* All extracted frames must be `freed' with a call to the function */ + /* FT_Stream_ReleaseFrame(). */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); + + /* release an extract frame (see FT_Stream_ExtractFrame) */ + FT_BASE( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ); + + /* read a byte from an entered frame */ + FT_BASE( FT_Char ) + FT_Stream_GetChar( FT_Stream stream ); + + /* read a 16-bit big-endian integer from an entered frame */ + FT_BASE( FT_Short ) + FT_Stream_GetShort( FT_Stream stream ); + + /* read a 24-bit big-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetOffset( FT_Stream stream ); + + /* read a 32-bit big-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetLong( FT_Stream stream ); + + /* read a 16-bit little-endian integer from an entered frame */ + FT_BASE( FT_Short ) + FT_Stream_GetShortLE( FT_Stream stream ); + + /* read a 32-bit little-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetLongLE( FT_Stream stream ); + + + /* read a byte from a stream */ + FT_BASE( FT_Char ) + FT_Stream_ReadChar( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit big-endian integer from a stream */ + FT_BASE( FT_Short ) + FT_Stream_ReadShort( FT_Stream stream, + FT_Error* error ); + + /* read a 24-bit big-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadOffset( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit big-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadLong( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit little-endian integer from a stream */ + FT_BASE( FT_Short ) + FT_Stream_ReadShortLE( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit little-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadLongLE( FT_Stream stream, + FT_Error* error ); + + /* Read a structure from a stream. The structure must be described */ + /* by an array of FT_Frame_Field records. */ + FT_BASE( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + + +#define FT_STREAM_POS() \ + FT_Stream_Pos( stream ) + +#define FT_STREAM_SEEK( position ) \ + FT_SET_ERROR( FT_Stream_Seek( stream, position ) ) + +#define FT_STREAM_SKIP( distance ) \ + FT_SET_ERROR( FT_Stream_Skip( stream, distance ) ) + +#define FT_STREAM_READ( buffer, count ) \ + FT_SET_ERROR( FT_Stream_Read( stream, \ + (FT_Byte*)buffer, \ + count ) ) + +#define FT_STREAM_READ_AT( position, buffer, count ) \ + FT_SET_ERROR( FT_Stream_ReadAt( stream, \ + position, \ + (FT_Byte*)buffer, \ + count ) ) + +#define FT_STREAM_READ_FIELDS( fields, object ) \ + FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) + + +#define FT_FRAME_ENTER( size ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, size ) ) ) + +#define FT_FRAME_EXIT() \ + FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) + +#define FT_FRAME_EXTRACT( size, bytes ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, size, \ + (FT_Byte**)&(bytes) ) ) ) + +#define FT_FRAME_RELEASE( bytes ) \ + FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ + (FT_Byte**)&(bytes) ) ) + + +FT_END_HEADER + +#endif /* __FTSTREAM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/fttrace.h b/src/freetype2/freetype/internal/fttrace.h new file mode 100644 index 0000000..81916fc --- /dev/null +++ b/src/freetype2/freetype/internal/fttrace.h @@ -0,0 +1,133 @@ +/***************************************************************************/ +/* */ +/* fttrace.h */ +/* */ +/* Tracing handling (specification only). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + + /* definitions of trace levels for FreeType 2 */ + + /* the first level must always be `trace_any' */ +FT_TRACE_DEF( any ) + + /* base components */ +FT_TRACE_DEF( calc ) /* calculations (ftcalc.c) */ +FT_TRACE_DEF( memory ) /* memory manager (ftobjs.c) */ +FT_TRACE_DEF( stream ) /* stream manager (ftstream.c) */ +FT_TRACE_DEF( io ) /* i/o interface (ftsystem.c) */ +FT_TRACE_DEF( list ) /* list management (ftlist.c) */ +FT_TRACE_DEF( init ) /* initialization (ftinit.c) */ +FT_TRACE_DEF( objs ) /* base objects (ftobjs.c) */ +FT_TRACE_DEF( outline ) /* outline management (ftoutln.c) */ +FT_TRACE_DEF( glyph ) /* glyph management (ftglyph.c) */ + +FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ +FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ +FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ +FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ + + /* Cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + + /* SFNT driver components */ +FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */ +FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ +FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ +FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ +FT_TRACE_DEF( ttmtx ) /* metrics-related tables (ttmtx.c) */ +FT_TRACE_DEF( ttpost ) /* PS table processing (ttpost.c) */ +FT_TRACE_DEF( ttsbit ) /* TrueType sbit handling (ttsbit.c) */ + + /* TrueType driver components */ +FT_TRACE_DEF( ttdriver ) /* TT font driver (ttdriver.c) */ +FT_TRACE_DEF( ttgload ) /* TT glyph loader (ttgload.c) */ +FT_TRACE_DEF( ttinterp ) /* bytecode interpreter (ttinterp.c) */ +FT_TRACE_DEF( ttobjs ) /* TT objects manager (ttobjs.c) */ +FT_TRACE_DEF( ttpload ) /* TT data/program loader (ttpload.c) */ +FT_TRACE_DEF( ttgxvar ) /* TrueType GX var handler (ttgxvar.c) */ + + /* Type 1 driver components */ +FT_TRACE_DEF( t1driver ) +FT_TRACE_DEF( t1gload ) +FT_TRACE_DEF( t1hint ) +FT_TRACE_DEF( t1load ) +FT_TRACE_DEF( t1objs ) +FT_TRACE_DEF( t1parse ) + + /* PostScript helper module `psaux' */ +FT_TRACE_DEF( t1decode ) +FT_TRACE_DEF( psobjs ) + + /* PostScript hinting module `pshinter' */ +FT_TRACE_DEF( pshrec ) +FT_TRACE_DEF( pshalgo1 ) +FT_TRACE_DEF( pshalgo2 ) + + /* Type 2 driver components */ +FT_TRACE_DEF( cffdriver ) +FT_TRACE_DEF( cffgload ) +FT_TRACE_DEF( cffload ) +FT_TRACE_DEF( cffobjs ) +FT_TRACE_DEF( cffparse ) + + /* Type 42 driver component */ +FT_TRACE_DEF( t42 ) + + /* CID driver components */ +FT_TRACE_DEF( cidafm ) +FT_TRACE_DEF( ciddriver ) +FT_TRACE_DEF( cidgload ) +FT_TRACE_DEF( cidload ) +FT_TRACE_DEF( cidobjs ) +FT_TRACE_DEF( cidparse ) + + /* Windows font component */ +FT_TRACE_DEF( winfnt ) + + /* PCF font components */ +FT_TRACE_DEF( pcfdriver ) +FT_TRACE_DEF( pcfread ) + + /* BDF font components */ +FT_TRACE_DEF( bdfdriver ) +FT_TRACE_DEF( bdflib ) + + /* PFR font component */ +FT_TRACE_DEF( pfr ) + + /* OpenType validation components */ +FT_TRACE_DEF( otvmodule ) +FT_TRACE_DEF( otvcommon ) +FT_TRACE_DEF( otvbase ) +FT_TRACE_DEF( otvgdef ) +FT_TRACE_DEF( otvgpos ) +FT_TRACE_DEF( otvgsub ) +FT_TRACE_DEF( otvjstf ) + + /* TrueTypeGX/AAT validation components */ +FT_TRACE_DEF( gxvmodule ) +FT_TRACE_DEF( gxvcommon ) +FT_TRACE_DEF( gxvfeat ) +FT_TRACE_DEF( gxvmort ) +FT_TRACE_DEF( gxvmorx ) +FT_TRACE_DEF( gxvbsln ) +FT_TRACE_DEF( gxvjust ) +FT_TRACE_DEF( gxvkern ) +FT_TRACE_DEF( gxvopbd ) +FT_TRACE_DEF( gxvtrak ) +FT_TRACE_DEF( gxvprop ) +FT_TRACE_DEF( gxvlcar ) + + +/* END */ diff --git a/src/freetype2/freetype/internal/ftvalid.h b/src/freetype2/freetype/internal/ftvalid.h new file mode 100644 index 0000000..00cd85e --- /dev/null +++ b/src/freetype2/freetype/internal/ftvalid.h @@ -0,0 +1,150 @@ +/***************************************************************************/ +/* */ +/* ftvalid.h */ +/* */ +/* FreeType validation support (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTVALID_H__ +#define __FTVALID_H__ + +#include <ft2build.h> +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_setjmp and ft_longjmp */ + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** V A L I D A T I O N ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to a validation object */ + typedef struct FT_ValidatorRec_ volatile* FT_Validator; + + + /*************************************************************************/ + /* */ + /* There are three distinct validation levels defined here: */ + /* */ + /* FT_VALIDATE_DEFAULT :: */ + /* A table that passes this validation level can be used reliably by */ + /* FreeType. It generally means that all offsets have been checked to */ + /* prevent out-of-bound reads, that array counts are correct, etc. */ + /* */ + /* FT_VALIDATE_TIGHT :: */ + /* A table that passes this validation level can be used reliably and */ + /* doesn't contain invalid data. For example, a charmap table that */ + /* returns invalid glyph indices will not pass, even though it can */ + /* be used with FreeType in default mode (the library will simply */ + /* return an error later when trying to load the glyph). */ + /* */ + /* It also checks that fields which must be a multiple of 2, 4, or 8, */ + /* don't have incorrect values, etc. */ + /* */ + /* FT_VALIDATE_PARANOID :: */ + /* Only for font debugging. Checks that a table follows the */ + /* specification by 100%. Very few fonts will be able to pass this */ + /* level anyway but it can be useful for certain tools like font */ + /* editors/converters. */ + /* */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + + } FT_ValidationLevel; + + + /* validator structure */ + typedef struct FT_ValidatorRec_ + { + const FT_Byte* base; /* address of table in memory */ + const FT_Byte* limit; /* `base' + sizeof(table) in memory */ + FT_ValidationLevel level; /* validation level */ + FT_Error error; /* error returned. 0 means success */ + + ft_jmp_buf jump_buffer; /* used for exception handling */ + + } FT_ValidatorRec; + + +#define FT_VALIDATOR( x ) ((FT_Validator)( x )) + + + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); + + /* Do not use this. It's broken and will cause your validator to crash */ + /* if you run it on an invalid font. */ + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); + + /* Sets the error field in a validator, then calls `longjmp' to return */ + /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ + /* error checks within the validation routines. */ + /* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); + + + /* Calls ft_validate_error. Assumes that the `valid' local variable */ + /* holds a pointer to the current validator object. */ + /* */ + /* Use preprocessor prescan to pass FT_ERR_PREFIX. */ + /* */ +#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid, _prefix ## _error ) + + /* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) + + /* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) + + /* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + +FT_END_HEADER + +#endif /* __FTVALID_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/internal.h b/src/freetype2/freetype/internal/internal.h new file mode 100644 index 0000000..27d5dc5 --- /dev/null +++ b/src/freetype2/freetype/internal/internal.h @@ -0,0 +1,50 @@ +/***************************************************************************/ +/* */ +/* internal.h */ +/* */ +/* Internal header files (specification only). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is automatically included by `ft2build.h'. */ + /* Do not include it manually! */ + /* */ + /*************************************************************************/ + + +#define FT_INTERNAL_OBJECTS_H <freetype/internal/ftobjs.h> +#define FT_INTERNAL_STREAM_H <freetype/internal/ftstream.h> +#define FT_INTERNAL_MEMORY_H <freetype/internal/ftmemory.h> +#define FT_INTERNAL_DEBUG_H <freetype/internal/ftdebug.h> +#define FT_INTERNAL_CALC_H <freetype/internal/ftcalc.h> +#define FT_INTERNAL_DRIVER_H <freetype/internal/ftdriver.h> +#define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h> +#define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.h> +#define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h> +#define FT_INTERNAL_SERVICE_H <freetype/internal/ftserv.h> +#define FT_INTERNAL_RFORK_H <freetype/internal/ftrfork.h> +#define FT_INTERNAL_VALIDATE_H <freetype/internal/ftvalid.h> + +#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h> +#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h> + +#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h> +#define FT_INTERNAL_POSTSCRIPT_HINTS_H <freetype/internal/pshints.h> +#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H <freetype/internal/psglobal.h> + +#define FT_INTERNAL_AUTOHINT_H <freetype/internal/autohint.h> + + +/* END */ diff --git a/src/freetype2/freetype/internal/pcftypes.h b/src/freetype2/freetype/internal/pcftypes.h new file mode 100644 index 0000000..382796f --- /dev/null +++ b/src/freetype2/freetype/internal/pcftypes.h @@ -0,0 +1,56 @@ +/* pcftypes.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCFTYPES_H__ +#define __PCFTYPES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + typedef struct PCF_Public_FaceRec_ + { + FT_FaceRec root; + FT_StreamRec gzip_stream; + FT_Stream gzip_source; + + char* charset_encoding; + char* charset_registry; + + } PCF_Public_FaceRec, *PCF_Public_Face; + + +FT_END_HEADER + +#endif /* __PCFTYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/psaux.h b/src/freetype2/freetype/internal/psaux.h new file mode 100644 index 0000000..4baf7a0 --- /dev/null +++ b/src/freetype2/freetype/internal/psaux.h @@ -0,0 +1,879 @@ +/***************************************************************************/ +/* */ +/* psaux.h */ +/* */ +/* Auxiliary functions and data structures related to PostScript fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PSAUX_H__ +#define __PSAUX_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_TableRec_* PS_Table; + typedef const struct PS_Table_FuncsRec_* PS_Table_Funcs; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_Table_FuncsRec */ + /* */ + /* <Description> */ + /* A set of function pointers to manage PS_Table objects. */ + /* */ + /* <Fields> */ + /* table_init :: Used to initialize a table. */ + /* */ + /* table_done :: Finalizes resp. destroy a given table. */ + /* */ + /* table_add :: Adds a new object to a table. */ + /* */ + /* table_release :: Releases table data, then finalizes it. */ + /* */ + typedef struct PS_Table_FuncsRec_ + { + FT_Error + (*init)( PS_Table table, + FT_Int count, + FT_Memory memory ); + + void + (*done)( PS_Table table ); + + FT_Error + (*add)( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ); + + void + (*release)( PS_Table table ); + + } PS_Table_FuncsRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_TableRec */ + /* */ + /* <Description> */ + /* A PS_Table is a simple object used to store an array of objects in */ + /* a single memory block. */ + /* */ + /* <Fields> */ + /* block :: The address in memory of the growheap's block. This */ + /* can change between two object adds, due to */ + /* reallocation. */ + /* */ + /* cursor :: The current top of the grow heap within its block. */ + /* */ + /* capacity :: The current size of the heap block. Increments by */ + /* 1kByte chunks. */ + /* */ + /* max_elems :: The maximum number of elements in table. */ + /* */ + /* num_elems :: The current number of elements in table. */ + /* */ + /* elements :: A table of element addresses within the block. */ + /* */ + /* lengths :: A table of element sizes within the block. */ + /* */ + /* memory :: The object used for memory operations */ + /* (alloc/realloc). */ + /* */ + /* funcs :: A table of method pointers for this object. */ + /* */ + typedef struct PS_TableRec_ + { + FT_Byte* block; /* current memory block */ + FT_Offset cursor; /* current cursor in memory block */ + FT_Offset capacity; /* current size of memory block */ + FT_Long init; + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_PtrDist* lengths; /* lengths of table elements */ + + FT_Memory memory; + PS_Table_FuncsRec funcs; + + } PS_TableRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 FIELDS & TOKENS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PS_ParserRec_* PS_Parser; + + typedef struct T1_TokenRec_* T1_Token; + + typedef struct T1_FieldRec_* T1_Field; + + + /* simple enumeration type used to identify token types */ + typedef enum T1_TokenType_ + { + T1_TOKEN_TYPE_NONE = 0, + T1_TOKEN_TYPE_ANY, + T1_TOKEN_TYPE_STRING, + T1_TOKEN_TYPE_ARRAY, + T1_TOKEN_TYPE_KEY, /* aka `name' */ + + /* do not remove */ + T1_TOKEN_TYPE_MAX + + } T1_TokenType; + + + /* a simple structure used to identify tokens */ + typedef struct T1_TokenRec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + T1_TokenType type; /* type of token */ + + } T1_TokenRec; + + + /* enumeration type used to identify object fields */ + typedef enum T1_FieldType_ + { + T1_FIELD_TYPE_NONE = 0, + T1_FIELD_TYPE_BOOL, + T1_FIELD_TYPE_INTEGER, + T1_FIELD_TYPE_FIXED, + T1_FIELD_TYPE_FIXED_1000, + T1_FIELD_TYPE_STRING, + T1_FIELD_TYPE_KEY, + T1_FIELD_TYPE_BBOX, + T1_FIELD_TYPE_INTEGER_ARRAY, + T1_FIELD_TYPE_FIXED_ARRAY, + T1_FIELD_TYPE_CALLBACK, + + /* do not remove */ + T1_FIELD_TYPE_MAX + + } T1_FieldType; + + + typedef enum T1_FieldLocation_ + { + T1_FIELD_LOCATION_CID_INFO, + T1_FIELD_LOCATION_FONT_DICT, + T1_FIELD_LOCATION_FONT_INFO, + T1_FIELD_LOCATION_PRIVATE, + T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, + + /* do not remove */ + T1_FIELD_LOCATION_MAX + + } T1_FieldLocation; + + + typedef void + (*T1_Field_ParseFunc)( FT_Face face, + FT_Pointer parser ); + + + /* structure type used to model object fields */ + typedef struct T1_FieldRec_ + { + const char* ident; /* field identifier */ + T1_FieldLocation location; + T1_FieldType type; /* type of field */ + T1_Field_ParseFunc reader; + FT_UInt offset; /* offset of field in object */ + FT_Byte size; /* size of field in bytes */ + FT_UInt array_max; /* maximal number of elements for */ + /* array */ + FT_UInt count_offset; /* offset of element count for */ + /* arrays */ + FT_UInt dict; /* where we expect it */ + } T1_FieldRec; + +#define T1_FIELD_DICT_FONTDICT ( 1 << 0 ) /* also FontInfo and FDArray */ +#define T1_FIELD_DICT_PRIVATE ( 1 << 1 ) + + + +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE( _fname ), \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ + { \ + _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ + (T1_Field_ParseFunc)_reader, \ + 0, 0, \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, \ + FT_FIELD_OFFSET( num_ ## _fname ), \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, 0, \ + _dict \ + }, + + +#define T1_FIELD_BOOL( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BOOL, _fname, _dict ) + +#define T1_FIELD_NUM( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER, _fname, _dict ) + +#define T1_FIELD_FIXED( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED, _fname, _dict ) + +#define T1_FIELD_FIXED_1000( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_1000, _fname, \ + _dict ) + +#define T1_FIELD_STRING( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_STRING, _fname, _dict ) + +#define T1_FIELD_KEY( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_KEY, _fname, _dict ) + +#define T1_FIELD_BBOX( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BBOX, _fname, _dict ) + + +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ + T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct PS_Parser_FuncsRec_* PS_Parser_Funcs; + + typedef struct PS_Parser_FuncsRec_ + { + void + (*init)( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + void + (*done)( PS_Parser parser ); + + void + (*skip_spaces)( PS_Parser parser ); + void + (*skip_PS_token)( PS_Parser parser ); + + FT_Long + (*to_int)( PS_Parser parser ); + FT_Fixed + (*to_fixed)( PS_Parser parser, + FT_Int power_ten ); + + FT_Error + (*to_bytes)( PS_Parser parser, + FT_Byte* bytes, + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); + + FT_Int + (*to_coord_array)( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_Int + (*to_fixed_array)( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + void + (*to_token)( PS_Parser parser, + T1_Token token ); + void + (*to_token_array)( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_Error + (*load_field)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_Error + (*load_field_table)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + } PS_Parser_FuncsRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_ParserRec */ + /* */ + /* <Description> */ + /* A PS_Parser is an object used to parse a Type 1 font very quickly. */ + /* */ + /* <Fields> */ + /* cursor :: The current position in the text. */ + /* */ + /* base :: Start of the processed text. */ + /* */ + /* limit :: End of the processed text. */ + /* */ + /* error :: The last error returned. */ + /* */ + /* memory :: The object used for memory operations (alloc/realloc). */ + /* */ + /* funcs :: A table of functions for the parser. */ + /* */ + typedef struct PS_ParserRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Error error; + FT_Memory memory; + + PS_Parser_FuncsRec funcs; + + } PS_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_BuilderRec_* T1_Builder; + + + typedef FT_Error + (*T1_Builder_Check_Points_Func)( T1_Builder builder, + FT_Int count ); + + typedef void + (*T1_Builder_Add_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + typedef FT_Error + (*T1_Builder_Add_Point1_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef FT_Error + (*T1_Builder_Add_Contour_Func)( T1_Builder builder ); + + typedef FT_Error + (*T1_Builder_Start_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef void + (*T1_Builder_Close_Contour_Func)( T1_Builder builder ); + + + typedef const struct T1_Builder_FuncsRec_* T1_Builder_Funcs; + + typedef struct T1_Builder_FuncsRec_ + { + void + (*init)( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Bool hinting ); + + void + (*done)( T1_Builder builder ); + + T1_Builder_Check_Points_Func check_points; + T1_Builder_Add_Point_Func add_point; + T1_Builder_Add_Point1_Func add_point1; + T1_Builder_Add_Contour_Func add_contour; + T1_Builder_Start_Point_Func start_point; + T1_Builder_Close_Contour_Func close_contour; + + } T1_Builder_FuncsRec; + + + /* an enumeration type to handle charstring parsing states */ + typedef enum T1_ParseState_ + { + T1_Parse_Start, + T1_Parse_Have_Width, + T1_Parse_Have_Moveto, + T1_Parse_Have_Path + + } T1_ParseState; + + + /*************************************************************************/ + /* */ + /* <Structure> */ + /* T1_BuilderRec */ + /* */ + /* <Description> */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* <Fields> */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* loader :: XXX */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* max_points :: maximum points in builder outline */ + /* */ + /* max_contours :: Maximal number of contours in builder outline. */ + /* */ + /* last :: The last point position. */ + /* */ + /* scale_x :: The horizontal scaling value (FUnits to */ + /* sub-pixels). */ + /* */ + /* scale_y :: The vertical scaling value (FUnits to sub-pixels). */ + /* */ + /* pos_x :: The horizontal translation (if composite glyph). */ + /* */ + /* pos_y :: The vertical translation (if composite glyph). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* bbox :: Unused. */ + /* */ + /* parse_state :: An enumeration which controls the charstring */ + /* parsing state. */ + /* */ + /* load_points :: If this flag is not set, no points are loaded. */ + /* */ + /* no_recurse :: Set but not used. */ + /* */ + /* metrics_only :: A boolean indicating that we only want to compute */ + /* the metrics of a given glyph, not load all of its */ + /* points. */ + /* */ + /* funcs :: An array of function pointers for the builder. */ + /* */ + typedef struct T1_BuilderRec_ + { + FT_Memory memory; + FT_Face face; + FT_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Vector last; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + T1_ParseState parse_state; + FT_Bool load_points; + FT_Bool no_recurse; + FT_Bool shift; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + T1_Builder_FuncsRec funcs; + + } T1_BuilderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 0 + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 8 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + +#endif /* 0 */ + + + typedef struct T1_Decoder_ZoneRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + } T1_Decoder_ZoneRec, *T1_Decoder_Zone; + + + typedef struct T1_DecoderRec_* T1_Decoder; + typedef const struct T1_Decoder_FuncsRec_* T1_Decoder_Funcs; + + + typedef FT_Error + (*T1_Decoder_Callback)( T1_Decoder decoder, + FT_UInt glyph_index ); + + + typedef struct T1_Decoder_FuncsRec_ + { + FT_Error + (*init)( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback callback ); + + void + (*done)( T1_Decoder decoder ); + + FT_Error + (*parse_charstrings)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); + + } T1_Decoder_FuncsRec; + + + typedef struct T1_DecoderRec_ + { + T1_BuilderRec builder; + + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + + T1_Decoder_ZoneRec zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone zone; + + FT_Service_PsCMaps psnames; /* for seac */ + FT_UInt num_glyphs; + FT_Byte** glyph_names; + + FT_Int lenIV; /* internal for sub routine calls */ + FT_UInt num_subrs; + FT_Byte** subrs; + FT_PtrDist* subrs_len; /* array of subrs length (optional) */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + PS_Blend blend; /* for multiple master support */ + + FT_Render_Mode hint_mode; + + T1_Decoder_Callback parse_callback; + T1_Decoder_FuncsRec funcs; + + FT_Int* buildchar; + FT_UInt len_buildchar; + + } T1_DecoderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** AFM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_ParserRec_* AFM_Parser; + + typedef struct AFM_Parser_FuncsRec_ + { + FT_Error + (*init)( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + void + (*done)( AFM_Parser parser ); + + FT_Error + (*parse)( AFM_Parser parser ); + + } AFM_Parser_FuncsRec; + + + typedef struct AFM_StreamRec_* AFM_Stream; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* AFM_ParserRec */ + /* */ + /* <Description> */ + /* An AFM_Parser is a parser for the AFM files. */ + /* */ + /* <Fields> */ + /* memory :: The object used for memory operations (alloc and */ + /* realloc). */ + /* */ + /* stream :: This is an opaque object. */ + /* */ + /* FontInfo :: The result will be stored here. */ + /* */ + /* get_index :: A user provided function to get a glyph index by its */ + /* name. */ + /* */ + typedef struct AFM_ParserRec_ + { + FT_Memory memory; + AFM_Stream stream; + + AFM_FontInfo FontInfo; + + FT_Int + (*get_index)( const char* name, + FT_UInt len, + void* user_data ); + + void* user_data; + + } AFM_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CHARMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct T1_CMap_ClassesRec_* T1_CMap_Classes; + + typedef struct T1_CMap_ClassesRec_ + { + FT_CMap_Class standard; + FT_CMap_Class expert; + FT_CMap_Class custom; + FT_CMap_Class unicode; + + } T1_CMap_ClassesRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PSAux Module Interface *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSAux_ServiceRec_ + { + /* don't use `PS_Table_Funcs' and friends to avoid compiler warnings */ + const PS_Table_FuncsRec* ps_table_funcs; + const PS_Parser_FuncsRec* ps_parser_funcs; + const T1_Builder_FuncsRec* t1_builder_funcs; + const T1_Decoder_FuncsRec* t1_decoder_funcs; + + void + (*t1_decrypt)( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + T1_CMap_Classes t1_cmap_classes; + + /* fields after this comment line were added after version 2.1.10 */ + const AFM_Parser_FuncsRec* afm_parser_funcs; + + } PSAux_ServiceRec, *PSAux_Service; + + /* backwards-compatible type definition */ + typedef PSAux_ServiceRec PSAux_Interface; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Some convenience functions *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) + +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) + +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) + +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) + +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) + +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) + +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) + +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) + + +FT_END_HEADER + +#endif /* __PSAUX_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/pshints.h b/src/freetype2/freetype/internal/pshints.h new file mode 100644 index 0000000..48452c0 --- /dev/null +++ b/src/freetype2/freetype/internal/pshints.h @@ -0,0 +1,687 @@ +/***************************************************************************/ +/* */ +/* pshints.h */ +/* */ +/* Interface to Postscript-specific (Type 1 and Type 2) hints */ +/* recorders (specification only). These are used to support native */ +/* T1/T2 hints in the `type1', `cid', and `cff' font drivers. */ +/* */ +/* Copyright 2001, 2002, 2003, 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 __PSHINTS_H__ +#define __PSHINTS_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INTERNAL REPRESENTATION OF GLOBALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSH_GlobalsRec_* PSH_Globals; + + typedef FT_Error + (*PSH_Globals_NewFunc)( FT_Memory memory, + T1_Private* private_dict, + PSH_Globals* aglobals ); + + typedef FT_Error + (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + typedef void + (*PSH_Globals_DestroyFunc)( PSH_Globals globals ); + + + typedef struct PSH_Globals_FuncsRec_ + { + PSH_Globals_NewFunc create; + PSH_Globals_SetScaleFunc set_scale; + PSH_Globals_DestroyFunc destroy; + + } PSH_Globals_FuncsRec, *PSH_Globals_Funcs; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 1 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * T1_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 1 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stem', `stem3', or `reset'). Note that these functions do + * not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * PostScript hinter. + * + */ + typedef struct T1_HintsRec_* T1_Hints; + + + /************************************************************************* + * + * @type: + * T1_Hints_Funcs + * + * @description: + * A pointer to the @T1_Hints_FuncsRec structure that defines the API of + * a given @T1_Hints object. + * + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; + + + /************************************************************************* + * + * @functype: + * T1_Hints_OpenFunc + * + * @description: + * A method of the @T1_Hints class used to prepare it for a new Type 1 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T1_Hints_OpenFunc)( T1_Hints hints ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_SetStemFunc + * + * @description: + * A method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 `hstem' and `vstem' + * operators. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * coords :: + * Array of 2 integers, used as (position,length) stem descriptor. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * `coords[0]' is the absolute stem position (lowest coordinate); + * `coords[1]' is the length. + * + * The length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + * If the length is -21 (corresponding to a bottom ghost stem), then + * the real stem position is `coords[0]+coords[1]'. + * + */ + typedef void + (*T1_Hints_SetStemFunc)( T1_Hints hints, + FT_UInt dimension, + FT_Long* coords ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_SetStem3Func + * + * @description: + * A method of the @T1_Hints class used to record three + * counter-controlled horizontal or vertical stems at once. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems, 1 for vertical ones. + * + * coords :: + * An array of 6 integers, holding 3 (position,length) pairs for the + * counter-controlled stems. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * The lengths cannot be negative (ghost stems are never + * counter-controlled). + * + */ + typedef void + (*T1_Hints_SetStem3Func)( T1_Hints hints, + FT_UInt dimension, + FT_Long* coords ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_ResetFunc + * + * @description: + * A method of the @T1_Hints class used to reset the stems hints in a + * recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph in which the + * previously defined hints apply. + * + */ + typedef void + (*T1_Hints_ResetFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_CloseFunc + * + * @description: + * A method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T1_Hints_CloseFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_ApplyFunc + * + * @description: + * A method of the @T1_Hints class used to apply hints to the + * corresponding glyph outline. Must be called once all hints have been + * recorded. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font as the glyph. + * + */ + typedef FT_Error + (*T1_Hints_ApplyFunc)( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************* + * + * @struct: + * T1_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T1_Hints objects. + * + * @fields: + * hints :: + * A handle to the T1 Hints recorder. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stem :: + * The function to set a simple stem. + * + * stem3 :: + * The function to set counter-controlled stems. + * + * reset :: + * The function to reset stem hints. + * + * apply :: + * The function to apply the hints to the corresponding glyph outline. + * + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints hints; + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + T1_Hints_ApplyFunc apply; + + } T1_Hints_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 2 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * T2_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 2 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stems', `hintmask', `counters'). Note that these + * functions do not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * Postscript hinter. + * + */ + typedef struct T2_HintsRec_* T2_Hints; + + + /************************************************************************* + * + * @type: + * T2_Hints_Funcs + * + * @description: + * A pointer to the @T2_Hints_FuncsRec structure that defines the API of + * a given @T2_Hints object. + * + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; + + + /************************************************************************* + * + * @functype: + * T2_Hints_OpenFunc + * + * @description: + * A method of the @T2_Hints class used to prepare it for a new Type 2 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T2_Hints_OpenFunc)( T2_Hints hints ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_StemsFunc + * + * @description: + * A method of the @T2_Hints class used to set the table of stems in + * either the vertical or horizontal dimension. Equivalent to the + * `hstem', `vstem', `hstemhm', and `vstemhm' Type 2 operators. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * count :: + * The number of stems. + * + * coords :: + * An array of `count' (position,length) pairs. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * There are `2*count' elements in the `coords' array. Each even + * element is an absolute position in font units, each odd element is a + * length in font units. + * + * A length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + */ + typedef void + (*T2_Hints_StemsFunc)( T2_Hints hints, + FT_UInt dimension, + FT_UInt count, + FT_Fixed* coordinates ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_MaskFunc + * + * @description: + * A method of the @T2_Hints class used to set a given hintmask (this + * corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The glyph index of the last point to which the previously defined + * or activated hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_MaskFunc)( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_CounterFunc + * + * @description: + * A method of the @T2_Hints class used to set a given counter mask + * (this corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * A glyph index of the last point to which the previously defined or + * active hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_CloseFunc + * + * @description: + * A method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T2_Hints_CloseFunc)( T2_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_ApplyFunc + * + * @description: + * A method of the @T2_Hints class used to apply hints to the + * corresponding glyph outline. Must be called after the `close' + * method. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font than the glyph. + * + */ + typedef FT_Error + (*T2_Hints_ApplyFunc)( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************* + * + * @struct: + * T2_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T2_Hints objects. + * + * @fields: + * hints :: + * A handle to the T2 hints recorder object. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stems :: + * The function to set the dimension's stems table. + * + * hintmask :: + * The function to set hint masks. + * + * counter :: + * The function to set counter masks. + * + * apply :: + * The function to apply the hints on the corresponding glyph outline. + * + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints hints; + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + T2_Hints_ApplyFunc apply; + + } T2_Hints_FuncsRec; + + + /* */ + + + typedef struct PSHinter_Interface_ + { + PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module ); + T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module ); + T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module ); + + } PSHinter_Interface; + + typedef PSHinter_Interface* PSHinter_Service; + + +FT_END_HEADER + +#endif /* __PSHINTS_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svbdf.h b/src/freetype2/freetype/internal/services/svbdf.h new file mode 100644 index 0000000..0f7fc61 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svbdf.h @@ -0,0 +1,57 @@ +/***************************************************************************/ +/* */ +/* svbdf.h */ +/* */ +/* The FreeType BDF services (specification). */ +/* */ +/* Copyright 2003 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 __SVBDF_H__ +#define __SVBDF_H__ + +#include FT_BDF_H +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_BDF "bdf" + + typedef FT_Error + (*FT_BDF_GetCharsetIdFunc)( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + typedef FT_Error + (*FT_BDF_GetPropertyFunc)( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + + FT_DEFINE_SERVICE( BDF ) + { + FT_BDF_GetCharsetIdFunc get_charset_id; + FT_BDF_GetPropertyFunc get_property; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVBDF_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svgldict.h b/src/freetype2/freetype/internal/services/svgldict.h new file mode 100644 index 0000000..e5e56b2 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svgldict.h @@ -0,0 +1,60 @@ +/***************************************************************************/ +/* */ +/* svgldict.h */ +/* */ +/* The FreeType glyph dictionary services (specification). */ +/* */ +/* Copyright 2003 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 __SVGLDICT_H__ +#define __SVGLDICT_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A service used to retrieve glyph names, as well as to find the + * index of a given glyph name in a font. + * + */ + +#define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" + + + typedef FT_Error + (*FT_GlyphDict_GetNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_GlyphDict_NameIndexFunc)( FT_Face face, + FT_String* glyph_name ); + + + FT_DEFINE_SERVICE( GlyphDict ) + { + FT_GlyphDict_GetNameFunc get_name; + FT_GlyphDict_NameIndexFunc name_index; /* optional */ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVGLDICT_H__ */ diff --git a/src/freetype2/freetype/internal/services/svgxval.h b/src/freetype2/freetype/internal/services/svgxval.h new file mode 100644 index 0000000..2cdab50 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svgxval.h @@ -0,0 +1,72 @@ +/***************************************************************************/ +/* */ +/* svgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005 by */ +/* Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVGXVAL_H__ +#define __SVGXVAL_H__ + +#include FT_GX_VALIDATE_H +#include FT_INTERNAL_VALIDATE_H + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_GX_VALIDATE "truetypegx-validate" +#define FT_SERVICE_ID_CLASSICKERN_VALIDATE "classickern-validate" + + typedef FT_Error + (*gxv_validate_func)( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + typedef FT_Error + (*ckern_validate_func)( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes *ckern_table ); + + + FT_DEFINE_SERVICE( GXvalidate ) + { + gxv_validate_func validate; + }; + + FT_DEFINE_SERVICE( CKERNvalidate ) + { + ckern_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVGXVAL_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svkern.h b/src/freetype2/freetype/internal/services/svkern.h new file mode 100644 index 0000000..1488adf --- /dev/null +++ b/src/freetype2/freetype/internal/services/svkern.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* svkern.h */ +/* */ +/* The FreeType Kerning service (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVKERN_H__ +#define __SVKERN_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + +#define FT_SERVICE_ID_KERNING "kerning" + + + typedef FT_Error + (*FT_Kerning_TrackGetFunc)( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + FT_DEFINE_SERVICE( Kerning ) + { + FT_Kerning_TrackGetFunc get_track; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVKERN_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svmm.h b/src/freetype2/freetype/internal/services/svmm.h new file mode 100644 index 0000000..8a99ec4 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svmm.h @@ -0,0 +1,79 @@ +/***************************************************************************/ +/* */ +/* svmm.h */ +/* */ +/* The FreeType Multiple Masters and GX var services (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVMM_H__ +#define __SVMM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A service used to manage multiple-masters data in a given face. + * + * See the related APIs in `ftmm.h' (FT_MULTIPLE_MASTERS_H). + * + */ + +#define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" + + + typedef FT_Error + (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + + typedef FT_Error + (*FT_Get_MM_Var_Func)( FT_Face face, + FT_MM_Var* *master ); + + typedef FT_Error + (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + typedef FT_Error + (*FT_Set_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + FT_DEFINE_SERVICE( MultiMasters ) + { + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + }; + + /* */ + + +FT_END_HEADER + +#endif /* __SVMM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svotval.h b/src/freetype2/freetype/internal/services/svotval.h new file mode 100644 index 0000000..970bbd5 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svotval.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* svotval.h */ +/* */ +/* The FreeType OpenType validation service (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVOTVAL_H__ +#define __SVOTVAL_H__ + +#include FT_OPENTYPE_VALIDATE_H +#include FT_INTERNAL_VALIDATE_H + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + + + typedef FT_Error + (*otv_validate_func)( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + + + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVOTVAL_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svpfr.h b/src/freetype2/freetype/internal/services/svpfr.h new file mode 100644 index 0000000..462786f --- /dev/null +++ b/src/freetype2/freetype/internal/services/svpfr.h @@ -0,0 +1,66 @@ +/***************************************************************************/ +/* */ +/* svpfr.h */ +/* */ +/* Internal PFR service functions (specification). */ +/* */ +/* Copyright 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPFR_H__ +#define __SVPFR_H__ + +#include FT_PFR_H +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PFR_METRICS "pfr-metrics" + + + typedef FT_Error + (*FT_PFR_GetMetricsFunc)( FT_Face face, + FT_UInt *aoutline, + FT_UInt *ametrics, + FT_Fixed *ax_scale, + FT_Fixed *ay_scale ); + + typedef FT_Error + (*FT_PFR_GetKerningFunc)( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + typedef FT_Error + (*FT_PFR_GetAdvanceFunc)( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + + FT_DEFINE_SERVICE( PfrMetrics ) + { + FT_PFR_GetMetricsFunc get_metrics; + FT_PFR_GetKerningFunc get_kerning; + FT_PFR_GetAdvanceFunc get_advance; + + }; + + /* */ + +FT_END_HEADER + +#endif /* __SVPFR_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svpostnm.h b/src/freetype2/freetype/internal/services/svpostnm.h new file mode 100644 index 0000000..282da68 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svpostnm.h @@ -0,0 +1,58 @@ +/***************************************************************************/ +/* */ +/* svpostnm.h */ +/* */ +/* The FreeType PostScript name services (specification). */ +/* */ +/* Copyright 2003, 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 __SVPOSTNM_H__ +#define __SVPOSTNM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + /* + * A trivial service used to retrieve the PostScript name of a given + * font when available. The `get_name' field should never be NULL. + * + * The corresponding function can return NULL to indicate that the + * PostScript name is not available. + * + * The name is owned by the face and will be destroyed with it. + */ + +#define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" + + + typedef const char* + (*FT_PsName_GetFunc)( FT_Face face ); + + + FT_DEFINE_SERVICE( PsFontName ) + { + FT_PsName_GetFunc get_ps_font_name; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPOSTNM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svpscmap.h b/src/freetype2/freetype/internal/services/svpscmap.h new file mode 100644 index 0000000..c4e25ed --- /dev/null +++ b/src/freetype2/freetype/internal/services/svpscmap.h @@ -0,0 +1,129 @@ +/***************************************************************************/ +/* */ +/* svpscmap.h */ +/* */ +/* The FreeType PostScript charmap service (specification). */ +/* */ +/* Copyright 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPSCMAP_H__ +#define __SVPSCMAP_H__ + +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" + + + /* + * Adobe glyph name to unicode value. + */ + typedef FT_UInt32 + (*PS_Unicode_ValueFunc)( const char* glyph_name ); + + /* + * Macintosh name id to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Macintosh_NameFunc)( FT_UInt name_index ); + + /* + * Adobe standard string ID to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); + + + /* + * Simple unicode -> glyph index charmap built from font glyph names + * table. + */ + typedef struct PS_UniMap_ + { + FT_UInt32 unicode; /* bit 31 set: is glyph variant */ + FT_UInt glyph_index; + + } PS_UniMap; + + + typedef struct PS_UnicodesRec_* PS_Unicodes; + + typedef struct PS_UnicodesRec_ + { + FT_CMapRec cmap; + FT_UInt num_maps; + PS_UniMap* maps; + + } PS_UnicodesRec; + + + /* + * A function which returns a glyph name for a given index. Returns + * NULL if invalid index. + */ + typedef const char* + (*PS_GetGlyphNameFunc)( FT_Pointer data, + FT_UInt string_index ); + + /* + * A function used to release the glyph name returned by + * PS_GetGlyphNameFunc, when needed + */ + typedef void + (*PS_FreeGlyphNameFunc)( FT_Pointer data, + const char* name ); + + typedef FT_Error + (*PS_Unicodes_InitFunc)( FT_Memory memory, + PS_Unicodes unicodes, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ); + + typedef FT_UInt + (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, + FT_UInt32 unicode ); + + typedef FT_ULong + (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, + FT_UInt32 *unicode ); + + + FT_DEFINE_SERVICE( PsCMaps ) + { + PS_Unicode_ValueFunc unicode_value; + + PS_Unicodes_InitFunc unicodes_init; + PS_Unicodes_CharIndexFunc unicodes_char_index; + PS_Unicodes_CharNextFunc unicodes_char_next; + + PS_Macintosh_NameFunc macintosh_name; + PS_Adobe_Std_StringsFunc adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPSCMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svpsinfo.h b/src/freetype2/freetype/internal/services/svpsinfo.h new file mode 100644 index 0000000..63f5db9 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svpsinfo.h @@ -0,0 +1,60 @@ +/***************************************************************************/ +/* */ +/* svpsinfo.h */ +/* */ +/* The FreeType PostScript info service (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPSINFO_H__ +#define __SVPSINFO_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_INTERNAL_TYPE1_TYPES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" + + + typedef FT_Error + (*PS_GetFontInfoFunc)( FT_Face face, + PS_FontInfoRec* afont_info ); + + typedef FT_Int + (*PS_HasGlyphNamesFunc)( FT_Face face ); + + typedef FT_Error + (*PS_GetFontPrivateFunc)( FT_Face face, + PS_PrivateRec* afont_private ); + + + FT_DEFINE_SERVICE( PsInfo ) + { + PS_GetFontInfoFunc ps_get_font_info; + PS_HasGlyphNamesFunc ps_has_glyph_names; + PS_GetFontPrivateFunc ps_get_font_private; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPSINFO_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svsfnt.h b/src/freetype2/freetype/internal/services/svsfnt.h new file mode 100644 index 0000000..b4a85d9 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svsfnt.h @@ -0,0 +1,80 @@ +/***************************************************************************/ +/* */ +/* svsfnt.h */ +/* */ +/* The FreeType SFNT table loading service (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVSFNT_H__ +#define __SVSFNT_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" + + + /* + * Used to implement FT_Load_Sfnt_Table(). + */ + typedef FT_Error + (*FT_SFNT_TableLoadFunc)( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + /* + * Used to implement FT_Get_Sfnt_Table(). + */ + typedef void* + (*FT_SFNT_TableGetFunc)( FT_Face face, + FT_Sfnt_Tag tag ); + + + /* + * Used to implement FT_Sfnt_Table_Info(). + */ + typedef FT_Error + (*FT_SFNT_TableInfoFunc)( FT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *length ); + + + FT_DEFINE_SERVICE( SFNT_Table ) + { + FT_SFNT_TableLoadFunc load_table; + FT_SFNT_TableGetFunc get_table; + FT_SFNT_TableInfoFunc table_info; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVSFNT_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svttcmap.h b/src/freetype2/freetype/internal/services/svttcmap.h new file mode 100644 index 0000000..1e02d15 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svttcmap.h @@ -0,0 +1,78 @@ +/***************************************************************************/ +/* */ +/* svsttcmap.h */ +/* */ +/* The FreeType TrueType/sfnt cmap extra information service. */ +/* */ +/* Copyright 2003 by */ +/* Masatake YAMATO, Redhat K.K. */ +/* */ +/* Copyright 2003 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. */ +/* */ +/***************************************************************************/ + +/* Development of this service is support of + Information-technology Promotion Agency, Japan. */ + +#ifndef __SVTTCMAP_H__ +#define __SVTTCMAP_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_CMAP "tt-cmaps" + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_CMapInfo */ + /* */ + /* <Description> */ + /* A structure used to store TrueType/sfnt specific cmap information */ + /* which is not covered by the generic @FT_CharMap structure. This */ + /* structure can be accessed with the @FT_Get_TT_CMap_Info function. */ + /* */ + /* <Fields> */ + /* language :: */ + /* The language ID used in Mac fonts. Definitions of values are in */ + /* freetype/ttnameid.h. */ + /* */ + typedef struct TT_CMapInfo_ + { + FT_ULong language; + FT_Long format; + + } TT_CMapInfo; + + + typedef FT_Error + (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + + FT_DEFINE_SERVICE( TTCMaps ) + { + TT_CMap_Info_GetFunc get_cmap_info; + }; + + /* */ + + +FT_END_HEADER + +#endif /* __SVTTCMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svtteng.h b/src/freetype2/freetype/internal/services/svtteng.h new file mode 100644 index 0000000..58e02a6 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svtteng.h @@ -0,0 +1,53 @@ +/***************************************************************************/ +/* */ +/* svtteng.h */ +/* */ +/* The FreeType TrueType engine query service (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVTTENG_H__ +#define __SVTTENG_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" + + /* + * Used to implement FT_Get_TrueType_Engine_Type + */ + + FT_DEFINE_SERVICE( TrueTypeEngine ) + { + FT_TrueTypeEngineType engine_type; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVTTENG_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svttglyf.h b/src/freetype2/freetype/internal/services/svttglyf.h new file mode 100644 index 0000000..e57d484 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svttglyf.h @@ -0,0 +1,48 @@ +/***************************************************************************/ +/* */ +/* svttglyf.h */ +/* */ +/* The FreeType TrueType glyph service. */ +/* */ +/* Copyright 2007 by David Turner. */ +/* */ +/* 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 __SVTTGLYF_H__ +#define __SVTTGLYF_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_GLYF "tt-glyf" + + + typedef FT_ULong + (*TT_Glyf_GetLocationFunc)( FT_Face face, + FT_UInt gindex, + FT_ULong *psize ); + + FT_DEFINE_SERVICE( TTGlyf ) + { + TT_Glyf_GetLocationFunc get_location; + }; + + /* */ + + +FT_END_HEADER + +#endif /* __SVTTGLYF_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svwinfnt.h b/src/freetype2/freetype/internal/services/svwinfnt.h new file mode 100644 index 0000000..57f7765 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svwinfnt.h @@ -0,0 +1,50 @@ +/***************************************************************************/ +/* */ +/* svwinfnt.h */ +/* */ +/* The FreeType Windows FNT/FONT service (specification). */ +/* */ +/* Copyright 2003 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 __SVWINFNT_H__ +#define __SVWINFNT_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_WINFONTS_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_WINFNT "winfonts" + + typedef FT_Error + (*FT_WinFnt_GetHeaderFunc)( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + FT_DEFINE_SERVICE( WinFnt ) + { + FT_WinFnt_GetHeaderFunc get_header; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVWINFNT_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/services/svxf86nm.h b/src/freetype2/freetype/internal/services/svxf86nm.h new file mode 100644 index 0000000..ca5d884 --- /dev/null +++ b/src/freetype2/freetype/internal/services/svxf86nm.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* svxf86nm.h */ +/* */ +/* The FreeType XFree86 services (specification only). */ +/* */ +/* Copyright 2003 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 __SVXF86NM_H__ +#define __SVXF86NM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A trivial service used to return the name of a face's font driver, + * according to the XFree86 nomenclature. Note that the service data + * is a simple constant string pointer. + */ + +#define FT_SERVICE_ID_XF86_NAME "xf86-driver-name" + +#define FT_XF86_FORMAT_TRUETYPE "TrueType" +#define FT_XF86_FORMAT_TYPE_1 "Type 1" +#define FT_XF86_FORMAT_BDF "BDF" +#define FT_XF86_FORMAT_PCF "PCF" +#define FT_XF86_FORMAT_TYPE_42 "Type 42" +#define FT_XF86_FORMAT_CID "CID Type 1" +#define FT_XF86_FORMAT_CFF "CFF" +#define FT_XF86_FORMAT_PFR "PFR" +#define FT_XF86_FORMAT_WINFNT "Windows FNT" + + /* */ + + +FT_END_HEADER + + +#endif /* __SVXF86NM_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/sfnt.h b/src/freetype2/freetype/internal/sfnt.h new file mode 100644 index 0000000..7e8f684 --- /dev/null +++ b/src/freetype2/freetype/internal/sfnt.h @@ -0,0 +1,762 @@ +/***************************************************************************/ +/* */ +/* sfnt.h */ +/* */ +/* High-level `sfnt' driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SFNT_H__ +#define __SFNT_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Init_Face_Func */ + /* */ + /* <Description> */ + /* First part of the SFNT face object initialization. This finds */ + /* the face in a SFNT file or collection, and load its format tag in */ + /* face->format_tag. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* Once the format tag has been validated by the font driver, it */ + /* should then call the TT_Load_Face_Func() callback to read the rest */ + /* of the SFNT tables in the object. */ + /* */ + typedef FT_Error + (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Face_Func */ + /* */ + /* <Description> */ + /* Second part of the SFNT face object initialization. This loads */ + /* the common SFNT tables (head, OS/2, maxp, metrics, etc.) in the */ + /* face object. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function must be called after TT_Init_Face_Func(). */ + /* */ + typedef FT_Error + (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Done_Face_Func */ + /* */ + /* <Description> */ + /* A callback used to delete the common SFNT data from a face. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Note> */ + /* This function does NOT destroy the face object. */ + /* */ + typedef void + (*TT_Done_Face_Func)( TT_Face face ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SFNT_HeaderRec_Func */ + /* */ + /* <Description> */ + /* Loads the header of a SFNT font file. Supports collections. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* <Output> */ + /* sfnt :: The SFNT header. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* This function checks that the header is valid by looking at the */ + /* values of `search_range', `entry_selector', and `range_shift'. */ + /* */ + typedef FT_Error + (*TT_Load_SFNT_HeaderRec_Func)( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header sfnt ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Directory_Func */ + /* */ + /* <Description> */ + /* Loads the table directory into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* sfnt :: The SFNT header. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be on the first byte after the 4-byte font */ + /* format tag. This is the case just after a call to */ + /* TT_Load_Format_Tag(). */ + /* */ + typedef FT_Error + (*TT_Load_Directory_Func)( TT_Face face, + FT_Stream stream, + SFNT_Header sfnt ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Any_Func */ + /* */ + /* <Description> */ + /* Load any font table into client memory. */ + /* */ + /* <Input> */ + /* face :: The face object to look for. */ + /* */ + /* tag :: The tag of table to load. Use the value 0 if you want */ + /* to access the whole font file, else set this parameter */ + /* to a valid TrueType table tag that you can forge with */ + /* the MAKE_TT_TAG macro. */ + /* */ + /* offset :: The starting offset in the table (or the file if */ + /* tag == 0). */ + /* */ + /* length :: The address of the decision variable: */ + /* */ + /* If length == NULL: */ + /* Loads the whole table. Returns an error if */ + /* `offset' == 0! */ + /* */ + /* If *length == 0: */ + /* Exits immediately; returning the length of the given */ + /* table or of the font file, depending on the value of */ + /* `tag'. */ + /* */ + /* If *length != 0: */ + /* Loads the next `length' bytes of table or font, */ + /* starting at offset `offset' (in table or font too). */ + /* */ + /* <Output> */ + /* buffer :: The address of target buffer. */ + /* */ + /* <Return> */ + /* TrueType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte *buffer, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Find_SBit_Image_Func */ + /* */ + /* <Description> */ + /* Check whether an embedded bitmap (an `sbit') exists for a given */ + /* glyph, at a given strike. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* strike_index :: The current strike index. */ + /* */ + /* <Output> */ + /* arange :: The SBit range containing the glyph index. */ + /* */ + /* astrike :: The SBit strike containing the glyph index. */ + /* */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns */ + /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */ + /* glyph. */ + /* */ + typedef FT_Error + (*TT_Find_SBit_Image_Func)( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SBit_Metrics_Func */ + /* */ + /* <Description> */ + /* Get the big metrics for a given embedded bitmap. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* range :: The SBit range containing the glyph. */ + /* */ + /* <Output> */ + /* big_metrics :: A big SBit metrics structure for the glyph. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be positioned at the glyph's offset within */ + /* the `EBDT' table before the call. */ + /* */ + /* If the image format uses variable metrics, the stream cursor is */ + /* positioned just after the metrics header in the `EBDT' table on */ + /* function exit. */ + /* */ + typedef FT_Error + (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SBit_Image_Func */ + /* */ + /* <Description> */ + /* Load a given glyph sbit image from the font resource. This also */ + /* returns its metrics. */ + /* */ + /* <Input> */ + /* face :: */ + /* The target face object. */ + /* */ + /* strike_index :: */ + /* The strike index. */ + /* */ + /* glyph_index :: */ + /* The current glyph index. */ + /* */ + /* load_flags :: */ + /* The current load flags. */ + /* */ + /* stream :: */ + /* The input stream. */ + /* */ + /* <Output> */ + /* amap :: */ + /* The target pixmap. */ + /* */ + /* ametrics :: */ + /* A big sbit metrics structure for the glyph image. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* glyph sbit exists for the index. */ + /* */ + /* <Note> */ + /* The `map.buffer' field is always freed before the glyph is loaded. */ + /* */ + typedef FT_Error + (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *amap, + TT_SBit_MetricsRec *ametrics ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Set_SBit_Strike_OldFunc */ + /* */ + /* <Description> */ + /* Select an sbit strike for a given size request. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* req :: The size request. */ + /* */ + /* <Output> */ + /* astrike_index :: The index of the sbit strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* sbit strike exists for the selected ppem values. */ + /* */ + typedef FT_Error + (*TT_Set_SBit_Strike_OldFunc)( TT_Face face, + FT_UInt x_ppem, + FT_UInt y_ppem, + FT_ULong* astrike_index ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_CharMap_Load_Func */ + /* */ + /* <Description> */ + /* Loads a given TrueType character map into memory. */ + /* */ + /* <Input> */ + /* face :: A handle to the parent face object. */ + /* */ + /* stream :: A handle to the current stream object. */ + /* */ + /* <InOut> */ + /* cmap :: A pointer to a cmap object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The function assumes that the stream is already in use (i.e., */ + /* opened). In case of error, all partially allocated tables are */ + /* released. */ + /* */ + typedef FT_Error + (*TT_CharMap_Load_Func)( TT_Face face, + void* cmap, + FT_Stream input ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_CharMap_Free_Func */ + /* */ + /* <Description> */ + /* Destroys a character mapping table. */ + /* */ + /* <Input> */ + /* face :: A handle to the parent face object. */ + /* */ + /* cmap :: A handle to a cmap object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_CharMap_Free_Func)( TT_Face face, + void* cmap ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Set_SBit_Strike_Func */ + /* */ + /* <Description> */ + /* Select an sbit strike for a given size request. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* req :: The size request. */ + /* */ + /* <Output> */ + /* astrike_index :: The index of the sbit strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* sbit strike exists for the selected ppem values. */ + /* */ + typedef FT_Error + (*TT_Set_SBit_Strike_Func)( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Strike_Metrics_Func */ + /* */ + /* <Description> */ + /* Load the metrics of a given strike. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* strike_index :: The strike index. */ + /* */ + /* <Output> */ + /* metrics :: the metrics of the strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* such sbit strike exists. */ + /* */ + typedef FT_Error + (*TT_Load_Strike_Metrics_Func)( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Get_PS_Name_Func */ + /* */ + /* <Description> */ + /* Get the PostScript glyph name of a glyph. */ + /* */ + /* <Input> */ + /* idx :: The glyph index. */ + /* */ + /* PSname :: The address of a string pointer. Will be NULL in case */ + /* of error, otherwise it is a pointer to the glyph name. */ + /* */ + /* You must not modify the returned string! */ + /* */ + /* <Output> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Metrics_Func */ + /* */ + /* <Description> */ + /* Load a metrics table, which is a table with a horizontal and a */ + /* vertical version. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load the vertical one. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Get_Metrics_Func */ + /* */ + /* <Description> */ + /* Load the horizontal or vertical header in a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load vertical metrics. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Get_Metrics_Func)( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Table_Func */ + /* */ + /* <Description> */ + /* Load a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The function uses `face->goto_table' to seek the stream to the */ + /* start of the table, except while loading the font directory. */ + /* */ + typedef FT_Error + (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Free_Table_Func */ + /* */ + /* <Description> */ + /* Free a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + typedef void + (*TT_Free_Table_Func)( TT_Face face ); + + + /* + * @functype: + * TT_Face_GetKerningFunc + * + * @description: + * Return the horizontal kerning value between two glyphs. + * + * @input: + * face :: A handle to the source face object. + * left_glyph :: The left glyph index. + * right_glyph :: The right glyph index. + * + * @return: + * The kerning value in font units. + */ + typedef FT_Int + (*TT_Face_GetKerningFunc)( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* SFNT_Interface */ + /* */ + /* <Description> */ + /* This structure holds pointers to the functions used to load and */ + /* free the basic tables that are required in a `sfnt' font file. */ + /* */ + /* <Fields> */ + /* Check the various xxx_Func() descriptions for details. */ + /* */ + typedef struct SFNT_Interface_ + { + TT_Loader_GotoTableFunc goto_table; + + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; + + TT_Load_Any_Func load_any; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Load_SFNT_HeaderRec_Func load_sfnt_header; + TT_Load_Directory_Func load_directory; +#endif + + /* these functions are called by `load_face' but they can also */ + /* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; + + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; + + /* optional tables */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Load_Table_Func load_hdmx_stub; + TT_Free_Table_Func free_hdmx_stub; +#endif + + /* this field was called `load_kerning' up to version 2.1.10 */ + TT_Load_Table_Func load_kern; + + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; + + /* see `ttload.h'; this field was called `load_bitmap_header' up to */ + /* version 2.1.10 */ + TT_Load_Table_Func load_bhed; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* see `ttsbit.h' */ + TT_Set_SBit_Strike_OldFunc set_sbit_strike_stub; + TT_Load_Table_Func load_sbits_stub; + + /* + * The following two fields appeared in version 2.1.8, and were placed + * between `load_sbits' and `load_sbit_image'. We support them as a + * special exception since they are used by Xfont library within the + * X.Org xserver, and because the probability that other rogue clients + * use the other version 2.1.7 fields below is _extremely_ low. + * + * Note that this forces us to disable an interesting memory-saving + * optimization though... + */ + + TT_Find_SBit_Image_Func find_sbit_image; + TT_Load_SBit_Metrics_Func load_sbit_metrics; + +#endif + + TT_Load_SBit_Image_Func load_sbit_image; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Free_Table_Func free_sbits_stub; +#endif + + /* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_CharMap_Load_Func load_charmap_stub; + TT_CharMap_Free_Func free_charmap_stub; +#endif + + /* starting here, the structure differs from version 2.1.7 */ + + /* this field was introduced in version 2.1.8, named `get_psname' */ + TT_Face_GetKerningFunc get_kerning; + + /* new elements introduced after version 2.1.10 */ + + /* load the font directory, i.e., the offset table and */ + /* the table directory */ + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; + + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; + + TT_Set_SBit_Strike_Func set_sbit_strike; + TT_Load_Strike_Metrics_Func load_strike_metrics; + + TT_Get_Metrics_Func get_metrics; + + } SFNT_Interface; + + + /* transitional */ + typedef SFNT_Interface* SFNT_Service; + + +FT_END_HEADER + +#endif /* __SFNT_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/t1types.h b/src/freetype2/freetype/internal/t1types.h new file mode 100644 index 0000000..047c6d5 --- /dev/null +++ b/src/freetype2/freetype/internal/t1types.h @@ -0,0 +1,252 @@ +/***************************************************************************/ +/* */ +/* t1types.h */ +/* */ +/* Basic Type1/Type2 type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1TYPES_H__ +#define __T1TYPES_H__ + + +#include <ft2build.h> +#include FT_TYPE1_TABLES_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include FT_INTERNAL_SERVICE_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_EncodingRec */ + /* */ + /* <Description> */ + /* A structure modeling a custom encoding. */ + /* */ + /* <Fields> */ + /* num_chars :: The number of character codes in the encoding. */ + /* Usually 256. */ + /* */ + /* code_first :: The lowest valid character code in the encoding. */ + /* */ + /* code_last :: The highest valid character code in the encoding. */ + /* */ + /* char_index :: An array of corresponding glyph indices. */ + /* */ + /* char_name :: An array of corresponding glyph names. */ + /* */ + typedef struct T1_EncodingRecRec_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + + FT_UShort* char_index; + FT_String** char_name; + + } T1_EncodingRec, *T1_Encoding; + + + typedef enum T1_EncodingType_ + { + T1_ENCODING_TYPE_NONE = 0, + T1_ENCODING_TYPE_ARRAY, + T1_ENCODING_TYPE_STANDARD, + T1_ENCODING_TYPE_ISOLATIN1, + T1_ENCODING_TYPE_EXPERT + + } T1_EncodingType; + + + typedef struct T1_FontRec_ + { + PS_FontInfoRec font_info; /* font info dictionary */ + PS_PrivateRec private_dict; /* private dictionary */ + FT_String* font_name; /* top-level dictionary */ + + T1_EncodingType encoding_type; + T1_EncodingRec encoding; + + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + + FT_Int num_subrs; + FT_Byte** subrs; + FT_PtrDist* subrs_len; + + FT_Int num_glyphs; + FT_String** glyph_names; /* array of glyph names */ + FT_Byte** charstrings; /* array of glyph charstrings */ + FT_PtrDist* charstrings_len; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_BBox font_bbox; + FT_Long font_id; + + FT_Fixed stroke_width; + + } T1_FontRec, *T1_Font; + + + typedef struct CID_SubrsRec_ + { + FT_UInt num_subrs; + FT_Byte** code; + + } CID_SubrsRec, *CID_Subrs; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** AFM FONT INFORMATION STRUCTURES ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_TrackKernRec_ + { + FT_Int degree; + FT_Fixed min_ptsize; + FT_Fixed min_kern; + FT_Fixed max_ptsize; + FT_Fixed max_kern; + + } AFM_TrackKernRec, *AFM_TrackKern; + + typedef struct AFM_KernPairRec_ + { + FT_Int index1; + FT_Int index2; + FT_Int x; + FT_Int y; + + } AFM_KernPairRec, *AFM_KernPair; + + typedef struct AFM_FontInfoRec_ + { + FT_Bool IsCIDFont; + FT_BBox FontBBox; + FT_Fixed Ascender; + FT_Fixed Descender; + AFM_TrackKern TrackKerns; /* free if non-NULL */ + FT_Int NumTrackKern; + AFM_KernPair KernPairs; /* free if non-NULL */ + FT_Int NumKernPair; + + } AFM_FontInfoRec, *AFM_FontInfo; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL T1_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + + + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + PS_Unicodes unicode_map; +#endif + + /* support for Multiple Masters fonts */ + PS_Blend blend; + + /* undocumented, optional: indices of subroutines that express */ + /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ + /* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; + + /* undocumented, optional: has the same meaning as len_buildchar */ + /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + FT_Int* buildchar; + + /* since version 2.1 - interface to PostScript hinter */ + const void* pshinter; + + } T1_FaceRec; + + + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + void* psaux; + CID_FaceInfoRec cid; + void* afm_data; + CID_Subrs subrs; + + /* since version 2.1 - interface to PostScript hinter */ + void* pshinter; + + /* since version 2.1.8, but was originally positioned after `afm_data' */ + FT_Byte* binary_data; /* used if hex data has been converted */ + FT_Stream cid_stream; + + } CID_FaceRec; + + +FT_END_HEADER + +#endif /* __T1TYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/internal/tttypes.h b/src/freetype2/freetype/internal/tttypes.h new file mode 100644 index 0000000..dfbb6a1 --- /dev/null +++ b/src/freetype2/freetype/internal/tttypes.h @@ -0,0 +1,1543 @@ +/***************************************************************************/ +/* */ +/* tttypes.h */ +/* */ +/* Basic SFNT/TrueType type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTTYPES_H__ +#define __TTTYPES_H__ + + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H +#include FT_INTERNAL_OBJECTS_H + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include FT_MULTIPLE_MASTERS_H +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TTC_HeaderRec */ + /* */ + /* <Description> */ + /* TrueType collection header. This table contains the offsets of */ + /* the font headers of each distinct TrueType face in the file. */ + /* */ + /* <Fields> */ + /* tag :: Must be `ttc ' to indicate a TrueType collection. */ + /* */ + /* version :: The version number. */ + /* */ + /* count :: The number of faces in the collection. The */ + /* specification says this should be an unsigned long, but */ + /* we use a signed long since we need the value -1 for */ + /* specific purposes. */ + /* */ + /* offsets :: The offsets of the font headers, one per face. */ + /* */ + typedef struct TTC_HeaderRec_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + + } TTC_HeaderRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* SFNT_HeaderRec */ + /* */ + /* <Description> */ + /* SFNT file format header. */ + /* */ + /* <Fields> */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of tables in file. */ + /* */ + /* search_range :: Must be `16 * (max power of 2 <= num_tables)'. */ + /* */ + /* entry_selector :: Must be log2 of `search_range / 16'. */ + /* */ + /* range_shift :: Must be `num_tables * 16 - search_range'. */ + /* */ + typedef struct SFNT_HeaderRec_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; + + FT_ULong offset; /* not in file */ + + } SFNT_HeaderRec, *SFNT_Header; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_TableRec */ + /* */ + /* <Description> */ + /* This structure describes a given table of a TrueType font. */ + /* */ + /* <Fields> */ + /* Tag :: A four-bytes tag describing the table. */ + /* */ + /* CheckSum :: The table checksum. This value can be ignored. */ + /* */ + /* Offset :: The offset of the table from the start of the TrueType */ + /* font in its resource. */ + /* */ + /* Length :: The table length (in bytes). */ + /* */ + typedef struct TT_TableRec_ + { + FT_ULong Tag; /* table type */ + FT_ULong CheckSum; /* table checksum */ + FT_ULong Offset; /* table file offset */ + FT_ULong Length; /* table length */ + + } TT_TableRec, *TT_Table; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_LongMetricsRec */ + /* */ + /* <Description> */ + /* A structure modeling the long metrics of the `hmtx' and `vmtx' */ + /* TrueType tables. The values are expressed in font units. */ + /* */ + /* <Fields> */ + /* advance :: The advance width or height for the glyph. */ + /* */ + /* bearing :: The left-side or top-side bearing for the glyph. */ + /* */ + typedef struct TT_LongMetricsRec_ + { + FT_UShort advance; + FT_Short bearing; + + } TT_LongMetricsRec, *TT_LongMetrics; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_ShortMetrics */ + /* */ + /* <Description> */ + /* A simple type to model the short metrics of the `hmtx' and `vmtx' */ + /* tables. */ + /* */ + typedef FT_Short TT_ShortMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_NameEntryRec */ + /* */ + /* <Description> */ + /* A structure modeling TrueType name records. Name records are used */ + /* to store important strings like family name, style name, */ + /* copyright, etc. in _localized_ versions (i.e., language, encoding, */ + /* etc). */ + /* */ + /* <Fields> */ + /* platformID :: The ID of the name's encoding platform. */ + /* */ + /* encodingID :: The platform-specific ID for the name's encoding. */ + /* */ + /* languageID :: The platform-specific ID for the name's language. */ + /* */ + /* nameID :: The ID specifying what kind of name this is. */ + /* */ + /* stringLength :: The length of the string in bytes. */ + /* */ + /* stringOffset :: The offset to the string in the `name' table. */ + /* */ + /* string :: A pointer to the string's bytes. Note that these */ + /* are usually UTF-16 encoded characters. */ + /* */ + typedef struct TT_NameEntryRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_NameEntryRec, *TT_NameEntry; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_NameTableRec */ + /* */ + /* <Description> */ + /* A structure modeling the TrueType name table. */ + /* */ + /* <Fields> */ + /* format :: The format of the name table. */ + /* */ + /* numNameRecords :: The number of names in table. */ + /* */ + /* storageOffset :: The offset of the name table in the `name' */ + /* TrueType table. */ + /* */ + /* names :: An array of name records. */ + /* */ + /* stream :: the file's input stream. */ + /* */ + typedef struct TT_NameTableRec_ + { + FT_UShort format; + FT_UInt numNameRecords; + FT_UInt storageOffset; + TT_NameEntryRec* names; + FT_Stream stream; + + } TT_NameTableRec, *TT_NameTable; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GaspRangeRec */ + /* */ + /* <Description> */ + /* A tiny structure used to model a gasp range according to the */ + /* TrueType specification. */ + /* */ + /* <Fields> */ + /* maxPPEM :: The maximum ppem value to which `gaspFlag' applies. */ + /* */ + /* gaspFlag :: A flag describing the grid-fitting and anti-aliasing */ + /* modes to be used. */ + /* */ + typedef struct TT_GaspRangeRec_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + + } TT_GaspRangeRec, *TT_GaspRange; + + +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GaspRec */ + /* */ + /* <Description> */ + /* A structure modeling the TrueType `gasp' table used to specify */ + /* grid-fitting and anti-aliasing behaviour. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* numRanges :: The number of gasp ranges in table. */ + /* */ + /* gaspRanges :: An array of gasp ranges. */ + /* */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange gaspRanges; + + } TT_GaspRec; + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HdmxEntryRec */ + /* */ + /* <Description> */ + /* A small structure used to model the pre-computed widths of a given */ + /* size. They are found in the `hdmx' table. */ + /* */ + /* <Fields> */ + /* ppem :: The pixels per EM value at which these metrics apply. */ + /* */ + /* max_width :: The maximum advance width for this metric. */ + /* */ + /* widths :: An array of widths. Note: These are 8-bit bytes. */ + /* */ + typedef struct TT_HdmxEntryRec_ + { + FT_Byte ppem; + FT_Byte max_width; + FT_Byte* widths; + + } TT_HdmxEntryRec, *TT_HdmxEntry; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HdmxRec */ + /* */ + /* <Description> */ + /* A structure used to model the `hdmx' table, which contains */ + /* pre-computed widths for a set of given sizes/dimensions. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* num_records :: The number of hdmx records. */ + /* */ + /* records :: An array of hdmx records. */ + /* */ + typedef struct TT_HdmxRec_ + { + FT_UShort version; + FT_Short num_records; + TT_HdmxEntry records; + + } TT_HdmxRec, *TT_Hdmx; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Kern0_PairRec */ + /* */ + /* <Description> */ + /* A structure used to model a kerning pair for the kerning table */ + /* format 0. The engine now loads this table if it finds one in the */ + /* font file. */ + /* */ + /* <Fields> */ + /* left :: The index of the left glyph in pair. */ + /* */ + /* right :: The index of the right glyph in pair. */ + /* */ + /* value :: The kerning distance. A positive value spaces the */ + /* glyphs, a negative one makes them closer. */ + /* */ + typedef struct TT_Kern0_PairRec_ + { + FT_UShort left; /* index of left glyph in pair */ + FT_UShort right; /* index of right glyph in pair */ + FT_FWord value; /* kerning value */ + + } TT_Kern0_PairRec, *TT_Kern0_Pair; + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BITMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_MetricsRec */ + /* */ + /* <Description> */ + /* A structure used to hold the big metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or `bloc' (Apple) table. */ + /* */ + /* <Fields> */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* horiBearingX :: The horizontal left bearing. */ + /* */ + /* horiBearingY :: The horizontal top bearing. */ + /* */ + /* horiAdvance :: The horizontal advance. */ + /* */ + /* vertBearingX :: The vertical left bearing. */ + /* */ + /* vertBearingY :: The vertical top bearing. */ + /* */ + /* vertAdvance :: The vertical advance. */ + /* */ + typedef struct TT_SBit_MetricsRec_ + { + FT_Byte height; + FT_Byte width; + + FT_Char horiBearingX; + FT_Char horiBearingY; + FT_Byte horiAdvance; + + FT_Char vertBearingX; + FT_Char vertBearingY; + FT_Byte vertAdvance; + + } TT_SBit_MetricsRec, *TT_SBit_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_SmallMetricsRec */ + /* */ + /* <Description> */ + /* A structure used to hold the small metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or the `bdat' (Apple) table. */ + /* */ + /* <Fields> */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* bearingX :: The left-side bearing. */ + /* */ + /* bearingY :: The top-side bearing. */ + /* */ + /* advance :: The advance width or height. */ + /* */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + + } TT_SBit_SmallMetricsRec, *TT_SBit_SmallMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_LineMetricsRec */ + /* */ + /* <Description> */ + /* A structure used to describe the text line metrics of a given */ + /* bitmap strike, for either a horizontal or vertical layout. */ + /* */ + /* <Fields> */ + /* ascender :: The ascender in pixels. */ + /* */ + /* descender :: The descender in pixels. */ + /* */ + /* max_width :: The maximum glyph width in pixels. */ + /* */ + /* caret_slope_enumerator :: Rise of the caret slope, typically set */ + /* to 1 for non-italic fonts. */ + /* */ + /* caret_slope_denominator :: Rise of the caret slope, typically set */ + /* to 0 for non-italic fonts. */ + /* */ + /* caret_offset :: Offset in pixels to move the caret for */ + /* proper positioning. */ + /* */ + /* min_origin_SB :: Minimum of horiBearingX (resp. */ + /* vertBearingY). */ + /* min_advance_SB :: Minimum of */ + /* */ + /* horizontal advance - */ + /* ( horiBearingX + width ) */ + /* */ + /* resp. */ + /* */ + /* vertical advance - */ + /* ( vertBearingY + height ) */ + /* */ + /* max_before_BL :: Maximum of horiBearingY (resp. */ + /* vertBearingY). */ + /* */ + /* min_after_BL :: Minimum of */ + /* */ + /* horiBearingY - height */ + /* */ + /* resp. */ + /* */ + /* vertBearingX - width */ + /* */ + /* pads :: Unused (to make the size of the record */ + /* a multiple of 32 bits. */ + /* */ + typedef struct TT_SBit_LineMetricsRec_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + + } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_RangeRec */ + /* */ + /* <Description> */ + /* A TrueType/OpenType subIndexTable as defined in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* <Fields> */ + /* first_glyph :: The first glyph index in the range. */ + /* */ + /* last_glyph :: The last glyph index in the range. */ + /* */ + /* index_format :: The format of index table. Valid values are 1 */ + /* to 5. */ + /* */ + /* image_format :: The format of `EBDT' image data. */ + /* */ + /* image_offset :: The offset to image data in `EBDT'. */ + /* */ + /* image_size :: For index formats 2 and 5. This is the size in */ + /* bytes of each glyph bitmap. */ + /* */ + /* big_metrics :: For index formats 2 and 5. This is the big */ + /* metrics for each glyph bitmap. */ + /* */ + /* num_glyphs :: For index formats 4 and 5. This is the number of */ + /* glyphs in the code array. */ + /* */ + /* glyph_offsets :: For index formats 1 and 3. */ + /* */ + /* glyph_codes :: For index formats 4 and 5. */ + /* */ + /* table_offset :: The offset of the index table in the `EBLC' */ + /* table. Only used during strike loading. */ + /* */ + typedef struct TT_SBit_RangeRec + { + FT_UShort first_glyph; + FT_UShort last_glyph; + + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + + FT_ULong image_size; + TT_SBit_MetricsRec metrics; + FT_ULong num_glyphs; + + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + + FT_ULong table_offset; + + } TT_SBit_RangeRec, *TT_SBit_Range; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_StrikeRec */ + /* */ + /* <Description> */ + /* A structure used describe a given bitmap strike in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* <Fields> */ + /* num_index_ranges :: The number of index ranges. */ + /* */ + /* index_ranges :: An array of glyph index ranges. */ + /* */ + /* color_ref :: Unused. `color_ref' is put in for future */ + /* enhancements, but these fields are already */ + /* in use by other platforms (e.g. Newton). */ + /* For details, please see */ + /* */ + /* http://fonts.apple.com/ */ + /* TTRefMan/RM06/Chap6bloc.html */ + /* */ + /* hori :: The line metrics for horizontal layouts. */ + /* */ + /* vert :: The line metrics for vertical layouts. */ + /* */ + /* start_glyph :: The lowest glyph index for this strike. */ + /* */ + /* end_glyph :: The highest glyph index for this strike. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* bit_depth :: The bit depth. Valid values are 1, 2, 4, */ + /* and 8. */ + /* */ + /* flags :: Is this a vertical or horizontal strike? For */ + /* details, please see */ + /* */ + /* http://fonts.apple.com/ */ + /* TTRefMan/RM06/Chap6bloc.html */ + /* */ + typedef struct TT_SBit_StrikeRec_ + { + FT_Int num_ranges; + TT_SBit_Range sbit_ranges; + FT_ULong ranges_offset; + + FT_ULong color_ref; + + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_UShort start_glyph; + FT_UShort end_glyph; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte bit_depth; + FT_Char flags; + + } TT_SBit_StrikeRec, *TT_SBit_Strike; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_ComponentRec */ + /* */ + /* <Description> */ + /* A simple structure to describe a compound sbit element. */ + /* */ + /* <Fields> */ + /* glyph_code :: The element's glyph index. */ + /* */ + /* x_offset :: The element's left bearing. */ + /* */ + /* y_offset :: The element's top bearing. */ + /* */ + typedef struct TT_SBit_ComponentRec_ + { + FT_UShort glyph_code; + FT_Char x_offset; + FT_Char y_offset; + + } TT_SBit_ComponentRec, *TT_SBit_Component; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_ScaleRec */ + /* */ + /* <Description> */ + /* A structure used describe a given bitmap scaling table, as defined */ + /* in the `EBSC' table. */ + /* */ + /* <Fields> */ + /* hori :: The horizontal line metrics. */ + /* */ + /* vert :: The vertical line metrics. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* x_ppem_substitute :: Substitution x_ppem value. */ + /* */ + /* y_ppem_substitute :: Substitution y_ppem value. */ + /* */ + typedef struct TT_SBit_ScaleRec_ + { + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + + } TT_SBit_ScaleRec, *TT_SBit_Scale; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_20Rec */ + /* */ + /* <Description> */ + /* Postscript names sub-table, format 2.0. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* <Fields> */ + /* num_glyphs :: The number of named glyphs in the table. */ + /* */ + /* num_names :: The number of PS names stored in the table. */ + /* */ + /* glyph_indices :: The indices of the glyphs in the names arrays. */ + /* */ + /* glyph_names :: The PS names not in Mac Encoding. */ + /* */ + typedef struct TT_Post_20Rec_ + { + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Char** glyph_names; + + } TT_Post_20Rec, *TT_Post_20; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_25Rec */ + /* */ + /* <Description> */ + /* Postscript names sub-table, format 2.5. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* <Fields> */ + /* num_glyphs :: The number of glyphs in the table. */ + /* */ + /* offsets :: An array of signed offsets in a normal Mac */ + /* Postscript name encoding. */ + /* */ + typedef struct TT_Post_25_ + { + FT_UShort num_glyphs; + FT_Char* offsets; + + } TT_Post_25Rec, *TT_Post_25; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_NamesRec */ + /* */ + /* <Description> */ + /* Postscript names table, either format 2.0 or 2.5. */ + /* */ + /* <Fields> */ + /* loaded :: A flag to indicate whether the PS names are loaded. */ + /* */ + /* format_20 :: The sub-table used for format 2.0. */ + /* */ + /* format_25 :: The sub-table used for format 2.5. */ + /* */ + typedef struct TT_Post_NamesRec_ + { + FT_Bool loaded; + + union + { + TT_Post_20Rec format_20; + TT_Post_25Rec format_25; + + } names; + + } TT_Post_NamesRec, *TT_Post_Names; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** GX VARIATION TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + typedef struct GX_BlendRec_ *GX_Blend; +#endif + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BDF PROPERTIES TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * These types are used to support a `BDF ' table that isn't part of the + * official TrueType specification. It is mainly used in SFNT-based + * bitmap fonts that were generated from a set of BDF fonts. + * + * The format of the table is as follows. + * + * USHORT version `BDF ' table version number, should be 0x0001. + * USHORT strikeCount Number of strikes (bitmap sizes) in this table. + * ULONG stringTable Offset (from start of BDF table) to string + * table. + * + * This is followed by an array of `strikeCount' descriptors, having the + * following format. + * + * USHORT ppem Vertical pixels per EM for this strike. + * USHORT numItems Number of items for this strike (properties and + * atoms). Maximum is 255. + * + * This array in turn is followed by `strikeCount' value sets. Each + * `value set' is an array of `numItems' items with the following format. + * + * ULONG item_name Offset in string table to item name. + * USHORT item_type The item type. Possible values are + * 0 => string (e.g., COMMENT) + * 1 => atom (e.g., FONT or even SIZE) + * 2 => int32 + * 3 => uint32 + * 0x10 => A flag to indicate a properties. This + * is ORed with the above values. + * ULONG item_value For strings => Offset into string table without + * the corresponding double quotes. + * For atoms => Offset into string table. + * For integers => Direct value. + * + * All strings in the string table consist of bytes and are + * zero-terminated. + * + */ + +#ifdef TT_CONFIG_OPTION_BDF + + typedef struct TT_BDFRec_ + { + FT_Byte* table; + FT_Byte* table_end; + FT_Byte* strings; + FT_UInt32 strings_size; + FT_UInt num_strikes; + FT_Bool loaded; + + } TT_BDFRec, *TT_BDF; + +#endif /* TT_CONFIG_OPTION_BDF */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL TT_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This structure/class is defined here because it is common to the */ + /* following formats: TTF, OpenType-TT, and OpenType-CFF. */ + /* */ + /* Note, however, that the classes TT_Size and TT_GlyphSlot are not */ + /* shared between font drivers, and are thus defined in `ttobjs.h'. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_Face */ + /* */ + /* <Description> */ + /* A handle to a TrueType face/font object. A TT_Face encapsulates */ + /* the resolution and scaling independent parts of a TrueType font */ + /* resource. */ + /* */ + /* <Note> */ + /* The TT_Face structure is also used as a `parent class' for the */ + /* OpenType-CFF class (T2_Face). */ + /* */ + typedef struct TT_FaceRec_* TT_Face; + + + /* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error + (*TT_Interpreter)( void* exec_context ); + + /* forward declaration */ + typedef struct TT_LoaderRec_* TT_Loader; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_GotoTableFunc */ + /* */ + /* <Description> */ + /* Seeks a stream to the start of a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* tag :: A 4-byte tag used to name the table. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Output> */ + /* length :: The length of the table in bytes. Set to 0 if not */ + /* needed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + typedef FT_Error + (*TT_Loader_GotoTableFunc)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_StartGlyphFunc */ + /* */ + /* <Description> */ + /* Seeks a stream to the start of a given glyph element, and opens a */ + /* frame for it. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* glyph index :: The index of the glyph to access. */ + /* */ + /* offset :: The offset of the glyph according to the */ + /* `locations' table. */ + /* */ + /* byte_count :: The size of the frame in bytes. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function is normally equivalent to FT_STREAM_SEEK(offset) */ + /* followed by FT_FRAME_ENTER(byte_count) with the loader's stream, */ + /* but alternative formats (e.g. compressed ones) might use something */ + /* different. */ + /* */ + typedef FT_Error + (*TT_Loader_StartGlyphFunc)( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_ReadGlyphFunc */ + /* */ + /* <Description> */ + /* Reads one glyph element (its header, a simple glyph, or a */ + /* composite) from the loader's current stream frame. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_EndGlyphFunc */ + /* */ + /* <Description> */ + /* Closes the current loader stream frame for the glyph. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + typedef void + (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); + + + /*************************************************************************/ + /* */ + /* TrueType Face Type */ + /* */ + /* <Struct> */ + /* TT_Face */ + /* */ + /* <Description> */ + /* The TrueType face class. These objects model the resolution and */ + /* point-size independent data found in a TrueType font file. */ + /* */ + /* <Fields> */ + /* root :: The base FT_Face structure, managed by the */ + /* base layer. */ + /* */ + /* ttc_header :: The TrueType collection header, used when */ + /* the file is a `ttc' rather than a `ttf'. */ + /* For ordinary font files, the field */ + /* `ttc_header.count' is set to 0. */ + /* */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of TrueType tables in this font */ + /* file. */ + /* */ + /* dir_tables :: The directory of TrueType tables for this */ + /* font file. */ + /* */ + /* header :: The font's font header (`head' table). */ + /* Read on font opening. */ + /* */ + /* horizontal :: The font's horizontal header (`hhea' */ + /* table). This field also contains the */ + /* associated horizontal metrics table */ + /* (`hmtx'). */ + /* */ + /* max_profile :: The font's maximum profile table. Read on */ + /* font opening. Note that some maximum */ + /* values cannot be taken directly from this */ + /* table. We thus define additional fields */ + /* below to hold the computed maxima. */ + /* */ + /* vertical_info :: A boolean which is set when the font file */ + /* contains vertical metrics. If not, the */ + /* value of the `vertical' field is */ + /* undefined. */ + /* */ + /* vertical :: The font's vertical header (`vhea' table). */ + /* This field also contains the associated */ + /* vertical metrics table (`vmtx'), if found. */ + /* IMPORTANT: The contents of this field is */ + /* undefined if the `verticalInfo' field is */ + /* unset. */ + /* */ + /* num_names :: The number of name records within this */ + /* TrueType font. */ + /* */ + /* name_table :: The table of name records (`name'). */ + /* */ + /* os2 :: The font's OS/2 table (`OS/2'). */ + /* */ + /* postscript :: The font's PostScript table (`post' */ + /* table). The PostScript glyph names are */ + /* not loaded by the driver on face opening. */ + /* See the `ttpost' module for more details. */ + /* */ + /* cmap_table :: Address of the face's `cmap' SFNT table */ + /* in memory (it's an extracted frame). */ + /* */ + /* cmap_size :: The size in bytes of the `cmap_table' */ + /* described above. */ + /* */ + /* goto_table :: A function called by each TrueType table */ + /* loader to position a stream's cursor to */ + /* the start of a given table according to */ + /* its tag. It defaults to TT_Goto_Face but */ + /* can be different for strange formats (e.g. */ + /* Type 42). */ + /* */ + /* access_glyph_frame :: A function used to access the frame of a */ + /* given glyph within the face's font file. */ + /* */ + /* forget_glyph_frame :: A function used to forget the frame of a */ + /* given glyph when all data has been loaded. */ + /* */ + /* read_glyph_header :: A function used to read a glyph header. */ + /* It must be called between an `access' and */ + /* `forget'. */ + /* */ + /* read_simple_glyph :: A function used to read a simple glyph. */ + /* It must be called after the header was */ + /* read, and before the `forget'. */ + /* */ + /* read_composite_glyph :: A function used to read a composite glyph. */ + /* It must be called after the header was */ + /* read, and before the `forget'. */ + /* */ + /* sfnt :: A pointer to the SFNT service. */ + /* */ + /* psnames :: A pointer to the PostScript names service. */ + /* */ + /* hdmx :: The face's horizontal device metrics */ + /* (`hdmx' table). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* gasp :: The grid-fitting and scaling properties */ + /* table (`gasp'). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* pclt :: The `pclt' SFNT table. */ + /* */ + /* num_sbit_strikes :: The number of sbit strikes, i.e., bitmap */ + /* sizes, embedded in this font. */ + /* */ + /* sbit_strikes :: An array of sbit strikes embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* num_sbit_scales :: The number of sbit scales for this font. */ + /* */ + /* sbit_scales :: Array of sbit scales embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* postscript_names :: A table used to store the Postscript names */ + /* of the glyphs for this font. See the */ + /* file `ttconfig.h' for comments on the */ + /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. */ + /* */ + /* num_locations :: The number of glyph locations in this */ + /* TrueType file. This should be */ + /* identical to the number of glyphs. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* glyph_locations :: An array of longs. These are offsets to */ + /* glyph data within the `glyf' table. */ + /* Ignored for Type 2 font faces. */ + /* */ + /* glyf_len :: The length of the `glyf' table. Needed */ + /* for malformed `loca' tables. */ + /* */ + /* font_program_size :: Size in bytecodes of the face's font */ + /* program. 0 if none defined. Ignored for */ + /* Type 2 fonts. */ + /* */ + /* font_program :: The face's font program (bytecode stream) */ + /* executed at load time, also used during */ + /* glyph rendering. Comes from the `fpgm' */ + /* table. Ignored for Type 2 font fonts. */ + /* */ + /* cvt_program_size :: The size in bytecodes of the face's cvt */ + /* program. Ignored for Type 2 fonts. */ + /* */ + /* cvt_program :: The face's cvt program (bytecode stream) */ + /* executed each time an instance/size is */ + /* changed/reset. Comes from the `prep' */ + /* table. Ignored for Type 2 fonts. */ + /* */ + /* cvt_size :: Size of the control value table (in */ + /* entries). Ignored for Type 2 fonts. */ + /* */ + /* cvt :: The face's original control value table. */ + /* Coordinates are expressed in unscaled font */ + /* units. Comes from the `cvt ' table. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* num_kern_pairs :: The number of kerning pairs present in the */ + /* font file. The engine only loads the */ + /* first horizontal format 0 kern table it */ + /* finds in the font file. Ignored for */ + /* Type 2 fonts. */ + /* */ + /* kern_table_index :: The index of the kerning table in the font */ + /* kerning directory. Ignored for Type 2 */ + /* fonts. */ + /* */ + /* interpreter :: A pointer to the TrueType bytecode */ + /* interpreters field is also used to hook */ + /* the debugger in `ttdebug'. */ + /* */ + /* unpatented_hinting :: If true, use only unpatented methods in */ + /* the bytecode interpreter. */ + /* */ + /* doblend :: A boolean which is set if the font should */ + /* be blended (this is for GX var). */ + /* */ + /* blend :: Contains the data needed to control GX */ + /* variation tables (rather like Multiple */ + /* Master data). */ + /* */ + /* extra :: Reserved for third-party font drivers. */ + /* */ + /* postscript_name :: The PS name of the font. Used by the */ + /* postscript name service. */ + /* */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + + TTC_HeaderRec ttc_header; + + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table dir_tables; + + TT_Header header; /* TrueType header table */ + TT_HoriHeader horizontal; /* TrueType horizontal header */ + + TT_MaxProfile max_profile; +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_ULong max_components; /* stubbed to 0 */ +#endif + + FT_Bool vertical_info; + TT_VertHeader vertical; /* TT Vertical header, if present */ + + FT_UShort num_names; /* number of name records */ + TT_NameTableRec name_table; /* name table */ + + TT_OS2 os2; /* TrueType OS/2 table */ + TT_Postscript postscript; /* TrueType Postscript table */ + + FT_Byte* cmap_table; /* extracted `cmap' table */ + FT_ULong cmap_size; + + TT_Loader_GotoTableFunc goto_table; + + TT_Loader_StartGlyphFunc access_glyph_frame; + TT_Loader_EndGlyphFunc forget_glyph_frame; + TT_Loader_ReadGlyphFunc read_glyph_header; + TT_Loader_ReadGlyphFunc read_simple_glyph; + TT_Loader_ReadGlyphFunc read_composite_glyph; + + /* a typeless pointer to the SFNT_Interface table used to load */ + /* the basic TrueType tables in the face object */ + void* sfnt; + + /* a typeless pointer to the FT_Service_PsCMapsRec table used to */ + /* handle glyph names <-> unicode & Mac values */ + void* psnames; + + + /***********************************************************************/ + /* */ + /* Optional TrueType/OpenType tables */ + /* */ + /***********************************************************************/ + + /* horizontal device metrics */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_HdmxRec hdmx; +#endif + + /* grid-fitting and scaling table */ + TT_GaspRec gasp; /* the `gasp' table */ + + /* PCL 5 table */ + TT_PCLT pclt; + + /* embedded bitmaps support */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_ULong num_sbit_strikes; + TT_SBit_Strike sbit_strikes; +#endif + + FT_ULong num_sbit_scales; + TT_SBit_Scale sbit_scales; + + /* postscript names table */ + TT_Post_NamesRec postscript_names; + + + /***********************************************************************/ + /* */ + /* TrueType-specific fields (ignored by the OTF-Type2 driver) */ + /* */ + /***********************************************************************/ + + /* the glyph locations */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_UShort num_locations_stub; + FT_Long* glyph_locations_stub; +#endif + + /* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; + + /* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; + + /* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Short* cvt; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + /* the format 0 kerning table, if any */ + FT_Int num_kern_pairs; + FT_Int kern_table_index; + TT_Kern0_Pair kern_pairs; +#endif + + /* A pointer to the bytecode interpreter to use. This is also */ + /* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + /* Use unpatented hinting only. */ + FT_Bool unpatented_hinting; +#endif + + /***********************************************************************/ + /* */ + /* Other tables or fields. This is used by derivative formats like */ + /* OpenType. */ + /* */ + /***********************************************************************/ + + FT_Generic extra; + + const char* postscript_name; + + /* since version 2.1.8, but was originally placed after */ + /* `glyph_locations_stub' */ + FT_ULong glyf_len; + + /* since version 2.1.8, but was originally placed before `extra' */ +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Bool doblend; + GX_Blend blend; +#endif + + /* since version 2.2 */ + + FT_Byte* horz_metrics; + FT_ULong horz_metrics_size; + + FT_Byte* vert_metrics; + FT_ULong vert_metrics_size; + + FT_UInt num_locations; + FT_Byte* glyph_locations; + + FT_Byte* hdmx_table; + FT_ULong hdmx_table_size; + FT_UInt hdmx_record_count; + FT_ULong hdmx_record_size; + FT_Byte* hdmx_record_sizes; + + FT_Byte* sbit_table; + FT_ULong sbit_table_size; + FT_UInt sbit_num_strikes; + + FT_Byte* kern_table; + FT_ULong kern_table_size; + FT_UInt num_kern_tables; + FT_UInt32 kern_avail_bits; + FT_UInt32 kern_order_bits; + +#ifdef TT_CONFIG_OPTION_BDF + TT_BDFRec bdf; +#endif /* TT_CONFIG_OPTION_BDF */ + + /* since 2.3.0 */ + FT_ULong horz_metrics_offset; + FT_ULong vert_metrics_offset; + + } TT_FaceRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GlyphZoneRec */ + /* */ + /* <Description> */ + /* A glyph zone is used to load, scale and hint glyph outline */ + /* coordinates. */ + /* */ + /* <Fields> */ + /* memory :: A handle to the memory manager. */ + /* */ + /* max_points :: The maximal size in points of the zone. */ + /* */ + /* max_contours :: Max size in links contours of the zone. */ + /* */ + /* n_points :: The current number of points in the zone. */ + /* */ + /* n_contours :: The current number of contours in the zone. */ + /* */ + /* org :: The original glyph coordinates (font */ + /* units/scaled). */ + /* */ + /* cur :: The current glyph coordinates (scaled/hinted). */ + /* */ + /* tags :: The point control tags. */ + /* */ + /* contours :: The contours end points. */ + /* */ + /* first_point :: Offset of the current subglyph's first point. */ + /* */ + typedef struct TT_GlyphZoneRec_ + { + FT_Memory memory; + FT_UShort max_points; + FT_UShort max_contours; + FT_UShort n_points; /* number of points in zone */ + FT_Short n_contours; /* number of contours */ + + FT_Vector* org; /* original point coordinates */ + FT_Vector* cur; /* current point coordinates */ + FT_Vector* orus; /* original (unscaled) point coordinates */ + + FT_Byte* tags; /* current touch flags */ + FT_UShort* contours; /* contour end points */ + + FT_UShort first_point; /* offset of first (#0) point */ + + } TT_GlyphZoneRec, *TT_GlyphZone; + + + /* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; + + /* glyph loader structure */ + typedef struct TT_LoaderRec_ + { + FT_Face face; + FT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader gloader; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_Int byte_len; + + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Int linear; + FT_Bool linear_def; + FT_Bool preserve_pps; + FT_Vector pp1; + FT_Vector pp2; + + FT_ULong glyf_offset; + + /* the zone where we load our glyphs */ + TT_GlyphZoneRec base; + TT_GlyphZoneRec zone; + + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; + + /* for possible extensibility in other formats */ + void* other; + + /* since version 2.1.8 */ + FT_Int top_bearing; + FT_Int vadvance; + FT_Vector pp3; + FT_Vector pp4; + + /* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + + } TT_LoaderRec; + + +FT_END_HEADER + +#endif /* __TTTYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/t1tables.h b/src/freetype2/freetype/t1tables.h new file mode 100644 index 0000000..250629d --- /dev/null +++ b/src/freetype2/freetype/t1tables.h @@ -0,0 +1,450 @@ +/***************************************************************************/ +/* */ +/* t1tables.h */ +/* */ +/* Basic Type 1/Type 2 tables definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1TABLES_H__ +#define __T1TABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* type1_tables */ + /* */ + /* <Title> */ + /* Type 1 Tables */ + /* */ + /* <Abstract> */ + /* Type 1 (PostScript) specific font tables. */ + /* */ + /* <Description> */ + /* This section contains the definition of Type 1-specific tables, */ + /* including structures related to other PostScript font formats. */ + /* */ + /*************************************************************************/ + + + /* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ + /* structures in order to support Multiple Master fonts. */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_FontInfoRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own */ + /* FontInfo dictionary. */ + /* */ + typedef struct PS_FontInfoRec + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } PS_FontInfoRec, *PS_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_FontInfo */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_FontInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_FontInfoRec T1_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_PrivateRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type1/Type2 private dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own Private */ + /* dictionary. */ + /* */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* including std width */ + FT_Short snap_heights[13]; /* including std height */ + + FT_Fixed expansion_factor; + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } PS_PrivateRec, *PS_Private; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_Private */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_PrivateRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_PrivateRec T1_Private; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* T1_Blend_Flags */ + /* */ + /* <Description> */ + /* A set of flags used to indicate which fields are present in a */ + /* given blend dictionary (font info or private). Used to support */ + /* Multiple Masters fonts. */ + /* */ + typedef enum + { + /*# required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, + + /*# required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, + + /*# never remove */ + T1_BLEND_MAX + + } T1_Blend_Flags; + + /* */ + + + /*# backwards compatible definitions */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX + + + /* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 + + /* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 + + /* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backwards-compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backwards-compatible definition */ + typedef PS_BlendRec T1_Blend; + + + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_Int sd_bytes; + + } CID_FaceDictRec, *CID_FaceDict; + + + /* backwards-compatible definition */ + typedef CID_FaceDictRec CID_FontDict; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceInfoRec */ + /* */ + /* <Description> */ + /* A structure used to represent CID Face information. */ + /* */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + FT_ULong cidmap_offset; + FT_Int fd_bytes; + FT_Int gd_bytes; + FT_ULong cid_count; + + FT_Int num_dicts; + CID_FaceDict font_dicts; + + FT_ULong data_offset; + + } CID_FaceInfoRec, *CID_FaceInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_Info */ + /* */ + /* <Description> */ + /* This type is equivalent to @CID_FaceInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef CID_FaceInfoRec CID_Info; + + /* */ + + + /************************************************************************ + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable Postscript glyph + * names. This is similar to using the @FT_HAS_GLYPH_NAMES macro, + * except that certain fonts (mostly TrueType) contain incorrect + * glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * Postscript font. + * + * @input: + * face :: + * Postscript face handle. + * + * @output: + * afont_info :: + * Output font info structure pointer. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not Postscript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec *afont_info ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * Postscript font. + * + * @input: + * face :: + * Postscript face handle. + * + * @output: + * afont_private :: + * Output private dictionary structure pointer. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not Postscript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec *afont_private ); + + /* */ + + + +FT_END_HEADER + +#endif /* __T1TABLES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ttnameid.h b/src/freetype2/freetype/ttnameid.h new file mode 100644 index 0000000..b9acbda --- /dev/null +++ b/src/freetype2/freetype/ttnameid.h @@ -0,0 +1,1132 @@ +/***************************************************************************/ +/* */ +/* ttnameid.h */ +/* */ +/* TrueType name ID definitions (specification only). */ +/* */ +/* Copyright 1996-2002, 2003, 2004, 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 __TTNAMEID_H__ +#define __TTNAMEID_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* Possible values for the `platform' identifier code in the name */ + /* records of the TTF `name' table. */ + /* */ + /*************************************************************************/ + + + /*********************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id' identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id' values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name entry. + * See @TT_MAC_ID_XXX for corresponding `encoding_id' values. Note that + * most TrueType fonts contain an Apple roman charmap to be usable on + * MacOS systems (even if they contain a Microsoft charmap as well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify Unicode charmaps. It is however + * now deprecated. See @TT_ISO_ID_XXX for a list of corresponding + * `encoding_id' values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id' values. + * Note that most fonts contain a Unicode charmap using + * (TT_PLATFORM_MICROSOFT, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ + +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +#define TT_PLATFORM_ADOBE 7 /* artificial */ + + + /*********************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + */ + +#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ +#define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ + + + /*********************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + * + * @values: + * TT_MAC_ID_ROMAN :: + * TT_MAC_ID_JAPANESE :: + * TT_MAC_ID_TRADITIONAL_CHINESE :: + * TT_MAC_ID_KOREAN :: + * TT_MAC_ID_ARABIC :: + * TT_MAC_ID_HEBREW :: + * TT_MAC_ID_GREEK :: + * TT_MAC_ID_RUSSIAN :: + * TT_MAC_ID_RSYMBOL :: + * TT_MAC_ID_DEVANAGARI :: + * TT_MAC_ID_GURMUKHI :: + * TT_MAC_ID_GUJARATI :: + * TT_MAC_ID_ORIYA :: + * TT_MAC_ID_BENGALI :: + * TT_MAC_ID_TAMIL :: + * TT_MAC_ID_TELUGU :: + * TT_MAC_ID_KANNADA :: + * TT_MAC_ID_MALAYALAM :: + * TT_MAC_ID_SINHALESE :: + * TT_MAC_ID_BURMESE :: + * TT_MAC_ID_KHMER :: + * TT_MAC_ID_THAI :: + * TT_MAC_ID_LAOTIAN :: + * TT_MAC_ID_GEORGIAN :: + * TT_MAC_ID_ARMENIAN :: + * TT_MAC_ID_MALDIVIAN :: + * TT_MAC_ID_SIMPLIFIED_CHINESE :: + * TT_MAC_ID_TIBETAN :: + * TT_MAC_ID_MONGOLIAN :: + * TT_MAC_ID_GEEZ :: + * TT_MAC_ID_SLAVIC :: + * TT_MAC_ID_VIETNAMESE :: + * TT_MAC_ID_SINDHI :: + * TT_MAC_ID_UNINTERP :: + */ + +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /*********************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ISO charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ + +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /*********************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Corresponds to Microsoft symbol encoding. See + * @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Corresponds to a Microsoft WGL4 charmap, matching Unicode. See + * @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Corresponds to SJIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_GB2312 :: + * Corresponds to Simplified Chinese as used in Mainland China. See + * @FT_ENCODING_GB2312. + * + * TT_MS_ID_BIG_5 :: + * Corresponds to Traditional Chinese as used in Taiwan and Hong Kong. + * See @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Corresponds to Korean Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Corresponds to Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * Corresponds to UCS-4 or UTF-32 charmaps. This has been added to + * the OpenType specification version 1.4 (mid-2001.) + */ + +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_GB2312 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 + + + /*********************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ADOBE charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + */ + +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MACINTOSH. */ + /* */ + /* The canonical source for the Apple assigned Language ID's is at */ + /* */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6name.html */ + /* */ +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + +#if 0 /* these seem to be errors that have been dropped */ + +#define TT_MAC_LANGID_SCOTTISH_GAELIC 140 +#define TT_MAC_LANGID_IRISH_GAELIC 141 + +#endif + + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MICROSOFT. */ + /* */ + /* The canonical source for the MS assigned LCID's (seems to) be at */ + /* */ + /* http://www.microsoft.com/globaldev/reference/lcid-all.mspx */ + /* */ + /* It used to be at various places, among them */ + /* */ + /* http://www.microsoft.com/typography/OTSPEC/lcid-cp.txt */ + /* http://www.microsoft.com/globaldev/reference/loclanghome.asp */ + /* http://support.microsoft.com/support/kb/articles/Q224/8/04.ASP */ + /* http://msdn.microsoft.com/library/en-us/passport25/ */ + /* NET_Passport_VBScript_Documentation/Single_Sign_In/ */ + /* Advanced_Single_Sign_In/Localization_and_LCIDs.asp */ + /* */ + /* Hopefully, it seems now that the Globaldev site prevails... */ + /* (updated by Antoine, 2004-02-17) */ + +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_SPAIN 0x0403 +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 + +#if 1 /* this looks like the correct value */ +#define TT_MS_LANGID_CHINESE_MACAU 0x1404 +#else /* but beware, Microsoft may change its mind... + the most recent Word reference has the following: */ +#define TT_MS_LANGID_CHINESE_MACAU TT_MS_LANGID_CHINESE_HONG_KONG +#endif + +#if 0 /* used only with .NET `cultures'; commented out */ +#define TT_MS_LANGID_CHINESE_TRADITIONAL 0x7C04 +#endif + +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 + + /* don't ask what this one means... It is commented out currently. */ +#if 0 +#define TT_MS_LANGID_GREEK_GREECE2 0x2008 +#endif + +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a +#define TT_MS_LANGID_SPANISH_MEXICO 0x080a +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a +#define TT_MS_LANGID_SPANISH_PANAMA 0x180a +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a +#define TT_MS_LANGID_SPANISH_PERU 0x280a +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a +#define TT_MS_LANGID_SPANISH_CHILE 0x340a +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540a + /* The following ID blatantly violate MS specs by using a */ + /* sublanguage > 0x1F. */ +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40aU +#define TT_MS_LANGID_FINNISH_FINLAND 0x040b +#define TT_MS_LANGID_FRENCH_FRANCE 0x040c +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c +#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c +#define TT_MS_LANGID_FRENCH_MONACO 0x180c +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c +#define TT_MS_LANGID_FRENCH_REUNION 0x200c +#define TT_MS_LANGID_FRENCH_CONGO 0x240c + /* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c +#define TT_MS_LANGID_FRENCH_MALI 0x340c +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380c +#define TT_MS_LANGID_FRENCH_HAITI 0x3c0c + /* and another violation of the spec (see 0xE40aU) */ +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40cU +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412 +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a + +#if 0 /* this used to be this value, but it looks like we were wrong */ +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a +#else /* current sources say */ +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101a +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141a + /* and XPsp2 Platform SDK added (2004-07-26) */ + /* Names are shortened to be significant within 40 chars. */ +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181a +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181a +#endif + +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d +#define TT_MS_LANGID_THAI_THAILAND 0x041e +#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c +#define TT_MS_LANGID_BASQUE_SPAIN 0x042d +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043a + /* Added by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043b +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083b +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3b +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103b +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143b +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183b +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3b +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203b +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243b + /* ... and we also keep our old identifier... */ +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b + +#if 0 /* this seems to be a previous inversion */ +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#else +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#endif + +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN /* Cyrillic*/ 0x0440 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN + +#define TT_MS_LANGID_SWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ORIYA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044a +#define TT_MS_LANGID_KANNADA_INDIA 0x044b +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d +#define TT_MS_LANGID_MARATHI_INDIA 0x044e +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN 0x0850 +#define TT_MS_LANGID_TIBETAN_CHINA 0x0451 + /* Don't use the next constant! It has */ + /* (1) the wrong spelling (Dzonghka) */ + /* (2) Microsoft doesn't officially define it -- */ + /* at least it is not in the List of Local */ + /* ID Values. */ + /* (3) Dzongkha is not the same language as */ + /* Tibetan, so merging it is wrong anyway. */ + /* */ + /* TT_MS_LANGID_TIBETAN_BHUTAN is correct, BTW. */ +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 + +#if 0 + /* the following used to be defined */ +#define TT_MS_LANGID_TIBETAN_BHUTAN 0x0451 + /* ... but it was changed; */ +#else + /* So we will continue to #define it, but with the correct value */ +#define TT_MS_LANGID_TIBETAN_BHUTAN TT_MS_LANGID_DZONGHKA_BHUTAN +#endif + +#define TT_MS_LANGID_WELSH_WALES 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +#define TT_MS_LANGID_MANIPURI_INDIA /* Bengali */ 0x0458 +#define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 + /* Missing a LCID for Sindhi in Devanagari script */ +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a +#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045f +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f + /* Missing a LCID for Tifinagh script */ +#define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 + /* Spelled this way by XPsp2 Platform SDK (2004-07-26) */ + /* script is yet unclear... might be Arabic, Nagari or Sharada */ +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 + /* ... and aliased (by MS) for compatibility reasons. */ +#define TT_MS_LANGID_KASHMIRI_INDIA TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_DIVEHI_MALDIVES TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046a +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046b +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086b +#define TT_MS_LANGID_QUECHUA_PERU 0x0c6b +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046c + /* Also spelled by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SEPEDI_SOUTH_AFRICA + /* language codes 0x046d, 0x046e and 0x046f are (still) unknown. */ +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 + /* also spelled in the `Passport SDK' list as: */ +#define TT_MS_LANGID_TIGRIGNA_ERYTREA TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 + /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ + /* not written (but OTOH the peculiar writing system is worth */ + /* studying). */ +#define TT_MS_LANGID_YI_CHINA 0x0478 +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 + /* language codes from 0x047a to 0x047f are (still) unknown. */ +#define TT_MS_LANGID_UIGHUR_CHINA 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 + +#if 0 /* not deemed useful for fonts */ +#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04ff +#endif + + + /*************************************************************************/ + /* */ + /* Possible values of the `name' identifier field in the name records of */ + /* the TTF `name' table. These values are platform independent. */ + /* */ +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + + /* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 + /* number 15 is reserved */ +#define TT_NAME_ID_PREFERRED_FAMILY 16 +#define TT_NAME_ID_PREFERRED_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + + /* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + /* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 + + + /*************************************************************************/ + /* */ + /* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */ + /* */ + /* Updated 02-Jul-2000. */ + /* */ + + /* General Scripts Area */ + + /* Bit 0 Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* Bit 5 Spacing Modifier Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* Bit 6 Combining Diacritical Marks */ +#define TT_UCR_COMBINING_DIACRITICS (1L << 6) /* U+0300-U+036F */ + /* Bit 7 Greek and Coptic */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 is reserved (was: Greek Symbols and Coptic) */ + /* Bit 9 Cyrillic + */ + /* Cyrillic Supplementary */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* U+0500-U+052F */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 is reserved (was: Hebrew Extended) */ + /* Bit 13 Arabic */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* Bit 14 is reserved (was: Arabic Extended) */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* Bit 27 is reserved (was Georgian Extended) */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + + /* Symbols Area */ + + /* Bit 31 General Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows + */ + /* Supplemental Arrows-A + */ + /* Supplemental Arrows-B */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* U+27F0-U+27FF */ + /* U+2900-U+297F */ + /* Bit 38 Mathematical Operators + */ + /* Supplemental Mathematical Operators + */ + /* Miscellaneous Mathematical Symbols-A + */ + /* Miscellaneous Mathematical Symbols-B */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* U+2A00-U+2AFF */ + /* U+27C0-U+27EF */ + /* U+2980-U+29FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + + /* CJK Phonetics and Symbols Area */ + + /* Bit 48 CJK Symbols and Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana + */ + /* Katakana Phonetic Extensions */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* U+31F0-U+31FF */ + /* Bit 51 Bopomofo + */ + /* Bopomofo Extended */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 Kanbun */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+3190-U+319F */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC + /* Bit 54 Enclosed CJK Letters and Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + + /* Hangul Syllables Area */ + + /* Bit 56 Hangul */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + + /* Surrogates Area */ + + /* Bit 57 High Surrogates + */ + /* High Private Use Surrogates + */ + /* Low Surrogates */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ + /* U+DB80-U+DBFF */ + /* U+DC00-U+DFFF */ + /* According to OpenType specs v.1.3+, setting bit 57 implies that there */ + /* is at least one codepoint beyond the Basic Multilingual Plane that is */ + /* supported by this font. So it really means: >= U+10000 */ + + /* Bit 58 is reserved for Unicode SubRanges */ + + /* CJK Ideographs Area */ + + /* Bit 59 CJK Unified Ideographs + */ + /* CJK Radicals Supplement + */ + /* Kangxi Radicals + */ + /* Ideographic Description Characters + */ + /* CJK Unified Ideographs Extension A */ + /* CJK Unified Ideographs Extension A + */ + /* CJK Unified Ideographs Extension B + */ + /* Kanbun */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+3400-U+4DB5 */ + /*U+20000-U+2A6DF*/ + /* U+3190-U+319F */ + + /* Private Use Area */ + + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + + /* Compatibility Area and Specials */ + + /* Bit 61 CJK Compatibility Ideographs + */ + /* CJK Compatibility Ideographs Supplement */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+F900-U+FAFF */ + /*U+2F800-U+2FA1F*/ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) /* U+FB50-U+FDFF */ + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth and Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Unified Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille Patterns */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi Syllables + */ + /* Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ + /* U+A490-U+A4CF */ + /* Bit 84 Tagalog + */ + /* Hanunoo + */ + /* Buhid + */ + /* Tagbanwa */ +#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ + /* U+1720-U+173F */ + /* U+1740-U+175F */ + /* U+1760-U+177F */ + /* Bit 85 Old Italic */ +#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ + /* Bit 86 Gothic */ +#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ + /* Bit 87 Deseret */ +#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ + /* Bit 88 Byzantine Musical Symbols + */ + /* Musical Symbols */ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ + /*U+1D100-U+1D1FF*/ + /* Bit 89 Mathematical Alphanumeric Symbols */ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ + /* Bit 90 Private Use (plane 15) + */ + /* Private Use (plane 16) */ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ + /*U+100000-U+10FFFD*/ + /* Bit 91 Variation Selectors */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ + /* Bit 92 Tags */ +#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ + + + /*************************************************************************/ + /* */ + /* Some compilers have a very limited length of identifiers. */ + /* */ +#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ ) +#define HAVE_LIMIT_ON_IDENTS +#endif + + +#ifndef HAVE_LIMIT_ON_IDENTS + + + /*************************************************************************/ + /* */ + /* Here some alias #defines in order to be clearer. */ + /* */ + /* These are not always #defined to stay within the 31 character limit */ + /* which some compilers have. */ + /* */ + /* Credits go to Dave Hoo <dhoo@flash.net> for pointing out that modern */ + /* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */ + /* If you get a warning with such a compiler, use the -i40 switch. */ + /* */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \ + TT_UCR_ARABIC_PRESENTATIONS_A +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \ + TT_UCR_ARABIC_PRESENTATIONS_B + +#define TT_UCR_COMBINING_DIACRITICAL_MARKS \ + TT_UCR_COMBINING_DIACRITICS +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + TT_UCR_COMBINING_DIACRITICS_SYMB + + +#endif /* !HAVE_LIMIT_ON_IDENTS */ + + +FT_END_HEADER + +#endif /* __TTNAMEID_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/tttables.h b/src/freetype2/freetype/tttables.h new file mode 100644 index 0000000..43eca2e --- /dev/null +++ b/src/freetype2/freetype/tttables.h @@ -0,0 +1,756 @@ +/***************************************************************************/ +/* */ +/* tttables.h */ +/* */ +/* Basic SFNT/TrueType tables definitions and interface */ +/* (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTTABLES_H__ +#define __TTTABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* truetype_tables */ + /* */ + /* <Title> */ + /* TrueType Tables */ + /* */ + /* <Abstract> */ + /* TrueType specific table types and functions. */ + /* */ + /* <Description> */ + /* This section contains the definition of TrueType-specific tables */ + /* as well as some routines used to access and process them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Header */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType font header table. All */ + /* fields follow the TrueType specification. */ + /* */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_Long Created [2]; + FT_Long Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HoriHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType horizontal header, the `hhea' */ + /* table, as well as the corresponding horizontal metrics table, */ + /* i.e., the `hmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of all */ + /* glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoAscender' field */ + /* of the OS/2 table instead if you want */ + /* the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the distance */ + /* from the baseline to the bottom-most of */ + /* all glyph points found in the font. It */ + /* is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Width_Max :: This field is the maximum of all advance */ + /* widths found in the font. It can be */ + /* used to compute the maximum width of an */ + /* arbitrary string of text. */ + /* */ + /* min_Left_Side_Bearing :: The minimum left side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Right_Side_Bearing :: The minimum right side bearing of all */ + /* glyphs within the font. */ + /* */ + /* xMax_Extent :: The maximum horizontal extent (i.e., the */ + /* `width' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* Reserved :: 10 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */ + /* table -- this value can be smaller than */ + /* the total number of glyphs in the font. */ + /* */ + /* long_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* `HMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_VertHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType vertical header, the `vhea' */ + /* table, as well as the corresponding vertical metrics table, i.e., */ + /* the `vmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of */ + /* all glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoAscender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the */ + /* distance from the baseline to the */ + /* bottom-most of all glyph points found */ + /* in the font. It is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Height_Max :: This field is the maximum of all */ + /* advance heights found in the font. It */ + /* can be used to compute the maximum */ + /* height of an arbitrary string of text. */ + /* */ + /* min_Top_Side_Bearing :: The minimum top side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */ + /* glyphs within the font. */ + /* */ + /* yMax_Extent :: The maximum vertical extent (i.e., the */ + /* `height' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* caret_Offset :: The cursor's offset for slanted fonts. */ + /* This value is `reserved' in vmtx */ + /* version 1.0. */ + /* */ + /* Reserved :: 8 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of VMetrics entries in the */ + /* `vmtx' table -- this value can be */ + /* smaller than the total number of glyphs */ + /* in the font. */ + /* */ + /* long_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */ + FT_Short yMax_Extent; /* xmax or ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they're used to connect the metrics header to the relevant */ + /* `HMTX' or `VMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_OS2 */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType OS/2 table. This is the long */ + /* table version. All fields comply to the TrueType specification. */ + /* */ + /* Note that we now support old Mac fonts which do not include an */ + /* OS/2 table. In this case, the `version' field is always set to */ + /* 0xFFFF. */ + /* */ + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_Short fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 tables: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 tables: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + } TT_OS2; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Postscript */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType Postscript table. All fields */ + /* comply to the TrueType specification. This structure does not */ + /* reference the Postscript glyph names, which can be nevertheless */ + /* accessed with the `ttpost' module. */ + /* */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the file, but we don't */ + /* load them by default. See the ttpost.c file. */ + + } TT_Postscript; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_PCLT */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType PCLT table. All fields */ + /* comply to the TrueType specification. */ + /* */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_MaxProfile */ + /* */ + /* <Description> */ + /* The maximum profile is a table containing many max values which */ + /* can be used to pre-allocate arrays. This ensures that no memory */ + /* allocation occurs during a glyph load. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* numGlyphs :: The number of glyphs in this TrueType */ + /* font. */ + /* */ + /* maxPoints :: The maximum number of points in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositePoints'. */ + /* */ + /* maxContours :: The maximum number of contours in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositeContours'. */ + /* */ + /* maxCompositePoints :: The maximum number of points in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxPoints'. */ + /* */ + /* maxCompositeContours :: The maximum number of contours in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxContours'. */ + /* */ + /* maxZones :: The maximum number of zones used for */ + /* glyph hinting. */ + /* */ + /* maxTwilightPoints :: The maximum number of points in the */ + /* twilight zone used for glyph hinting. */ + /* */ + /* maxStorage :: The maximum number of elements in the */ + /* storage area used for glyph hinting. */ + /* */ + /* maxFunctionDefs :: The maximum number of function */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxInstructionDefs :: The maximum number of instruction */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxStackElements :: The maximum number of stack elements used */ + /* during bytecode interpretation. */ + /* */ + /* maxSizeOfInstructions :: The maximum number of TrueType opcodes */ + /* used for glyph hinting. */ + /* */ + /* maxComponentElements :: The maximum number of simple (i.e., non- */ + /* composite) glyphs in a composite glyph. */ + /* */ + /* maxComponentDepth :: The maximum nesting depth of composite */ + /* glyphs. */ + /* */ + /* <Note> */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Sfnt_Tag */ + /* */ + /* <Description> */ + /* An enumeration used to specify the index of an SFNT table. */ + /* Used in the @FT_Get_Sfnt_Table API function. */ + /* */ + typedef enum + { + ft_sfnt_head = 0, + ft_sfnt_maxp = 1, + ft_sfnt_os2 = 2, + ft_sfnt_hhea = 3, + ft_sfnt_vhea = 4, + ft_sfnt_post = 5, + ft_sfnt_pclt = 6, + + sfnt_max /* internal end mark */ + + } FT_Sfnt_Tag; + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Table */ + /* */ + /* <Description> */ + /* Returns a pointer to a given SFNT table within a face. */ + /* */ + /* <Input> */ + /* face :: A handle to the source. */ + /* */ + /* tag :: The index of the SFNT table. */ + /* */ + /* <Return> */ + /* A type-less pointer to the table. This will be 0 in case of */ + /* error, or if the corresponding table was not found *OR* loaded */ + /* from the file. */ + /* */ + /* <Note> */ + /* The table is owned by the face object and disappears with it. */ + /* */ + /* This function is only useful to access SFNT tables that are loaded */ + /* by the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for */ + /* a list. */ + /* */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + + + /************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Loads any font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use the value 0 if you want + * to access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag == 0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length' parameter is NULL, then try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length' is 0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length' set to 0, as in the following example: + * + * { + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * } + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Returns information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @output: + * tag :: + * The name tag of the SFNT table. + * + * length :: + * The length of the SFNT table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * SFNT tables with length zero are treated as missing by Windows. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Language_ID */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap language ID. Definitions of */ + /* language ID values are in `freetype/ttnameid.h'. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The language ID of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, just return 0 as the default value. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Format */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap format. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The format of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, return -1. */ + /* */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); + + /* */ + + +FT_END_HEADER + +#endif /* __TTTABLES_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/tttags.h b/src/freetype2/freetype/tttags.h new file mode 100644 index 0000000..e10244c --- /dev/null +++ b/src/freetype2/freetype/tttags.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* tttags.h */ +/* */ +/* Tags for TrueType and OpenType tables (specification only). */ +/* */ +/* Copyright 1996-2001, 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 __TTAGS_H__ +#define __TTAGS_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) + + +FT_END_HEADER + +#endif /* __TTAGS_H__ */ + + +/* END */ diff --git a/src/freetype2/freetype/ttunpat.h b/src/freetype2/freetype/ttunpat.h new file mode 100644 index 0000000..a016275 --- /dev/null +++ b/src/freetype2/freetype/ttunpat.h @@ -0,0 +1,59 @@ +/***************************************************************************/ +/* */ +/* ttunpat.h */ +/* */ +/* Definitions for the unpatented TrueType hinting system */ +/* */ +/* Copyright 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* Written by Graham Asher <graham.asher@btinternet.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 __TTUNPAT_H__ +#define __TTUNPAT_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_UNPATENTED_HINTING + * + * @description: + * A constant used as the tag of an @FT_Parameter structure to indicate + * that unpatented methods only should be used by the TrueType bytecode + * interpreter for a typeface opened by @FT_Open_Face. + * + */ +#define FT_PARAM_TAG_UNPATENTED_HINTING FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) + + /* */ + +FT_END_HEADER + + +#endif /* __TTUNPAT_H__ */ + + +/* END */ diff --git a/src/freetype2/ft2build.h b/src/freetype2/ft2build.h new file mode 100644 index 0000000..923d887 --- /dev/null +++ b/src/freetype2/ft2build.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* ft2build.h */ +/* */ +/* FreeType 2 build and setup macros. */ +/* (Generic version) */ +/* */ +/* Copyright 1996-2001, 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 file corresponds to the default `ft2build.h' file for */ + /* FreeType 2. It uses the `freetype' include root. */ + /* */ + /* Note that specific platforms might use a different configuration. */ + /* See builds/unix/ft2unix.h for an example. */ + /* */ + /*************************************************************************/ + + +#ifndef __FT2_BUILD_GENERIC_H__ +#define __FT2_BUILD_GENERIC_H__ + +#include <freetype/config/ftheader.h> + +#endif /* __FT2_BUILD_GENERIC_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvalid.c b/src/freetype2/gxvalid/gxvalid.c new file mode 100644 index 0000000..bc36e67 --- /dev/null +++ b/src/freetype2/gxvalid/gxvalid.c @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* gxvalid.c */ +/* */ +/* FreeType validator for TrueTypeGX/AAT tables (body only). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> + +#include "gxvfeat.c" +#include "gxvcommn.c" +#include "gxvbsln.c" +#include "gxvtrak.c" +#include "gxvjust.c" +#include "gxvmort.c" +#include "gxvmort0.c" +#include "gxvmort1.c" +#include "gxvmort2.c" +#include "gxvmort4.c" +#include "gxvmort5.c" +#include "gxvmorx.c" +#include "gxvmorx0.c" +#include "gxvmorx1.c" +#include "gxvmorx2.c" +#include "gxvmorx4.c" +#include "gxvmorx5.c" +#include "gxvkern.c" +#include "gxvopbd.c" +#include "gxvprop.c" +#include "gxvlcar.c" +#include "gxvmod.c" + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvalid.h b/src/freetype2/gxvalid/gxvalid.h new file mode 100644 index 0000000..27be9ec --- /dev/null +++ b/src/freetype2/gxvalid/gxvalid.h @@ -0,0 +1,107 @@ +/***************************************************************************/ +/* */ +/* gxvalid.h */ +/* */ +/* TrueTyeeGX/AAT table validation (specification only). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __GXVALID_H__ +#define __GXVALID_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#include "gxverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ + +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + +FT_END_HEADER + + +#endif /* __GXVALID_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvbsln.c b/src/freetype2/gxvalid/gxvbsln.c new file mode 100644 index 0000000..6cca658 --- /dev/null +++ b/src/freetype2/gxvalid/gxvbsln.c @@ -0,0 +1,333 @@ +/***************************************************************************/ +/* */ +/* gxvbsln.c */ +/* */ +/* TrueTypeGX/AAT bsln table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.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_gxvbsln + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_BSLN_VALUE_COUNT 32 +#define GXV_BSLN_VALUE_EMPTY 0xFFFFU + + + typedef struct GXV_bsln_DataRec_ + { + FT_Bytes ctlPoints_p; + FT_UShort defaultBaseline; + + } GXV_bsln_DataRec, *GXV_bsln_Data; + + +#define GXV_BSLN_DATA( field ) GXV_TABLE_DATA( bsln, field ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_bsln_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UShort v = value.u; + FT_UShort* ctlPoints; + + FT_UNUSED( glyph ); + + + GXV_NAME_ENTER( "lookup value" ); + + if ( v >= GXV_BSLN_VALUE_COUNT ) + FT_INVALID_DATA; + + ctlPoints = (FT_UShort*)GXV_BSLN_DATA( ctlPoints_p ); + if ( ctlPoints && ctlPoints[v] == GXV_BSLN_VALUE_EMPTY ) + FT_INVALID_DATA; + + GXV_EXIT; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_bsln_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range ? */ + offset = (FT_UShort)( base_value.u + + ( relative_gindex * sizeof ( FT_UShort ) ) ); + + p = valid->lookuptbl_head + offset; + limit = lookuptbl_limit; + GXV_LIMIT_CHECK( 2 ); + + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_bsln_parts_fmt0_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 0" ); + + /* deltas */ + GXV_LIMIT_CHECK( 2 * GXV_BSLN_VALUE_COUNT ); + + valid->table_data = NULL; /* No ctlPoints here. */ + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt1_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 1" ); + + /* deltas */ + gxv_bsln_parts_fmt0_validate( p, limit, valid ); + + /* mappingData */ + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_bsln_LookupValue_validate; + valid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + 2 * GXV_BSLN_VALUE_COUNT, + limit, + valid ); + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt2_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = tables; + + FT_UShort stdGlyph; + FT_UShort ctlPoint; + FT_Int i; + + FT_UShort defaultBaseline = GXV_BSLN_DATA( defaultBaseline ); + + + GXV_NAME_ENTER( "parts format 2" ); + + GXV_LIMIT_CHECK( 2 + ( 2 * GXV_BSLN_VALUE_COUNT ) ); + + /* stdGlyph */ + stdGlyph = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (stdGlyph = %u)\n", stdGlyph )); + + gxv_glyphid_validate( stdGlyph, valid ); + + /* Record the position of ctlPoints */ + GXV_BSLN_DATA( ctlPoints_p ) = p; + + /* ctlPoints */ + for ( i = 0; i < GXV_BSLN_VALUE_COUNT; i++ ) + { + ctlPoint = FT_NEXT_USHORT( p ); + if ( ctlPoint == GXV_BSLN_VALUE_EMPTY ) + { + if ( i == defaultBaseline ) + FT_INVALID_DATA; + } + else + gxv_ctlPoint_validate( stdGlyph, (FT_Short)ctlPoint, valid ); + } + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt3_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator valid) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 3" ); + + /* stdGlyph + ctlPoints */ + gxv_bsln_parts_fmt2_validate( p, limit, valid ); + + /* mappingData */ + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_bsln_LookupValue_validate; + valid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + ( 2 + 2 * GXV_BSLN_VALUE_COUNT ), + limit, + valid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** bsln TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + + GXV_bsln_DataRec bslnrec; + GXV_bsln_Data bsln = &bslnrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + FT_UShort format; + FT_UShort defaultBaseline; + + GXV_Validate_Func fmt_funcs_table [] = + { + gxv_bsln_parts_fmt0_validate, + gxv_bsln_parts_fmt1_validate, + gxv_bsln_parts_fmt2_validate, + gxv_bsln_parts_fmt3_validate, + }; + + + valid->root = ftvalid; + valid->table_data = bsln; + valid->face = face; + + FT_TRACE3(( "validating `bsln' table\n" )); + GXV_INIT; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + defaultBaseline = FT_NEXT_USHORT( p ); + + /* only version 1.0 is defined (1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* only format 1, 2, 3 are defined (1996) */ + GXV_TRACE(( " (format = %d)\n", format )); + if ( format > 3 ) + FT_INVALID_FORMAT; + + if ( defaultBaseline > 31 ) + FT_INVALID_FORMAT; + + bsln->defaultBaseline = defaultBaseline; + + fmt_funcs_table[format]( p, limit, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* arch-tag: ebe81143-fdaa-4c68-a4d1-b57227daa3bc + (do not change this comment) */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvcommn.c b/src/freetype2/gxvalid/gxvcommn.c new file mode 100644 index 0000000..82fd6b3 --- /dev/null +++ b/src/freetype2/gxvalid/gxvcommn.c @@ -0,0 +1,1758 @@ +/***************************************************************************/ +/* */ +/* gxvcommn.c */ +/* */ +/* TrueTypeGX/AAT common tables validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvcommn.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_gxvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 16bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static int + gxv_compare_ushort_offset( FT_UShort* a, + FT_UShort* b ) + { + if ( *a < *b ) + return ( -1 ); + else if ( *a > *b ) + return ( 1 ); + else + return ( 0 ); + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator valid ) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), + ( int(*)(const void*, const void*) )gxv_compare_ushort_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] ); + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static int + gxv_compare_ulong_offset( FT_ULong* a, + FT_ULong* b ) + { + if ( *a < *b ) + return ( -1 ); + else if ( *a > *b ) + return ( 1 ); + else + return ( 0 ); + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator valid) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), + ( int(*)(const void*, const void*) )gxv_compare_ulong_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = buff[j + 1] - buff[j]; + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** scan value array and get min & max *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + *min = 0xFF; + *max = 0x00; + + while ( p < limit ) + { + FT_Byte val; + + + GXV_LIMIT_CHECK( 1 ); + val = FT_NEXT_BYTE( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + valid->subtable_length = p - table; + } + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + *min = 0xFFFFU; + *max = 0x0000; + + while ( p < limit ) + { + FT_UShort val; + + + GXV_LIMIT_CHECK( 2 ); + val = FT_NEXT_USHORT( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + valid->subtable_length = p - table; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BINSEARCHHEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_BinSrchHeader_ + { + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + } GXV_BinSrchHeader; + + + static void + gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, + GXV_Validator valid ) + { + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + + if ( binSrchHeader->unitSize == 0 ) + FT_INVALID_DATA; + + if ( binSrchHeader->nUnits == 0 ) + { + if ( binSrchHeader->searchRange == 0 && + binSrchHeader->entrySelector == 0 && + binSrchHeader->rangeShift == 0 ) + return; + else + FT_INVALID_DATA; + } + + for ( searchRange = 1, entrySelector = 1; + ( searchRange * 2 ) <= binSrchHeader->nUnits && + searchRange < 0x8000U; + searchRange *= 2, entrySelector++ ) + ; + + entrySelector--; + searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize ); + rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize + - searchRange ); + + if ( searchRange != binSrchHeader->searchRange || + entrySelector != binSrchHeader->entrySelector || + rangeShift != binSrchHeader->rangeShift ) + { + GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" )); + GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + binSrchHeader->searchRange, binSrchHeader->entrySelector, + binSrchHeader->rangeShift )); + GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + searchRange, entrySelector, rangeShift )); + + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + } + + + /* + * parser & validator of BinSrchHeader + * which is used in LookupTable format 2, 4, 6. + * + * Essential parameters (unitSize, nUnits) are returned by + * given pointer, others (searchRange, entrySelector, rangeShift) + * can be calculated by essential parameters, so they are just + * validated and discarded. + * + * However, wrong values in searchRange, entrySelector, rangeShift + * won't cause fatal errors, because these parameters might be + * only used in old m68k font driver in MacOS. + * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> + */ + + FT_LOCAL_DEF( void ) + gxv_BinSrchHeader_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator valid ) + { + FT_Bytes p = table; + GXV_BinSrchHeader binSrchHeader; + + + GXV_NAME_ENTER( "BinSrchHeader validate" ); + + if ( *unitSize_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.unitSize = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.unitSize = *unitSize_p; + + if ( *nUnits_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.nUnits = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.nUnits = *nUnits_p; + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + binSrchHeader.searchRange = FT_NEXT_USHORT( p ); + binSrchHeader.entrySelector = FT_NEXT_USHORT( p ); + binSrchHeader.rangeShift = FT_NEXT_USHORT( p ); + GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits )); + + gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid ); + + if ( *unitSize_p == 0 ) + *unitSize_p = binSrchHeader.unitSize; + + if ( *nUnits_p == 0 ) + *nUnits_p = binSrchHeader.nUnits; + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \ + ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) ) + + static GXV_LookupValueDesc + gxv_lookup_value_load( FT_Bytes p, + int signspec ) + { + GXV_LookupValueDesc v; + + + if ( signspec == GXV_LOOKUPVALUE_UNSIGNED ) + v.u = FT_NEXT_USHORT( p ); + else + v.s = FT_NEXT_SHORT( p ); + + return v; + } + + +#define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \ + FT_BEGIN_STMNT \ + if ( UNITSIZE != CORRECTSIZE ) \ + { \ + FT_ERROR(( "unitSize=%d differs from" \ + "expected unitSize=%d" \ + "in LookupTable %s", \ + UNITSIZE, CORRECTSIZE, FORMAT )); \ + if ( UNITSIZE != 0 && NUNITS != 0 ) \ + { \ + FT_ERROR(( " cannot validate anymore\n" )); \ + FT_INVALID_FORMAT; \ + } \ + else \ + FT_ERROR(( " forcibly continues\n" )); \ + } \ + FT_END_STMNT + + + /* ================= Simple Array Format 0 Lookup Table ================ */ + static void + gxv_LookupTable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 0" ); + + GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs ); + + for ( i = 0; i < valid->face->num_glyphs; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */ + { + GXV_TRACE(( "too short, glyphs %d - %d are missing\n", + i, valid->face->num_glyphs )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + break; + } + + value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); + valid->lookupval_func( i, value, valid ); + } + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + /* ================= Segment Single Format 2 Loolup Table ============== */ + /* + * Apple spec says: + * + * To guarantee that a binary search terminates, you must include one or + * more special `end of search table' values at the end of the data to + * be searched. The number of termination values that need to be + * included is table-specific. The value that indicates binary search + * termination is 0xFFFF. + * + * The problem is that nUnits does not include this end-marker. It's + * quite difficult to discriminate whether the following 0xFFFF comes from + * the end-marker or some next data. + * + * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> + */ + static void + gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + while ( ( p + 4 ) < valid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */ + p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ + break; + p += unitSize; + } + + valid->subtable_length = p - table; + } + + + static void + gxv_LookupTable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort unit; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 2" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); + p += valid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); + + gxv_glyphid_validate( firstGlyph, valid ); + gxv_glyphid_validate( lastGlyph, valid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:", + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + + if ( valid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + valid->lookupval_func( gid, value, valid ); + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); + p += valid->subtable_length; + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + /* ================= Segment Array Format 4 Lookup Table =============== */ + static void + gxv_LookupTable_fmt4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc base_value; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 4" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); + p += valid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, valid ); + gxv_glyphid_validate( lastGlyph, valid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:", + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + + if ( valid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + GXV_LIMIT_CHECK( 2 ); + base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED ); + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + { + value = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), + base_value, + limit, + valid ); + + valid->lookupval_func( gid, value, valid ); + } + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid ); + p += valid->subtable_length; + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + /* ================= Segment Table Format 6 Lookup Table =============== */ + static void + gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + while ( p < valid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF ) + break; + p += unitSize; + } + + valid->subtable_length = p - table; + } + + + static void + gxv_LookupTable_fmt6_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort prev_glyph; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort glyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 6" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid ); + p += valid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 ); + + for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + glyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); + + if ( gxv_glyphid_validate( glyph, valid ) ) + GXV_TRACE(( " endmarker found within defined range" + " (entry %d < nUnits=%d)\n", + unit, nUnits )); + + if ( prev_glyph > glyph ) + { + GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n", + glyph, prev_glyph )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + prev_glyph = glyph; + + valid->lookupval_func( glyph, value, valid ); + } + + gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid ); + p += valid->subtable_length; + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + /* ================= Trimmed Array Format 8 Lookup Table =============== */ + static void + gxv_LookupTable_fmt8_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + FT_UShort firstGlyph; + FT_UShort glyphCount; + + + GXV_NAME_ENTER( "LookupTable format 8" ); + + /* firstGlyph + glyphCount */ + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + glyphCount = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, valid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid ); + + /* valueArray */ + for ( i = 0; i < glyphCount; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign ); + valid->lookupval_func( (FT_UShort)( firstGlyph + i ), value, valid ); + } + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort format; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_LookupTable_fmt0_validate, /* 0 */ + NULL, /* 1 */ + gxv_LookupTable_fmt2_validate, /* 2 */ + NULL, /* 3 */ + gxv_LookupTable_fmt4_validate, /* 4 */ + NULL, /* 5 */ + gxv_LookupTable_fmt6_validate, /* 6 */ + NULL, /* 7 */ + gxv_LookupTable_fmt8_validate, /* 8 */ + }; + + GXV_Validate_Func func; + + + GXV_NAME_ENTER( "LookupTable" ); + + /* lookuptbl_head may be used in fmt4 transit function. */ + valid->lookuptbl_head = table; + + /* format */ + GXV_LIMIT_CHECK( 2 ); + format = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (format %d)\n", format )); + + if ( format > 8 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[format]; + if ( func == NULL ) + FT_INVALID_FORMAT; + + func( p, limit, valid ); + p += valid->subtable_length; + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator valid ) + { + FT_Face face; + + + if ( gid == 0xFFFFU ) + { + GXV_EXIT; + return 1; + } + + face = valid->face; + if ( face->num_glyphs < gid ) + { + GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n", + face->num_glyphs, gid )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + + return 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_Short ctl_point, + GXV_Validator valid ) + { + FT_Face face; + FT_Error error; + + FT_GlyphSlot glyph; + FT_Outline outline; + short n_points; + + + face = valid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + outline = glyph->outline; + n_points = outline.n_points; + + + if ( !( ctl_point < n_points ) ) + FT_INVALID_DATA; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator valid ) + { + FT_SfntName name; + FT_UInt i; + FT_UInt nnames; + + + GXV_NAME_ENTER( "sfntName" ); + + if ( name_index < min_index || max_index < name_index ) + FT_INVALID_FORMAT; + + nnames = FT_Get_Sfnt_Name_Count( valid->face ); + for ( i = 0; i < nnames; i++ ) + { + if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok ) + continue ; + + if ( name.name_id == name_index ) + goto Out; + } + + GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); + FT_INVALID_DATA; + goto Exit; /* make compiler happy */ + + Out: + FT_TRACE1(( " nameIndex = %d (", name_index )); + GXV_TRACE_HEXDUMP_SFNTNAME( name ); + FT_TRACE1(( ")\n" )); + + Exit: + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* -------------------------- Class Table --------------------------- */ + + /* + * highestClass specifies how many classes are defined in this + * Class Subtable. Apple spec does not mention whether undefined + * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) + * are permitted. At present, holes in a defined class are not checked. + * -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp> + */ + + static void + gxv_ClassTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_UShort stateSize, + FT_Byte* maxClassID_p, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "ClassTable" ); + + *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); + + if ( !nGlyphs ) + goto Out; + + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid ); + + { + FT_Byte nGlyphInClass[256]; + FT_Byte classID; + FT_UShort i; + + + ft_memset( nGlyphInClass, 0, 256 ); + + + for ( i = 0; i < nGlyphs; i++ ) + { + GXV_LIMIT_CHECK( 1 ); + classID = FT_NEXT_BYTE( p ); + switch ( classID ) + { + /* following classes should not appear in class array */ + case 0: /* end of text */ + case 2: /* out of bounds */ + case 3: /* end of line */ + FT_INVALID_DATA; + break; + + case 1: /* out of bounds */ + default: /* user-defined: 4 - ( stateSize - 1 ) */ + if ( classID >= stateSize ) + FT_INVALID_DATA; /* assign glyph to undefined state */ + + nGlyphInClass[classID]++; + break; + } + } + *length_p = (FT_UShort)( p - table ); + + /* scan max ClassID in use */ + for ( i = 0; i < stateSize; i++ ) + if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) + *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ + } + + Out: + GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", + stateSize, *maxClassID_p )); + GXV_EXIT; + } + + + /* --------------------------- State Array ----------------------------- */ + + static void + gxv_StateArray_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxClassID, + FT_UShort stateSize, + FT_Byte* maxState_p, + FT_Byte* maxEntry_p, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte clazz; + FT_Byte entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "StateArray" ); + + GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", + (int)(*length_p), stateSize, (int)(maxClassID) )); + + /* + * 2 states are predefined and must be described in StateArray: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( 1 + maxClassID ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_BYTE( p ); + *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* --------------------------- Entry Table ----------------------------- */ + + static void + gxv_EntryTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxEntry, + FT_UShort stateArray, + FT_UShort stateArray_length, + FT_Byte maxClassID, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte entry; + FT_Byte state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); + + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_NAME_ENTER( "EntryTable" ); + + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( maxEntry + 1 ) * entrySize > *length_p ) + { + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_TOO_SHORT; + + /* ftxvalidator and FontValidator both warn and continue */ + maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); + GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", + maxEntry )); + } + + for ( entry = 0; entry <= maxEntry; entry++ ) + { + FT_UShort newState; + FT_UShort flags; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + + if ( newState < stateArray || + stateArray + stateArray_length < newState ) + { + GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", + newState )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + continue; + } + + if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) + { + GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", + newState, 1 + maxClassID )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + continue; + } + + state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); + + switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + + default: + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_FORMAT; + goto Exit; + } + + if ( NULL != valid->statetable.entry_validate_func ) + valid->statetable.entry_validate_func( state, + flags, + glyphOffset, + statetable_table, + statetable_limit, + valid ); + } + + Exit: + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* =========================== State Table ============================= */ + + FT_LOCAL_DEF( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ) + { + FT_UShort o[3]; + FT_UShort* l[3]; + FT_UShort buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid ); + } + + + FT_LOCAL_DEF( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort stateSize; + FT_UShort classTable; /* offset to Class(Sub)Table */ + FT_UShort stateArray; /* offset to StateArray */ + FT_UShort entryTable; /* offset to EntryTable */ + + FT_UShort classTable_length; + FT_UShort stateArray_length; + FT_UShort entryTable_length; + FT_Byte maxClassID; + FT_Byte maxState; + FT_Byte maxEntry; + + GXV_StateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "StateTable" ); + + GXV_TRACE(( "StateTable header\n" )); + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + stateSize = FT_NEXT_USHORT( p ); + classTable = FT_NEXT_USHORT( p ); + stateArray = FT_NEXT_USHORT( p ); + entryTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); + GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); + + if ( stateSize > 0xFF ) + FT_INVALID_DATA; + + if ( valid->statetable.optdata_load_func != NULL ) + valid->statetable.optdata_load_func( p, limit, valid ); + + if ( valid->statetable.subtable_setup_func != NULL) + setup_func = valid->statetable.subtable_setup_func; + else + setup_func = gxv_StateTable_subtable_setup; + + setup_func( (FT_UShort)( limit - table ), + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + valid ); + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( classTable != 0 ) + gxv_ClassTable_validate( table + classTable, + &classTable_length, + stateSize, + &maxClassID, + valid ); + else + maxClassID = (FT_Byte)( stateSize - 1 ); + + if ( stateArray != 0 ) + gxv_StateArray_validate( table + stateArray, + &stateArray_length, + maxClassID, + stateSize, + &maxState, + &maxEntry, + valid ); + else + { + maxState = 1; /* 0:start of text, 1:start of line are predefined */ + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_EntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray, + stateArray_length, + maxClassID, + table, + limit, + valid ); + + GXV_EXIT; + } + + + /* ================= eXtended State Table (for morx) =================== */ + + FT_LOCAL_DEF( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ) + { + FT_ULong o[3]; + FT_ULong* l[3]; + FT_ULong buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid ); + } + + + static void + gxv_XClassTable_lookupval_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UNUSED( glyph ); + + if ( value.u >= valid->xstatetable.nClasses ) + FT_INVALID_DATA; + if ( value.u > valid->xstatetable.maxClassID ) + valid->xstatetable.maxClassID = value.u; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + static GXV_LookupValueDesc + gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value.u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = valid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_XStateArray_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxClassID, + FT_ULong stateSize, + FT_UShort* maxState_p, + FT_UShort* maxEntry_p, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort clazz; + FT_UShort entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "XStateArray" ); + + GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", + (int)(*length_p), stateSize, (int)(maxClassID) )); + + /* + * 2 states are predefined and must be described: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_USHORT( p ); + *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = p - table; + + GXV_EXIT; + } + + + static void + gxv_XEntryTable_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxEntry, + FT_ULong stateArray_length, + FT_UShort maxClassID, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort entry; + FT_UShort state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); + + + GXV_NAME_ENTER( "XEntryTable" ); + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) + FT_INVALID_TOO_SHORT; + + for (entry = 0; entry <= maxEntry ; entry++ ) + { + FT_UShort newState_idx; + FT_UShort flags; + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState_idx = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) + { + GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", + newState_idx )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + } + + state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); + if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) + { + FT_TRACE4(( "-> new state = %d (supposed)\n" + "but newState index 0x%04x is not aligned to %d-classes\n", + state, newState_idx, 1 + maxClassID )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + } + + switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + + default: + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_FORMAT; + goto Exit; + } + + if ( NULL != valid->xstatetable.entry_validate_func ) + valid->xstatetable.entry_validate_func( state, + flags, + glyphOffset, + xstatetable_table, + xstatetable_limit, + valid ); + } + + Exit: + *length_p = p - table; + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + /* StateHeader members */ + FT_ULong classTable; /* offset to Class(Sub)Table */ + FT_ULong stateArray; /* offset to StateArray */ + FT_ULong entryTable; /* offset to EntryTable */ + + FT_ULong classTable_length; + FT_ULong stateArray_length; + FT_ULong entryTable_length; + FT_UShort maxState; + FT_UShort maxEntry; + + GXV_XStateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "XStateTable" ); + + GXV_TRACE(( "XStateTable header\n" )); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + valid->xstatetable.nClasses = FT_NEXT_ULONG( p ); + classTable = FT_NEXT_ULONG( p ); + stateArray = FT_NEXT_ULONG( p ); + entryTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses )); + GXV_TRACE(( "offset to classTable=0x%08x\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable )); + + if ( valid->xstatetable.nClasses > 0xFFFFU ) + FT_INVALID_DATA; + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( valid->xstatetable.optdata_load_func != NULL ) + valid->xstatetable.optdata_load_func( p, limit, valid ); + + if ( valid->xstatetable.subtable_setup_func != NULL ) + setup_func = valid->xstatetable.subtable_setup_func; + else + setup_func = gxv_XStateTable_subtable_setup; + + setup_func( limit - table, + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + valid ); + + if ( classTable != 0 ) + { + valid->xstatetable.maxClassID = 0; + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_XClassTable_lookupval_validate; + valid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; + gxv_LookupTable_validate( table + classTable, + table + classTable + classTable_length, + valid ); + if ( valid->subtable_length < classTable_length ) + classTable_length = valid->subtable_length; + } + else + { + /* XXX: check range? */ + valid->xstatetable.maxClassID = + (FT_UShort)( valid->xstatetable.nClasses - 1 ); + } + + if ( stateArray != 0 ) + gxv_XStateArray_validate( table + stateArray, + &stateArray_length, + valid->xstatetable.maxClassID, + valid->xstatetable.nClasses, + &maxState, + &maxEntry, + valid ); + else + { + maxState = 1; /* 0:start of text, 1:start of line are predefined */ + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_XEntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray_length, + valid->xstatetable.maxClassID, + table, + limit, + valid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static int + gxv_compare_ranges( FT_Bytes table1_start, + FT_ULong table1_length, + FT_Bytes table2_start, + FT_ULong table2_length ) + { + if ( table1_start == table2_start ) + { + if ( ( table1_length == 0 || table2_length == 0 ) ) + goto Out; + } + else if ( table1_start < table2_start ) + { + if ( ( table1_start + table1_length ) <= table2_start ) + goto Out; + } + else if ( table1_start > table2_start ) + { + if ( ( table1_start >= table2_start + table2_length ) ) + goto Out; + } + return 1; + + Out: + return 0; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ) + { + odtect->range[ odtect->nRanges ].start = start; + odtect->range[ odtect->nRanges ].length = length; + odtect->range[ odtect->nRanges ].name = (FT_String*)name; + odtect->nRanges++; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator valid ) + { + FT_UInt i, j; + + + GXV_NAME_ENTER( "check overlap among multi ranges" ); + + for ( i = 0; i < odtect->nRanges; i++ ) + for ( j = 0; j < i; j++ ) + if ( 0 != gxv_compare_ranges( odtect->range[i].start, + odtect->range[i].length, + odtect->range[j].start, + odtect->range[j].length ) ) + { + if ( odtect->range[i].name || odtect->range[j].name ) + GXV_TRACE(( "found overlap between range %d and range %d\n", + i, j )); + else + GXV_TRACE(( "found overlap between `%s' and `%s\'\n", + odtect->range[i].name, + odtect->range[j].name )); + FT_INVALID_OFFSET; + } + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvcommn.h b/src/freetype2/gxvalid/gxvcommn.h new file mode 100644 index 0000000..0128eca --- /dev/null +++ b/src/freetype2/gxvalid/gxvcommn.h @@ -0,0 +1,560 @@ +/***************************************************************************/ +/* */ +/* gxvcommn.h */ +/* */ +/* TrueTypeGX/AAT common tables validation (specification). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + + /* + * keywords in variable naming + * --------------------------- + * table: Of type FT_Bytes, pointing to the start of this table/subtable. + * limit: Of type FT_Bytes, pointing to the end of this table/subtable, + * including padding for alignment. + * offset: Of type FT_UInt, the number of octets from the start to target. + * length: Of type FT_UInt, the number of octets from the start to the + * end in this table/subtable, including padding for alignment. + * + * _MIN, _MAX: Should be added to the tail of macros, as INT_MIN, etc. + */ + + +#ifndef __GXVCOMMN_H__ +#define __GXVCOMMN_H__ + + +#include <ft2build.h> +#include "gxvalid.h" +#include FT_INTERNAL_DEBUG_H +#include FT_SFNT_NAMES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_ValidatorRec_* GXV_Validator; + + +#define DUMMY_LIMIT 0 + + typedef void + (*GXV_Validate_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + + /* ====================== LookupTable Validator ======================== */ + + typedef union GXV_LookupValueDesc_ + { + FT_UShort u; + FT_Short s; + + } GXV_LookupValueDesc; + + typedef enum GXV_LookupValue_SignSpec_ + { + GXV_LOOKUPVALUE_UNSIGNED = 0, + GXV_LOOKUPVALUE_SIGNED + + } GXV_LookupValue_SignSpec; + + + typedef void + (*GXV_Lookup_Value_Validate_Func)( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ); + + typedef GXV_LookupValueDesc + (*GXV_Lookup_Fmt4_Transit_Func)( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ); + + + /* ====================== StateTable Validator ========================= */ + + typedef enum GXV_GlyphOffset_Format_ + { + GXV_GLYPHOFFSET_NONE = -1, + GXV_GLYPHOFFSET_UCHAR = 2, + GXV_GLYPHOFFSET_CHAR, + GXV_GLYPHOFFSET_USHORT = 4, + GXV_GLYPHOFFSET_SHORT, + GXV_GLYPHOFFSET_ULONG = 8, + GXV_GLYPHOFFSET_LONG + + } GXV_GlyphOffset_Format; + + +#define GXV_GLYPHOFFSET_FMT( table ) \ + ( valid->table.entry_glyphoffset_fmt ) + +#define GXV_GLYPHOFFSET_SIZE( table ) \ + ( valid->table.entry_glyphoffset_fmt / 2 ) + + + /* ----------------------- 16bit StateTable ---------------------------- */ + + typedef union GXV_StateTable_GlyphOffsetDesc_ + { + FT_Byte uc; + FT_UShort u; /* same as GXV_LookupValueDesc */ + FT_ULong ul; + FT_Char c; + FT_Short s; /* same as GXV_LookupValueDesc */ + FT_Long l; + + } GXV_StateTable_GlyphOffsetDesc; + + + typedef void + (*GXV_StateTable_Subtable_Setup_Func)( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ); + + typedef void + (*GXV_StateTable_Entry_Validate_Func)( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator valid ); + + typedef void + (*GXV_StateTable_OptData_Load_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + typedef struct GXV_StateTable_ValidatorRec_ + { + GXV_GlyphOffset_Format entry_glyphoffset_fmt; + void* optdata; + + GXV_StateTable_Subtable_Setup_Func subtable_setup_func; + GXV_StateTable_Entry_Validate_Func entry_validate_func; + GXV_StateTable_OptData_Load_Func optdata_load_func; + + } GXV_StateTable_ValidatorRec, *GXV_StateTable_ValidatorRecData; + + + /* ---------------------- 32bit XStateTable ---------------------------- */ + + typedef GXV_StateTable_GlyphOffsetDesc GXV_XStateTable_GlyphOffsetDesc; + + typedef void + (*GXV_XStateTable_Subtable_Setup_Func)( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ); + + typedef void + (*GXV_XStateTable_Entry_Validate_Func)( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator valid ); + + + typedef GXV_StateTable_OptData_Load_Func GXV_XStateTable_OptData_Load_Func; + + + typedef struct GXV_XStateTable_ValidatorRec_ + { + int entry_glyphoffset_fmt; + void* optdata; + + GXV_XStateTable_Subtable_Setup_Func subtable_setup_func; + GXV_XStateTable_Entry_Validate_Func entry_validate_func; + GXV_XStateTable_OptData_Load_Func optdata_load_func; + + FT_ULong nClasses; + FT_UShort maxClassID; + + } GXV_XStateTable_ValidatorRec, *GXV_XStateTable_ValidatorRecData; + + + /* ===================================================================== */ + + typedef struct GXV_ValidatorRec_ + { + FT_Validator root; + + FT_Face face; + void* table_data; + + FT_ULong subtable_length; + + GXV_LookupValue_SignSpec lookupval_sign; + GXV_Lookup_Value_Validate_Func lookupval_func; + GXV_Lookup_Fmt4_Transit_Func lookupfmt4_trans; + FT_Bytes lookuptbl_head; + + GXV_StateTable_ValidatorRec statetable; + GXV_XStateTable_ValidatorRec xstatetable; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } GXV_ValidatorRec; + + +#define GXV_TABLE_DATA( tag, field ) \ + ( ( (GXV_ ## tag ## _Data)valid->table_data )->field ) + +#undef FT_INVALID_ +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid->root, _prefix ## _error ) + +#define GXV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + _count > ( limit? limit : valid->root->limit ) ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define GXV_INIT valid->debug_indent = 0 + +#define GXV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + valid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define GXV_EXIT valid->debug_indent -= 2 + +#define GXV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define GXV_INIT do ; while ( 0 ) +#define GXV_NAME_ENTER( name ) do ; while ( 0 ) +#define GXV_EXIT do ; while ( 0 ) + +#define GXV_TRACE( s ) do ; while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit alignment checking *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_32BIT_ALIGNMENT_VALIDATE( a ) \ + FT_BEGIN_STMNT \ + { \ + if ( 0 != ( (a) % 4 ) ) \ + FT_INVALID_OFFSET ; \ + } \ + FT_END_STMNT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Dumping Binary Data *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_TRACE_HEXDUMP( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + FT_TRACE1(("\\x%02x", *b)) ; \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_C( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + if ( 0x40 < *b && *b < 0x7e ) \ + FT_TRACE1(("%c", *b)) ; \ + else \ + FT_TRACE1(("\\x%02x", *b)) ; \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_SFNTNAME( n ) \ + GXV_TRACE_HEXDUMP( n.string, n.string_len ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_BinSrchHeader_validate( FT_Bytes p, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_Short ctl_point, + GXV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY MACROS AND FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator valid); + + +#define GXV_SUBTABLE_OFFSET_CHECK( _offset ) \ + FT_BEGIN_STMNT \ + if ( (_offset) > valid->subtable_length ) \ + FT_INVALID_OFFSET; \ + FT_END_STMNT + +#define GXV_SUBTABLE_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( ( p + (_count) - valid->subtable_start ) > \ + valid->subtable_length ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define GXV_USHORT_TO_SHORT( _us ) \ + ( ( 0x8000U < ( _us ) ) ? ( ( _us ) - 0x8000U ) : ( _us ) ) + +#define GXV_STATETABLE_HEADER_SIZE ( 2 + 2 + 2 + 2 ) +#define GXV_STATEHEADER_SIZE GXV_STATETABLE_HEADER_SIZE + +#define GXV_XSTATETABLE_HEADER_SIZE ( 4 + 4 + 4 + 4 ) +#define GXV_XSTATEHEADER_SIZE GXV_XSTATETABLE_HEADER_SIZE + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_odtect_DataRec_ + { + FT_Bytes start; + FT_ULong length; + FT_String* name; + + } GXV_odtect_DataRec, *GXV_odtect_Data; + + typedef struct GXV_odtect_RangeRec_ + { + FT_UInt nRanges; + GXV_odtect_Data range; + + } GXV_odtect_RangeRec, *GXV_odtect_Range; + + + FT_LOCAL( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ); + + FT_LOCAL( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator valid ); + + +#define GXV_ODTECT( n, odtect ) \ + GXV_odtect_DataRec odtect ## _range[n]; \ + GXV_odtect_RangeRec odtect ## _rec = { 0, NULL }; \ + GXV_odtect_Range odtect = NULL + +#define GXV_ODTECT_INIT( odtect ) \ + FT_BEGIN_STMNT \ + odtect ## _rec.nRanges = 0; \ + odtect ## _rec.range = odtect ## _range; \ + odtect = & odtect ## _rec; \ + FT_END_STMNT + + + /* */ + +FT_END_HEADER + +#endif /* __GXVCOMMN_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxverror.h b/src/freetype2/gxvalid/gxverror.h new file mode 100644 index 0000000..0196199 --- /dev/null +++ b/src/freetype2/gxvalid/gxverror.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* gxverror.h */ +/* */ +/* TrueTypeGX/AAT validation module error codes (specification only). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the OpenType validation module error */ + /* enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __GXVERROR_H__ +#define __GXVERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX GXV_Err_ +#define FT_ERR_BASE FT_Mod_Err_GXV + +#define FT_KEEP_ERR_PREFIX + +#include FT_ERRORS_H + +#endif /* __GXVERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvfeat.c b/src/freetype2/gxvalid/gxvfeat.c new file mode 100644 index 0000000..d7c6ad1 --- /dev/null +++ b/src/freetype2/gxvalid/gxvfeat.c @@ -0,0 +1,343 @@ +/***************************************************************************/ +/* */ +/* gxvfeat.c */ +/* */ +/* TrueTypeGX/AAT feat table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.h" +#include "gxvfeat.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_gxvfeat + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_feat_DataRec_ + { + FT_UInt reserved_size; + FT_UShort feature; + FT_UShort setting; + + } GXV_feat_DataRec, *GXV_feat_Data; + + +#define GXV_FEAT_DATA( field ) GXV_TABLE_DATA( feat, field ) + + + typedef enum + { + GXV_FEAT_MASK_EXCLUSIVE_SETTINGS = 0x8000U, + GXV_FEAT_MASK_DYNAMIC_DEFAULT = 0x4000, + GXV_FEAT_MASK_UNUSED = 0x3F00, + GXV_FEAT_MASK_DEFAULT_SETTING = 0x00FF + + } GXV_FeatureFlagsMask; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_feat_registry_validate( FT_UShort feature, + FT_UShort nSettings, + FT_Bool exclusive, + GXV_Validator valid ) + { + GXV_NAME_ENTER( "feature in registry" ); + + GXV_TRACE(( " (feature = %u)\n", feature )); + + if ( feature >= gxv_feat_registry_length ) + { + GXV_TRACE(( "feature number %d is out of range %d\n", + feature, gxv_feat_registry_length )); + if ( valid->root->level == FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + goto Exit; + } + + if ( gxv_feat_registry[feature].existence == 0 ) + { + GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n", + feature )); + if ( valid->root->level == FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + goto Exit; + } + + if ( gxv_feat_registry[feature].apple_reserved ) + { + /* Don't use here. Apple is reserved. */ + GXV_TRACE(( "feature number %d is reserved by Apple\n", feature )); + if ( valid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( nSettings != gxv_feat_registry[feature].nSettings ) + { + GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n", + feature, nSettings, + gxv_feat_registry[feature].nSettings )); + if ( valid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( exclusive != gxv_feat_registry[feature].exclusive ) + { + GXV_TRACE(( "exclusive flag %d differs from predefined value\n", + exclusive )); + if ( valid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + Exit: + GXV_EXIT; + } + + + static void + gxv_feat_name_index_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + FT_Short nameIndex; + + + GXV_NAME_ENTER( "nameIndex" ); + + GXV_LIMIT_CHECK( 2 ); + nameIndex = FT_NEXT_SHORT ( p ); + GXV_TRACE(( " (nameIndex = %d)\n", nameIndex )); + + gxv_sfntName_validate( (FT_UShort)nameIndex, + 255, + 32768U, + valid ); + + GXV_EXIT; + } + + + static void + gxv_feat_setting_validate( FT_Bytes table, + FT_Bytes limit, + FT_Bool exclusive, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort setting; + + + GXV_NAME_ENTER( "setting" ); + + GXV_LIMIT_CHECK( 2 ); + + setting = FT_NEXT_USHORT( p ); + + /* If we have exclusive setting, the setting should be odd. */ + if ( exclusive && ( setting % 2 ) == 0 ) + FT_INVALID_DATA; + + gxv_feat_name_index_validate( p, limit, valid ); + + GXV_FEAT_DATA( setting ) = setting; + + GXV_EXIT; + } + + + static void + gxv_feat_name_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); + + FT_UShort feature; + FT_UShort nSettings; + FT_UInt settingTable; + FT_UShort featureFlags; + + FT_Bool exclusive; + FT_Int last_setting; + FT_UInt i; + + + GXV_NAME_ENTER( "name" ); + + /* feature + nSettings + settingTable + featureFlags */ + GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); + + feature = FT_NEXT_USHORT( p ); + GXV_FEAT_DATA( feature ) = feature; + + nSettings = FT_NEXT_USHORT( p ); + settingTable = FT_NEXT_ULONG ( p ); + featureFlags = FT_NEXT_USHORT( p ); + + if ( settingTable < reserved_size ) + FT_INVALID_OFFSET; + + if ( valid->root->level == FT_VALIDATE_PARANOID && + ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) + FT_INVALID_DATA; + + exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); + if ( exclusive ) + { + FT_Byte dynamic_default; + + + if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) + dynamic_default = (FT_Byte)( featureFlags & + GXV_FEAT_MASK_DEFAULT_SETTING ); + else + dynamic_default = 0; + + /* If exclusive, check whether default setting is in the range. */ + if ( !( dynamic_default < nSettings ) ) + FT_INVALID_FORMAT; + } + + gxv_feat_registry_validate( feature, nSettings, exclusive, valid ); + + gxv_feat_name_index_validate( p, limit, valid ); + + p = valid->root->base + settingTable; + for ( last_setting = -1, i = 0; i < nSettings; i++ ) + { + gxv_feat_setting_validate( p, limit, exclusive, valid ); + + if ( valid->root->level == FT_VALIDATE_PARANOID && + (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) + FT_INVALID_FORMAT; + + last_setting = (FT_Int)GXV_FEAT_DATA( setting ); + /* setting + nameIndex */ + p += ( 2 + 2 ); + } + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** feat TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + + GXV_feat_DataRec featrec; + GXV_feat_Data feat = &featrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_UInt featureNameCount; + + FT_UInt i; + FT_Int last_feature; + + + valid->root = ftvalid; + valid->table_data = feat; + valid->face = face; + + FT_TRACE3(( "validating `feat' table\n" )); + GXV_INIT; + + feat->reserved_size = 0; + + /* version + featureNameCount + none_0 + none_1 */ + GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); + feat->reserved_size += 4 + 2 + 2 + 4; + + if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ + FT_INVALID_FORMAT; + + featureNameCount = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); + + if ( valid->root->level != FT_VALIDATE_PARANOID ) + p += 6; /* skip (none) and (none) */ + else + { + if ( FT_NEXT_USHORT( p ) != 0 ) + FT_INVALID_DATA; + + if ( FT_NEXT_ULONG( p ) != 0 ) + FT_INVALID_DATA; + } + + feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); + + for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) + { + gxv_feat_name_validate( p, limit, valid ); + + if ( valid->root->level == FT_VALIDATE_PARANOID && + (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) + FT_INVALID_FORMAT; + + last_feature = GXV_FEAT_DATA( feature ); + p += 2 + 2 + 4 + 2 + 2; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvfeat.h b/src/freetype2/gxvalid/gxvfeat.h new file mode 100644 index 0000000..049d23a --- /dev/null +++ b/src/freetype2/gxvalid/gxvfeat.h @@ -0,0 +1,172 @@ +/***************************************************************************/ +/* */ +/* gxvfeat.h */ +/* */ +/* TrueTypeGX/AAT feat table validation (specification). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __GXVFEAT_H__ +#define __GXVFEAT_H__ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Registry predefined by Apple *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* TODO: More compact format */ + typedef struct GXV_Feature_RegistryRec_ + { + FT_Bool existence; + FT_Bool apple_reserved; + FT_Bool exclusive; + FT_Byte nSettings; + + } GX_Feature_RegistryRec; + + +#define gxv_feat_registry_length \ + ( sizeof ( gxv_feat_registry ) / \ + sizeof ( GX_Feature_RegistryRec ) ) + + + static GX_Feature_RegistryRec gxv_feat_registry[] = + { + /* Generated from gxvfgen.c */ + {1, 0, 0, 1}, /* All Typographic Features */ + {1, 0, 0, 8}, /* Ligatures */ + {1, 0, 1, 3}, /* Cursive Connection */ + {1, 0, 1, 6}, /* Letter Case */ + {1, 0, 0, 1}, /* Vertical Substitution */ + {1, 0, 0, 1}, /* Linguistic Rearrangement */ + {1, 0, 1, 2}, /* Number Spacing */ + {1, 1, 0, 0}, /* Apple Reserved 1 */ + {1, 0, 0, 5}, /* Smart Swashes */ + {1, 0, 1, 3}, /* Diacritics */ + {1, 0, 1, 4}, /* Vertical Position */ + {1, 0, 1, 3}, /* Fractions */ + {1, 1, 0, 0}, /* Apple Reserved 2 */ + {1, 0, 0, 1}, /* Overlapping Characters */ + {1, 0, 0, 6}, /* Typographic Extras */ + {1, 0, 0, 5}, /* Mathematical Extras */ + {1, 0, 1, 7}, /* Ornament Sets */ + {1, 0, 1, 1}, /* Character Alternatives */ + {1, 0, 1, 5}, /* Design Complexity */ + {1, 0, 1, 6}, /* Style Options */ + {1, 0, 1, 11}, /* Character Shape */ + {1, 0, 1, 2}, /* Number Case */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 10}, /* Transliteration */ + {1, 0, 1, 9}, /* Annotation */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {1, 0, 1, 4}, /* CJK Roman Spacing */ + }; + + +#endif /* __GXVFEAT_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvfgen.c b/src/freetype2/gxvalid/gxvfgen.c new file mode 100644 index 0000000..e48778a --- /dev/null +++ b/src/freetype2/gxvalid/gxvfgen.c @@ -0,0 +1,482 @@ +/***************************************************************************/ +/* */ +/* gxfgen.c */ +/* */ +/* Generate feature registry data for gxv `feat' validator. */ +/* This program is derived from gxfeatreg.c in gxlayout. */ +/* */ +/* Copyright 2004, 2005, 2006 by Masatake YAMATO and Redhat K.K. */ +/* */ +/* This file 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. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* gxfeatreg.c */ +/* */ +/* Database of font features pre-defined by Apple Computer, Inc. */ +/* http://developer.apple.com/fonts/Registry/ */ +/* (body). */ +/* */ +/* Copyright 2003 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* This file 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. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* Development of gxfeatreg.c is supported by */ +/* Information-technology Promotion Agency, Japan. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* This file is compiled as a stand-alone executable. */ +/* This file is never compiled into `libfreetype2'. */ +/* The output of this file is used in `gxvfeat.c'. */ +/* ----------------------------------------------------------------------- */ +/* Compile: gcc `pkg-config --cflags freetype2` gxvfgen.c -o gxvfgen */ +/* Run: ./gxvfgen > tmp.c */ +/* */ +/***************************************************************************/ + + /*******************************************************************/ + /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ + /*******************************************************************/ + + /* + * If you add a new setting to a feature, check the number of settings + * in the feature. If the number is greater than the value defined as + * FEATREG_MAX_SETTING, update the value. + */ +#define FEATREG_MAX_SETTING 12 + + /*******************************************************************/ + /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ + /*******************************************************************/ + + +#include <stdio.h> +#include <string.h> + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define APPLE_RESERVED "Apple Reserved" +#define APPLE_RESERVED_LENGTH 14 + + typedef struct GX_Feature_RegistryRec_ + { + const char* feat_name; + char exclusive; + char* setting_name[FEATREG_MAX_SETTING]; + + } GX_Feature_RegistryRec; + + +#define EMPTYFEAT {0, 0, {NULL}} + + + static GX_Feature_RegistryRec featreg_table[] = { + { /* 0 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + }, { /* 1 */ + "Ligatures", + 0, + { + "Required Ligatures", + "Common Ligatures", + "Rare Ligatures", + "Logos", + "Rebus Pictures", + "Diphthong Ligatures", + "Squared Ligatures", + "Squared Ligatures, Abbreviated", + NULL + } + }, { /* 2 */ + "Cursive Connection", + 1, + { + "Unconnected", + "Partially Connected", + "Cursive", + NULL + } + }, { /* 3 */ + "Letter Case", + 1, + { + "Upper & Lower Case", + "All Caps", + "All Lower Case", + "Small Caps", + "Initial Caps", + "Initial Caps & Small Caps", + NULL + } + }, { /* 4 */ + "Vertical Substitution", + 0, + { + /* "Substitute Vertical Forms", */ + "Turns on the feature", + NULL + } + }, { /* 5 */ + "Linguistic Rearrangement", + 0, + { + /* "Linguistic Rearrangement", */ + "Turns on the feature", + NULL + } + }, { /* 6 */ + "Number Spacing", + 1, + { + "Monospaced Numbers", + "Proportional Numbers", + NULL + } + }, { /* 7 */ + APPLE_RESERVED " 1", + 0, + {NULL} + }, { /* 8 */ + "Smart Swashes", + 0, + { + "Word Initial Swashes", + "Word Final Swashes", + "Line Initial Swashes", + "Line Final Swashes", + "Non-Final Swashes", + NULL + } + }, { /* 9 */ + "Diacritics", + 1, + { + "Show Diacritics", + "Hide Diacritics", + "Decompose Diacritics", + NULL + } + }, { /* 10 */ + "Vertical Position", + 1, + { + /* "Normal Position", */ + "No Vertical Position", + "Superiors", + "Inferiors", + "Ordinals", + NULL + } + }, { /* 11 */ + "Fractions", + 1, + { + "No Fractions", + "Vertical Fractions", + "Diagonal Fractions", + NULL + } + }, { /* 12 */ + APPLE_RESERVED " 2", + 0, + {NULL} + }, { /* 13 */ + "Overlapping Characters", + 0, + { + /* "Prevent Overlap", */ + "Turns on the feature", + NULL + } + }, { /* 14 */ + "Typographic Extras", + 0, + { + "Hyphens to Em Dash", + "Hyphens to En Dash", + "Unslashed Zero", + "Form Interrobang", + "Smart Quotes", + "Periods to Ellipsis", + NULL + } + }, { /* 15 */ + "Mathematical Extras", + 0, + { + "Hyphens to Minus", + "Asterisk to Multiply", + "Slash to Divide", + "Inequality Ligatures", + "Exponents", + NULL + } + }, { /* 16 */ + "Ornament Sets", + 1, + { + "No Ornaments", + "Dingbats", + "Pi Characters", + "Fleurons", + "Decorative Borders", + "International Symbols", + "Math Symbols", + NULL + } + }, { /* 17 */ + "Character Alternatives", + 1, + { + "No Alternates", + /* TODO */ + NULL + } + }, { /* 18 */ + "Design Complexity", + 1, + { + "Design Level 1", + "Design Level 2", + "Design Level 3", + "Design Level 4", + "Design Level 5", + /* TODO */ + NULL + } + }, { /* 19 */ + "Style Options", + 1, + { + "No Style Options", + "Display Text", + "Engraved Text", + "Illuminated Caps", + "Tilling Caps", + "Tall Caps", + NULL + } + }, { /* 20 */ + "Character Shape", + 1, + { + "Traditional Characters", + "Simplified Characters", + "JIS 1978 Characters", + "JIS 1983 Characters", + "JIS 1990 Characters", + "Traditional Characters, Alternative Set 1", + "Traditional Characters, Alternative Set 2", + "Traditional Characters, Alternative Set 3", + "Traditional Characters, Alternative Set 4", + "Traditional Characters, Alternative Set 5", + "Expert Characters", + NULL /* count => 12 */ + } + }, { /* 21 */ + "Number Case", + 1, + { + "Lower Case Numbers", + "Upper Case Numbers", + NULL + } + }, { /* 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, /* Here after Newer */ { /* 23 */ + "Transliteration", + 1, + { + "No Transliteration", + "Hanja To Hangul", + "Hiragana to Katakana", + "Katakana to Hiragana", + "Kana to Romanization", + "Romanization to Hiragana", + "Romanization to Katakana", + "Hanja to Hangul, Alternative Set 1", + "Hanja to Hangul, Alternative Set 2", + "Hanja to Hangul, Alternative Set 3", + NULL + } + }, { /* 24 */ + "Annotation", + 1, + { + "No Annotation", + "Box Annotation", + "Rounded Box Annotation", + "Circle Annotation", + "Inverted Circle Annotation", + "Parenthesis Annotation", + "Period Annotation", + "Roman Numeral Annotation", + "Diamond Annotation", + NULL + } + }, { /* 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 27-30 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 31-35 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 36-40 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 40-45 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 46-50 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 51-55 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 56-60 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 61-65 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 66-70 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 71-75 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 76-80 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 81-85 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 86-90 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 91-95 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 96-98 */ + EMPTYFEAT, /* 99 */ { /* 100 => 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, { /* 101 => 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 102 => 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 103 */ + "CJK Roman Spacing", + 1, + { + "Half-width", + "Proportional", + "Default Roman", + "Full-width Roman", + NULL + } + }, { /* 104 => 1 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + } + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Generator *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + int + main( void ) + { + int i; + + + printf( " {\n" ); + printf( " /* Generated from %s */\n", __FILE__ ); + + for ( i = 0; + i < sizeof ( featreg_table ) / sizeof ( GX_Feature_RegistryRec ); + i++ ) + { + const char* feat_name; + int nSettings; + + + feat_name = featreg_table[i].feat_name; + for ( nSettings = 0; + featreg_table[i].setting_name[nSettings]; + nSettings++) + ; /* Do nothing */ + + printf( " {%1d, %1d, %1d, %2d}, /* %s */\n", + feat_name ? 1 : 0, + ( feat_name && + ( ft_strncmp( feat_name, + APPLE_RESERVED, APPLE_RESERVED_LENGTH ) == 0 ) + ) ? 1 : 0, + featreg_table[i].exclusive ? 1 : 0, + nSettings, + feat_name ? feat_name : "__EMPTY__" ); + } + + printf( " };\n" ); + + return 0; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvjust.c b/src/freetype2/gxvalid/gxvjust.c new file mode 100644 index 0000000..29bf840 --- /dev/null +++ b/src/freetype2/gxvalid/gxvjust.c @@ -0,0 +1,630 @@ +/***************************************************************************/ +/* */ +/* gxvjust.c */ +/* */ +/* TrueTypeGX/AAT just table validation (body). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.h" + +#include FT_SFNT_NAMES_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_gxvjust + + /* + * referred `just' table format specification: + * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6just.html + * last updated 2000. + * ---------------------------------------------- + * [JUST HEADER]: GXV_JUST_HEADER_SIZE + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (2000) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * ---------------------------------------------- + */ + + typedef struct GXV_just_DataRec_ + { + FT_UShort wdc_offset_max; + FT_UShort wdc_offset_min; + FT_UShort pc_offset_max; + FT_UShort pc_offset_min; + + } GXV_just_DataRec, *GXV_just_Data; + + +#define GXV_JUST_DATA( a ) GXV_TABLE_DATA( just, a ) + + + static void + gxv_just_wdp_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong justClass; + FT_Fixed beforeGrowLimit; + FT_Fixed beforeShrinkGrowLimit; + FT_Fixed afterGrowLimit; + FT_Fixed afterShrinkGrowLimit; + FT_UShort growFlags; + FT_UShort shrinkFlags; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); + justClass = FT_NEXT_ULONG( p ); + beforeGrowLimit = FT_NEXT_ULONG( p ); + beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); + afterGrowLimit = FT_NEXT_ULONG( p ); + afterShrinkGrowLimit = FT_NEXT_ULONG( p ); + growFlags = FT_NEXT_USHORT( p ); + shrinkFlags = FT_NEXT_USHORT( p ); + + /* TODO: decode flags for human readability */ + + valid->subtable_length = p - table; + } + + + static void + gxv_just_wdc_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong count, i; + + + GXV_LIMIT_CHECK( 4 ); + count = FT_NEXT_ULONG( p ); + for ( i = 0; i < count; i++ ) + { + GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count )); + gxv_just_wdp_entry_validate( p, limit, valid ); + p += valid->subtable_length; + } + + valid->subtable_length = p - table; + } + + + static void + gxv_just_widthDeltaClusters_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table ; + FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); + FT_UInt i; + + + GXV_NAME_ENTER( "just justDeltaClusters" ); + + if ( limit <= wdc_end ) + FT_INVALID_OFFSET; + + for ( i = 0; p <= wdc_end; i++ ) + { + gxv_just_wdc_entry_validate( p, limit, valid ); + p += valid->subtable_length; + } + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static void + gxv_just_actSubrecord_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + FT_Fixed lowerLimit; + FT_Fixed upperLimit; + + FT_UShort order; + FT_UShort decomposedCount; + + FT_UInt i; + + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); + lowerLimit = FT_NEXT_ULONG( p ); + upperLimit = FT_NEXT_ULONG( p ); + order = FT_NEXT_USHORT( p ); + decomposedCount = FT_NEXT_USHORT( p ); + + for ( i = 0; i < decomposedCount; i++ ) + { + FT_UShort glyphs; + + + GXV_LIMIT_CHECK( 2 ); + glyphs = FT_NEXT_USHORT( p ); + } + + valid->subtable_length = p - table; + } + + + static void + gxv_just_actSubrecord_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort addGlyph; + + + GXV_LIMIT_CHECK( 2 ); + addGlyph = FT_NEXT_USHORT( p ); + + valid->subtable_length = p - table; + } + + + static void + gxv_just_actSubrecord_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ + FT_UShort addGlyph; + FT_UShort substGlyph; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + substThreshhold = FT_NEXT_ULONG( p ); + addGlyph = FT_NEXT_USHORT( p ); + substGlyph = FT_NEXT_USHORT( p ); + + valid->subtable_length = p - table; + } + + + static void + gxv_just_actSubrecord_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong variantsAxis; + FT_Fixed minimumLimit; + FT_Fixed noStretchValue; + FT_Fixed maximumLimit; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + variantsAxis = FT_NEXT_ULONG( p ); + minimumLimit = FT_NEXT_ULONG( p ); + noStretchValue = FT_NEXT_ULONG( p ); + maximumLimit = FT_NEXT_ULONG( p ); + + valid->subtable_length = p - table; + } + + + static void + gxv_just_actSubrecord_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort flags; + FT_UShort glyph; + + + GXV_LIMIT_CHECK( 2 + 2 ); + flags = FT_NEXT_USHORT( p ); + glyph = FT_NEXT_USHORT( p ); + + valid->subtable_length = p - table; + } + + + /* parse single actSubrecord */ + static void + gxv_just_actSubrecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort actionClass; + FT_UShort actionType; + FT_ULong actionLength; + + + GXV_NAME_ENTER( "just actSubrecord" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + actionClass = FT_NEXT_USHORT( p ); + actionType = FT_NEXT_USHORT( p ); + actionLength = FT_NEXT_ULONG( p ); + + if ( actionType == 0 ) + gxv_just_actSubrecord_type0_validate( p, limit, valid ); + else if ( actionType == 1 ) + gxv_just_actSubrecord_type1_validate( p, limit, valid ); + else if ( actionType == 2 ) + gxv_just_actSubrecord_type2_validate( p, limit, valid ); + else if ( actionType == 3 ) + ; /* Stretch glyph action: no actionData */ + else if ( actionType == 4 ) + gxv_just_actSubrecord_type4_validate( p, limit, valid ); + else if ( actionType == 5 ) + gxv_just_actSubrecord_type5_validate( p, limit, valid ); + else + FT_INVALID_DATA; + + valid->subtable_length = actionLength; + + GXV_EXIT; + } + + + static void + gxv_just_pcActionRecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong actionCount; + FT_ULong i; + + + GXV_LIMIT_CHECK( 4 ); + actionCount = FT_NEXT_ULONG( p ); + GXV_TRACE(( "actionCount = %d\n", actionCount )); + + for ( i = 0; i < actionCount; i++ ) + { + gxv_just_actSubrecord_validate( p, limit, valid ); + p += valid->subtable_length; + } + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static void + gxv_just_pcTable_LookupValue_entry_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UNUSED( glyph ); + + if ( value.u > GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_max ) = value.u; + if ( value.u < GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_min ) = value.u; + } + + + static void + gxv_just_pcLookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just pcLookupTable" ); + GXV_JUST_DATA( pc_offset_max ) = 0x0000; + GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU; + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate; + + gxv_LookupTable_validate( p, limit, valid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_postcompTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just postcompTable" ); + + gxv_just_pcLookupTable_validate( p, limit, valid ); + p += valid->subtable_length; + + gxv_just_pcActionRecord_validate( p, limit, valid ); + p += valid->subtable_length; + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static void + gxv_just_classTable_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort setMark; + FT_UShort dontAdvance; + FT_UShort markClass; + FT_UShort currentClass; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + FT_UNUSED( valid ); + + + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markClass = (FT_UShort)( ( flags >> 7 ) & 0x7F ); + currentClass = (FT_UShort)( flags & 0x7F ); + + /* TODO: validate markClass & currentClass */ + } + + + static void + gxv_just_justClassTable_validate ( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort length; + FT_UShort coverage; + FT_ULong subFeatureFlags; + + + GXV_NAME_ENTER( "just justClassTable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + subFeatureFlags = FT_NEXT_ULONG( p ); + + GXV_TRACE(( " justClassTable: coverage = 0x%04x (%s)", + coverage, + ( 0x4000 & coverage ) == 0 ? "ascending" : "descending" )); + + valid->statetable.optdata = NULL; + valid->statetable.optdata_load_func = NULL; + valid->statetable.subtable_setup_func = NULL; + valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + valid->statetable.entry_validate_func = + gxv_just_classTable_entry_validate; + + gxv_StateTable_validate( p, table + length, valid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_wdcTable_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UNUSED( glyph ); + + if ( value.u > GXV_JUST_DATA( wdc_offset_max ) ) + GXV_JUST_DATA( wdc_offset_max ) = value.u; + if ( value.u < GXV_JUST_DATA( wdc_offset_min ) ) + GXV_JUST_DATA( wdc_offset_min ) = value.u; + } + + + static void + gxv_just_justData_lookuptable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_JUST_DATA( wdc_offset_max ) = 0x0000; + GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU; + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_just_wdcTable_LookupValue_validate; + + gxv_LookupTable_validate( p, limit, valid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + /* + * gxv_just_justData_validate() parses and validates horizData, vertData. + */ + static void + gxv_just_justData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + /* + * following 3 offsets are measured from the start of `just' + * (which table points to), not justData + */ + FT_UShort justClassTableOffset; + FT_UShort wdcTableOffset; + FT_UShort pcTableOffset; + FT_Bytes p = table; + + GXV_ODTECT( 4, odtect ); + + + GXV_NAME_ENTER( "just justData" ); + + GXV_ODTECT_INIT( odtect ); + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + justClassTableOffset = FT_NEXT_USHORT( p ); + wdcTableOffset = FT_NEXT_USHORT( p ); + pcTableOffset = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset )); + GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset )); + GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset )); + + gxv_just_justData_lookuptable_validate( p, limit, valid ); + gxv_odtect_add_range( p, valid->subtable_length, + "just_LookupTable", odtect ); + + if ( wdcTableOffset ) + { + gxv_just_widthDeltaClusters_validate( + valid->root->base + wdcTableOffset, limit, valid ); + gxv_odtect_add_range( valid->root->base + wdcTableOffset, + valid->subtable_length, "just_wdcTable", odtect ); + } + + if ( pcTableOffset ) + { + gxv_just_postcompTable_validate( valid->root->base + pcTableOffset, + limit, valid ); + gxv_odtect_add_range( valid->root->base + pcTableOffset, + valid->subtable_length, "just_pcTable", odtect ); + } + + if ( justClassTableOffset ) + { + gxv_just_justClassTable_validate( + valid->root->base + justClassTableOffset, limit, valid ); + gxv_odtect_add_range( valid->root->base + justClassTableOffset, + valid->subtable_length, "just_justClassTable", + odtect ); + } + + gxv_odtect_validate( odtect, valid ); + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_UInt table_size; + + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + GXV_just_DataRec justrec; + GXV_just_Data just = &justrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + + GXV_ODTECT( 3, odtect ); + + + GXV_ODTECT_INIT( odtect ); + + valid->root = ftvalid; + valid->table_data = just; + valid->face = face; + + FT_TRACE3(( "validating `just' table\n" )); + GXV_INIT; + + limit = valid->root->limit; + table_size = limit - table; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + gxv_odtect_add_range( table, p - table, "just header", odtect ); + + + /* Version 1.0 (always:2000) */ + GXV_TRACE(( " (version = 0x%08x)\n", version )); + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:2000) */ + GXV_TRACE(( " (format = 0x%04x)\n", format )); + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_TRACE(( " (horizOffset = %d)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = %d)\n", vertOffset )); + + + /* validate justData */ + if ( 0 < horizOffset ) + { + gxv_just_justData_validate( table + horizOffset, limit, valid ); + gxv_odtect_add_range( table + horizOffset, valid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_just_justData_validate( table + vertOffset, limit, valid ); + gxv_odtect_add_range( table + vertOffset, valid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvkern.c b/src/freetype2/gxvalid/gxvkern.c new file mode 100644 index 0000000..bfb405f --- /dev/null +++ b/src/freetype2/gxvalid/gxvkern.c @@ -0,0 +1,876 @@ +/***************************************************************************/ +/* */ +/* gxvkern.c */ +/* */ +/* TrueTypeGX/AAT kern table validation (body). */ +/* */ +/* Copyright 2004, 2005, 2006, 2007 */ +/* by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.h" + +#include FT_SFNT_NAMES_H +#include FT_SERVICE_GX_VALIDATE_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_gxvkern + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum GXV_kern_Version_ + { + KERN_VERSION_CLASSIC = 0x0000, + KERN_VERSION_NEW = 0x0001 + + } GXV_kern_Version; + + + typedef enum GXV_kern_Dialect_ + { + KERN_DIALECT_UNKNOWN = 0, + KERN_DIALECT_MS = FT_VALIDATE_MS, + KERN_DIALECT_APPLE = FT_VALIDATE_APPLE, + KERN_DIALECT_ANY = FT_VALIDATE_CKERN + + } GXV_kern_Dialect; + + + typedef struct GXV_kern_DataRec_ + { + GXV_kern_Version version; + void *subtable_data; + GXV_kern_Dialect dialect_request; + + } GXV_kern_DataRec, *GXV_kern_Data; + + +#define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field ) + +#define KERN_IS_CLASSIC( valid ) \ + ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) ) +#define KERN_IS_NEW( valid ) \ + ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) ) + +#define KERN_DIALECT( valid ) \ + GXV_KERN_DATA( dialect_request ) +#define KERN_ALLOWS_MS( valid ) \ + ( KERN_DIALECT( valid ) & KERN_DIALECT_MS ) +#define KERN_ALLOWS_APPLE( valid ) \ + ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE ) + +#define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 4 ) +#define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 6 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SUBTABLE VALIDATORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* ============================= format 0 ============================== */ + + static void + gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nPairs, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort i; + + FT_UShort last_gid_left = 0; + FT_UShort last_gid_right = 0; + + FT_UNUSED( limit ); + + + GXV_NAME_ENTER( "kern format 0 pairs" ); + + for ( i = 0; i < nPairs; i++ ) + { + FT_UShort gid_left; + FT_UShort gid_right; + FT_Short kernValue; + + + /* left */ + gid_left = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_left, valid ); + + /* right */ + gid_right = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_right, valid ); + + /* Pairs of left and right GIDs must be unique and sorted. */ + GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right )); + if ( gid_left == last_gid_left ) + { + if ( last_gid_right < gid_right ) + last_gid_right = gid_right; + else + FT_INVALID_DATA; + } + else if ( last_gid_left < gid_left ) + { + last_gid_left = gid_left; + last_gid_right = gid_right; + } + else + FT_INVALID_DATA; + + /* skip the kern value */ + kernValue = FT_NEXT_SHORT( p ); + } + + GXV_EXIT; + } + + static void + gxv_kern_subtable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + + FT_UShort nPairs; + FT_UShort unitSize; + + + GXV_NAME_ENTER( "kern subtable format 0" ); + + unitSize = 2 + 2 + 2; + nPairs = 0; + + /* nPairs, searchRange, entrySelector, rangeShift */ + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid ); + p += 2 + 2 + 2 + 2; + + gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid ); + + GXV_EXIT; + } + + + /* ============================= format 1 ============================== */ + + + typedef struct GXV_kern_fmt1_StateOptRec_ + { + FT_UShort valueTable; + FT_UShort valueTable_length; + + } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData; + + + static void + gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->valueTable = FT_NEXT_USHORT( p ); + } + + + /* + * passed tables_size covers whole StateTable, including kern fmt1 header + */ + static void + gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->valueTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->valueTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid ); + } + + + /* + * passed table & limit are of whole StateTable, not including subtables + */ + static void + gxv_kern_subtable_fmt1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort push; + FT_UShort dontAdvance; + FT_UShort valueOffset; + FT_UShort kernAction; + FT_UShort kernValue; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset ); + + + push = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + valueOffset = (FT_UShort)( flags & 0x3FFF ); + + { + GXV_kern_fmt1_StateOptRecData vt_rec = + (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata; + FT_Bytes p; + + + if ( valueOffset < vt_rec->valueTable ) + FT_INVALID_OFFSET; + + p = table + valueOffset; + limit = table + vt_rec->valueTable + vt_rec->valueTable_length; + + GXV_LIMIT_CHECK( 2 + 2 ); + kernAction = FT_NEXT_USHORT( p ); + kernValue = FT_NEXT_USHORT( p ); + } + } + + + static void + gxv_kern_subtable_fmt1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRec vt_rec; + + + GXV_NAME_ENTER( "kern subtable format 1" ); + + valid->statetable.optdata = + &vt_rec; + valid->statetable.optdata_load_func = + gxv_kern_subtable_fmt1_valueTable_load; + valid->statetable.subtable_setup_func = + gxv_kern_subtable_fmt1_subtable_setup; + valid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + valid->statetable.entry_validate_func = + gxv_kern_subtable_fmt1_entry_validate; + + gxv_StateTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + + /* ================ Data for Class-Based Subtables 2, 3 ================ */ + + typedef enum GXV_kern_ClassSpec_ + { + GXV_KERN_CLS_L = 0, + GXV_KERN_CLS_R + + } GXV_kern_ClassSpec; + + + /* ============================= format 2 ============================== */ + + /* ---------------------- format 2 specific data ----------------------- */ + + typedef struct GXV_kern_subtable_fmt2_DataRec_ + { + FT_UShort rowWidth; + FT_UShort array; + FT_UShort offset_min[2]; + FT_UShort offset_max[2]; + const FT_String* class_tag[2]; + GXV_odtect_Range odtect; + + } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data; + + +#define GXV_KERN_FMT2_DATA( field ) \ + ( ( (GXV_kern_subtable_fmt2_DataRec *) \ + ( GXV_KERN_DATA( subtable_data ) ) )->field ) + + + /* -------------------------- utility functions ----------------------- */ + + static void + gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, + FT_Bytes limit, + GXV_kern_ClassSpec spec, + GXV_Validator valid ) + { + const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); + GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); + + FT_Bytes p = table; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "kern format 2 classTable" ); + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", + tag, firstGlyph, nGlyphs )); + + gxv_glyphid_validate( firstGlyph, valid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid ); + + gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), + &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), + &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), + valid ); + + gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); + + GXV_EXIT; + } + + + static void + gxv_kern_subtable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + GXV_ODTECT( 3, odtect ); + GXV_kern_subtable_fmt2_DataRec fmt2_rec = + { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; + + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort leftOffsetTable; + FT_UShort rightOffsetTable; + + + GXV_NAME_ENTER( "kern subtable format 2" ); + + GXV_ODTECT_INIT( odtect ); + fmt2_rec.odtect = odtect; + GXV_KERN_DATA( subtable_data ) = &fmt2_rec; + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); + leftOffsetTable = FT_NEXT_USHORT( p ); + rightOffsetTable = FT_NEXT_USHORT( p ); + GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); + + + GXV_LIMIT_CHECK( leftOffsetTable ); + GXV_LIMIT_CHECK( rightOffsetTable ); + GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, + GXV_KERN_CLS_L, valid ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, + GXV_KERN_CLS_R, valid ); + + if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) + < GXV_KERN_FMT2_DATA( array ) ) + FT_INVALID_OFFSET; + + gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) + - GXV_KERN_FMT2_DATA( array ), + "array", odtect ); + + gxv_odtect_validate( odtect, valid ); + + GXV_EXIT; + } + + + /* ============================= format 3 ============================== */ + + static void + gxv_kern_subtable_fmt3_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort glyphCount; + FT_Byte kernValueCount; + FT_Byte leftClassCount; + FT_Byte rightClassCount; + FT_Byte flags; + + + GXV_NAME_ENTER( "kern subtable format 3" ); + + GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); + glyphCount = FT_NEXT_USHORT( p ); + kernValueCount = FT_NEXT_BYTE( p ); + leftClassCount = FT_NEXT_BYTE( p ); + rightClassCount = FT_NEXT_BYTE( p ); + flags = FT_NEXT_BYTE( p ); + + if ( valid->face->num_glyphs != glyphCount ) + { + GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", + valid->face->num_glyphs, glyphCount )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + + /* + * just skip kernValue[kernValueCount] + */ + GXV_LIMIT_CHECK( 2 * kernValueCount ); + p += 2 * kernValueCount; + + /* + * check leftClass[gid] < leftClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); + p += valid->subtable_length; + + if ( leftClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check rightClass[gid] < rightClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); + p += valid->subtable_length; + + if ( rightClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check kernIndex[i, j] < kernValueCount + */ + { + FT_UShort i, j; + + + for ( i = 0; i < leftClassCount; i++ ) + { + for ( j = 0; j < rightClassCount; j++ ) + { + GXV_LIMIT_CHECK( 1 ); + if ( kernValueCount < FT_NEXT_BYTE( p ) ) + FT_INVALID_OFFSET; + } + } + } + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static FT_Bool + gxv_kern_coverage_new_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator valid ) + { + /* new Apple-dialect */ + FT_Bool kernVertical; + FT_Bool kernCrossStream; + FT_Bool kernVariation; + + FT_UNUSED( valid ); + + + /* reserved bits = 0 */ + if ( coverage & 0x1FFC ) + return 0; + + kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 ); + kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 ); + kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 ); + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "new Apple-dialect: " + "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n", + !kernVertical, kernCrossStream, kernVariation, *format )); + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return 1; + } + + + static FT_Bool + gxv_kern_coverage_classic_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator valid ) + { + /* classic Apple-dialect */ + FT_Bool horizontal; + FT_Bool cross_stream; + + + /* check expected flags, but don't check if MS-dialect is impossible */ + if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) ) + return 0; + + /* reserved bits = 0 */ + if ( coverage & 0x02FC ) + return 0; + + horizontal = FT_BOOL( ( coverage >> 15 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 ); + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "classic Apple-dialect: " + "horizontal=%d, cross-stream=%d, format=%d\n", + horizontal, cross_stream, *format )); + + /* format 1 requires GX State Machine, too new for classic */ + if ( *format == 1 ) + return 0; + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return 1; + } + + + static FT_Bool + gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator valid ) + { + /* classic Microsoft-dialect */ + FT_Bool horizontal; + FT_Bool minimum; + FT_Bool cross_stream; + FT_Bool override; + + FT_UNUSED( valid ); + + + /* reserved bits = 0 */ + if ( coverage & 0xFDF0 ) + return 0; + + horizontal = FT_BOOL( coverage & 1 ); + minimum = FT_BOOL( ( coverage >> 1 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 ); + override = FT_BOOL( ( coverage >> 3 ) & 1 ); + + *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 ); + + GXV_TRACE(( "classic Microsoft-dialect: " + "horizontal=%d, minimum=%d, cross-stream=%d, " + "override=%d, format=%d\n", + horizontal, minimum, cross_stream, override, *format )); + + if ( *format == 2 ) + GXV_TRACE(( + "kerning values in Microsoft format 2 subtable are ignored\n" )); + + return 1; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MAIN *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static GXV_kern_Dialect + gxv_kern_coverage_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator valid ) + { + GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN; + + + GXV_NAME_ENTER( "validating coverage" ); + + GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage )); + + if ( KERN_IS_NEW( valid ) ) + { + if ( gxv_kern_coverage_new_apple_validate( coverage, + format, + valid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) ) + { + if ( gxv_kern_coverage_classic_apple_validate( coverage, + format, + valid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) ) + { + if ( gxv_kern_coverage_classic_microsoft_validate( coverage, + format, + valid ) ) + { + result = KERN_DIALECT_MS; + goto Exit; + } + } + + GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" )); + + Exit: + GXV_EXIT; + return result; + } + + + static void + gxv_kern_subtable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort version = 0; /* MS only: subtable version, unused */ + FT_ULong length; /* MS: 16bit, Apple: 32bit*/ + FT_UShort coverage; + FT_UShort tupleIndex = 0; /* Apple only */ + FT_UShort u16[2]; + FT_UShort format = 255; /* subtable format */ + + + GXV_NAME_ENTER( "kern subtable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */ + u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */ + coverage = FT_NEXT_USHORT( p ); + + switch ( gxv_kern_coverage_validate( coverage, &format, valid ) ) + { + case KERN_DIALECT_MS: + version = u16[0]; + length = u16[1]; + tupleIndex = 0; + GXV_TRACE(( "Subtable version = %d\n", version )); + GXV_TRACE(( "Subtable length = %d\n", length )); + break; + + case KERN_DIALECT_APPLE: + version = 0; + length = ( u16[0] << 16 ) + u16[1]; + tupleIndex = 0; + GXV_TRACE(( "Subtable length = %d\n", length )); + + if ( KERN_IS_NEW( valid ) ) + { + GXV_LIMIT_CHECK( 2 ); + tupleIndex = FT_NEXT_USHORT( p ); + GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex )); + } + break; + + default: + length = u16[1]; + GXV_TRACE(( "cannot detect subtable dialect, " + "just skip %d byte\n", length )); + goto Exit; + } + + /* formats 1, 2, 3 require the position of the start of this subtable */ + if ( format == 0 ) + gxv_kern_subtable_fmt0_validate( table, table + length, valid ); + else if ( format == 1 ) + gxv_kern_subtable_fmt1_validate( table, table + length, valid ); + else if ( format == 2 ) + gxv_kern_subtable_fmt2_validate( table, table + length, valid ); + else if ( format == 3 ) + gxv_kern_subtable_fmt3_validate( table, table + length, valid ); + else + FT_INVALID_DATA; + + Exit: + valid->subtable_length = length; + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** kern TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_kern_validate_generic( FT_Bytes table, + FT_Face face, + FT_Bool classic_only, + GXV_kern_Dialect dialect_request, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + + GXV_kern_DataRec kernrec; + GXV_kern_Data kern = &kernrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong nTables = 0; + FT_UInt i; + + + valid->root = ftvalid; + valid->table_data = kern; + valid->face = face; + + FT_TRACE3(( "validating `kern' table\n" )); + GXV_INIT; + KERN_DIALECT( valid ) = dialect_request; + + GXV_LIMIT_CHECK( 2 ); + GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p ); + GXV_TRACE(( "version 0x%04x (higher 16bit)\n", + GXV_KERN_DATA( version ) )); + + if ( 0x0001 < GXV_KERN_DATA( version ) ) + FT_INVALID_FORMAT; + else if ( KERN_IS_CLASSIC( valid ) ) + { + GXV_LIMIT_CHECK( 2 ); + nTables = FT_NEXT_USHORT( p ); + } + else if ( KERN_IS_NEW( valid ) ) + { + if ( classic_only ) + FT_INVALID_FORMAT; + + if ( 0x0000 != FT_NEXT_USHORT( p ) ) + FT_INVALID_FORMAT; + + GXV_LIMIT_CHECK( 4 ); + nTables = FT_NEXT_ULONG( p ); + } + + for ( i = 0; i < nTables; i++ ) + { + GXV_TRACE(( "validating subtable %d/%d\n", i, nTables )); + /* p should be 32bit-aligned? */ + gxv_kern_subtable_validate( p, 0, valid ); + p += valid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator ftvalid ) + { + GXV_kern_Dialect dialect_request; + + + dialect_request = (GXV_kern_Dialect)dialect_flags; + gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid ); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvlcar.c b/src/freetype2/gxvalid/gxvlcar.c new file mode 100644 index 0000000..48821ea --- /dev/null +++ b/src/freetype2/gxvalid/gxvlcar.c @@ -0,0 +1,223 @@ +/***************************************************************************/ +/* */ +/* gxvlcar.c */ +/* */ +/* TrueTypeGX/AAT lcar table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.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_gxvlcar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_lcar_DataRec_ + { + FT_UShort format; + + } GXV_lcar_DataRec, *GXV_lcar_Data; + + +#define GXV_LCAR_DATA( FIELD ) GXV_TABLE_DATA( lcar, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_lcar_partial_validate( FT_UShort partial, + FT_UShort glyph, + GXV_Validator valid ) + { + GXV_NAME_ENTER( "partial" ); + + if ( GXV_LCAR_DATA( format ) != 1 ) + goto Exit; + + gxv_ctlPoint_validate( glyph, partial, valid ); + + Exit: + GXV_EXIT; + } + + + static void + gxv_lcar_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_Bytes p = valid->root->base + value.u; + FT_Bytes limit = valid->root->limit; + FT_UShort count; + FT_Short partial; + FT_UShort i; + + + GXV_NAME_ENTER( "element in lookupTable" ); + + GXV_LIMIT_CHECK( 2 ); + count = FT_NEXT_USHORT( p ); + + GXV_LIMIT_CHECK( 2 * count ); + for ( i = 0; i < count; i++ ) + { + partial = FT_NEXT_SHORT( p ); + gxv_lcar_partial_validate( partial, glyph, valid ); + } + + GXV_EXIT; + } + + + /* + +------ lcar --------------------+ + | | + | +===============+ | + | | looup header | | + | +===============+ | + | | BinSrchHeader | | + | +===============+ | + | | lastGlyph[0] | | + | +---------------+ | + | | firstGlyph[0] | | head of lcar sfnt table + | +---------------+ | + + | | offset[0] | -> | offset [byte] + | +===============+ | + + | | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + | +---------------+ | + | | firstGlyph[1] | | + | +---------------+ | + | | offset[1] | | + | +===============+ | + | | + | .... | + | | + | 16bit value array | + | +===============+ | + +------| value | <-------+ + | .... + | + | + | + | + | + +----> lcar values...handled by lcar callback function + */ + + static GXV_LookupValueDesc + gxv_lcar_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + + /* XXX: check range? */ + offset = (FT_UShort)( base_value.u + + relative_gindex * sizeof ( FT_UShort ) ); + p = valid->root->base + offset; + limit = valid->root->limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** lcar TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + + GXV_lcar_DataRec lcarrec; + GXV_lcar_Data lcar = &lcarrec; + + FT_Fixed version; + + + valid->root = ftvalid; + valid->table_data = lcar; + valid->face = face; + + FT_TRACE3(( "validating `lcar' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_ULONG( p ); + GXV_LCAR_DATA( format ) = FT_NEXT_USHORT( p ); + + if ( version != 0x00010000UL) + FT_INVALID_FORMAT; + + if ( GXV_LCAR_DATA( format ) > 1 ) + FT_INVALID_FORMAT; + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_lcar_LookupValue_validate; + valid->lookupfmt4_trans = gxv_lcar_LookupFmt4_transit; + gxv_LookupTable_validate( p, limit, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmod.c b/src/freetype2/gxvalid/gxvmod.c new file mode 100644 index 0000000..b2b16b1 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmod.c @@ -0,0 +1,285 @@ +/***************************************************************************/ +/* */ +/* gxvmod.c */ +/* */ +/* FreeType's TrueTypeGX/AAT validation module implementation (body). */ +/* */ +/* Copyright 2004, 2005, 2006 */ +/* by suzuki toshiya, Masatake YAMATO, Red Hat 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_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H +#include FT_GX_VALIDATE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_GX_VALIDATE_H + +#include "gxvmod.h" +#include "gxvalid.h" +#include "gxvcommn.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_gxvmodule + + + static FT_Error + gxv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( error == GXV_Err_Table_Missing ) + return GXV_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_ALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + +#define GXV_TABLE_DECL( _sfnt ) \ + FT_Byte* volatile _sfnt = NULL; \ + FT_ULong len_ ## _sfnt = 0 + +#define GXV_TABLE_LOAD( _sfnt ) \ + if ( ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) && \ + ( gx_flags & FT_VALIDATE_ ## _sfnt ) ) \ + { \ + error = gxv_load_table( face, TTAG_ ## _sfnt, \ + &_sfnt, &len_ ## _sfnt ); \ + if ( error ) \ + goto Exit; \ + } + +#define GXV_TABLE_VALIDATE( _sfnt ) \ + if ( _sfnt ) \ + { \ + ft_validator_init( &valid, _sfnt, _sfnt + len_ ## _sfnt, \ + FT_VALIDATE_DEFAULT ); \ + if ( ft_setjmp( valid.jump_buffer ) == 0 ) \ + gxv_ ## _sfnt ## _validate( _sfnt, face, &valid ); \ + error = valid.error; \ + if ( error ) \ + goto Exit; \ + } + +#define GXV_TABLE_SET( _sfnt ) \ + if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) \ + tables[FT_VALIDATE_ ## _sfnt ## _INDEX] = (FT_Bytes)_sfnt + + + static FT_Error + gxv_validate( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_count ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Error error = GXV_Err_Ok; + FT_ValidatorRec volatile valid; + + FT_UInt i; + + + GXV_TABLE_DECL( feat ); + GXV_TABLE_DECL( bsln ); + GXV_TABLE_DECL( trak ); + GXV_TABLE_DECL( just ); + GXV_TABLE_DECL( mort ); + GXV_TABLE_DECL( morx ); + GXV_TABLE_DECL( kern ); + GXV_TABLE_DECL( opbd ); + GXV_TABLE_DECL( prop ); + GXV_TABLE_DECL( lcar ); + + for ( i = 0; i < table_count; i++ ) + tables[i] = 0; + + /* load tables */ + GXV_TABLE_LOAD( feat ); + GXV_TABLE_LOAD( bsln ); + GXV_TABLE_LOAD( trak ); + GXV_TABLE_LOAD( just ); + GXV_TABLE_LOAD( mort ); + GXV_TABLE_LOAD( morx ); + GXV_TABLE_LOAD( kern ); + GXV_TABLE_LOAD( opbd ); + GXV_TABLE_LOAD( prop ); + GXV_TABLE_LOAD( lcar ); + + /* validate tables */ + GXV_TABLE_VALIDATE( feat ); + GXV_TABLE_VALIDATE( bsln ); + GXV_TABLE_VALIDATE( trak ); + GXV_TABLE_VALIDATE( just ); + GXV_TABLE_VALIDATE( mort ); + GXV_TABLE_VALIDATE( morx ); + GXV_TABLE_VALIDATE( kern ); + GXV_TABLE_VALIDATE( opbd ); + GXV_TABLE_VALIDATE( prop ); + GXV_TABLE_VALIDATE( lcar ); + + /* Set results */ + GXV_TABLE_SET( feat ); + GXV_TABLE_SET( mort ); + GXV_TABLE_SET( morx ); + GXV_TABLE_SET( bsln ); + GXV_TABLE_SET( just ); + GXV_TABLE_SET( kern ); + GXV_TABLE_SET( opbd ); + GXV_TABLE_SET( trak ); + GXV_TABLE_SET( prop ); + GXV_TABLE_SET( lcar ); + + Exit: + if ( error ) + { + FT_FREE( feat ); + FT_FREE( bsln ); + FT_FREE( trak ); + FT_FREE( just ); + FT_FREE( mort ); + FT_FREE( morx ); + FT_FREE( kern ); + FT_FREE( opbd ); + FT_FREE( prop ); + FT_FREE( lcar ); + } + + return error; + } + + + static FT_Error + classic_kern_validate( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes* ckern_table ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Byte* volatile ckern = NULL; + FT_ULong len_ckern = 0; + + /* without volatile on `error' GCC 4.1.1. emits: */ + /* warning: variable 'error' might be clobbered by 'longjmp' or 'vfork' */ + /* this warning seems spurious but --- */ + FT_Error volatile error = GXV_Err_Ok; + FT_ValidatorRec volatile valid; + + + *ckern_table = NULL; + + error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern ); + if ( error ) + goto Exit; + + if ( ckern ) + { + ft_validator_init( &valid, ckern, ckern + len_ckern, + FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + gxv_kern_validate_classic( ckern, face, + ckern_flags & FT_VALIDATE_CKERN, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ckern_table = ckern; + + Exit: + if ( error ) + FT_FREE( ckern ); + + return error; + } + + + static + const FT_Service_GXvalidateRec gxvalid_interface = + { + gxv_validate + }; + + + static + const FT_Service_CKERNvalidateRec ckernvalid_interface = + { + classic_kern_validate + }; + + + static + const FT_ServiceDescRec gxvalid_services[] = + { + { FT_SERVICE_ID_GX_VALIDATE, &gxvalid_interface }, + { FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + gxvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( gxvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class gxv_module_class = + { + 0, + sizeof( FT_ModuleRec ), + "gxvalid", + 0x10000L, + 0x20000L, + + 0, /* module-specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) gxvalid_get_service + }; + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmod.h b/src/freetype2/gxvalid/gxvmod.h new file mode 100644 index 0000000..466584e --- /dev/null +++ b/src/freetype2/gxvalid/gxvmod.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* gxvmod.h */ +/* */ +/* FreeType's TrueTypeGX/AAT validation module implementation */ +/* (specification). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __GXVMOD_H__ +#define __GXVMOD_H__ + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) gxv_module_class; + + +FT_END_HEADER + +#endif /* __GXVMOD_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort.c b/src/freetype2/gxvalid/gxvmort.c new file mode 100644 index 0000000..6fb71b9 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort.c @@ -0,0 +1,285 @@ +/***************************************************************************/ +/* */ +/* gxvmort.c */ +/* */ +/* TrueTypeGX/AAT mort table validation (body). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.h" +#include "gxvfeat.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_gxvmort + + + static void + gxv_mort_feature_validate( GXV_mort_feature f, + GXV_Validator valid ) + { + if ( f->featureType > gxv_feat_registry_length ) + { + GXV_TRACE(( "featureType %d is out of registered range, " + "setting %d is unchecked\n", + f->featureType, f->featureSetting )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + else if ( !gxv_feat_registry[f->featureType].existence ) + { + GXV_TRACE(( "featureType %d is within registered area " + "but undefined, setting %d is unchecked\n", + f->featureType, f->featureSetting )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + else + { + FT_Byte nSettings_max; + + + /* nSettings in gxvfeat.c is halved for exclusive on/off settings */ + nSettings_max = gxv_feat_registry[f->featureType].nSettings; + if ( gxv_feat_registry[f->featureType].exclusive ) + nSettings_max = (FT_Byte)( 2 * nSettings_max ); + + GXV_TRACE(( "featureType %d is registered", f->featureType )); + GXV_TRACE(( "setting %d", f->featureSetting )); + + if ( f->featureSetting > nSettings_max ) + { + GXV_TRACE(( "out of defined range %d", nSettings_max )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + GXV_TRACE(( "\n" )); + } + + /* TODO: enableFlags must be unique value in specified chain? */ + } + + + /* + * nFeatureFlags is typed to FT_UInt to accept that in + * mort (typed FT_UShort) and morx (typed FT_ULong). + */ + FT_LOCAL_DEF( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_UInt nFeatureFlags, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt i; + + GXV_mort_featureRec f = GXV_MORT_FEATURE_OFF; + + + GXV_NAME_ENTER( "mort feature list" ); + for ( i = 0; i < nFeatureFlags; i++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 ); + f.featureType = FT_NEXT_USHORT( p ); + f.featureSetting = FT_NEXT_USHORT( p ); + f.enableFlags = FT_NEXT_ULONG( p ); + f.disableFlags = FT_NEXT_ULONG( p ); + + gxv_mort_feature_validate( &f, valid ); + } + + if ( !IS_GXV_MORT_FEATURE_OFF( f ) ) + FT_INVALID_DATA; + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator valid ) + { + FT_UNUSED( valid ); + + if ( coverage & 0x8000U ) + GXV_TRACE(( " this subtable is for vertical text only\n" )); + else + GXV_TRACE(( " this subtable is for horizontal text only\n" )); + + if ( coverage & 0x4000 ) + GXV_TRACE(( " this subtable is applied to glyph array " + "in descending order\n" )); + else + GXV_TRACE(( " this subtable is applied to glyph array " + "in ascending order\n" )); + + if ( coverage & 0x2000 ) + GXV_TRACE(( " this subtable is forcibly applied to " + "vertical/horizontal text\n" )); + + if ( coverage & 0x1FF8 ) + GXV_TRACE(( " coverage has non-zero bits in reserved area\n" )); + } + + + static void + gxv_mort_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_mort_subtable_type0_validate, /* 0 */ + gxv_mort_subtable_type1_validate, /* 1 */ + gxv_mort_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_mort_subtable_type4_validate, /* 4 */ + gxv_mort_subtable_type5_validate, /* 5 */ + + }; + + GXV_Validate_Func func; + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + FT_UShort length; + FT_UShort coverage; + FT_ULong subFeatureFlags; + FT_UInt type; + FT_UInt rest; + + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + subFeatureFlags = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", + i + 1, nSubtables, length )); + type = coverage & 0x0007; + rest = length - ( 2 + 2 + 4 ); + + GXV_LIMIT_CHECK( rest ); + gxv_mort_coverage_validate( coverage, valid ); + + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( func == NULL ) + GXV_TRACE(( "morx type %d is reserved\n", type )); + + func( p, p + rest, valid ); + + p += rest; + } + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static void + gxv_mort_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong defaultFlags; + FT_ULong chainLength; + FT_UShort nFeatureFlags; + FT_UShort nSubtables; + + + GXV_NAME_ENTER( "mort chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); + defaultFlags = FT_NEXT_ULONG( p ); + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_USHORT( p ); + nSubtables = FT_NEXT_USHORT( p ); + + gxv_mort_featurearray_validate( p, table + chainLength, + nFeatureFlags, valid ); + p += valid->subtable_length; + gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid ); + valid->subtable_length = chainLength; + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + valid->root = ftvalid; + valid->face = face; + limit = valid->root->limit; + + FT_TRACE3(( "validating `mort' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if (version != 0x00010000UL) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_mort_chain_validate( p, limit, valid ); + p += valid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort.h b/src/freetype2/gxvalid/gxvmort.h new file mode 100644 index 0000000..1d64e69 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort.h @@ -0,0 +1,93 @@ +/***************************************************************************/ +/* */ +/* gxvmort.h */ +/* */ +/* TrueTypeGX/AAT common definition for mort table (specification). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __GXVMORT_H__ +#define __GXVMORT_H__ + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include FT_SFNT_NAMES_H + + + typedef struct GXV_mort_featureRec_ + { + FT_UShort featureType; + FT_UShort featureSetting; + FT_ULong enableFlags; + FT_ULong disableFlags; + + } GXV_mort_featureRec, *GXV_mort_feature; + +#define GXV_MORT_FEATURE_OFF {0, 1, 0x00000000UL, 0x00000000UL} + +#define IS_GXV_MORT_FEATURE_OFF( f ) \ + ( (f).featureType == 0 || \ + (f).featureSetting == 1 || \ + (f).enableFlags == 0x00000000UL || \ + (f).disableFlags == 0x00000000UL ) + + + FT_LOCAL( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_UInt nFeatureFlags, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + +#endif /* __GXVMORT_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort0.c b/src/freetype2/gxvalid/gxvmort0.c new file mode 100644 index 0000000..0902056 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort0.c @@ -0,0 +1,137 @@ +/***************************************************************************/ +/* */ +/* gxvmort0.c */ +/* */ +/* TrueTypeGX/AAT mort table validation */ +/* body for type0 (Indic Script Rearrangement) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.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_gxvmort + + + static const char* GXV_Mort_IndicScript_Msg[] = + { + "no change", + "Ax => xA", + "xD => Dx", + "AxD => DxA", + "ABx => xAB", + "ABx => xBA", + "xCD => CDx", + "xCD => DCx", + "AxCD => CDxA", + "AxCD => DCxA", + "ABxD => DxAB", + "ABxD => DxBA", + "ABxCD => CDxAB", + "ABxCD => CDxBA", + "ABxCD => DCxAB", + "ABxCD => DCxBA", + + }; + + + static void + gxv_mort_subtable_type0_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; + FT_UShort reserved; + FT_UShort verb = 0; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + FT_UNUSED( GXV_Mort_IndicScript_Msg[verb] ); /* for the non-debugging */ + FT_UNUSED( glyphOffset ); /* case */ + + + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x1FF0 ); + verb = (FT_UShort)( flags & 0x000F ); + + GXV_TRACE(( " IndicScript MorphRule for glyphOffset 0x%04x", + glyphOffset.u )); + GXV_TRACE(( " markFirst=%01d", markFirst )); + GXV_TRACE(( " dontAdvance=%01d", dontAdvance )); + GXV_TRACE(( " markLast=%01d", markLast )); + GXV_TRACE(( " %02d", verb )); + GXV_TRACE(( " %s\n", GXV_Mort_IndicScript_Msg[verb] )); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + FT_INVALID_DATA; + } + else + GXV_TRACE(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "mort chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + valid->statetable.optdata = NULL; + valid->statetable.optdata_load_func = NULL; + valid->statetable.subtable_setup_func = NULL; + valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + valid->statetable.entry_validate_func = + gxv_mort_subtable_type0_entry_validate; + + gxv_StateTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort1.c b/src/freetype2/gxvalid/gxvmort1.c new file mode 100644 index 0000000..0575b12 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort1.c @@ -0,0 +1,258 @@ +/***************************************************************************/ +/* */ +/* gxvmort1.c */ +/* */ +/* TrueTypeGX/AAT mort table validation */ +/* body for type1 (Contextual Substitution) subtable. */ +/* */ +/* Copyright 2005, 2007 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.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_gxvmort + + + typedef struct GXV_mort_subtable_type1_StateOptRec_ + { + FT_UShort substitutionTable; + FT_UShort substitutionTable_length; + + } GXV_mort_subtable_type1_StateOptRec, + *GXV_mort_subtable_type1_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_mort_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)valid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_mort_subtable_type1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)valid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &( optdata->substitutionTable_length ); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid ); + } + + + static void + gxv_mort_subtable_type1_offset_to_subst_validate( + FT_Short wordOffset, + const FT_String* tag, + FT_Byte state, + GXV_Validator valid ) + { + FT_UShort substTable; + FT_UShort substTable_limit; + FT_UShort min_gid; + FT_UShort max_gid; + + FT_UNUSED( tag ); + FT_UNUSED( state ); + + + substTable = + ((GXV_mort_subtable_type1_StateOptRec *) + (valid->statetable.optdata))->substitutionTable; + substTable_limit = + (FT_UShort)( substTable + + ((GXV_mort_subtable_type1_StateOptRec *) + (valid->statetable.optdata))->substitutionTable_length ); + + min_gid = (FT_UShort)( ( substTable - wordOffset * 2 ) / 2 ); + max_gid = (FT_UShort)( ( substTable_limit - wordOffset * 2 ) / 2 ); + max_gid = (FT_UShort)( FT_MAX( max_gid, valid->face->num_glyphs ) ); + + /* XXX: check range? */ + + /* TODO: min_gid & max_gid comparison with ClassTable contents */ + } + + + static void + gxv_mort_subtable_type1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort setMark; + FT_UShort dontAdvance; + FT_UShort reserved; + FT_Short markOffset; + FT_Short currentOffset; + + FT_UNUSED( table ); + FT_UNUSED( limit ); + + + setMark = (FT_UShort)( flags >> 15 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + reserved = (FT_Short)( flags & 0x3FFF ); + + markOffset = (FT_Short)( glyphOffset.ul >> 16 ); + currentOffset = (FT_Short)( glyphOffset.ul ); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + + gxv_mort_subtable_type1_offset_to_subst_validate( markOffset, + "markOffset", + state, + valid ); + + gxv_mort_subtable_type1_offset_to_subst_validate( currentOffset, + "currentOffset", + state, + valid ); + } + + + static void + gxv_mort_subtable_type1_substTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort num_gids = (FT_UShort)( + ((GXV_mort_subtable_type1_StateOptRec *) + (valid->statetable.optdata))->substitutionTable_length / 2 ); + FT_UShort i; + + + GXV_NAME_ENTER( "validating contents of substitutionTable" ); + for ( i = 0; i < num_gids ; i ++ ) + { + FT_UShort dst_gid; + + + GXV_LIMIT_CHECK( 2 ); + dst_gid = FT_NEXT_USHORT( p ); + + if ( dst_gid >= 0xFFFFU ) + continue; + + if ( dst_gid > valid->face->num_glyphs ) + { + GXV_TRACE(( "substTable include toolarge gid[%d]=%d >" + " max defined gid #%d\n", + i, dst_gid, valid->face->num_glyphs )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_GLYPH_ID; + } + } + + GXV_EXIT; + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, and entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "mort chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE ); + + valid->statetable.optdata = + &st_rec; + valid->statetable.optdata_load_func = + gxv_mort_subtable_type1_substitutionTable_load; + valid->statetable.subtable_setup_func = + gxv_mort_subtable_type1_subtable_setup; + valid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + valid->statetable.entry_validate_func = + + gxv_mort_subtable_type1_entry_validate; + gxv_StateTable_validate( p, limit, valid ); + + gxv_mort_subtable_type1_substTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort2.c b/src/freetype2/gxvalid/gxvmort2.c new file mode 100644 index 0000000..f19d15d --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort2.c @@ -0,0 +1,282 @@ +/***************************************************************************/ +/* */ +/* gxvmort2.c */ +/* */ +/* TrueTypeGX/AAT mort table validation */ +/* body for type2 (Ligature Substitution) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.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_gxvmort + + + typedef struct GXV_mort_subtable_type2_StateOptRec_ + { + FT_UShort ligActionTable; + FT_UShort componentTable; + FT_UShort ligatureTable; + FT_UShort ligActionTable_length; + FT_UShort componentTable_length; + FT_UShort ligatureTable_length; + + } GXV_mort_subtable_type2_StateOptRec, + *GXV_mort_subtable_type2_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 ) + + + static void + gxv_mort_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + optdata->ligActionTable = FT_NEXT_USHORT( p ); + optdata->componentTable = FT_NEXT_USHORT( p ); + optdata->ligatureTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%04x\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%04x\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%04x\n", + optdata->ligatureTable )); + } + + + static void + gxv_mort_subtable_type2_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort *classTable_length_p, + FT_UShort *stateArray_length_p, + FT_UShort *entryTable_length_p, + GXV_Validator valid ) + { + FT_UShort o[6]; + FT_UShort *l[6]; + FT_UShort buff[7]; + + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, valid ); + + GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%04x length=0x%04x\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + + static void + gxv_mort_subtable_type2_ligActionOffset_validate( + FT_Bytes table, + FT_UShort ligActionOffset, + GXV_Validator valid ) + { + /* access ligActionTable */ + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = table + ligActionOffset; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset ); + if ( p < lat_base ) + { + GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n", + ligActionOffset, lat_base - p )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n", + ligActionOffset, p - lat_limit )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_OFFSET; + } + else + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; + FT_UShort last; + FT_UShort store; + FT_ULong offset; + + + lig_action = FT_NEXT_ULONG( p ); + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); + + offset = lig_action & 0x3FFFFFFFUL; + } + } + + + static void + gxv_mort_subtable_type2_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort setComponent; + FT_UShort dontAdvance; + FT_UShort offset; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset ); + FT_UNUSED( limit ); + + + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + + offset = (FT_UShort)( flags & 0x3FFFU ); + + if ( 0 < offset ) + gxv_mort_subtable_type2_ligActionOffset_validate( table, offset, + valid ); + } + + + static void + gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator valid ) + { + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" ); + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + } + } + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE ); + + valid->statetable.optdata = + &lig_rec; + valid->statetable.optdata_load_func = + gxv_mort_subtable_type2_opttable_load; + valid->statetable.subtable_setup_func = + gxv_mort_subtable_type2_subtable_setup; + valid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + valid->statetable.entry_validate_func = + gxv_mort_subtable_type2_entry_validate; + + gxv_StateTable_validate( p, limit, valid ); + + p += valid->subtable_length; + gxv_mort_subtable_type2_ligatureTable_validate( table, valid ); + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort4.c b/src/freetype2/gxvalid/gxvmort4.c new file mode 100644 index 0000000..a04bc1e --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort4.c @@ -0,0 +1,125 @@ +/***************************************************************************/ +/* */ +/* gxvmort4.c */ +/* */ +/* TrueTypeGX/AAT mort table validation */ +/* body for type4 (Non-Contextual Glyph Substitution) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.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_gxvmort + + + static void + gxv_mort_subtable_type4_lookupval_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UNUSED( glyph ); + + gxv_glyphid_validate( value.u, valid ); + } + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + + static GXV_LookupValueDesc + gxv_mort_subtable_type4_lookupfmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value.u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = valid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "mort chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_mort_subtable_type4_lookupval_validate; + valid->lookupfmt4_trans = gxv_mort_subtable_type4_lookupfmt4_transit; + + gxv_LookupTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmort5.c b/src/freetype2/gxvalid/gxvmort5.c new file mode 100644 index 0000000..a7cabc3 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmort5.c @@ -0,0 +1,226 @@ +/***************************************************************************/ +/* */ +/* gxvmort5.c */ +/* */ +/* TrueTypeGX/AAT mort table validation */ +/* body for type5 (Contextual Glyph Insertion) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmort.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_gxvmort + + + /* + * mort subtable type5 (Contextual Glyph Insertion) + * has the format of StateTable with insertion-glyph-list, + * but without name. The offset is given by glyphOffset in + * entryTable. There is no table location declaration + * like xxxTable. + */ + + typedef struct GXV_mort_subtable_type5_StateOptRec_ + { + FT_UShort classTable; + FT_UShort stateArray; + FT_UShort entryTable; + +#define GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE GXV_STATETABLE_HEADER_SIZE + + FT_UShort* classTable_length_p; + FT_UShort* stateArray_length_p; + FT_UShort* entryTable_length_p; + + } GXV_mort_subtable_type5_StateOptRec, + *GXV_mort_subtable_type5_StateOptRecData; + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type5_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator valid ) + { + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)valid->statetable.optdata; + + + gxv_StateTable_subtable_setup( table_size, + classTable, + stateArray, + entryTable, + classTable_length_p, + stateArray_length_p, + entryTable_length_p, + valid ); + + optdata->classTable = classTable; + optdata->stateArray = stateArray; + optdata->entryTable = entryTable; + + optdata->classTable_length_p = classTable_length_p; + optdata->stateArray_length_p = stateArray_length_p; + optdata->entryTable_length_p = entryTable_length_p; + } + + + static void + gxv_mort_subtable_type5_InsertList_validate( FT_UShort offset, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + /* + * We don't know the range of insertion-glyph-list. + * Set range by whole of state table. + */ + FT_Bytes p = table + offset; + + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)valid->statetable.optdata; + + if ( optdata->classTable < offset && + offset < optdata->classTable + *(optdata->classTable_length_p) ) + GXV_TRACE(( " offset runs into ClassTable" )); + if ( optdata->stateArray < offset && + offset < optdata->stateArray + *(optdata->stateArray_length_p) ) + GXV_TRACE(( " offset runs into StateArray" )); + if ( optdata->entryTable < offset && + offset < optdata->entryTable + *(optdata->entryTable_length_p) ) + GXV_TRACE(( " offset runs into EntryTable" )); + + while ( p < table + offset + ( count * 2 ) ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + + GXV_TRACE(( "\n" )); + } + + + static void + gxv_mort_subtable_type5_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_UShort currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_UShort)( glyphOffset.ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset.ul ); + + if ( 0 != currentInsertList && 0 != currentInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, + limit, + valid ); + } + + if ( 0 != markedInsertList && 0 != markedInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, + limit, + valid ); + } + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type5_StateOptRec et_rec; + GXV_mort_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "mort chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE ); + + valid->statetable.optdata = + et; + valid->statetable.optdata_load_func = + NULL; + valid->statetable.subtable_setup_func = + gxv_mort_subtable_type5_subtable_setup; + valid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + valid->statetable.entry_validate_func = + gxv_mort_subtable_type5_entry_validate; + + gxv_StateTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx.c b/src/freetype2/gxvalid/gxvmorx.c new file mode 100644 index 0000000..849d5e9 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx.c @@ -0,0 +1,183 @@ +/***************************************************************************/ +/* */ +/* gxvmorx.c */ +/* */ +/* TrueTypeGX/AAT morx table validation (body). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + static void + gxv_morx_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_morx_subtable_type0_validate, /* 0 */ + gxv_morx_subtable_type1_validate, /* 1 */ + gxv_morx_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_morx_subtable_type4_validate, /* 4 */ + gxv_morx_subtable_type5_validate, /* 5 */ + + }; + + GXV_Validate_Func func; + + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + FT_ULong length; + FT_ULong coverage; + FT_ULong subFeatureFlags; + FT_UInt type; + FT_UInt rest; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + length = FT_NEXT_ULONG( p ); + coverage = FT_NEXT_ULONG( p ); + subFeatureFlags = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", + i + 1, nSubtables, length )); + + type = coverage & 0x0007; + rest = length - ( 4 + 4 + 4 ); + GXV_LIMIT_CHECK( rest ); + + /* morx coverage consists of mort_coverage & 16bit padding */ + gxv_mort_coverage_validate( (FT_UShort)( ( coverage >> 16 ) | coverage ), + valid ); + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( func == NULL ) + GXV_TRACE(( "morx type %d is reserved\n", type )); + + func( p, p + rest, valid ); + + p += rest; + } + + valid->subtable_length = p - table; + + GXV_EXIT; + } + + + static void + gxv_morx_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_ULong defaultFlags; + FT_ULong chainLength; + FT_ULong nFeatureFlags; + FT_ULong nSubtables; + + + GXV_NAME_ENTER( "morx chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + defaultFlags = FT_NEXT_ULONG( p ); + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_ULONG( p ); + nSubtables = FT_NEXT_ULONG( p ); + + /* feature-array of morx is same with that of mort */ + gxv_mort_featurearray_validate( p, limit, nFeatureFlags, valid ); + p += valid->subtable_length; + + if ( nSubtables >= 0x10000 ) + FT_INVALID_DATA; + + gxv_morx_subtables_validate( p, table + chainLength, + (FT_UShort)nSubtables, valid ); + + valid->subtable_length = chainLength; + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + valid->root = ftvalid; + valid->face = face; + + FT_TRACE3(( "validating `morx' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if ( version != 0x00020000UL ) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_morx_chain_validate( p, limit, valid ); + p += valid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx.h b/src/freetype2/gxvalid/gxvmorx.h new file mode 100644 index 0000000..28c1a44 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx.h @@ -0,0 +1,67 @@ +/***************************************************************************/ +/* */ +/* gxvmorx.h */ +/* */ +/* TrueTypeGX/AAT common definition for morx table (specification). */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __GXVMORX_H__ +#define __GXVMORX_H__ + + +#include "gxvalid.h" +#include "gxvcommn.h" +#include "gxvmort.h" + +#include FT_SFNT_NAMES_H + + + FT_LOCAL( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ); + + +#endif /* __GXVMORX_H__ */ + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx0.c b/src/freetype2/gxvalid/gxvmorx0.c new file mode 100644 index 0000000..ca92b6c --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx0.c @@ -0,0 +1,103 @@ +/***************************************************************************/ +/* */ +/* gxvmorx0.c */ +/* */ +/* TrueTypeGX/AAT morx table validation */ +/* body for type0 (Indic Script Rearrangement) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + static void + gxv_morx_subtable_type0_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_XStateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; + FT_UShort reserved; + FT_UShort verb; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x1FF0 ); + verb = (FT_UShort)( flags & 0x000F ); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + FT_INVALID_DATA; + } + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "morx chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + valid->xstatetable.optdata = NULL; + valid->xstatetable.optdata_load_func = NULL; + valid->xstatetable.subtable_setup_func = NULL; + valid->xstatetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + valid->xstatetable.entry_validate_func = + gxv_morx_subtable_type0_entry_validate; + + gxv_XStateTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx1.c b/src/freetype2/gxvalid/gxvmorx1.c new file mode 100644 index 0000000..331d4cc --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx1.c @@ -0,0 +1,274 @@ +/***************************************************************************/ +/* */ +/* gxvmorx1.c */ +/* */ +/* TrueTypeGX/AAT morx table validation */ +/* body for type1 (Contextual Substitution) subtable. */ +/* */ +/* Copyright 2005, 2007 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + typedef struct GXV_morx_subtable_type1_StateOptRec_ + { + FT_ULong substitutionTable; + FT_ULong substitutionTable_length; + FT_UShort substitutionTable_num_lookupTables; + + } GXV_morx_subtable_type1_StateOptRec, + *GXV_morx_subtable_type1_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_morx_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_morx_subtable_type1_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ) + { + FT_ULong o[4]; + FT_ULong *l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->substitutionTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid ); + } + + + static void + gxv_morx_subtable_type1_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort setMark; + FT_UShort dontAdvance; + FT_UShort reserved; + FT_Short markIndex; + FT_Short currentIndex; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x3FFF ); + + markIndex = (FT_Short)( glyphOffset.ul >> 16 ); + currentIndex = (FT_Short)( glyphOffset.ul ); + + GXV_TRACE(( " setMark=%01d dontAdvance=%01d\n", + setMark, dontAdvance )); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + if ( valid->root->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + } + + GXV_TRACE(( "markIndex = %d, currentIndex = %d\n", + markIndex, currentIndex )); + + if ( optdata->substitutionTable_num_lookupTables < markIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_Short)( markIndex + 1 ); + + if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_Short)( currentIndex + 1 ); + } + + + static void + gxv_morx_subtable_type1_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + FT_UNUSED( glyph ); /* for the non-debugging case */ + + GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value.u )); + + if ( value.u > valid->face->num_glyphs ) + FT_INVALID_GLYPH_ID; + } + + + static GXV_LookupValueDesc + gxv_morx_subtable_type1_LookupFmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value.u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = valid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /* + * TODO: length should be limit? + **/ + static void + gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata; + + + /* TODO: calculate offset/length for each lookupTables */ + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_morx_subtable_type1_LookupValue_validate; + valid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit; + + for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ ) + { + FT_ULong offset; + + + GXV_LIMIT_CHECK( 4 ); + offset = FT_NEXT_ULONG( p ); + + gxv_LookupTable_validate( table + offset, limit, valid ); + } + + /* TODO: overlapping of lookupTables in substitutionTable */ + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE ); + + st_rec.substitutionTable_num_lookupTables = 0; + + valid->xstatetable.optdata = + &st_rec; + valid->xstatetable.optdata_load_func = + gxv_morx_subtable_type1_substitutionTable_load; + valid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type1_subtable_setup; + valid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + valid->xstatetable.entry_validate_func = + gxv_morx_subtable_type1_entry_validate; + + gxv_XStateTable_validate( p, limit, valid ); + + gxv_morx_subtable_type1_substitutionTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx2.c b/src/freetype2/gxvalid/gxvmorx2.c new file mode 100644 index 0000000..5cad516 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx2.c @@ -0,0 +1,285 @@ +/***************************************************************************/ +/* */ +/* gxvmorx2.c */ +/* */ +/* TrueTypeGX/AAT morx table validation */ +/* body for type2 (Ligature Substitution) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + typedef struct GXV_morx_subtable_type2_StateOptRec_ + { + FT_ULong ligActionTable; + FT_ULong componentTable; + FT_ULong ligatureTable; + FT_ULong ligActionTable_length; + FT_ULong componentTable_length; + FT_ULong ligatureTable_length; + + } GXV_morx_subtable_type2_StateOptRec, + *GXV_morx_subtable_type2_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 ) + + + static void + gxv_morx_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + optdata->ligActionTable = FT_NEXT_ULONG( p ); + optdata->componentTable = FT_NEXT_ULONG( p ); + optdata->ligatureTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%08x\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%08x\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%08x\n", + optdata->ligatureTable )); + } + + + static void + gxv_morx_subtable_type2_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ) + { + FT_ULong o[6]; + FT_ULong* l[6]; + FT_ULong buff[7]; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, valid ); + + GXV_TRACE(( "classTable: offset=0x%08x length=0x%08x\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%08x length=0x%08x\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%08x length=0x%08x\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%08x length=0x%08x\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%08x length=0x%08x\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%08x length=0x%08x\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + +#define GXV_MORX_LIGACTION_ENTRY_SIZE 4 + + + static void + gxv_morx_subtable_type2_ligActionIndex_validate( + FT_Bytes table, + FT_UShort ligActionIndex, + GXV_Validator valid ) + { + /* access ligActionTable */ + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = lat_base + + ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + if ( p < lat_base ) + { + GXV_TRACE(( "p < lat_base (%d byte rewind)\n", lat_base - p )); + FT_INVALID_OFFSET; + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "lat_limit < p (%d byte overrun)\n", p - lat_limit )); + FT_INVALID_OFFSET; + } + + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; + FT_UShort last; + FT_UShort store; + FT_ULong offset; + + + lig_action = FT_NEXT_ULONG( p ); + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); + + offset = lig_action & 0x3FFFFFFFUL; + } + } + + + static void + gxv_morx_subtable_type2_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_UShort setComponent; + FT_UShort dontAdvance; + FT_UShort performAction; + FT_UShort reserved; + FT_UShort ligActionIndex; + + FT_UNUSED( state ); + FT_UNUSED( limit ); + + + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + performAction = (FT_UShort)( ( flags >> 13 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x1FFF ); + ligActionIndex = glyphOffset.u; + + if ( reserved > 0 ) + GXV_TRACE(( " reserved 14bit is non-zero\n" )); + + if ( 0 < ligActionIndex ) + gxv_morx_subtable_type2_ligActionIndex_validate( + table, ligActionIndex, valid ); + } + + + static void + gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator valid ) + { + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "morx chain subtable type2 - substitutionTable" ); + + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + } + } + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "morx chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE ); + + valid->xstatetable.optdata = + &lig_rec; + valid->xstatetable.optdata_load_func = + gxv_morx_subtable_type2_opttable_load; + valid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type2_subtable_setup; + valid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_USHORT; + valid->xstatetable.entry_validate_func = + gxv_morx_subtable_type2_entry_validate; + + gxv_XStateTable_validate( p, limit, valid ); + + p += valid->subtable_length; + gxv_morx_subtable_type2_ligatureTable_validate( table, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx4.c b/src/freetype2/gxvalid/gxvmorx4.c new file mode 100644 index 0000000..c0d2f78 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx4.c @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* gxvmorx4.c */ +/* */ +/* TrueTypeGX/AAT morx table validation */ +/* body for "morx" type4 (Non-Contextual Glyph Substitution) subtable. */ +/* */ +/* Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + GXV_NAME_ENTER( "morx chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + gxv_mort_subtable_type4_validate( table, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvmorx5.c b/src/freetype2/gxvalid/gxvmorx5.c new file mode 100644 index 0000000..d911561 --- /dev/null +++ b/src/freetype2/gxvalid/gxvmorx5.c @@ -0,0 +1,217 @@ +/***************************************************************************/ +/* */ +/* gxvmorx5.c */ +/* */ +/* TrueTypeGX/AAT morx table validation */ +/* body for type5 (Contextual Glyph Insertion) subtable. */ +/* */ +/* Copyright 2005, 2007 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvmorx.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_gxvmorx + + + /* + * `morx' subtable type5 (Contextual Glyph Insertion) + * has format of a StateTable with insertion-glyph-list + * without name. However, the 32bit offset from the head + * of subtable to the i-g-l is given after `entryTable', + * without variable name specification (the existence of + * this offset to the table is different from mort type5). + */ + + + typedef struct GXV_morx_subtable_type5_StateOptRec_ + { + FT_ULong insertionGlyphList; + FT_ULong insertionGlyphList_length; + + } GXV_morx_subtable_type5_StateOptRec, + *GXV_morx_subtable_type5_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 4 ) + + + static void + gxv_morx_subtable_type5_insertionGlyphList_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)valid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 ); + optdata->insertionGlyphList = FT_NEXT_ULONG( p ); + } + + + static void + gxv_morx_subtable_type5_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator valid ) + { + FT_ULong o[4]; + FT_ULong* l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)valid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->insertionGlyphList; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->insertionGlyphList_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid ); + } + + + static void + gxv_morx_subtable_type5_InsertList_validate( FT_UShort table_index, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table + table_index * 2; + + + while ( p < table + count * 2 + table_index * 2 ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + + GXV_TRACE(( "\n" )); + } + + + static void + gxv_morx_subtable_type5_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetDesc glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_Byte currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_Byte) ( glyphOffset.ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset.ul ); + + if ( currentInsertList && 0 != currentInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, limit, + valid ); + + if ( markedInsertList && 0 != markedInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, limit, + valid ); + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRec et_rec; + GXV_morx_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "morx chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE ); + + valid->xstatetable.optdata = + et; + valid->xstatetable.optdata_load_func = + gxv_morx_subtable_type5_insertionGlyphList_load; + valid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type5_subtable_setup; + valid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + valid->xstatetable.entry_validate_func = + gxv_morx_subtable_type5_entry_validate; + + gxv_XStateTable_validate( p, limit, valid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvopbd.c b/src/freetype2/gxvalid/gxvopbd.c new file mode 100644 index 0000000..8d6fe66 --- /dev/null +++ b/src/freetype2/gxvalid/gxvopbd.c @@ -0,0 +1,217 @@ +/***************************************************************************/ +/* */ +/* gxvopbd.c */ +/* */ +/* TrueTypeGX/AAT opbd table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.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_gxvopbd + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_opbd_DataRec_ + { + FT_UShort format; + FT_UShort valueOffset_min; + + } GXV_opbd_DataRec, *GXV_opbd_Data; + + +#define GXV_OPBD_DATA( FIELD ) GXV_TABLE_DATA( opbd, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_opbd_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + /* offset in LookupTable is measured from the head of opbd table */ + FT_Bytes p = valid->root->base + value.u; + FT_Bytes limit = valid->root->limit; + FT_Short delta_value; + int i; + + + if ( value.u < GXV_OPBD_DATA( valueOffset_min ) ) + GXV_OPBD_DATA( valueOffset_min ) = value.u; + + for ( i = 0; i < 4; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + delta_value = FT_NEXT_SHORT( p ); + + if ( GXV_OPBD_DATA( format ) ) /* format 1, value is ctrl pt. */ + { + if ( delta_value == -1 ) + continue; + + gxv_ctlPoint_validate( glyph, delta_value, valid ); + } + else /* format 0, value is distance */ + continue; + } + } + + + /* + opbd ---------------------+ + | + +===============+ | + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of opbd sfnt table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 4 * sizeof(FT_Short) [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 48bit value array | + +===============+ | + | value | <-------+ + | | + | | + | | + +---------------+ + .... */ + + static GXV_LookupValueDesc + gxv_opbd_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + FT_UNUSED( valid ); + + /* XXX: check range? */ + value.u = (FT_UShort)( base_value.u + + relative_gindex * 4 * sizeof ( FT_Short ) ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** opbd TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + GXV_opbd_DataRec opbdrec; + GXV_opbd_Data opbd = &opbdrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + + + valid->root = ftvalid; + valid->table_data = opbd; + valid->face = face; + + FT_TRACE3(( "validating `opbd' table\n" )); + GXV_INIT; + GXV_OPBD_DATA( valueOffset_min ) = 0xFFFFU; + + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_ULONG( p ); + GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p ); + + + /* only 0x00010000 is defined (1996) */ + GXV_TRACE(( "(version=0x%08x)\n", version )); + if ( 0x00010000UL != version ) + FT_INVALID_FORMAT; + + /* only values 0 and 1 are defined (1996) */ + GXV_TRACE(( "(format=0x%04x)\n", GXV_OPBD_DATA( format ) )); + if ( 0x0001 < GXV_OPBD_DATA( format ) ) + FT_INVALID_FORMAT; + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_opbd_LookupValue_validate; + valid->lookupfmt4_trans = gxv_opbd_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, valid ); + p += valid->subtable_length; + + if ( p > table + GXV_OPBD_DATA( valueOffset_min ) ) + { + GXV_TRACE(( + "found overlap between LookupTable and opbd_value array\n" )); + FT_INVALID_OFFSET; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvprop.c b/src/freetype2/gxvalid/gxvprop.c new file mode 100644 index 0000000..010eeda --- /dev/null +++ b/src/freetype2/gxvalid/gxvprop.c @@ -0,0 +1,301 @@ +/***************************************************************************/ +/* */ +/* gxvprop.c */ +/* */ +/* TrueTypeGX/AAT prop table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.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_gxvprop + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_PROP_HEADER_SIZE ( 4 + 2 + 2 ) +#define GXV_PROP_SIZE_MIN GXV_PROP_HEADER_SIZE + + typedef struct GXV_prop_DataRec_ + { + FT_Fixed version; + + } GXV_prop_DataRec, *GXV_prop_Data; + +#define GXV_PROP_DATA( field ) GXV_TABLE_DATA( prop, field ) + +#define GXV_PROP_FLOATER 0x8000U +#define GXV_PROP_USE_COMPLEMENTARY_BRACKET 0x1000U +#define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00U +#define GXV_PROP_ATTACHING_TO_RIGHT 0x0080U +#define GXV_PROP_RESERVED 0x0060U +#define GXV_PROP_DIRECTIONALITY_CLASS 0x001FU + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_prop_zero_advance_validate( FT_UShort gid, + GXV_Validator valid ) + { + FT_Face face; + FT_Error error; + FT_GlyphSlot glyph; + + + GXV_NAME_ENTER( "zero advance" ); + + face = valid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + + if ( glyph->advance.x != (FT_Pos)0 || + glyph->advance.y != (FT_Pos)0 ) + FT_INVALID_DATA; + + GXV_EXIT; + } + + + /* Pass 0 as GLYPH to check the default property */ + static void + gxv_prop_property_validate( FT_UShort property, + FT_UShort glyph, + GXV_Validator valid ) + { + if ( glyph != 0 && ( property & GXV_PROP_FLOATER ) ) + gxv_prop_zero_advance_validate( glyph, valid ); + + if ( property & GXV_PROP_USE_COMPLEMENTARY_BRACKET ) + { + FT_UShort offset; + char complement; + + + offset = (FT_UShort)( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ); + if ( offset == 0 ) + FT_INVALID_DATA; + + complement = (char)( offset >> 8 ); + if ( complement & 0x08 ) + { + /* Top bit is set: negative */ + + /* Calculate the absolute offset */ + complement = (char)( ( complement & 0x07 ) + 1 ); + + /* The gid for complement must be greater than 0 */ + if ( glyph <= complement ) + FT_INVALID_DATA; + } + else + { + /* The gid for complement must be the face. */ + gxv_glyphid_validate( (FT_UShort)( glyph + complement ), valid ); + } + } + else + { + if ( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ) + GXV_TRACE(( "glyph %d cannot have complementary bracketing\n", + glyph )); + } + + /* this is introduced in version 2.0 */ + if ( property & GXV_PROP_ATTACHING_TO_RIGHT ) + { + if ( GXV_PROP_DATA( version ) == 0x00010000UL ) + FT_INVALID_DATA; + } + + if ( property & GXV_PROP_RESERVED ) + FT_INVALID_DATA; + + if ( ( property & GXV_PROP_DIRECTIONALITY_CLASS ) > 11 ) + { + /* TODO: Too restricted. Use the validation level. */ + if ( GXV_PROP_DATA( version ) == 0x00010000UL || + GXV_PROP_DATA( version ) == 0x00020000UL ) + FT_INVALID_DATA; + } + } + + + static void + gxv_prop_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueDesc value, + GXV_Validator valid ) + { + gxv_prop_property_validate( value.u, glyph, valid ); + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_prop_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueDesc base_value, + FT_Bytes lookuptbl_limit, + GXV_Validator valid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value.u + + relative_gindex * sizeof( FT_UShort ) ); + p = valid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** prop TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + + GXV_prop_DataRec proprec; + GXV_prop_Data prop = &proprec; + + FT_Fixed version; + FT_UShort format; + FT_UShort defaultProp; + + + valid->root = ftvalid; + valid->table_data = prop; + valid->face = face; + + FT_TRACE3(( "validating `prop' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + defaultProp = FT_NEXT_USHORT( p ); + + /* only versions 1.0, 2.0, 3.0 are defined (1996) */ + if ( version != 0x00010000UL && + version != 0x00020000UL && + version != 0x00030000UL ) + FT_INVALID_FORMAT; + + + /* only formats 0x0000, 0x0001 are defined (1996) */ + if ( format > 1 ) + FT_INVALID_FORMAT; + + gxv_prop_property_validate( defaultProp, 0, valid ); + + if ( format == 0 ) + { + FT_TRACE3(( "(format 0, no per-glyph properties, " + "remaining %d bytes are skipped)", limit - p )); + goto Exit; + } + + /* format == 1 */ + GXV_PROP_DATA( version ) = version; + + valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + valid->lookupval_func = gxv_prop_LookupValue_validate; + valid->lookupfmt4_trans = gxv_prop_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, valid ); + + Exit: + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gxvalid/gxvtrak.c b/src/freetype2/gxvalid/gxvtrak.c new file mode 100644 index 0000000..432ee4e --- /dev/null +++ b/src/freetype2/gxvalid/gxvtrak.c @@ -0,0 +1,277 @@ +/***************************************************************************/ +/* */ +/* gxvtrak.c */ +/* */ +/* TrueTypeGX/AAT trak table validation (body). */ +/* */ +/* Copyright 2004, 2005 by suzuki toshiya, Masatake YAMATO, Red Hat 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 "gxvalid.h" +#include "gxvcommn.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_gxvtrak + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * referred track table format specification: + * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6trak.html + * last update was 1996. + * ---------------------------------------------- + * [MINIMUM HEADER]: GXV_TRAK_SIZE_MIN + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (1996) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * reserved (uint16: 16bit) = 0 + * ---------------------------------------------- + * [VARIABLE BODY]: + * horizData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + * vertData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + */ + typedef struct GXV_trak_DataRec_ + { + FT_UShort trackValueOffset_min; + FT_UShort trackValueOffset_max; + + } GXV_trak_DataRec, *GXV_trak_Data; + + +#define GXV_TRAK_DATA( FIELD ) GXV_TABLE_DATA( trak, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_trak_trackTable_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nTracks, + GXV_Validator valid ) + { + FT_Bytes p = table; + + FT_Fixed track; + FT_UShort nameIndex; + FT_UShort offset; + FT_UShort i; + + + GXV_NAME_ENTER( "trackTable" ); + + GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU; + GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000; + + for ( i = 0; i < nTracks; i ++ ) + { + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + track = FT_NEXT_LONG( p ); + nameIndex = FT_NEXT_USHORT( p ); + offset = FT_NEXT_USHORT( p ); + + if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) ) + GXV_TRAK_DATA( trackValueOffset_min ) = offset; + if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) ) + GXV_TRAK_DATA( trackValueOffset_max ) = offset; + + gxv_sfntName_validate( nameIndex, 256, 32767, valid ); + } + + valid->subtable_length = p - table; + GXV_EXIT; + } + + + static void + gxv_trak_trackData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator valid ) + { + FT_Bytes p = table; + FT_UShort nTracks; + FT_UShort nSizes; + FT_ULong sizeTableOffset; + + GXV_ODTECT( 4, odtect ); + + + GXV_ODTECT_INIT( odtect ); + GXV_NAME_ENTER( "trackData" ); + + /* read the header of trackData */ + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + nTracks = FT_NEXT_USHORT( p ); + nSizes = FT_NEXT_USHORT( p ); + sizeTableOffset = FT_NEXT_ULONG( p ); + + gxv_odtect_add_range( table, p - table, "trackData header", odtect ); + + /* validate trackTable */ + gxv_trak_trackTable_validate( p, limit, nTracks, valid ); + gxv_odtect_add_range( p, valid->subtable_length, + "trackTable", odtect ); + + /* sizeTable is array of FT_Fixed, don't check contents */ + p = valid->root->base + sizeTableOffset; + GXV_LIMIT_CHECK( nSizes * 4 ); + gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect ); + + /* validate trackValueOffet */ + p = valid->root->base + GXV_TRAK_DATA( trackValueOffset_min ); + if ( limit - p < nTracks * nSizes * 2 ) + GXV_TRACE(( "too short trackValue array\n" )); + + p = valid->root->base + GXV_TRAK_DATA( trackValueOffset_max ); + GXV_LIMIT_CHECK( nSizes * 2 ); + + gxv_odtect_add_range( valid->root->base + + GXV_TRAK_DATA( trackValueOffset_min ), + GXV_TRAK_DATA( trackValueOffset_max ) + - GXV_TRAK_DATA( trackValueOffset_min ) + + nSizes * 2, + "trackValue array", odtect ); + + gxv_odtect_validate( odtect, valid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** trak TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_UInt table_size; + + GXV_ValidatorRec validrec; + GXV_Validator valid = &validrec; + GXV_trak_DataRec trakrec; + GXV_trak_Data trak = &trakrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + FT_UShort reserved; + + + GXV_ODTECT( 3, odtect ); + + GXV_ODTECT_INIT( odtect ); + valid->root = ftvalid; + valid->table_data = trak; + valid->face = face; + + limit = valid->root->limit; + table_size = limit - table; + + FT_TRACE3(( "validating `trak' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + reserved = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (version = 0x%08x)\n", version )); + GXV_TRACE(( " (format = 0x%04x)\n", format )); + GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset )); + GXV_TRACE(( " (reserved = 0x%04x)\n", reserved )); + + /* Version 1.0 (always:1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:1996) */ + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset ); + GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset ); + + /* Reserved Fixed Value (always) */ + if ( reserved != 0x0000 ) + FT_INVALID_DATA; + + /* validate trackData */ + if ( 0 < horizOffset ) + { + gxv_trak_trackData_validate( table + horizOffset, limit, valid ); + gxv_odtect_add_range( table + horizOffset, valid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_trak_trackData_validate( table + vertOffset, limit, valid ); + gxv_odtect_add_range( table + vertOffset, valid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/gzip/adler32.c b/src/freetype2/gzip/adler32.c new file mode 100644 index 0000000..312c2f9 --- /dev/null +++ b/src/freetype2/gzip/adler32.c @@ -0,0 +1,48 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2008/10/17 06:10:37 scuri Exp $ */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +ZEXPORT(uLong) adler32( /* adler, buf, len) */ + uLong adler, + const Bytef *buf, + uInt len ) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/src/freetype2/gzip/ftgzip.c b/src/freetype2/gzip/ftgzip.c new file mode 100644 index 0000000..af2022d --- /dev/null +++ b/src/freetype2/gzip/ftgzip.c @@ -0,0 +1,682 @@ +/***************************************************************************/ +/* */ +/* ftgzip.c */ +/* */ +/* FreeType support for .gz compressed files. */ +/* */ +/* This optional component relies on zlib. It should mainly be used to */ +/* parse compressed PCF fonts, as found with many X11 server */ +/* distributions. */ +/* */ +/* 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_MEMORY_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_DEBUG_H +#include FT_GZIP_H +#include <string.h> + + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX Gzip_Err_ +#define FT_ERR_BASE FT_Mod_Err_Gzip + +#include FT_ERRORS_H + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + +#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB + +#include <zlib.h> + +#else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + /* In this case, we include our own modified sources of the ZLib */ + /* within the "ftgzip" component. The modifications were necessary */ + /* to #include all files without conflicts, as well as preventing */ + /* the definition of "extern" functions that may cause linking */ + /* conflicts when a program is linked with both FreeType and the */ + /* original ZLib. */ + +#define NO_DUMMY_DECL +#define MY_ZCALLOC + +#include "zlib.h" + +#undef SLOW +#define SLOW 1 /* we can't use asm-optimized sources here! */ + + /* Urgh. `inflate_mask' must not be declared twice -- C++ doesn't like + this. We temporarily disable it and load all necessary header files. */ +#define NO_INFLATE_MASK +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#undef NO_INFLATE_MASK + + /* infutil.c must be included before infcodes.c */ +#include "zutil.c" +#include "inftrees.c" +#include "infutil.c" +#include "infcodes.c" +#include "infblock.c" +#include "inflate.c" +#include "adler32.c" + +#endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + static voidpf + ft_gzip_alloc( FT_Memory memory, + uInt items, + uInt size ) + { + FT_ULong sz = (FT_ULong)size * items; + FT_Error error; + FT_Pointer p; + + + (void)FT_ALLOC( p, sz ); + return p; + } + + + static void + ft_gzip_free( FT_Memory memory, + voidpf address ) + { + FT_MEM_FREE( address ); + } + + +#ifndef FT_CONFIG_OPTION_SYSTEM_ZLIB + + local voidpf + zcalloc ( voidpf opaque, + unsigned items, + unsigned size ) + { + return ft_gzip_alloc( (FT_Memory)opaque, items, size ); + } + + local void + zcfree( voidpf opaque, + voidpf ptr ) + { + ft_gzip_free( (FT_Memory)opaque, ptr ); + } + +#endif /* !SYSTEM_ZLIB */ + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_GZIP_BUFFER_SIZE 4096 + + typedef struct FT_GZipFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + z_stream zstream; /* zlib input stream */ + + FT_ULong start; /* starting position, after .gz header */ + FT_Byte input[FT_GZIP_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_GZIP_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_GZipFileRec, *FT_GZipFile; + + + /* gzip flag byte */ +#define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */ +#define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */ + + + /* check and skip .gz header - we don't support `transparent' compression */ + static FT_Error + ft_gzip_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the method, and head[3] the flags */ + if ( head[0] != 0x1f || + head[1] != 0x8b || + head[2] != Z_DEFLATED || + (head[3] & FT_GZIP_RESERVED) ) + { + error = Gzip_Err_Invalid_File_Format; + goto Exit; + } + + /* skip time, xflags and os code */ + (void)FT_STREAM_SKIP( 6 ); + + /* skip the extra field */ + if ( head[3] & FT_GZIP_EXTRA_FIELD ) + { + FT_UInt len; + + + if ( FT_READ_USHORT_LE( len ) || + FT_STREAM_SKIP( len ) ) + goto Exit; + } + + /* skip original file name */ + if ( head[3] & FT_GZIP_ORIG_NAME ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip .gz comment */ + if ( head[3] & FT_GZIP_COMMENT ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip CRC */ + if ( head[3] & FT_GZIP_HEAD_CRC ) + if ( FT_STREAM_SKIP( 2 ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + ft_gzip_file_init( FT_GZipFile zip, + FT_Stream stream, + FT_Stream source ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = Gzip_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .gz header */ + { + stream = source; + + error = ft_gzip_check_header( stream ); + if ( error ) + goto Exit; + + zip->start = FT_STREAM_POS(); + } + + /* initialize zlib -- there is no zlib header in the compressed stream */ + zstream->zalloc = (alloc_func)ft_gzip_alloc; + zstream->zfree = (free_func) ft_gzip_free; + zstream->opaque = stream->memory; + + zstream->avail_in = 0; + zstream->next_in = zip->buffer; + + if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK || + zstream->next_in == NULL ) + error = Gzip_Err_Invalid_File_Format; + + Exit: + return error; + } + + + static void + ft_gzip_file_done( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + + + inflateEnd( zstream ); + + /* clear the rest */ + zstream->zalloc = NULL; + zstream->zfree = NULL; + zstream->opaque = NULL; + zstream->next_in = NULL; + zstream->next_out = NULL; + zstream->avail_in = 0; + zstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_gzip_file_reset( FT_GZipFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( zip->start ) ) + { + z_stream* zstream = &zip->zstream; + + + inflateReset( zstream ); + + zstream->avail_in = 0; + zstream->next_in = zip->input; + zstream->avail_out = 0; + zstream->next_out = zip->buffer; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_gzip_file_fill_input( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_GZIP_BUFFER_SIZE ); + if ( size == 0 ) + return Gzip_Err_Invalid_Stream_Operation; + } + else + { + size = stream->size - stream->pos; + if ( size > FT_GZIP_BUFFER_SIZE ) + size = FT_GZIP_BUFFER_SIZE; + + if ( size == 0 ) + return Gzip_Err_Invalid_Stream_Operation; + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + zstream->next_in = zip->input; + zstream->avail_in = size; + + return Gzip_Err_Ok; + } + + + static FT_Error + ft_gzip_file_fill_output( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = 0; + + + zip->cursor = zip->buffer; + zstream->next_out = zip->cursor; + zstream->avail_out = FT_GZIP_BUFFER_SIZE; + + while ( zstream->avail_out > 0 ) + { + int err; + + + if ( zstream->avail_in == 0 ) + { + error = ft_gzip_file_fill_input( zip ); + if ( error ) + break; + } + + err = inflate( zstream, Z_NO_FLUSH ); + + if ( err == Z_STREAM_END ) + { + zip->limit = zstream->next_out; + if ( zip->limit == zip->cursor ) + error = Gzip_Err_Invalid_Stream_Operation; + break; + } + else if ( err != Z_OK ) + { + error = Gzip_Err_Invalid_Stream_Operation; + break; + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */ + static FT_Error + ft_gzip_file_skip_output( FT_GZipFile zip, + FT_ULong count ) + { + FT_Error error = Gzip_Err_Ok; + FT_ULong delta; + + + for (;;) + { + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_gzip_file_io( FT_GZipFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if we're seeking backwards. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos ) + { + error = ft_gzip_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** G Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_gzip_stream_close( FT_Stream stream ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize gzip file descriptor */ + ft_gzip_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static FT_ULong + ft_gzip_stream_io( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + + + return ft_gzip_file_io( zip, pos, buffer, count ); + } + + + static FT_ULong + ft_gzip_get_uncompressed_size( FT_Stream stream ) + { + FT_Error error; + FT_ULong old_pos; + FT_ULong result = 0; + + + old_pos = stream->pos; + if ( !FT_Stream_Seek( stream, stream->size - 4 ) ) + { + result = (FT_ULong)FT_Stream_ReadLong( stream, &error ); + if ( error ) + result = 0; + + FT_Stream_Seek( stream, old_pos ); + } + + return result; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory = source->memory; + FT_GZipFile zip; + + + /* + * check the header right now; this prevents allocating un-necessary + * objects when we don't need them + */ + error = ft_gzip_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_gzip_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + /* + * We use the following trick to try to dramatically improve the + * performance while dealing with small files. If the original stream + * size is less than a certain threshold, we try to load the whole font + * file into memory. This saves us from using the 32KB buffer needed + * to inflate the file, plus the two 4KB intermediate input/output + * buffers used in the `FT_GZipFile' structure. + */ + { + FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); + + + if ( zip_size != 0 && zip_size < 40 * 1024 ) + { + FT_Byte* zip_buff; + + + if ( !FT_ALLOC( zip_buff, zip_size ) ) + { + FT_ULong count; + + + count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); + if ( count == zip_size ) + { + ft_gzip_file_done( zip ); + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + + stream->size = zip_size; + stream->pos = 0; + stream->base = zip_buff; + stream->read = NULL; + stream->close = ft_gzip_stream_close; + + goto Exit; + } + + ft_gzip_file_io( zip, 0, NULL, 0 ); + FT_FREE( zip_buff ); + } + error = 0; + } + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = 0; + stream->read = ft_gzip_stream_io; + stream->close = ft_gzip_stream_close; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return Gzip_Err_Unimplemented_Feature; + } + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + + +/* END */ diff --git a/src/freetype2/gzip/infblock.c b/src/freetype2/gzip/infblock.c new file mode 100644 index 0000000..d6e2dc2 --- /dev/null +++ b/src/freetype2/gzip/infblock.c @@ -0,0 +1,387 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +local void inflate_blocks_reset( /* s, z, c) */ +inflate_blocks_statef *s, +z_streamp z, +uLongf *c ) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +local inflate_blocks_statef *inflate_blocks_new( /* z, c, w) */ +z_streamp z, +check_func c, +uInt w ) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +local int inflate_blocks( /* s, z, r) */ +inflate_blocks_statef *s, +z_streamp z, +int r ) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, (const inflate_huft**)&tl, + (const inflate_huft**)&td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + } + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + } + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + ZFREE(z, s->sub.trees.blens); + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return 0; +#endif +} + + +local int inflate_blocks_free( /* s, z) */ +inflate_blocks_statef *s, +z_streamp z ) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + diff --git a/src/freetype2/gzip/infblock.h b/src/freetype2/gzip/infblock.h new file mode 100644 index 0000000..c2535a1 --- /dev/null +++ b/src/freetype2/gzip/infblock.h @@ -0,0 +1,36 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFBLOCK_H +#define _INFBLOCK_H + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +local inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +local int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +local void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +local int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +#endif /* _INFBLOCK_H */ diff --git a/src/freetype2/gzip/infcodes.c b/src/freetype2/gzip/infcodes.c new file mode 100644 index 0000000..f7bfd58 --- /dev/null +++ b/src/freetype2/gzip/infcodes.c @@ -0,0 +1,250 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +local inflate_codes_statef *inflate_codes_new( /* bl, bd, tl, td, z) */ +uInt bl, uInt bd, +inflate_huft *tl, +inflate_huft *td, /* need separate declaration for Borland C++ */ +z_streamp z ) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +local int inflate_codes( /* s, z, r) */ +inflate_blocks_statef *s, +z_streamp z, +int r ) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ + f = q - c->sub.copy.dist; + while (f < s->window) /* modulo window size-"while" instead */ + f += s->end - s->window; /* of "if" handles invalid distances */ + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +local void inflate_codes_free( /* c, z) */ +inflate_codes_statef *c, +z_streamp z ) +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/src/freetype2/gzip/infcodes.h b/src/freetype2/gzip/infcodes.h new file mode 100644 index 0000000..154d7f8 --- /dev/null +++ b/src/freetype2/gzip/infcodes.h @@ -0,0 +1,31 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFCODES_H +#define _INFCODES_H + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +local inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +local int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +local void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +#endif /* _INFCODES_H */ diff --git a/src/freetype2/gzip/inffixed.h b/src/freetype2/gzip/inffixed.h new file mode 100644 index 0000000..4d4760e --- /dev/null +++ b/src/freetype2/gzip/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local const uInt fixed_bl = 9; +local const uInt fixed_bd = 5; +local const inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local const inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/src/freetype2/gzip/inflate.c b/src/freetype2/gzip/inflate.c new file mode 100644 index 0000000..8877fa3 --- /dev/null +++ b/src/freetype2/gzip/inflate.c @@ -0,0 +1,273 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" + +#define DONE INFLATE_DONE +#define BAD INFLATE_BAD + +typedef enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +ZEXPORT(int) inflateReset( /* z) */ +z_streamp z ) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + + +ZEXPORT(int) inflateEnd( /* z) */ +z_streamp z ) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +ZEXPORT(int) inflateInit2_( /* z, w, version, stream_size) */ +z_streamp z, +int w, +const char *version, +int stream_size ) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + + +#undef NEEDBYTE +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} + +#undef NEXTBYTE +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + + +ZEXPORT(int) inflate( /* z, f) */ +z_streamp z, +int f ) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + diff --git a/src/freetype2/gzip/inftrees.c b/src/freetype2/gzip/inftrees.c new file mode 100644 index 0000000..3c39aca --- /dev/null +++ b/src/freetype2/gzip/inftrees.c @@ -0,0 +1,465 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + + +#if 0 +local const char inflate_copyright[] = + " inflate 1.1.4 Copyright 1995-2002 Mark Adler "; +#endif +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +local int huft_build( /* b, n, s, d, e, t, m, hp, hn, v) */ +uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ +uInt n, /* number of codes (assumed <= 288) */ +uInt s, /* number of simple-valued codes (0..s-1) */ +const uIntf *d, /* list of base values for non-simple codes */ +const uIntf *e, /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t, /* result: starting table */ +uIntf *m, /* maximum lookup bits, returns actual */ +inflate_huft *hp, /* space for trees */ +uInt *hn, /* hufts used in space */ +uIntf *v /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), or Z_DATA_ERROR if the input is invalid. */ +) +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Make compiler happy */ + r.base = 0; + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? (uInt)l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_DATA_ERROR; /* overflow of MANY */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +local int inflate_trees_bits( /* c, bb, tb, hp, z) */ +uIntf *c, /* 19 code lengths */ +uIntf *bb, /* bits tree desired/actual depth */ +inflate_huft * FAR *tb, /* bits tree result */ +inflate_huft *hp, /* space for trees */ +z_streamp z /* for messages */ +) +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +local int inflate_trees_dynamic( /* nl, nd, c, bl, bd, tl, td, hp, z) */ +uInt nl, /* number of literal/length codes */ +uInt nd, /* number of distance codes */ +uIntf *c, /* that many (total) code lengths */ +uIntf *bl, /* literal desired/actual bit depth */ +uIntf *bd, /* distance desired/actual bit depth */ +inflate_huft * FAR *tl, /* literal/length tree result */ +inflate_huft * FAR *td, /* distance tree result */ +inflate_huft *hp, /* space for trees */ +z_streamp z /* for messages */ +) +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED +local int fixed_built = 0; +#define FIXEDH 544 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; +#else +#include "inffixed.h" +#endif + + +local int inflate_trees_fixed( /* bl, bd, tl, td, z) */ +uIntf *bl, /* literal desired/actual bit depth */ +uIntf *bd, /* distance desired/actual bit depth */ +const inflate_huft * FAR *tl, /* literal/length tree result */ +const inflate_huft * FAR *td, /* distance tree result */ +z_streamp z /* for memory allocation */ +) +{ +#ifdef BUILDFIXED + /* build fixed tables if not already */ + if (!fixed_built) + { + int k; /* temporary variable */ + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); + + /* done */ + ZFREE(z, v); + ZFREE(z, c); + fixed_built = 1; + } +#else + FT_UNUSED(z); +#endif + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} diff --git a/src/freetype2/gzip/inftrees.h b/src/freetype2/gzip/inftrees.h new file mode 100644 index 0000000..07bf2aa --- /dev/null +++ b/src/freetype2/gzip/inftrees.h @@ -0,0 +1,63 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +#ifndef _INFTREES_H +#define _INFTREES_H + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +local int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +local int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +local int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + const inflate_huft * FAR *, /* literal/length tree result */ + const inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + +#endif /* _INFTREES_H */ diff --git a/src/freetype2/gzip/infutil.c b/src/freetype2/gzip/infutil.c new file mode 100644 index 0000000..6087b40 --- /dev/null +++ b/src/freetype2/gzip/infutil.c @@ -0,0 +1,86 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + + +/* And'ing with mask[n] masks the lower n bits */ +local const uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush( /* s, z, r) */ +inflate_blocks_statef *s, +z_streamp z, +int r ) +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/src/freetype2/gzip/infutil.h b/src/freetype2/gzip/infutil.h new file mode 100644 index 0000000..7174b6d --- /dev/null +++ b/src/freetype2/gzip/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}} +#define DUMPBITS(j) {b>>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +#ifndef NO_INFLATE_MASK +local uInt inflate_mask[17]; +#endif + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif diff --git a/src/freetype2/gzip/zconf.h b/src/freetype2/gzip/zconf.h new file mode 100644 index 0000000..fefdd86 --- /dev/null +++ b/src/freetype2/gzip/zconf.h @@ -0,0 +1,278 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2008/10/17 06:10:37 scuri Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C and LCC incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + +#if defined(__LCC__) +# define NEED_DUMMY_RETURN +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include <windows.h> +# define ZEXPORT(x) x WINAPI +# ifdef WIN32 +# define ZEXPORTVA(x) x WINAPIV +# else +# define ZEXPORTVA(x) x FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include <windows.h> +# define ZEXPORT(x) x __declspec(dllexport) WINAPI +# define ZEXPORTRVA(x) x __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT(x) x _export +# define ZEXPORTVA(x) x _export +# endif +# endif +# endif +#endif + + +#ifndef ZEXPORT +# define ZEXPORT(x) static x +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA(x) static x +#endif +#ifndef ZEXTERN +# define ZEXTERN(x) static x +#endif +#ifndef ZEXTERNDEF +# define ZEXTERNDEF(x) static x +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/src/freetype2/gzip/zlib.h b/src/freetype2/gzip/zlib.h new file mode 100644 index 0000000..50d0d3f --- /dev/null +++ b/src/freetype2/gzip/zlib.h @@ -0,0 +1,830 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.4, March 11th, 2002 + + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.4" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + + + /* basic functions */ + +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN(int) deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN(int) inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN(int) inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN(int) inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN(int) deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN(int) inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN(int) inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN(uLong) adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN(int) inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/src/freetype2/gzip/zutil.c b/src/freetype2/gzip/zutil.c new file mode 100644 index 0000000..bbb9506 --- /dev/null +++ b/src/freetype2/gzip/zutil.c @@ -0,0 +1,181 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2008/10/17 06:10:37 scuri Exp $ */ + +#include "zutil.h" + +#ifndef STDC +extern void exit OF((int)); +#endif + + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp ft_scalloc OF((uInt items, uInt size)); +extern void ft_sfree OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)ft_scalloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + ft_sfree(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/src/freetype2/gzip/zutil.h b/src/freetype2/gzip/zutil.h new file mode 100644 index 0000000..622c321 --- /dev/null +++ b/src/freetype2/gzip/zutil.h @@ -0,0 +1,215 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2008/10/17 06:10:37 scuri Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef STDC +# include <stddef.h> +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include <errno.h> +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include <alloc.h> +# endif +# else /* MSC or DJGPP */ +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + ft_fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) ft_fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy ft_memcpy +# define zmemcmp ft_memcmp +# define zmemzero(dest, len) ft_memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef Z_DEBUG +# include <stdio.h> + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Bytef *buf, + uInt len)); +local voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +local void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ diff --git a/src/freetype2/lzw/ftlzw.c b/src/freetype2/lzw/ftlzw.c new file mode 100644 index 0000000..45fbf7b --- /dev/null +++ b/src/freetype2/lzw/ftlzw.c @@ -0,0 +1,413 @@ +/***************************************************************************/ +/* */ +/* ftlzw.c */ +/* */ +/* FreeType support for .Z compressed files. */ +/* */ +/* This optional component relies on NetBSD's zopen(). It should mainly */ +/* be used to parse compressed PCF fonts, as found with many X11 server */ +/* distributions. */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* Albert Chin-A-Young. */ +/* */ +/* Based on code in src/gzip/ftgzip.c, Copyright 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_MEMORY_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_DEBUG_H +#include FT_LZW_H +#include <string.h> +#include <stdio.h> + + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX LZW_Err_ +#define FT_ERR_BASE FT_Mod_Err_LZW + +#include FT_ERRORS_H + + +#ifdef FT_CONFIG_OPTION_USE_LZW + +#include "ftzopen.h" + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_LZW_BUFFER_SIZE 4096 + + typedef struct FT_LZWFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + FT_LzwStateRec lzw; /* lzw decompressor state */ + + FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_LZWFileRec, *FT_LZWFile; + + + /* check and skip .Z header */ + static FT_Error + ft_lzw_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[2]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 2 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers */ + if ( head[0] != 0x1f || + head[1] != 0x9d ) + error = LZW_Err_Invalid_File_Format; + + Exit: + return error; + } + + + static FT_Error + ft_lzw_file_init( FT_LZWFile zip, + FT_Stream stream, + FT_Stream source ) + { + FT_LzwState lzw = &zip->lzw; + FT_Error error = LZW_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .Z header */ + { + stream = source; + + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + } + + /* initialize internal lzw variable */ + ft_lzwstate_init( lzw, source ); + + Exit: + return error; + } + + + static void + ft_lzw_file_done( FT_LZWFile zip ) + { + /* clear the rest */ + ft_lzwstate_done( &zip->lzw ); + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_lzw_file_reset( FT_LZWFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + ft_lzwstate_reset( &zip->lzw ); + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_lzw_file_fill_output( FT_LZWFile zip ) + { + FT_LzwState lzw = &zip->lzw; + FT_ULong count; + FT_Error error = 0; + + + zip->cursor = zip->buffer; + + count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE ); + + zip->limit = zip->cursor + count; + + if ( count == 0 ) + error = LZW_Err_Invalid_Stream_Operation; + + return error; + } + + + /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */ + static FT_Error + ft_lzw_file_skip_output( FT_LZWFile zip, + FT_ULong count ) + { + FT_Error error = LZW_Err_Ok; + + + /* first, we skip what we can from the output buffer */ + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + } + + /* next, we skip as many bytes remaining as possible */ + while ( count > 0 ) + { + FT_ULong delta = FT_LZW_BUFFER_SIZE; + FT_ULong numread; + + + if ( delta > count ) + delta = count; + + numread = ft_lzwstate_io( &zip->lzw, NULL, delta ); + if ( numread < delta ) + { + /* not enough bytes */ + error = LZW_Err_Invalid_Stream_Operation; + break; + } + + zip->pos += delta; + count -= delta; + } + + return error; + } + + + static FT_ULong + ft_lzw_file_io( FT_LZWFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* seeking backwards. */ + if ( pos < zip->pos ) + { + /* If the new position is within the output buffer, simply */ + /* decrement pointers, otherwise we reset the stream completely! */ + if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) ) + { + zip->cursor -= zip->pos - pos; + zip->pos = pos; + } + else + { + error = ft_lzw_file_reset( zip ); + if ( error ) + goto Exit; + } + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer + result, zip->cursor, delta ); + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_lzw_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** L Z W E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_lzw_stream_close( FT_Stream stream ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize lzw file descriptor */ + ft_lzw_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static FT_ULong + ft_lzw_stream_io( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + + + return ft_lzw_file_io( zip, pos, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory = source->memory; + FT_LZWFile zip; + + + /* + * Check the header right now; this prevents allocation of a huge + * LZWFile object (400 KByte of heap memory) if not necessary. + * + * Did I mention that you should never use .Z compressed font + * files? + */ + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_NEW( zip ) ) + { + error = ft_lzw_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = 0; + stream->read = ft_lzw_stream_io; + stream->close = ft_lzw_stream_close; + + Exit: + return error; + } + + +#include "ftzopen.c" + + +#else /* !FT_CONFIG_OPTION_USE_LZW */ + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return LZW_Err_Unimplemented_Feature; + } + + +#endif /* !FT_CONFIG_OPTION_USE_LZW */ + + +/* END */ diff --git a/src/freetype2/lzw/ftzopen.c b/src/freetype2/lzw/ftzopen.c new file mode 100644 index 0000000..fc78315 --- /dev/null +++ b/src/freetype2/lzw/ftzopen.c @@ -0,0 +1,398 @@ +/***************************************************************************/ +/* */ +/* ftzopen.c */ +/* */ +/* FreeType support for .Z compressed files. */ +/* */ +/* This optional component relies on NetBSD's zopen(). It should mainly */ +/* be used to parse compressed PCF fonts, as found with many X11 server */ +/* distributions. */ +/* */ +/* Copyright 2005, 2006, 2007 by David Turner. */ +/* */ +/* 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 "ftzopen.h" +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_DEBUG_H + + + static int + ft_lzwstate_refill( FT_LzwState state ) + { + FT_ULong count; + + + if ( state->in_eof ) + return -1; + + count = FT_Stream_TryRead( state->source, + state->buf_tab, + state->num_bits ); /* WHY? */ + + state->buf_size = (FT_UInt)count; + state->buf_total += count; + state->in_eof = FT_BOOL( count < state->num_bits ); + state->buf_offset = 0; + state->buf_size = ( state->buf_size << 3 ) - ( state->num_bits - 1 ); + + if ( count == 0 ) /* end of file */ + return -1; + + return 0; + } + + + static FT_Int32 + ft_lzwstate_get_code( FT_LzwState state ) + { + FT_UInt num_bits = state->num_bits; + FT_Int offset = state->buf_offset; + FT_Byte* p; + FT_Int result; + + + if ( state->buf_clear || + offset >= state->buf_size || + state->free_ent >= state->free_bits ) + { + if ( state->free_ent >= state->free_bits ) + { + state->num_bits = ++num_bits; + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << num_bits ) - 256 ) + : state->max_free + 1; + } + + if ( state->buf_clear ) + { + state->num_bits = num_bits = LZW_INIT_BITS; + state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 ); + state->buf_clear = 0; + } + + if ( ft_lzwstate_refill( state ) < 0 ) + return -1; + + offset = 0; + } + + state->buf_offset = offset + num_bits; + + p = &state->buf_tab[offset >> 3]; + offset &= 7; + result = *p++ >> offset; + offset = 8 - offset; + num_bits -= offset; + + if ( num_bits >= 8 ) + { + result |= *p++ << offset; + offset += 8; + num_bits -= 8; + } + if ( num_bits > 0 ) + result |= ( *p & LZW_MASK( num_bits ) ) << offset; + + return result; + } + + + /* grow the character stack */ + static int + ft_lzwstate_stack_grow( FT_LzwState state ) + { + if ( state->stack_top >= state->stack_size ) + { + FT_Memory memory = state->memory; + FT_Error error; + FT_UInt old_size = state->stack_size; + FT_UInt new_size = old_size; + + new_size = new_size + ( new_size >> 1 ) + 4; + + if ( state->stack == state->stack_0 ) + { + state->stack = NULL; + old_size = 0; + } + + if ( FT_RENEW_ARRAY( state->stack, old_size, new_size ) ) + return -1; + + state->stack_size = new_size; + } + return 0; + } + + + /* grow the prefix/suffix arrays */ + static int + ft_lzwstate_prefix_grow( FT_LzwState state ) + { + FT_UInt old_size = state->prefix_size; + FT_UInt new_size = old_size; + FT_Memory memory = state->memory; + FT_Error error; + + + if ( new_size == 0 ) /* first allocation -> 9 bits */ + new_size = 512; + else + new_size += new_size >> 2; /* don't grow too fast */ + + /* + * Note that the `suffix' array is located in the same memory block + * pointed to by `prefix'. + * + * I know that sizeof(FT_Byte) == 1 by definition, but it is clearer + * to write it literally. + * + */ + if ( FT_REALLOC_MULT( state->prefix, old_size, new_size, + sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ) ) + return -1; + + /* now adjust `suffix' and move the data accordingly */ + state->suffix = (FT_Byte*)( state->prefix + new_size ); + + FT_MEM_MOVE( state->suffix, + state->prefix + old_size, + old_size * sizeof ( FT_Byte ) ); + + state->prefix_size = new_size; + return 0; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_reset( FT_LzwState state ) + { + state->in_eof = 0; + state->buf_offset = 0; + state->buf_size = 0; + state->buf_clear = 0; + state->buf_total = 0; + state->stack_top = 0; + state->num_bits = LZW_INIT_BITS; + state->phase = FT_LZW_PHASE_START; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ) + { + FT_ZERO( state ); + + state->source = source; + state->memory = source->memory; + + state->prefix = NULL; + state->suffix = NULL; + state->prefix_size = 0; + + state->stack = state->stack_0; + state->stack_size = sizeof ( state->stack_0 ); + + ft_lzwstate_reset( state ); + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_done( FT_LzwState state ) + { + FT_Memory memory = state->memory; + + + ft_lzwstate_reset( state ); + + if ( state->stack != state->stack_0 ) + FT_FREE( state->stack ); + + FT_FREE( state->prefix ); + state->suffix = NULL; + + FT_ZERO( state ); + } + + +#define FTLZW_STACK_PUSH( c ) \ + FT_BEGIN_STMNT \ + if ( state->stack_top >= state->stack_size && \ + ft_lzwstate_stack_grow( state ) < 0 ) \ + goto Eof; \ + \ + state->stack[state->stack_top++] = (FT_Byte)(c); \ + FT_END_STMNT + + + FT_LOCAL_DEF( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ) + { + FT_ULong result = 0; + + FT_UInt old_char = state->old_char; + FT_UInt old_code = state->old_code; + FT_UInt in_code = state->in_code; + + + if ( out_size == 0 ) + goto Exit; + + switch ( state->phase ) + { + case FT_LZW_PHASE_START: + { + FT_Byte max_bits; + FT_Int32 c; + + + /* skip magic bytes, and read max_bits + block_flag */ + if ( FT_Stream_Seek( state->source, 2 ) != 0 || + FT_Stream_TryRead( state->source, &max_bits, 1 ) != 1 ) + goto Eof; + + state->max_bits = max_bits & LZW_BIT_MASK; + state->block_mode = max_bits & LZW_BLOCK_MASK; + state->max_free = (FT_UInt)( ( 1UL << state->max_bits ) - 256 ); + + if ( state->max_bits > LZW_MAX_BITS ) + goto Eof; + + state->num_bits = LZW_INIT_BITS; + state->free_ent = ( state->block_mode ? LZW_FIRST + : LZW_CLEAR ) - 256; + in_code = 0; + + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << state->num_bits ) - 256 ) + : state->max_free + 1; + + c = ft_lzwstate_get_code( state ); + if ( c < 0 ) + goto Eof; + + old_code = old_char = (FT_UInt)c; + + if ( buffer ) + buffer[result] = (FT_Byte)old_char; + + if ( ++result >= out_size ) + goto Exit; + + state->phase = FT_LZW_PHASE_CODE; + } + /* fall-through */ + + case FT_LZW_PHASE_CODE: + { + FT_Int32 c; + FT_UInt code; + + + NextCode: + c = ft_lzwstate_get_code( state ); + if ( c < 0 ) + goto Eof; + + code = (FT_UInt)c; + + if ( code == LZW_CLEAR && state->block_mode ) + { + /* why not LZW_FIRST-256 ? */ + state->free_ent = ( LZW_FIRST - 1 ) - 256; + state->buf_clear = 1; + c = ft_lzwstate_get_code( state ); + if ( c < 0 ) + goto Eof; + + code = (FT_UInt)c; + } + + in_code = code; /* save code for later */ + + if ( code >= 256U ) + { + /* special case for KwKwKwK */ + if ( code - 256U >= state->free_ent ) + { + FTLZW_STACK_PUSH( old_char ); + code = old_code; + } + + while ( code >= 256U ) + { + FTLZW_STACK_PUSH( state->suffix[code - 256] ); + code = state->prefix[code - 256]; + } + } + + old_char = code; + FTLZW_STACK_PUSH( old_char ); + + state->phase = FT_LZW_PHASE_STACK; + } + /* fall-through */ + + case FT_LZW_PHASE_STACK: + { + while ( state->stack_top > 0 ) + { + --state->stack_top; + + if ( buffer ) + buffer[result] = state->stack[state->stack_top]; + + if ( ++result == out_size ) + goto Exit; + } + + /* now create new entry */ + if ( state->free_ent < state->max_free ) + { + if ( state->free_ent >= state->prefix_size && + ft_lzwstate_prefix_grow( state ) < 0 ) + goto Eof; + + FT_ASSERT( state->free_ent < state->prefix_size ); + + state->prefix[state->free_ent] = (FT_UShort)old_code; + state->suffix[state->free_ent] = (FT_Byte) old_char; + + state->free_ent += 1; + } + + old_code = in_code; + + state->phase = FT_LZW_PHASE_CODE; + goto NextCode; + } + + default: /* state == EOF */ + ; + } + + Exit: + state->old_code = old_code; + state->old_char = old_char; + state->in_code = in_code; + + return result; + + Eof: + state->phase = FT_LZW_PHASE_EOF; + goto Exit; + } + + +/* END */ diff --git a/src/freetype2/lzw/ftzopen.h b/src/freetype2/lzw/ftzopen.h new file mode 100644 index 0000000..9788114 --- /dev/null +++ b/src/freetype2/lzw/ftzopen.h @@ -0,0 +1,171 @@ +/***************************************************************************/ +/* */ +/* ftzopen.h */ +/* */ +/* FreeType support for .Z compressed files. */ +/* */ +/* This optional component relies on NetBSD's zopen(). It should mainly */ +/* be used to parse compressed PCF fonts, as found with many X11 server */ +/* distributions. */ +/* */ +/* Copyright 2005, 2006, 2007 by David Turner. */ +/* */ +/* 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 __FT_ZOPEN_H__ +#define __FT_ZOPEN_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + + + /* + * This is a complete re-implementation of the LZW file reader, + * since the old one was incredibly badly written, using + * 400 KByte of heap memory before decompressing anything. + * + */ + +#define FT_LZW_IN_BUFF_SIZE 64 +#define FT_LZW_DEFAULT_STACK_SIZE 64 + +#define LZW_INIT_BITS 9 +#define LZW_MAX_BITS 16 + +#define LZW_CLEAR 256 +#define LZW_FIRST 257 + +#define LZW_BIT_MASK 0x1f +#define LZW_BLOCK_MASK 0x80 +#define LZW_MASK( n ) ( ( 1U << (n) ) - 1U ) + + + typedef enum + { + FT_LZW_PHASE_START = 0, + FT_LZW_PHASE_CODE, + FT_LZW_PHASE_STACK, + FT_LZW_PHASE_EOF + + } FT_LzwPhase; + + + /* + * state of LZW decompressor + * + * small technical note + * -------------------- + * + * We use a few tricks in this implementation that are explained here to + * ease debugging and maintenance. + * + * - First of all, the `prefix' and `suffix' arrays contain the suffix + * and prefix for codes over 256; this means that + * + * prefix_of(code) == state->prefix[code-256] + * suffix_of(code) == state->suffix[code-256] + * + * Each prefix is a 16-bit code, and each suffix an 8-bit byte. + * + * Both arrays are stored in a single memory block, pointed to by + * `state->prefix'. This means that the following equality is always + * true: + * + * state->suffix == (FT_Byte*)(state->prefix + state->prefix_size) + * + * Of course, state->prefix_size is the number of prefix/suffix slots + * in the arrays, corresponding to codes 256..255+prefix_size. + * + * - `free_ent' is the index of the next free entry in the `prefix' + * and `suffix' arrays. This means that the corresponding `next free + * code' is really `256+free_ent'. + * + * Moreover, `max_free' is the maximum value that `free_ent' can reach. + * + * `max_free' corresponds to `(1 << max_bits) - 256'. Note that this + * value is always <= 0xFF00, which means that both `free_ent' and + * `max_free' can be stored in an FT_UInt variable, even on 16-bit + * machines. + * + * If `free_ent == max_free', you cannot add new codes to the + * prefix/suffix table. + * + * - `num_bits' is the current number of code bits, starting at 9 and + * growing each time `free_ent' reaches the value of `free_bits'. The + * latter is computed as follows + * + * if num_bits < max_bits: + * free_bits = (1 << num_bits)-256 + * else: + * free_bits = max_free + 1 + * + * Since the value of `max_free + 1' can never be reached by + * `free_ent', `num_bits' cannot grow larger than `max_bits'. + */ + + typedef struct _FT_LzwStateRec + { + FT_LzwPhase phase; + FT_Int in_eof; + + FT_Byte buf_tab[16]; + FT_Int buf_offset; + FT_Int buf_size; + FT_Bool buf_clear; + FT_Int buf_total; + + FT_UInt max_bits; /* max code bits, from file header */ + FT_Int block_mode; /* block mode flag, from file header */ + FT_UInt max_free; /* (1 << max_bits) - 256 */ + + FT_UInt num_bits; /* current code bit number */ + FT_UInt free_ent; /* index of next free entry */ + FT_UInt free_bits; /* if reached by free_ent, increment num_bits */ + FT_UInt old_code; + FT_UInt old_char; + FT_UInt in_code; + + FT_UShort* prefix; /* always dynamically allocated / reallocated */ + FT_Byte* suffix; /* suffix = (FT_Byte*)(prefix + prefix_size) */ + FT_UInt prefix_size; /* number of slots in `prefix' or `suffix' */ + + FT_Byte* stack; /* character stack */ + FT_UInt stack_top; + FT_UInt stack_size; + FT_Byte stack_0[FT_LZW_DEFAULT_STACK_SIZE]; /* minimize heap alloc */ + + FT_Stream source; /* source stream */ + FT_Memory memory; + + } FT_LzwStateRec, *FT_LzwState; + + + FT_LOCAL( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ); + + FT_LOCAL( void ) + ft_lzwstate_done( FT_LzwState state ); + + + FT_LOCAL( void ) + ft_lzwstate_reset( FT_LzwState state ); + + + FT_LOCAL( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ); + +/* */ + +#endif /* __FT_ZOPEN_H__ */ + + +/* END */ diff --git a/src/freetype2/otvalid/otvalid.c b/src/freetype2/otvalid/otvalid.c new file mode 100644 index 0000000..2f85f60 --- /dev/null +++ b/src/freetype2/otvalid/otvalid.c @@ -0,0 +1,30 @@ +/***************************************************************************/ +/* */ +/* otvalid.c */ +/* */ +/* FreeType validator for OpenType tables (body only). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> + +#include "otvbase.c" +#include "otvcommn.c" +#include "otvgdef.c" +#include "otvgpos.c" +#include "otvgsub.c" +#include "otvjstf.c" +#include "otvmod.c" + +/* END */ diff --git a/src/freetype2/otvalid/otvalid.h b/src/freetype2/otvalid/otvalid.h new file mode 100644 index 0000000..38f030f --- /dev/null +++ b/src/freetype2/otvalid/otvalid.h @@ -0,0 +1,72 @@ +/***************************************************************************/ +/* */ +/* otvalid.h */ +/* */ +/* OpenType table validation (specification only). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVALID_H__ +#define __OTVALID_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#include "otverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ + +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + +FT_END_HEADER + +#endif /* __OTVALID_H__ */ + + +/* END */ diff --git a/src/freetype2/otvalid/otvbase.c b/src/freetype2/otvalid/otvbase.c new file mode 100644 index 0000000..8ad2238 --- /dev/null +++ b/src/freetype2/otvalid/otvbase.c @@ -0,0 +1,318 @@ +/***************************************************************************/ +/* */ +/* otvbase.c */ +/* */ +/* OpenType BASE table validation (body). */ +/* */ +/* Copyright 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 "otvalid.h" +#include "otvcommn.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_otvbase + + + static void + otv_BaseCoord_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordFormat; + + + OTV_NAME_ENTER( "BaseCoord" ); + + OTV_LIMIT_CHECK( 4 ); + BaseCoordFormat = FT_NEXT_USHORT( p ); + p += 2; /* skip Coordinate */ + + OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); + + switch ( BaseCoordFormat ) + { + case 1: /* BaseCoordFormat1 */ + break; + + case 2: /* BaseCoordFormat2 */ + OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ + break; + + case 3: /* BaseCoordFormat3 */ + OTV_LIMIT_CHECK( 2 ); + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static void + otv_BaseTagList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseTagCount; + + + OTV_NAME_ENTER( "BaseTagList" ); + + OTV_LIMIT_CHECK( 2 ); + + BaseTagCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); + + OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ + + OTV_EXIT; + } + + + static void + otv_BaseValues_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordCount; + + + OTV_NAME_ENTER( "BaseValues" ); + + OTV_LIMIT_CHECK( 4 ); + + p += 2; /* skip DefaultIndex */ + BaseCoordCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); + + OTV_LIMIT_CHECK( BaseCoordCount * 2 ); + + /* BaseCoord */ + for ( ; BaseCoordCount > 0; BaseCoordCount-- ) + otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + static void + otv_MinMax_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt FeatMinMaxCount; + + OTV_OPTIONAL_TABLE( MinCoord ); + OTV_OPTIONAL_TABLE( MaxCoord ); + + + OTV_NAME_ENTER( "MinMax" ); + + OTV_LIMIT_CHECK( 6 ); + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + FeatMinMaxCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); + + table_size = FeatMinMaxCount * 8 + 6; + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, valid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, valid ); + + OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); + + /* FeatMinMaxRecord */ + for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) + { + p += 4; /* skip FeatureTableTag */ + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, valid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, valid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScript_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt BaseLangSysCount; + + OTV_OPTIONAL_TABLE( BaseValues ); + OTV_OPTIONAL_TABLE( DefaultMinMax ); + + + OTV_NAME_ENTER( "BaseScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( BaseValues ); + OTV_OPTIONAL_OFFSET( DefaultMinMax ); + BaseLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); + + table_size = BaseLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( BaseValues ); + if ( BaseValues ) + otv_BaseValues_validate( table + BaseValues, valid ); + + OTV_SIZE_CHECK( DefaultMinMax ); + if ( DefaultMinMax ) + otv_MinMax_validate( table + DefaultMinMax, valid ); + + OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); + + /* BaseLangSysRecord */ + for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) + { + p += 4; /* skip BaseLangSysTag */ + + otv_MinMax_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScriptList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseScriptCount; + + + OTV_NAME_ENTER( "BaseScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + BaseScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); + + OTV_LIMIT_CHECK( BaseScriptCount * 6 ); + + /* BaseScriptRecord */ + for ( ; BaseScriptCount > 0; BaseScriptCount-- ) + { + p += 4; /* skip BaseScriptTag */ + + /* BaseScript */ + otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + static void + otv_Axis_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( BaseTagList ); + + + OTV_NAME_ENTER( "Axis" ); + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( BaseTagList ); + + table_size = 4; + + OTV_SIZE_CHECK( BaseTagList ); + if ( BaseTagList ) + otv_BaseTagList_validate( table + BaseTagList, valid ); + + /* BaseScriptList */ + otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( HorizAxis ); + OTV_OPTIONAL_TABLE( VertAxis ); + + + valid->root = ftvalid; + + FT_TRACE3(( "validating BASE table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + table_size = 6; + + OTV_OPTIONAL_OFFSET( HorizAxis ); + OTV_SIZE_CHECK( HorizAxis ); + if ( HorizAxis ) + otv_Axis_validate( table + HorizAxis, valid ); + + OTV_OPTIONAL_OFFSET( VertAxis ); + OTV_SIZE_CHECK( VertAxis ); + if ( VertAxis ) + otv_Axis_validate( table + VertAxis, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvcommn.c b/src/freetype2/otvalid/otvcommn.c new file mode 100644 index 0000000..d94e4f3 --- /dev/null +++ b/src/freetype2/otvalid/otvcommn.c @@ -0,0 +1,1055 @@ +/***************************************************************************/ +/* */ +/* otvcommn.c */ +/* */ +/* OpenType common tables validation (body). */ +/* */ +/* Copyright 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 "otvcommn.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_otvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat; + + + OTV_NAME_ENTER( "Coverage" ); + + OTV_LIMIT_CHECK( 4 ); + CoverageFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", CoverageFormat )); + + switch ( CoverageFormat ) + { + case 1: /* CoverageFormat1 */ + { + FT_UInt GlyphCount; + + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ + } + break; + + case 2: /* CoverageFormat2 */ + { + FT_UInt n, RangeCount; + FT_UInt Start, End, StartCoverageIndex, total = 0, last = 0; + + + RangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); + + OTV_LIMIT_CHECK( RangeCount * 6 ); + + /* RangeRecord */ + for ( n = 0; n < RangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + StartCoverageIndex = FT_NEXT_USHORT( p ); + + if ( Start > End || StartCoverageIndex != total ) + FT_INVALID_DATA; + + if ( n > 0 && Start <= last ) + FT_INVALID_DATA; + + total += End - Start + 1; + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to coverage tables */ + /* since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ) + { + FT_Bytes p = table; + + + p += 4; /* skip CoverageFormat and Glyph/RangeCount */ + + return FT_NEXT_USHORT( p ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + p += ( count - 1 ) * 2; + result = FT_NEXT_USHORT( p ); + break; + + case 2: + p += ( count - 1 ) * 6 + 2; + result = FT_NEXT_USHORT( p ); + break; + + default: + ; + } + + return result; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + return count; + + case 2: + { + FT_UInt Start, End; + + + for ( ; count > 0; count-- ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip StartCoverageIndex */ + + result += End - Start + 1; + } + } + break; + + default: + ; + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt ClassFormat; + + + OTV_NAME_ENTER( "ClassDef" ); + + OTV_LIMIT_CHECK( 4 ); + ClassFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", ClassFormat )); + + switch ( ClassFormat ) + { + case 1: /* ClassDefFormat1 */ + { + FT_UInt GlyphCount; + + + p += 2; /* skip StartGlyph */ + + OTV_LIMIT_CHECK( 2 ); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ + } + break; + + case 2: /* ClassDefFormat2 */ + { + FT_UInt n, ClassRangeCount; + FT_UInt Start, End, last = 0; + + + ClassRangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); + + OTV_LIMIT_CHECK( ClassRangeCount * 6 ); + + /* ClassRangeRecord */ + for ( n = 0; n < ClassRangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip Class */ + + if ( Start > End || ( n > 0 && Start <= last ) ) + FT_INVALID_DATA; + + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to class definition */ + /* tables since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt StartSize, EndSize, DeltaFormat, count; + + + OTV_NAME_ENTER( "Device" ); + + OTV_LIMIT_CHECK( 8 ); + StartSize = FT_NEXT_USHORT( p ); + EndSize = FT_NEXT_USHORT( p ); + DeltaFormat = FT_NEXT_USHORT( p ); + + if ( DeltaFormat < 1 || DeltaFormat > 3 || EndSize < StartSize ) + FT_INVALID_DATA; + + count = EndSize - StartSize + 1; + OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 ); /* DeltaValue */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_count */ + /* uses valid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupType, SubTableCount; + OTV_Validate_Func validate; + + + OTV_NAME_ENTER( "Lookup" ); + + OTV_LIMIT_CHECK( 6 ); + LookupType = FT_NEXT_USHORT( p ); + p += 2; /* skip LookupFlag */ + SubTableCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (type %d)\n", LookupType )); + + if ( LookupType == 0 || LookupType >= valid->type_count ) + FT_INVALID_DATA; + + validate = valid->type_funcs[LookupType - 1]; + + OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); + + OTV_LIMIT_CHECK( SubTableCount * 2 ); + + /* SubTable */ + for ( ; SubTableCount > 0; SubTableCount-- ) + validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "LookupList" ); + + OTV_LIMIT_CHECK( 2 ); + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + valid->lookup_count = LookupCount; + + /* Lookup */ + for ( ; LookupCount > 0; LookupCount-- ) + otv_Lookup_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + static FT_UInt + otv_LookupList_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "Feature" ); + + OTV_LIMIT_CHECK( 4 ); + p += 2; /* skip FeatureParams (unused) */ + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + /* LookupListIndex */ + for ( ; LookupCount > 0; LookupCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + static FT_UInt + otv_Feature_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /* sets valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "FeatureList" ); + + OTV_LIMIT_CHECK( 2 ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + valid->lookup_count = otv_LookupList_get_count( lookups ); + + /* FeatureRecord */ + for ( ; FeatureCount > 0; FeatureCount-- ) + { + p += 4; /* skip FeatureTag */ + + /* Feature */ + otv_Feature_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* uses valid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt ReqFeatureIndex; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "LangSys" ); + + OTV_LIMIT_CHECK( 6 ); + p += 2; /* skip LookupOrder (unused) */ + ReqFeatureIndex = FT_NEXT_USHORT( p ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= valid->extra1 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + /* FeatureIndex */ + for ( ; FeatureCount > 0; FeatureCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_UInt DefaultLangSys, LangSysCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "Script" ); + + OTV_LIMIT_CHECK( 4 ); + DefaultLangSys = FT_NEXT_USHORT( p ); + LangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); + + if ( DefaultLangSys != 0 ) + otv_LangSys_validate( table + DefaultLangSys, valid ); + + OTV_LIMIT_CHECK( LangSysCount * 6 ); + + /* LangSysRecord */ + for ( ; LangSysCount > 0; LangSysCount-- ) + { + p += 4; /* skip LangSysTag */ + + /* LangSys */ + otv_LangSys_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator valid ) + { + FT_UInt ScriptCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "ScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + ScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); + + OTV_LIMIT_CHECK( ScriptCount * 6 ); + + valid->extra1 = otv_Feature_get_count( features ); + + /* ScriptRecord */ + for ( ; ScriptCount > 0; ScriptCount-- ) + { + p += 4; /* skip ScriptTag */ + + otv_Script_validate( table + FT_NEXT_USHORT( p ), valid ); /* Script */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + u: uint16 + ux: unit16 [x] + + s: struct + sx: struct [x] + sxy: struct [x], using external y count + + x: uint16 x + + C: Coverage + + O: Offset + On: Offset (NULL) + Ox: Offset [x] + Onx: Offset (NULL) [x] + */ + + FT_LOCAL_DEF( void ) + otv_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count, Coverage; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( Count * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->extra1 (if > 0: array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + if ( valid->extra1 ) + { + for ( ; Count > 0; Count-- ) + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `ux' in the function's name is not really correct since only x-1 */ + /* elements are tested */ + + /* uses valid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count1, Count2; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Count1 = FT_NEXT_USHORT( p ); + Count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count1 = %d)\n", Count1 )); + OTV_TRACE(( " (Count2 = %d)\n", Count2 )); + + if ( Count1 == 0 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 ); + + for ( ; Count2 > 0; Count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= Count1 ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `uy' in the function's name is not really correct since only y-1 */ + /* elements are tested */ + + /* uses valid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BacktrackCount, InputCount, LookaheadCount; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + BacktrackCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); + + OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); + p += BacktrackCount * 2; + + InputCount = FT_NEXT_USHORT( p ); + if ( InputCount == 0 ) + FT_INVALID_DATA; + + OTV_TRACE(( " (InputCount = %d)\n", InputCount )); + + OTV_LIMIT_CHECK( InputCount * 2 ); + p += ( InputCount - 1 ) * 2; + + LookaheadCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); + + OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); + p += LookaheadCount * 2; + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 4 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage, ClassDef, ClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ClassDef = FT_NEXT_USHORT( p ); + ClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ClassDef_validate( table + ClassDef, valid ); + + OTV_LIMIT_CHECK( ClassSetCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = valid->lookup_count; + + for ( ; ClassSetCount > 0; ClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, valid ); + } + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt GlyphCount, Count, count1; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + GlyphCount = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); + + for ( count1 = GlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= GlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage; + FT_UInt BacktrackClassDef, InputClassDef, LookaheadClassDef; + FT_UInt ChainClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 10 ); + Coverage = FT_NEXT_USHORT( p ); + BacktrackClassDef = FT_NEXT_USHORT( p ); + InputClassDef = FT_NEXT_USHORT( p ); + LookaheadClassDef = FT_NEXT_USHORT( p ); + ChainClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + otv_ClassDef_validate( table + BacktrackClassDef, valid ); + otv_ClassDef_validate( table + InputClassDef, valid ); + otv_ClassDef_validate( table + LookaheadClassDef, valid ); + + OTV_LIMIT_CHECK( ChainClassSetCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = valid->lookup_count; + + for ( ; ChainClassSetCount > 0; ChainClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, valid ); + } + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount; + FT_UInt count1, count2; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + InputGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); + + OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); + + for ( count1 = InputGlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", count2 )); + + OTV_LIMIT_CHECK( count2 * 4 ); + + for ( ; count2 > 0; count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputGlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ) + { + FT_Bytes p = table + 8; + + + return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ) + { + FT_Bytes p, lookup; + FT_UInt count; + + + if ( !table ) + return 0; + + /* LookupList */ + p = table + 8; + table += FT_NEXT_USHORT( p ); + + /* LookupCount */ + p = table; + count = FT_NEXT_USHORT( p ); + + for ( ; count > 0; count-- ) + { + FT_Bytes oldp; + + + /* Lookup */ + lookup = table + FT_NEXT_USHORT( p ); + + oldp = p; + + /* LookupFlag */ + p = lookup + 2; + if ( FT_NEXT_USHORT( p ) & 0xFF00U ) + return 1; + + p = oldp; + } + + return 0; + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvcommn.h b/src/freetype2/otvalid/otvcommn.h new file mode 100644 index 0000000..be6ac69 --- /dev/null +++ b/src/freetype2/otvalid/otvcommn.h @@ -0,0 +1,436 @@ +/***************************************************************************/ +/* */ +/* otvcommn.h */ +/* */ +/* OpenType common tables validation (specification). */ +/* */ +/* Copyright 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 __OTVCOMMN_H__ +#define __OTVCOMMN_H__ + + +#include <ft2build.h> +#include "otvalid.h" +#include FT_INTERNAL_DEBUG_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct OTV_ValidatorRec_* OTV_Validator; + + typedef void (*OTV_Validate_Func)( FT_Bytes table, + OTV_Validator valid ); + + typedef struct OTV_ValidatorRec_ + { + FT_Validator root; + FT_UInt type_count; + OTV_Validate_Func* type_funcs; + + FT_UInt lookup_count; + FT_UInt glyph_count; + + FT_UInt nesting_level; + + OTV_Validate_Func func[3]; + + FT_UInt extra1; /* for passing parameters */ + FT_UInt extra2; + FT_Bytes extra3; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } OTV_ValidatorRec; + + +#undef FT_INVALID_ +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid->root, _prefix ## _error ) + +#define OTV_OPTIONAL_TABLE( _table ) FT_UShort _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_OFFSET( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_USHORT( p ); \ + FT_END_STMNT + +#define OTV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + (_count) > valid->root->limit ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define OTV_SIZE_CHECK( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( valid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" \ + "Invalid offset to optional table `%s'!\n" \ + "Set to zero.\n" \ + "\n", #_size )); \ + \ + /* always assume 16bit entities */ \ + _size = pp[0] = pp[1] = 0; \ + } \ + } \ + FT_END_STMNT + + +#define OTV_NAME_(x) #x +#define OTV_NAME(x) OTV_NAME_(x) + +#define OTV_FUNC_(x) x##Func +#define OTV_FUNC(x) OTV_FUNC_(x) + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + valid->debug_function_name[0] = OTV_NAME( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + valid->func[1] = OTV_FUNC( y ); \ + valid->debug_function_name[0] = OTV_NAME( x ); \ + valid->debug_function_name[1] = OTV_NAME( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + valid->func[1] = OTV_FUNC( y ); \ + valid->func[2] = OTV_FUNC( z ); \ + valid->debug_function_name[0] = OTV_NAME( x ); \ + valid->debug_function_name[1] = OTV_NAME( y ); \ + valid->debug_function_name[2] = OTV_NAME( z ); \ + FT_END_STMNT + +#define OTV_INIT valid->debug_indent = 0 + +#define OTV_ENTER \ + FT_BEGIN_STMNT \ + valid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4(( "%s table\n", \ + valid->debug_function_name[valid->nesting_level] )); \ + FT_END_STMNT + +#define OTV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + valid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define OTV_EXIT valid->debug_indent -= 2 + +#define OTV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + valid->func[1] = OTV_FUNC( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = OTV_FUNC( x ); \ + valid->func[1] = OTV_FUNC( y ); \ + valid->func[2] = OTV_FUNC( z ); \ + FT_END_STMNT + +#define OTV_INIT do ; while ( 0 ) +#define OTV_ENTER do ; while ( 0 ) +#define OTV_NAME_ENTER( name ) do ; while ( 0 ) +#define OTV_EXIT do ; while ( 0 ) + +#define OTV_TRACE( s ) do ; while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define OTV_RUN valid->func[0] + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator valid ); + + /* return first covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ); + + /* return last covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ); + + /* return number of covered glyphs */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator valid ); + + FT_LOCAL( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator valid ); + + /* lookups must already be validated */ + FT_LOCAL( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator valid ); + + /* features must already be validated */ + FT_LOCAL( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define ChainPosClassSetFunc otv_x_Ox +#define ChainPosRuleSetFunc otv_x_Ox +#define ChainSubClassSetFunc otv_x_Ox +#define ChainSubRuleSetFunc otv_x_Ox +#define JstfLangSysFunc otv_x_Ox +#define JstfMaxFunc otv_x_Ox +#define LigGlyphFunc otv_x_Ox +#define LigatureArrayFunc otv_x_Ox +#define LigatureSetFunc otv_x_Ox +#define PosClassSetFunc otv_x_Ox +#define PosRuleSetFunc otv_x_Ox +#define SubClassSetFunc otv_x_Ox +#define SubRuleSetFunc otv_x_Ox + + FT_LOCAL( void ) + otv_x_Ox ( FT_Bytes table, + OTV_Validator valid ); + +#define AlternateSubstFormat1Func otv_u_C_x_Ox +#define ChainContextPosFormat1Func otv_u_C_x_Ox +#define ChainContextSubstFormat1Func otv_u_C_x_Ox +#define ContextPosFormat1Func otv_u_C_x_Ox +#define ContextSubstFormat1Func otv_u_C_x_Ox +#define LigatureSubstFormat1Func otv_u_C_x_Ox +#define MultipleSubstFormat1Func otv_u_C_x_Ox + + FT_LOCAL( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator valid ); + +#define AlternateSetFunc otv_x_ux +#define AttachPointFunc otv_x_ux +#define ExtenderGlyphFunc otv_x_ux +#define JstfGPOSModListFunc otv_x_ux +#define JstfGSUBModListFunc otv_x_ux +#define SequenceFunc otv_x_ux + + FT_LOCAL( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator valid ); + +#define PosClassRuleFunc otv_x_y_ux_sy +#define PosRuleFunc otv_x_y_ux_sy +#define SubClassRuleFunc otv_x_y_ux_sy +#define SubRuleFunc otv_x_y_ux_sy + + FT_LOCAL( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator valid ); + +#define ChainPosClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainPosRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubRuleFunc otv_x_ux_y_uy_z_uz_p_sp + + FT_LOCAL( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator valid ); + +#define ContextPosFormat2Func otv_u_O_O_x_Onx +#define ContextSubstFormat2Func otv_u_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ); + +#define ContextPosFormat3Func otv_u_x_y_Ox_sy +#define ContextSubstFormat3Func otv_u_x_y_Ox_sy + + FT_LOCAL( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator valid ); + +#define ChainContextPosFormat2Func otv_u_O_O_O_O_x_Onx +#define ChainContextSubstFormat2Func otv_u_O_O_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ); + +#define ChainContextPosFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp +#define ChainContextSubstFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp + + FT_LOCAL( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator valid ); + + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ); + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ); + + /* */ + +FT_END_HEADER + +#endif /* __OTVCOMMN_H__ */ + + +/* END */ diff --git a/src/freetype2/otvalid/otverror.h b/src/freetype2/otvalid/otverror.h new file mode 100644 index 0000000..041b538 --- /dev/null +++ b/src/freetype2/otvalid/otverror.h @@ -0,0 +1,43 @@ +/***************************************************************************/ +/* */ +/* otverror.h */ +/* */ +/* OpenType validation module error codes (specification only). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the OpenType validation module error */ + /* enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __OTVERROR_H__ +#define __OTVERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX OTV_Err_ +#define FT_ERR_BASE FT_Mod_Err_OTvalid + +#define FT_KEEP_ERR_PREFIX + +#include FT_ERRORS_H + +#endif /* __OTVERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/otvalid/otvgdef.c b/src/freetype2/otvalid/otvgdef.c new file mode 100644 index 0000000..7d24902 --- /dev/null +++ b/src/freetype2/otvalid/otvgdef.c @@ -0,0 +1,219 @@ +/***************************************************************************/ +/* */ +/* otvgdef.c */ +/* */ +/* OpenType GDEF table validation (body). */ +/* */ +/* Copyright 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 "otvalid.h" +#include "otvcommn.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_otvgdef + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AttachListFunc otv_O_x_Ox +#define LigCaretListFunc otv_O_x_Ox + + /* sets valid->extra1 (0) */ + + static void + otv_O_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes Coverage; + FT_UInt GlyphCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( Coverage, valid ); + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = 0; + + for ( ; GlyphCount > 0; GlyphCount-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LIGATURE CARETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define CaretValueFunc otv_CaretValue_validate + + static void + otv_CaretValue_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt CaretValueFormat; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + + CaretValueFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); + + switch ( CaretValueFormat ) + { + case 1: /* CaretValueFormat1 */ + /* skip Coordinate, no test */ + break; + + case 2: /* CaretValueFormat2 */ + /* skip CaretValuePoint, no test */ + break; + + case 3: /* CaretValueFormat3 */ + p += 2; /* skip Coordinate */ + + OTV_LIMIT_CHECK( 2 ); + + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GDEF TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_Bool need_MarkAttachClassDef; + + OTV_OPTIONAL_TABLE( GlyphClassDef ); + OTV_OPTIONAL_TABLE( AttachListOffset ); + OTV_OPTIONAL_TABLE( LigCaretListOffset ); + OTV_OPTIONAL_TABLE( MarkAttachClassDef ); + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GDEF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 12 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + /* MarkAttachClassDef has been added to the OpenType */ + /* specification without increasing GDEF's version, */ + /* so we use this ugly hack to find out whether the */ + /* table is needed actually. */ + + need_MarkAttachClassDef = FT_BOOL( + otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || + otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); + + if ( need_MarkAttachClassDef ) + table_size = 12; /* OpenType >= 1.2 */ + else + table_size = 10; /* OpenType < 1.2 */ + + OTV_OPTIONAL_OFFSET( GlyphClassDef ); + OTV_SIZE_CHECK( GlyphClassDef ); + if ( GlyphClassDef ) + otv_ClassDef_validate( table + GlyphClassDef, valid ); + + OTV_OPTIONAL_OFFSET( AttachListOffset ); + OTV_SIZE_CHECK( AttachListOffset ); + if ( AttachListOffset ) + { + OTV_NEST2( AttachList, AttachPoint ); + OTV_RUN( table + AttachListOffset, valid ); + } + + OTV_OPTIONAL_OFFSET( LigCaretListOffset ); + OTV_SIZE_CHECK( LigCaretListOffset ); + if ( LigCaretListOffset ) + { + OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); + OTV_RUN( table + LigCaretListOffset, valid ); + } + + if ( need_MarkAttachClassDef ) + { + OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); + OTV_SIZE_CHECK( MarkAttachClassDef ); + if ( MarkAttachClassDef ) + otv_ClassDef_validate( table + MarkAttachClassDef, valid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvgpos.c b/src/freetype2/otvalid/otvgpos.c new file mode 100644 index 0000000..ed34705 --- /dev/null +++ b/src/freetype2/otvalid/otvgpos.c @@ -0,0 +1,1013 @@ +/***************************************************************************/ +/* */ +/* otvgpos.c */ +/* */ +/* OpenType GPOS table validation (body). */ +/* */ +/* Copyright 2002, 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 "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.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_otvgpos + + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ); + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define BaseArrayFunc otv_x_sxy +#define LigatureAttachFunc otv_x_sxy +#define Mark2ArrayFunc otv_x_sxy + + /* uses valid->extra1 (counter) */ + /* uses valid->extra2 (boolean to handle NULL anchor field) */ + + static void + otv_x_sxy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count, count1, table_size; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); + + table_size = Count * valid->extra1 * 2 + 2; + + for ( ; Count > 0; Count-- ) + for ( count1 = valid->extra1; count1 > 0; count1-- ) + { + OTV_OPTIONAL_TABLE( anchor_offset ); + + + OTV_OPTIONAL_OFFSET( anchor_offset ); + + if ( valid->extra2 ) + { + OTV_SIZE_CHECK( anchor_offset ); + if ( anchor_offset ) + otv_Anchor_validate( table + anchor_offset, valid ); + } + else + otv_Anchor_validate( table + anchor_offset, valid ); + } + + OTV_EXIT; + } + + +#define MarkBasePosFormat1Func otv_u_O_O_u_O_O +#define MarkLigPosFormat1Func otv_u_O_O_u_O_O +#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O + + /* sets valid->extra1 (class count) */ + + static void + otv_u_O_O_u_O_O( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage1, Coverage2, ClassCount; + FT_UInt Array1, Array2; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip PosFormat */ + + OTV_LIMIT_CHECK( 10 ); + Coverage1 = FT_NEXT_USHORT( p ); + Coverage2 = FT_NEXT_USHORT( p ); + ClassCount = FT_NEXT_USHORT( p ); + Array1 = FT_NEXT_USHORT( p ); + Array2 = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage1, valid ); + otv_Coverage_validate( table + Coverage2, valid ); + + otv_MarkArray_validate( table + Array1, valid ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = ClassCount; + + func( table + Array2, valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALUE RECORDS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_UInt + otv_value_length( FT_UInt format ) + { + FT_UInt count; + + + count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); + count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); + count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); + + return count * 2; + } + + + /* uses valid->extra3 (pointer to base table) */ + + static void + otv_ValueRecord_validate( FT_Bytes table, + FT_UInt format, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt count; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Int loop; + FT_ULong res = 0; + + + OTV_NAME_ENTER( "ValueRecord" ); + + /* display `format' in dual representation */ + for ( loop = 7; loop >= 0; loop-- ) + { + res <<= 4; + res += ( format >> loop ) & 1; + } + + OTV_TRACE(( " (format 0b%08lx)\n", res )); +#endif + + if ( format >= 0x100 ) + FT_INVALID_DATA; + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + /* XPlacement, YPlacement, XAdvance, YAdvance */ + OTV_LIMIT_CHECK( 2 ); + p += 2; + } + + format >>= 1; + } + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( device ); + + + /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ + OTV_LIMIT_CHECK( 2 ); + OTV_OPTIONAL_OFFSET( device ); + + /* XXX: this value is usually too small, especially if the current */ + /* ValueRecord is part of an array -- getting the correct table */ + /* size is probably not worth the trouble */ + + table_size = p - valid->extra3; + + OTV_SIZE_CHECK( device ); + if ( device ) + otv_Device_validate( valid->extra3 + device, valid ); + } + format >>= 1; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ANCHORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt AnchorFormat; + + + OTV_NAME_ENTER( "Anchor"); + + OTV_LIMIT_CHECK( 6 ); + AnchorFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", AnchorFormat )); + + p += 4; /* skip XCoordinate and YCoordinate */ + + switch ( AnchorFormat ) + { + case 1: + break; + + case 2: + OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ + break; + + case 3: + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( XDeviceTable ); + OTV_OPTIONAL_TABLE( YDeviceTable ); + + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( XDeviceTable ); + OTV_OPTIONAL_OFFSET( YDeviceTable ); + + table_size = 6 + 4; + + OTV_SIZE_CHECK( XDeviceTable ); + if ( XDeviceTable ) + otv_Device_validate( table + XDeviceTable, valid ); + + OTV_SIZE_CHECK( YDeviceTable ); + if ( YDeviceTable ) + otv_Device_validate( table + YDeviceTable, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK ARRAYS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt MarkCount; + + + OTV_NAME_ENTER( "MarkArray" ); + + OTV_LIMIT_CHECK( 2 ); + MarkCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + + OTV_LIMIT_CHECK( MarkCount * 4 ); + + /* MarkRecord */ + for ( ; MarkCount > 0; MarkCount-- ) + { + p += 2; /* skip Class */ + /* MarkAnchor */ + otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_SinglePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "SinglePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* SinglePosFormat1 */ + { + FT_UInt Coverage, ValueFormat; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ + } + break; + + case 2: /* SinglePosFormat2 */ + { + FT_UInt Coverage, ValueFormat, ValueCount, len_value; + + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + ValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + + len_value = otv_value_length( ValueFormat ); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( ValueCount * len_value ); + + /* Value */ + for ( ; ValueCount > 0; ValueCount-- ) + { + otv_ValueRecord_validate( p, ValueFormat, valid ); + p += len_value; + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_PairSet_validate( FT_Bytes table, + FT_UInt format1, + FT_UInt format2, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt value_len1, value_len2, PairValueCount; + + + OTV_NAME_ENTER( "PairSet" ); + + OTV_LIMIT_CHECK( 2 ); + PairValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + + value_len1 = otv_value_length( format1 ); + value_len2 = otv_value_length( format2 ); + + OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); + + /* PairValueRecord */ + for ( ; PairValueCount > 0; PairValueCount-- ) + { + p += 2; /* skip SecondGlyph */ + + if ( format1 ) + otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ + p += value_len1; + + if ( format2 ) + otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ + p += value_len2; + } + + OTV_EXIT; + } + + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_PairPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "PairPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* PairPosFormat1 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; + + + OTV_LIMIT_CHECK( 8 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + PairSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( PairSetCount * 2 ); + + /* PairSetOffset */ + for ( ; PairSetCount > 0; PairSetCount-- ) + otv_PairSet_validate( table + FT_NEXT_USHORT( p ), + ValueFormat1, ValueFormat2, valid ); + } + break; + + case 2: /* PairPosFormat2 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; + FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; + + + OTV_LIMIT_CHECK( 14 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + ClassDef1 = FT_NEXT_USHORT( p ); + ClassDef2 = FT_NEXT_USHORT( p ); + ClassCount1 = FT_NEXT_USHORT( p ); + ClassCount2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + + len_value1 = otv_value_length( ValueFormat1 ); + len_value2 = otv_value_length( ValueFormat2 ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ClassDef_validate( table + ClassDef1, valid ); + otv_ClassDef_validate( table + ClassDef2, valid ); + + OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * + ( len_value1 + len_value2 ) ); + + /* Class1Record */ + for ( ; ClassCount1 > 0; ClassCount1-- ) + { + /* Class2Record */ + for ( count = ClassCount2; count > 0; count-- ) + { + if ( ValueFormat1 ) + /* Value1 */ + otv_ValueRecord_validate( p, ValueFormat1, valid ); + p += len_value1; + + if ( ValueFormat2 ) + /* Value2 */ + otv_ValueRecord_validate( p, ValueFormat2, valid ); + p += len_value2; + } + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_CursivePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "CursivePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* CursivePosFormat1 */ + { + FT_UInt table_size; + FT_UInt Coverage, EntryExitCount; + + OTV_OPTIONAL_TABLE( EntryAnchor ); + OTV_OPTIONAL_TABLE( ExitAnchor ); + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + EntryExitCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( EntryExitCount * 4 ); + + table_size = EntryExitCount * 4 + 4; + + /* EntryExitRecord */ + for ( ; EntryExitCount > 0; EntryExitCount-- ) + { + OTV_OPTIONAL_OFFSET( EntryAnchor ); + OTV_OPTIONAL_OFFSET( ExitAnchor ); + + OTV_SIZE_CHECK( EntryAnchor ); + if ( EntryAnchor ) + otv_Anchor_validate( table + EntryAnchor, valid ); + + OTV_SIZE_CHECK( ExitAnchor ); + if ( ExitAnchor ) + otv_Anchor_validate( table + ExitAnchor, valid ); + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkBasePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkBasePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkBasePosFormat1, BaseArray ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (1) */ + + static void + otv_MarkLigPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkLigPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 1; + OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkMarkPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkMarkPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ChainContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ChainContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ChainContextPosFormat1, + ChainPosRuleSet, ChainPosRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextPosFormat2, + ChainPosClassSet, ChainPosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ChainContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 9 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_funcs */ + + static void + otv_ExtensionPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ExtensionPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* ExtensionPosFormat1 */ + { + FT_UInt ExtensionLookupType, ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) + FT_INVALID_DATA; + + validate = valid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gpos_validate_funcs[9] = + { + otv_SinglePos_validate, + otv_PairPos_validate, + otv_CursivePos_validate, + otv_MarkBasePos_validate, + otv_MarkLigPos_validate, + otv_MarkMarkPos_validate, + otv_ContextPos_validate, + otv_ChainContextPos_validate, + otv_ExtensionPos_validate + }; + + + /* sets valid->type_count */ + /* sets valid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ) + { + valid->type_count = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + + otv_Lookup_validate( table, valid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt ScriptList, FeatureList, LookupList; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GPOS table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + valid->type_count = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + valid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + valid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + valid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvgpos.h b/src/freetype2/otvalid/otvgpos.h new file mode 100644 index 0000000..14ca408 --- /dev/null +++ b/src/freetype2/otvalid/otvgpos.h @@ -0,0 +1,36 @@ +/***************************************************************************/ +/* */ +/* otvgpos.h */ +/* */ +/* OpenType GPOS table validator (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVGPOS_H__ +#define __OTVGPOS_H__ + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ); + + +FT_END_HEADER + +#endif /* __OTVGPOS_H__ */ + + +/* END */ diff --git a/src/freetype2/otvalid/otvgsub.c b/src/freetype2/otvalid/otvgsub.c new file mode 100644 index 0000000..91dae0b --- /dev/null +++ b/src/freetype2/otvalid/otvgsub.c @@ -0,0 +1,584 @@ +/***************************************************************************/ +/* */ +/* otvgsub.c */ +/* */ +/* OpenType GSUB table validation (body). */ +/* */ +/* Copyright 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 "otvalid.h" +#include "otvcommn.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_otvgsub + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->glyph_count */ + + static void + otv_SingleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "SingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* SingleSubstFormat1 */ + { + FT_Bytes Coverage; + FT_Int DeltaGlyphID; + FT_Long idx; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + DeltaGlyphID = FT_NEXT_SHORT( p ); + + otv_Coverage_validate( Coverage, valid ); + + idx = otv_Coverage_get_first( Coverage ) + DeltaGlyphID; + if ( idx < 0 ) + FT_INVALID_DATA; + + idx = otv_Coverage_get_last( Coverage ) + DeltaGlyphID; + if ( (FT_UInt)idx >= valid->glyph_count ) + FT_INVALID_DATA; + } + break; + + case 2: /* SingleSubstFormat2 */ + { + FT_UInt Coverage, GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) + FT_INVALID_DATA; + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (glyph count) */ + + static void + otv_MultipleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "MultipleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + valid->extra1 = valid->glyph_count; + OTV_NEST2( MultipleSubstFormat1, Sequence ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (glyph count) */ + + static void + otv_AlternateSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "AlternateSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + valid->extra1 = valid->glyph_count; + OTV_NEST2( AlternateSubstFormat1, AlternateSet ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define LigatureFunc otv_Ligature_validate + + /* uses valid->glyph_count */ + + static void + otv_Ligature_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LigatureGlyph, CompCount; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + LigatureGlyph = FT_NEXT_USHORT( p ); + if ( LigatureGlyph >= valid->glyph_count ) + FT_INVALID_DATA; + + CompCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (CompCount = %d)\n", CompCount )); + + if ( CompCount == 0 ) + FT_INVALID_DATA; + + CompCount--; + + OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ + + /* no need to check the Component glyph indices */ + + OTV_EXIT; + } + + + static void + otv_LigatureSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "LigatureSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ContextSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ContextSubstFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ChainContextSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ChainContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ChainContextSubstFormat1, + ChainSubRuleSet, ChainSubRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextSubstFormat2, + ChainSubClassSet, ChainSubClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ChainContextSubstFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_funcs */ + + static void + otv_ExtensionSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ExtensionSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ExtensionSubstFormat1 */ + { + FT_UInt ExtensionLookupType, ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || + ExtensionLookupType == 7 || + ExtensionLookupType > 8 ) + FT_INVALID_DATA; + + validate = valid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->glyph_count */ + + static void + otv_ReverseChainSingleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table, Coverage; + FT_UInt SubstFormat; + FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; + + + OTV_NAME_ENTER( "ReverseChainSingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ReverseChainSingleSubstFormat1 */ + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + otv_Coverage_validate( Coverage, valid ); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) + FT_INVALID_DATA; + + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gsub_validate_funcs[8] = + { + otv_SingleSubst_validate, + otv_MultipleSubst_validate, + otv_AlternateSubst_validate, + otv_LigatureSubst_validate, + otv_ContextSubst_validate, + otv_ChainContextSubst_validate, + otv_ExtensionSubst_validate, + otv_ReverseChainSingleSubst_validate + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->type_count */ + /* sets valid->type_funcs */ + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt ScriptList, FeatureList, LookupList; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GSUB table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + valid->type_count = 8; + valid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; + valid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + valid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + valid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvjstf.c b/src/freetype2/otvalid/otvjstf.c new file mode 100644 index 0000000..80b8dd6 --- /dev/null +++ b/src/freetype2/otvalid/otvjstf.c @@ -0,0 +1,258 @@ +/***************************************************************************/ +/* */ +/* otvjstf.c */ +/* */ +/* OpenType JSTF table validation (body). */ +/* */ +/* Copyright 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 "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.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_otvjstf + + +#define JstfPriorityFunc otv_JstfPriority_validate +#define JstfLookupFunc otv_GPOS_subtable_validate + + /* uses valid->extra1 (GSUB lookup count) */ + /* uses valid->extra2 (GPOS lookup count) */ + /* sets valid->extra1 (counter) */ + + static void + otv_JstfPriority_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt gsub_lookup_count, gpos_lookup_count; + + OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); + OTV_OPTIONAL_TABLE( ExtensionJstfMax ); + + + OTV_ENTER; + OTV_TRACE(( "JstfPriority table\n" )); + + OTV_LIMIT_CHECK( 20 ); + + gsub_lookup_count = valid->extra1; + gpos_lookup_count = valid->extra2; + + table_size = 20; + + valid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); + OTV_SIZE_CHECK( ShrinkageEnableGSUB ); + if ( ShrinkageEnableGSUB ) + otv_x_ux( table + ShrinkageEnableGSUB, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); + OTV_SIZE_CHECK( ShrinkageDisableGSUB ); + if ( ShrinkageDisableGSUB ) + otv_x_ux( table + ShrinkageDisableGSUB, valid ); + + valid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); + OTV_SIZE_CHECK( ShrinkageEnableGPOS ); + if ( ShrinkageEnableGPOS ) + otv_x_ux( table + ShrinkageEnableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); + OTV_SIZE_CHECK( ShrinkageDisableGPOS ); + if ( ShrinkageDisableGPOS ) + otv_x_ux( table + ShrinkageDisableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); + OTV_SIZE_CHECK( ShrinkageJstfMax ); + if ( ShrinkageJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ShrinkageJstfMax, valid ); + } + + valid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); + OTV_SIZE_CHECK( ExtensionEnableGSUB ); + if ( ExtensionEnableGSUB ) + otv_x_ux( table + ExtensionEnableGSUB, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); + OTV_SIZE_CHECK( ExtensionDisableGSUB ); + if ( ExtensionDisableGSUB ) + otv_x_ux( table + ExtensionDisableGSUB, valid ); + + valid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); + OTV_SIZE_CHECK( ExtensionEnableGPOS ); + if ( ExtensionEnableGPOS ) + otv_x_ux( table + ExtensionEnableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); + OTV_SIZE_CHECK( ExtensionDisableGPOS ); + if ( ExtensionDisableGPOS ) + otv_x_ux( table + ExtensionDisableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); + OTV_SIZE_CHECK( ExtensionJstfMax ); + if ( ExtensionJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ExtensionJstfMax, valid ); + } + + valid->extra1 = gsub_lookup_count; + valid->extra2 = gpos_lookup_count; + + OTV_EXIT; + } + + + /* sets valid->extra (glyph count) */ + /* sets valid->func1 (otv_JstfPriority_validate) */ + + static void + otv_JstfScript_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt JstfLangSysCount; + + OTV_OPTIONAL_TABLE( ExtGlyph ); + OTV_OPTIONAL_TABLE( DefJstfLangSys ); + + + OTV_NAME_ENTER( "JstfScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( ExtGlyph ); + OTV_OPTIONAL_OFFSET( DefJstfLangSys ); + JstfLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); + + table_size = JstfLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( ExtGlyph ); + if ( ExtGlyph ) + { + valid->extra1 = valid->glyph_count; + OTV_NEST1( ExtenderGlyph ); + OTV_RUN( table + ExtGlyph, valid ); + } + + OTV_SIZE_CHECK( DefJstfLangSys ); + if ( DefJstfLangSys ) + { + OTV_NEST2( JstfLangSys, JstfPriority ); + OTV_RUN( table + DefJstfLangSys, valid ); + } + + OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); + + /* JstfLangSysRecord */ + OTV_NEST2( JstfLangSys, JstfPriority ); + for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) + { + p += 4; /* skip JstfLangSysTag */ + + OTV_RUN( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (GSUB lookup count) */ + /* sets valid->extra2 (GPOS lookup count) */ + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt JstfScriptCount; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating JSTF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + JstfScriptCount = FT_NEXT_USHORT( p ); + + FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); + + OTV_LIMIT_CHECK( JstfScriptCount * 6 ); + + if ( gsub ) + valid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); + else + valid->extra1 = 0; + + if ( gpos ) + valid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); + else + valid->extra2 = 0; + + valid->glyph_count = glyph_count; + + /* JstfScriptRecord */ + for ( ; JstfScriptCount > 0; JstfScriptCount-- ) + { + p += 4; /* skip JstfScriptTag */ + + /* JstfScript */ + otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/src/freetype2/otvalid/otvmod.c b/src/freetype2/otvalid/otvmod.c new file mode 100644 index 0000000..157272f --- /dev/null +++ b/src/freetype2/otvalid/otvmod.c @@ -0,0 +1,242 @@ +/***************************************************************************/ +/* */ +/* otvmod.c */ +/* */ +/* FreeType's OpenType validation module implementation (body). */ +/* */ +/* Copyright 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_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H +#include FT_OPENTYPE_VALIDATE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_OPENTYPE_VALIDATE_H + +#include "otvmod.h" +#include "otvalid.h" +#include "otvcommn.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_otvmodule + + + static FT_Error + otv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( error == OTV_Err_Table_Missing ) + return OTV_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_ALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + + static FT_Error + otv_validate( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *ot_base, + FT_Bytes *ot_gdef, + FT_Bytes *ot_gpos, + FT_Bytes *ot_gsub, + FT_Bytes *ot_jstf ) + { + FT_Error error = OTV_Err_Ok; + FT_Byte* volatile base; + FT_Byte* volatile gdef; + FT_Byte* volatile gpos; + FT_Byte* volatile gsub; + FT_Byte* volatile jstf; + FT_ULong len_base, len_gdef, len_gpos, len_gsub, len_jstf; + FT_ValidatorRec volatile valid; + + + base = gdef = gpos = gsub = jstf = NULL; + len_base = len_gdef = len_gpos = len_gsub = len_jstf = 0; + + /* load tables */ + + if ( ot_flags & FT_VALIDATE_BASE ) + { + error = otv_load_table( face, TTAG_BASE, &base, &len_base ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GDEF ) + { + error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GPOS ) + { + error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GSUB ) + { + error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_JSTF ) + { + error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf ); + if ( error ) + goto Exit; + } + + /* validate tables */ + + if ( base ) + { + ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_BASE_validate( base, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gpos ) + { + ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GPOS_validate( gpos, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gsub ) + { + ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GSUB_validate( gsub, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gdef ) + { + ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GDEF_validate( gdef, gsub, gpos, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( jstf ) + { + ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_JSTF_validate( jstf, gsub, gpos, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ot_base = (FT_Bytes)base; + *ot_gdef = (FT_Bytes)gdef; + *ot_gpos = (FT_Bytes)gpos; + *ot_gsub = (FT_Bytes)gsub; + *ot_jstf = (FT_Bytes)jstf; + + Exit: + if ( error ) { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( base ); + FT_FREE( gdef ); + FT_FREE( gpos ); + FT_FREE( gsub ); + FT_FREE( jstf ); + } + + return error; + } + + + static + const FT_Service_OTvalidateRec otvalid_interface = + { + otv_validate + }; + + + static + const FT_ServiceDescRec otvalid_services[] = + { + { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + otvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( otvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class otv_module_class = + { + 0, + sizeof( FT_ModuleRec ), + "otvalid", + 0x10000L, + 0x20000L, + + 0, /* module-specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) otvalid_get_service + }; + + +/* END */ diff --git a/src/freetype2/otvalid/otvmod.h b/src/freetype2/otvalid/otvmod.h new file mode 100644 index 0000000..1bfc189 --- /dev/null +++ b/src/freetype2/otvalid/otvmod.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* otvmod.h */ +/* */ +/* FreeType's OpenType validation module implementation */ +/* (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVMOD_H__ +#define __OTVMOD_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) otv_module_class; + + +FT_END_HEADER + +#endif /* __OTVMOD_H__ */ + + +/* END */ diff --git a/src/freetype2/pcf/README b/src/freetype2/pcf/README new file mode 100644 index 0000000..cc1480b --- /dev/null +++ b/src/freetype2/pcf/README @@ -0,0 +1,114 @@ + FreeType font driver for PCF fonts + + Francesco Zappa Nardelli + <francesco.zappa.nardelli@ens.fr> + + +Introduction +************ + +PCF (Portable Compiled Format) is a binary bitmap font format, largely used +in X world. This code implements a PCF driver for the FreeType library. +Glyph images are loaded into memory only on demand, thus leading to a small +memory footprint. + +Information on the PCF font format can only be worked out from +`pcfread.c', and `pcfwrite.c', to be found, for instance, in the XFree86 +(www.xfree86.org) source tree (xc/lib/font/bitmap/). + +Many good bitmap fonts in bdf format come with XFree86: they can be +compiled into the pcf format using the `bdftopcf' utility. + + +Supported hardware +****************** + +The driver has been tested on linux/x86 and sunos5.5/sparc. In both +cases the compiler was gcc. When back in Paris, I will test it also +on linux/alpha. + + +Encodings +********* + +The variety of encodings that accompanies pcf fonts appears to encompass the +small set defined in freetype.h. On the other hand, each pcf font defines +two properties that specify encoding and registry. + +I decided to make these two properties directly accessible, leaving to the +client application the work of interpreting them. For instance: + + #include "pcftypes.h" /* include/freetype/internal/pcftypes.h */ + + FT_Face face; + PCF_Public_Face pcfface; + + FT_New_Face( library,..., &face ); + + pcfface = (PCF_Public_Face)face; + + if ((pcfface->charset_registry == "ISO10646") && + (pcfface->charset_encoding) == "1")) [..] + +Thus the driver always export `ft_encoding_none' as +face->charmap.encoding. FT_Get_Char_Index() behavior is unmodified, that +is, it converts the ULong value given as argument into the corresponding +glyph number. + + +Known problems +************** + +- dealing explicitly with encodings breaks the uniformity of freetype2 + api. + +- except for encodings properties, client applications have no + visibility of the PCF_Face object. This means that applications + cannot directly access font tables and are obliged to trust + FreeType. + +- currently, glyph names and ink_metrics are ignored. + +I plan to give full visibility of the PCF_Face object in the next +release of the driver, thus implementing also glyph names and +ink_metrics. + +- height is defined as (ascent - descent). Is this correct? + +- if unable to read size information from the font, PCF_Init_Face + sets available_size->width and available_size->height to 12. + +- too many english grammar errors in the readme file :-( + + +License +******* + +Copyright (C) 2000 by Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Credits +******* + +Keith Packard wrote the pcf driver found in XFree86. His work is at +the same time the specification and the sample implementation of the +PCF format. Undoubtedly, this driver is inspired from his work. diff --git a/src/freetype2/pcf/pcf.c b/src/freetype2/pcf/pcf.c new file mode 100644 index 0000000..11d5b7b --- /dev/null +++ b/src/freetype2/pcf/pcf.c @@ -0,0 +1,36 @@ +/* pcf.c + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2003 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + + +#include <ft2build.h> +#include "pcfutil.c" +#include "pcfread.c" +#include "pcfdrivr.c" + +/* END */ diff --git a/src/freetype2/pcf/pcf.h b/src/freetype2/pcf/pcf.h new file mode 100644 index 0000000..9d2d8e0 --- /dev/null +++ b/src/freetype2/pcf/pcf.h @@ -0,0 +1,237 @@ +/* pcf.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002, 2003, 2006 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCF_H__ +#define __PCF_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + typedef struct PCF_TableRec_ + { + FT_ULong type; + FT_ULong format; + FT_ULong size; + FT_ULong offset; + + } PCF_TableRec, *PCF_Table; + + + typedef struct PCF_TocRec_ + { + FT_ULong version; + FT_ULong count; + PCF_Table tables; + + } PCF_TocRec, *PCF_Toc; + + + typedef struct PCF_ParsePropertyRec_ + { + FT_Long name; + FT_Byte isString; + FT_Long value; + + } PCF_ParsePropertyRec, *PCF_ParseProperty; + + + typedef struct PCF_PropertyRec_ + { + FT_String* name; + FT_Byte isString; + + union + { + FT_String* atom; + FT_Long integer; + FT_ULong cardinal; + + } value; + + } PCF_PropertyRec, *PCF_Property; + + + typedef struct PCF_Compressed_MetricRec_ + { + FT_Byte leftSideBearing; + FT_Byte rightSideBearing; + FT_Byte characterWidth; + FT_Byte ascent; + FT_Byte descent; + + } PCF_Compressed_MetricRec, *PCF_Compressed_Metric; + + + typedef struct PCF_MetricRec_ + { + FT_Short leftSideBearing; + FT_Short rightSideBearing; + FT_Short characterWidth; + FT_Short ascent; + FT_Short descent; + FT_Short attributes; + FT_ULong bits; + + } PCF_MetricRec, *PCF_Metric; + + + typedef struct PCF_AccelRec_ + { + FT_Byte noOverlap; + FT_Byte constantMetrics; + FT_Byte terminalFont; + FT_Byte constantWidth; + FT_Byte inkInside; + FT_Byte inkMetrics; + FT_Byte drawDirection; + FT_Long fontAscent; + FT_Long fontDescent; + FT_Long maxOverlap; + PCF_MetricRec minbounds; + PCF_MetricRec maxbounds; + PCF_MetricRec ink_minbounds; + PCF_MetricRec ink_maxbounds; + + } PCF_AccelRec, *PCF_Accel; + + + typedef struct PCF_EncodingRec_ + { + FT_Long enc; + FT_UShort glyph; + + } PCF_EncodingRec, *PCF_Encoding; + + + typedef struct PCF_FaceRec_ + { + FT_FaceRec root; + + FT_StreamRec gzip_stream; + FT_Stream gzip_source; + + char* charset_encoding; + char* charset_registry; + + PCF_TocRec toc; + PCF_AccelRec accel; + + int nprops; + PCF_Property properties; + + FT_Long nmetrics; + PCF_Metric metrics; + FT_Long nencodings; + PCF_Encoding encodings; + + FT_Short defaultChar; + + FT_ULong bitmapsFormat; + + FT_CharMap charmap_handle; + FT_CharMapRec charmap; /* a single charmap per face */ + + } PCF_FaceRec, *PCF_Face; + + + /* macros for pcf font format */ + +#define LSBFirst 0 +#define MSBFirst 1 + +#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \ + ( 'c' << 16 ) | \ + ( 'f' << 8 ) | 1 ) +#define PCF_FORMAT_MASK 0xFFFFFF00UL + +#define PCF_DEFAULT_FORMAT 0x00000000UL +#define PCF_INKBOUNDS 0x00000200UL +#define PCF_ACCEL_W_INKBOUNDS 0x00000100UL +#define PCF_COMPRESSED_METRICS 0x00000100UL + +#define PCF_FORMAT_MATCH( a, b ) \ + ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) ) + +#define PCF_GLYPH_PAD_MASK ( 3 << 0 ) +#define PCF_BYTE_MASK ( 1 << 2 ) +#define PCF_BIT_MASK ( 1 << 3 ) +#define PCF_SCAN_UNIT_MASK ( 3 << 4 ) + +#define PCF_BYTE_ORDER( f ) \ + ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_BIT_ORDER( f ) \ + ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_GLYPH_PAD_INDEX( f ) \ + ( (f) & PCF_GLYPH_PAD_MASK ) +#define PCF_GLYPH_PAD( f ) \ + ( 1 << PCF_GLYPH_PAD_INDEX( f ) ) +#define PCF_SCAN_UNIT_INDEX( f ) \ + ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 ) +#define PCF_SCAN_UNIT( f ) \ + ( 1 << PCF_SCAN_UNIT_INDEX( f ) ) +#define PCF_FORMAT_BITS( f ) \ + ( (f) & ( PCF_GLYPH_PAD_MASK | \ + PCF_BYTE_MASK | \ + PCF_BIT_MASK | \ + PCF_SCAN_UNIT_MASK ) ) + +#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 ) +#define PCF_INDEX_TO_SIZE( b ) ( 1 << b ) + +#define PCF_FORMAT( bit, byte, glyph, scan ) \ + ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \ + ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \ + ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \ + ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) ) + +#define PCF_PROPERTIES ( 1 << 0 ) +#define PCF_ACCELERATORS ( 1 << 1 ) +#define PCF_METRICS ( 1 << 2 ) +#define PCF_BITMAPS ( 1 << 3 ) +#define PCF_INK_METRICS ( 1 << 4 ) +#define PCF_BDF_ENCODINGS ( 1 << 5 ) +#define PCF_SWIDTHS ( 1 << 6 ) +#define PCF_GLYPH_NAMES ( 1 << 7 ) +#define PCF_BDF_ACCELERATORS ( 1 << 8 ) + +#define GLYPHPADOPTIONS 4 /* I'm not sure about this */ + + FT_LOCAL( FT_Error ) + pcf_load_font( FT_Stream, + PCF_Face ); + +FT_END_HEADER + +#endif /* __PCF_H__ */ + + +/* END */ diff --git a/src/freetype2/pcf/pcfdrivr.c b/src/freetype2/pcf/pcfdrivr.c new file mode 100644 index 0000000..c0f0e49 --- /dev/null +++ b/src/freetype2/pcf/pcfdrivr.c @@ -0,0 +1,668 @@ +/* pcfdrivr.c + + FreeType font driver for pcf files + + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include <ft2build.h> + +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_OBJECTS_H +#include FT_GZIP_H +#include FT_LZW_H +#include FT_ERRORS_H +#include FT_BDF_H + +#include "pcf.h" +#include "pcfdrivr.h" +#include "pcfread.h" + +#include "pcferror.h" +#include "pcfutil.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pcfread + +#include FT_SERVICE_BDF_H +#include FT_SERVICE_XFREE86_NAME_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_pcfdriver + + + typedef struct PCF_CMapRec_ + { + FT_CMapRec root; + FT_UInt num_encodings; + PCF_Encoding encodings; + + } PCF_CMapRec, *PCF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + pcf_cmap_init( FT_CMap pcfcmap, /* PCF_CMap */ + FT_Pointer init_data ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap ); + + FT_UNUSED( init_data ); + + + cmap->num_encodings = (FT_UInt)face->nencodings; + cmap->encodings = face->encodings; + + return PCF_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + pcf_cmap_done( FT_CMap pcfcmap ) /* PCF_CMap */ + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + + + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_index( FT_CMap pcfcmap, /* PCF_CMap */ + FT_UInt32 charcode ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Encoding encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_UInt result = 0; + + + min = 0; + max = cmap->num_encodings; + + while ( min < max ) + { + FT_UInt32 code; + + + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + + if ( charcode == code ) + { + result = encodings[mid].glyph + 1; + break; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_next( FT_CMap pcfcmap, /* PCF_CMap */ + FT_UInt32 *acharcode ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Encoding encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_UInt32 charcode = *acharcode + 1; + FT_UInt result = 0; + + + min = 0; + max = cmap->num_encodings; + + while ( min < max ) + { + FT_UInt32 code; + + + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + + if ( charcode == code ) + { + result = encodings[mid].glyph + 1; + goto Exit; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + + Exit: + *acharcode = charcode; + return result; + } + + + FT_CALLBACK_TABLE_DEF + const FT_CMap_ClassRec pcf_cmap_class = + { + sizeof ( PCF_CMapRec ), + pcf_cmap_init, + pcf_cmap_done, + pcf_cmap_char_index, + pcf_cmap_char_next + }; + + + FT_CALLBACK_DEF( void ) + PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */ + { + PCF_Face face = (PCF_Face)pcfface; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( face->encodings ); + FT_FREE( face->metrics ); + + /* free properties */ + { + PCF_Property prop; + FT_Int i; + + + if ( face->properties ) + { + for ( i = 0; i < face->nprops; i++ ) + { + prop = &face->properties[i]; + + if ( prop ) { + FT_FREE( prop->name ); + if ( prop->isString ) + FT_FREE( prop->value.atom ); + } + } + } + FT_FREE( face->properties ); + } + + FT_FREE( face->toc.tables ); + FT_FREE( pcfface->family_name ); + FT_FREE( pcfface->style_name ); + FT_FREE( pcfface->available_sizes ); + FT_FREE( face->charset_encoding ); + FT_FREE( face->charset_registry ); + + FT_TRACE4(( "PCF_Face_Done: done face\n" )); + + /* close gzip/LZW stream if any */ + if ( pcfface->stream == &face->gzip_stream ) + { + FT_Stream_Close( &face->gzip_stream ); + pcfface->stream = face->gzip_source; + } + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Face_Init( FT_Stream stream, + FT_Face pcfface, /* PCF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PCF_Face face = (PCF_Face)pcfface; + FT_Error error = PCF_Err_Ok; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + + + error = pcf_load_font( stream, face ); + if ( error ) + { + FT_Error error2; + + + PCF_Face_Done( pcfface ); + + /* this didn't work, try gzip support! */ + error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream ); + if ( FT_ERROR_BASE( error2 ) == FT_Err_Unimplemented_Feature ) + goto Fail; + + error = error2; + if ( error ) + { + FT_Error error3; + + + /* this didn't work, try LZW support! */ + error3 = FT_Stream_OpenLZW( &face->gzip_stream, stream ); + if ( FT_ERROR_BASE( error3 ) == FT_Err_Unimplemented_Feature ) + goto Fail; + + error = error3; + if ( error ) + goto Fail; + + face->gzip_source = stream; + pcfface->stream = &face->gzip_stream; + + stream = pcfface->stream; + + error = pcf_load_font( stream, face ); + if ( error ) + goto Fail; + } + else + { + face->gzip_source = stream; + pcfface->stream = &face->gzip_stream; + + stream = pcfface->stream; + + error = pcf_load_font( stream, face ); + if ( error ) + goto Fail; + } + } + + /* set up charmap */ + { + FT_String *charset_registry = face->charset_registry; + FT_String *charset_encoding = face->charset_encoding; + FT_Bool unicode_charmap = 0; + + + if ( charset_registry && charset_encoding ) + { + char* s = charset_registry; + + + /* Uh, oh, compare first letters manually to avoid dependency + on locales. */ + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( face->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + } + } + + { + FT_CharMapRec charmap; + + + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; + charmap.platform_id = 0; + charmap.encoding_id = 0; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = 3; + charmap.encoding_id = 1; + } + + error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL ); + +#if 0 + /* Select default charmap */ + if ( pcfface->num_charmaps ) + pcfface->charmap = pcfface->charmaps[0]; +#endif + } + } + + Exit: + return error; + + Fail: + FT_TRACE2(( "[not a valid PCF file]\n" )); + PCF_Face_Done( pcfface ); + error = PCF_Err_Unknown_File_Format; /* error */ + goto Exit; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + PCF_Accel accel = &( (PCF_Face)size->face )->accel; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = accel->fontAscent << 6; + size->metrics.descender = -accel->fontDescent << 6; + size->metrics.max_advance = accel->maxbounds.characterWidth << 6; + + return PCF_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + PCF_Face face = (PCF_Face)size->face; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = PCF_Err_Invalid_Pixel_Size; + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( bsize->y_ppem + 32 ) >> 6 ) + error = PCF_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( face->accel.fontAscent + + face->accel.fontDescent ) ) + error = PCF_Err_Ok; + break; + + default: + error = PCF_Err_Unimplemented_Feature; + break; + } + + if ( error ) + return error; + else + return PCF_Size_Select( size, 0 ); + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); + FT_Stream stream = face->root.stream; + FT_Error error = PCF_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + PCF_Metric metric; + int bytes; + + FT_UNUSED( load_flags ); + + + FT_TRACE4(( "load_glyph %d ---", glyph_index )); + + if ( !face || glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = PCF_Err_Invalid_Argument; + goto Exit; + } + + if ( glyph_index > 0 ) + glyph_index--; + + metric = face->metrics + glyph_index; + + bitmap->rows = metric->ascent + metric->descent; + bitmap->width = metric->rightSideBearing - metric->leftSideBearing; + bitmap->num_grays = 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n", + PCF_BIT_ORDER( face->bitmapsFormat ), + PCF_BYTE_ORDER( face->bitmapsFormat ), + PCF_GLYPH_PAD( face->bitmapsFormat ) )); + + switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) + { + case 1: + bitmap->pitch = ( bitmap->width + 7 ) >> 3; + break; + + case 2: + bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1; + break; + + case 4: + bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2; + break; + + case 8: + bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3; + break; + + default: + return PCF_Err_Invalid_File_Format; + } + + /* XXX: to do: are there cases that need repadding the bitmap? */ + bytes = bitmap->pitch * bitmap->rows; + + error = ft_glyphslot_alloc_bitmap( slot, bytes ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( metric->bits ) || + FT_STREAM_READ( bitmap->buffer, bytes ) ) + goto Exit; + + if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) + BitOrderInvert( bitmap->buffer, bytes ); + + if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != + PCF_BIT_ORDER( face->bitmapsFormat ) ) ) + { + switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) + { + case 1: + break; + + case 2: + TwoByteSwap( bitmap->buffer, bytes ); + break; + + case 4: + FourByteSwap( bitmap->buffer, bytes ); + break; + } + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = metric->leftSideBearing; + slot->bitmap_top = metric->ascent; + + slot->metrics.horiAdvance = metric->characterWidth << 6; + slot->metrics.horiBearingX = metric->leftSideBearing << 6; + slot->metrics.horiBearingY = metric->ascent << 6; + slot->metrics.width = ( metric->rightSideBearing - + metric->leftSideBearing ) << 6; + slot->metrics.height = bitmap->rows << 6; + + ft_synthesize_vertical_metrics( &slot->metrics, + ( face->accel.fontAscent + + face->accel.fontDescent ) << 6 ); + + FT_TRACE4(( " --- ok\n" )); + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + static FT_Error + pcf_get_bdf_property( PCF_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + PCF_Property prop; + + + prop = pcf_find_property( face, prop_name ); + if ( prop != NULL ) + { + if ( prop->isString ) + { + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + } + else + { + /* Apparently, the PCF driver loads all properties as signed integers! + * This really doesn't seem to be a problem, because this is + * sufficient for any meaningful values. + */ + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = prop->value.integer; + } + return 0; + } + + return PCF_Err_Invalid_Argument; + } + + + static FT_Error + pcf_get_charset_id( PCF_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + *acharset_encoding = face->charset_encoding; + *acharset_registry = face->charset_registry; + + return 0; + } + + + static const FT_Service_BDFRec pcf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, + (FT_BDF_GetPropertyFunc) pcf_get_bdf_property + }; + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pcf_services[] = + { + { FT_SERVICE_ID_BDF, &pcf_service_bdf }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PCF }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pcf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pcf_services, name ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pcf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "pcf", + 0x10000L, + 0x20000L, + + 0, + + 0, + 0, + pcf_driver_requester + }, + + sizeof ( PCF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + PCF_Face_Init, + PCF_Face_Done, + 0, /* FT_Size_InitFunc */ + 0, /* FT_Size_DoneFunc */ + 0, /* FT_Slot_InitFunc */ + 0, /* FT_Slot_DoneFunc */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + PCF_Glyph_Load, + + 0, /* FT_Face_GetKerningFunc */ + 0, /* FT_Face_AttachFunc */ + 0, /* FT_Face_GetAdvancesFunc */ + + PCF_Size_Request, + PCF_Size_Select + }; + + +/* END */ diff --git a/src/freetype2/pcf/pcfdrivr.h b/src/freetype2/pcf/pcfdrivr.h new file mode 100644 index 0000000..7ddf697 --- /dev/null +++ b/src/freetype2/pcf/pcfdrivr.h @@ -0,0 +1,44 @@ +/* pcfdrivr.h + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2002 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCFDRIVR_H__ +#define __PCFDRIVR_H__ + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class; + +FT_END_HEADER + + +#endif /* __PCFDRIVR_H__ */ + + +/* END */ diff --git a/src/freetype2/pcf/pcferror.h b/src/freetype2/pcf/pcferror.h new file mode 100644 index 0000000..d75c067 --- /dev/null +++ b/src/freetype2/pcf/pcferror.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* pcferror.h */ +/* */ +/* PCF error codes (specification only). */ +/* */ +/* Copyright 2001 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 PCF error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __PCFERROR_H__ +#define __PCFERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX PCF_Err_ +#define FT_ERR_BASE FT_Mod_Err_PCF + +#include FT_ERRORS_H + +#endif /* __PCFERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/pcf/pcfread.c b/src/freetype2/pcf/pcfread.c new file mode 100644 index 0000000..b9123cf --- /dev/null +++ b/src/freetype2/pcf/pcfread.c @@ -0,0 +1,1267 @@ +/* pcfread.c + + FreeType font driver for pcf fonts + + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include <ft2build.h> + +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_OBJECTS_H + +#include "pcf.h" +#include "pcfdrivr.h" +#include "pcfread.h" + +#include "pcferror.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_pcfread + + +#if defined( FT_DEBUG_LEVEL_TRACE ) + static const char* const tableNames[] = + { + "prop", "accl", "mtrcs", "bmps", "imtrcs", + "enc", "swidth", "names", "accel" + }; +#endif + + + static + const FT_Frame_Field pcf_toc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TocRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( version ), + FT_FRAME_ULONG_LE( count ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_table_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( type ), + FT_FRAME_ULONG_LE( format ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + + static FT_Error + pcf_read_TOC( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + PCF_Toc toc = &face->toc; + PCF_Table tables; + + FT_Memory memory = FT_FACE(face)->memory; + FT_UInt n; + + + if ( FT_STREAM_SEEK ( 0 ) || + FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) + return PCF_Err_Cannot_Open_Resource; + + if ( toc->version != PCF_FILE_VERSION || + toc->count > FT_ARRAY_MAX( face->toc.tables ) || + toc->count == 0 ) + return PCF_Err_Invalid_File_Format; + + if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) + return PCF_Err_Out_Of_Memory; + + tables = face->toc.tables; + for ( n = 0; n < toc->count; n++ ) + { + if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) + goto Exit; + tables++; + } + + /* Sort tables and check for overlaps. Because they are almost */ + /* always ordered already, an in-place bubble sort with simultaneous */ + /* boundary checking seems appropriate. */ + tables = face->toc.tables; + + for ( n = 0; n < toc->count - 1; n++ ) + { + FT_UInt i, have_change; + + + have_change = 0; + + for ( i = 0; i < toc->count - 1 - n; i++ ) + { + PCF_TableRec tmp; + + + if ( tables[i].offset > tables[i + 1].offset ) + { + tmp = tables[i]; + tables[i] = tables[i + 1]; + tables[i + 1] = tmp; + + have_change = 1; + } + + if ( ( tables[i].size > tables[i + 1].offset ) || + ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) + return PCF_Err_Invalid_Offset; + } + + if ( !have_change ) + break; + } + +#if defined( FT_DEBUG_LEVEL_TRACE ) + + { + FT_UInt i, j; + const char* name = "?"; + + + FT_TRACE4(( "pcf_read_TOC:\n" )); + + FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); + + tables = face->toc.tables; + for ( i = 0; i < toc->count; i++ ) + { + for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); + j++ ) + if ( tables[i].type == (FT_UInt)( 1 << j ) ) + name = tableNames[j]; + + FT_TRACE4(( " %d: type=%s, format=0x%X, " + "size=%ld (0x%lX), offset=%ld (0x%lX)\n", + i, name, + tables[i].format, + tables[i].size, tables[i].size, + tables[i].offset, tables[i].offset )); + } + } + +#endif + + return PCF_Err_Ok; + + Exit: + FT_FREE( face->toc.tables ); + return error; + } + + +#define PCF_METRIC_SIZE 12 + + static + const FT_Frame_Field pcf_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT_LE( leftSideBearing ), + FT_FRAME_SHORT_LE( rightSideBearing ), + FT_FRAME_SHORT_LE( characterWidth ), + FT_FRAME_SHORT_LE( ascent ), + FT_FRAME_SHORT_LE( descent ), + FT_FRAME_SHORT_LE( attributes ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_metric_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT( leftSideBearing ), + FT_FRAME_SHORT( rightSideBearing ), + FT_FRAME_SHORT( characterWidth ), + FT_FRAME_SHORT( ascent ), + FT_FRAME_SHORT( descent ), + FT_FRAME_SHORT( attributes ), + FT_FRAME_END + }; + + +#define PCF_COMPRESSED_METRIC_SIZE 5 + + static + const FT_Frame_Field pcf_compressed_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_Compressed_MetricRec + + FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), + FT_FRAME_BYTE( leftSideBearing ), + FT_FRAME_BYTE( rightSideBearing ), + FT_FRAME_BYTE( characterWidth ), + FT_FRAME_BYTE( ascent ), + FT_FRAME_BYTE( descent ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_metric( FT_Stream stream, + FT_ULong format, + PCF_Metric metric ) + { + FT_Error error = PCF_Err_Ok; + + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + const FT_Frame_Field* fields; + + + /* parsing normal metrics */ + fields = PCF_BYTE_ORDER( format ) == MSBFirst + ? pcf_metric_msb_header + : pcf_metric_header; + + /* the following sets `error' but doesn't return in case of failure */ + (void)FT_STREAM_READ_FIELDS( fields, metric ); + } + else + { + PCF_Compressed_MetricRec compr; + + + /* parsing compressed metrics */ + if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) + goto Exit; + + metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); + metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); + metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); + metric->ascent = (FT_Short)( compr.ascent - 0x80 ); + metric->descent = (FT_Short)( compr.descent - 0x80 ); + metric->attributes = 0; + } + + Exit: + return error; + } + + + static FT_Error + pcf_seek_to_table_type( FT_Stream stream, + PCF_Table tables, + FT_Int ntables, + FT_ULong type, + FT_ULong *aformat, + FT_ULong *asize ) + { + FT_Error error = PCF_Err_Invalid_File_Format; + FT_Int i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + { + if ( stream->pos > tables[i].offset ) + { + error = PCF_Err_Invalid_Stream_Skip; + goto Fail; + } + + if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) + { + error = PCF_Err_Invalid_Stream_Skip; + goto Fail; + } + + *asize = tables[i].size; + *aformat = tables[i].format; + + return PCF_Err_Ok; + } + + Fail: + *asize = 0; + return error; + } + + + static FT_Bool + pcf_has_table_type( PCF_Table tables, + FT_Int ntables, + FT_ULong type ) + { + FT_Int i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + return TRUE; + + return FALSE; + } + + +#define PCF_PROPERTY_SIZE 9 + + static + const FT_Frame_Field pcf_property_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG_LE( name ), + FT_FRAME_BYTE ( isString ), + FT_FRAME_LONG_LE( value ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_property_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG( name ), + FT_FRAME_BYTE( isString ), + FT_FRAME_LONG( value ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ) + { + PCF_Property properties = face->properties; + FT_Bool found = 0; + int i; + + + for ( i = 0 ; i < face->nprops && !found; i++ ) + { + if ( !ft_strcmp( properties[i].name, prop ) ) + found = 1; + } + + if ( found ) + return properties + i - 1; + else + return NULL; + } + + + static FT_Error + pcf_get_properties( FT_Stream stream, + PCF_Face face ) + { + PCF_ParseProperty props = 0; + PCF_Property properties; + FT_UInt nprops, i; + FT_ULong format, size; + FT_Error error; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong string_size; + FT_String* strings = 0; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_PROPERTIES, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_properties:\n" )); + + FT_TRACE4(( " format = %ld\n", format )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( nprops ); + else + (void)FT_READ_ULONG_LE( nprops ); + if ( error ) + goto Bail; + + FT_TRACE4(( " nprop = %d\n", nprops )); + + /* rough estimate */ + if ( nprops > size / PCF_PROPERTY_SIZE ) + { + error = PCF_Err_Invalid_Table; + goto Bail; + } + + face->nprops = nprops; + + if ( FT_NEW_ARRAY( props, nprops ) ) + goto Bail; + + for ( i = 0; i < nprops; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) + goto Bail; + } + } + + /* pad the property array */ + /* */ + /* clever here - nprops is the same as the number of odd-units read, */ + /* as only isStringProp are odd length (Keith Packard) */ + /* */ + if ( nprops & 3 ) + { + i = 4 - ( nprops & 3 ); + FT_Stream_Skip( stream, i ); + } + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( string_size ); + else + (void)FT_READ_ULONG_LE( string_size ); + if ( error ) + goto Bail; + + FT_TRACE4(( " string_size = %ld\n", string_size )); + + /* rough estimate */ + if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) + { + error = PCF_Err_Invalid_Table; + goto Bail; + } + + if ( FT_NEW_ARRAY( strings, string_size ) ) + goto Bail; + + error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); + if ( error ) + goto Bail; + + if ( FT_NEW_ARRAY( properties, nprops ) ) + goto Bail; + + face->properties = properties; + + for ( i = 0; i < nprops; i++ ) + { + FT_Long name_offset = props[i].name; + + + if ( ( name_offset < 0 ) || + ( (FT_ULong)name_offset > string_size ) ) + { + error = PCF_Err_Invalid_Offset; + goto Bail; + } + + if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) + goto Bail; + + FT_TRACE4(( " %s:", properties[i].name )); + + properties[i].isString = props[i].isString; + + if ( props[i].isString ) + { + FT_Long value_offset = props[i].value; + + + if ( ( value_offset < 0 ) || + ( (FT_ULong)value_offset > string_size ) ) + { + error = PCF_Err_Invalid_Offset; + goto Bail; + } + + if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) + goto Bail; + + FT_TRACE4(( " `%s'\n", properties[i].value.atom )); + } + else + { + properties[i].value.integer = props[i].value; + + FT_TRACE4(( " %d\n", properties[i].value.integer )); + } + } + + error = PCF_Err_Ok; + + Bail: + FT_FREE( props ); + FT_FREE( strings ); + + return error; + } + + + static FT_Error + pcf_get_metrics( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong format, size; + PCF_Metric metrics = 0; + FT_ULong nmetrics, i; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_METRICS, + &format, + &size ); + if ( error ) + return error; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) + return PCF_Err_Invalid_File_Format; + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( nmetrics ); + else + (void)FT_READ_ULONG_LE( nmetrics ); + } + else + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_USHORT( nmetrics ); + else + (void)FT_READ_USHORT_LE( nmetrics ); + } + if ( error ) + return PCF_Err_Invalid_File_Format; + + face->nmetrics = nmetrics; + + FT_TRACE4(( "pcf_get_metrics:\n" )); + + FT_TRACE4(( " number of metrics: %d\n", nmetrics )); + + /* rough estimate */ + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( nmetrics > size / PCF_METRIC_SIZE ) + return PCF_Err_Invalid_Table; + } + else + { + if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) + return PCF_Err_Invalid_Table; + } + + if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) + return PCF_Err_Out_Of_Memory; + + metrics = face->metrics; + for ( i = 0; i < nmetrics; i++ ) + { + pcf_get_metric( stream, format, metrics + i ); + + metrics[i].bits = 0; + + FT_TRACE5(( " idx %d: width=%d, " + "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", + i, + ( metrics + i )->characterWidth, + ( metrics + i )->leftSideBearing, + ( metrics + i )->rightSideBearing, + ( metrics + i )->ascent, + ( metrics + i )->descent, + ( metrics + i )->attributes )); + + if ( error ) + break; + } + + if ( error ) + FT_FREE( face->metrics ); + + Bail: + return error; + } + + + static FT_Error + pcf_get_bitmaps( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_Long* offsets; + FT_Long bitmapSizes[GLYPHPADOPTIONS]; + FT_ULong format, size; + int nbitmaps, i, sizebitmaps = 0; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BITMAPS, + &format, + &size ); + if ( error ) + return error; + + error = FT_Stream_EnterFrame( stream, 8 ); + if ( error ) + return error; + + format = FT_GET_ULONG_LE(); + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + nbitmaps = FT_GET_ULONG(); + else + nbitmaps = FT_GET_ULONG_LE(); + + FT_Stream_ExitFrame( stream ); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return PCF_Err_Invalid_File_Format; + + FT_TRACE4(( "pcf_get_bitmaps:\n" )); + + FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); + + if ( nbitmaps != face->nmetrics ) + return PCF_Err_Invalid_File_Format; + + if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) + return error; + + for ( i = 0; i < nbitmaps; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_LONG( offsets[i] ); + else + (void)FT_READ_LONG_LE( offsets[i] ); + + FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", + i, offsets[i], offsets[i] )); + } + if ( error ) + goto Bail; + + for ( i = 0; i < GLYPHPADOPTIONS; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_LONG( bitmapSizes[i] ); + else + (void)FT_READ_LONG_LE( bitmapSizes[i] ); + if ( error ) + goto Bail; + + sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; + + FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); + } + + FT_TRACE4(( " %d bitmaps, padding index %ld\n", + nbitmaps, + PCF_GLYPH_PAD_INDEX( format ) )); + FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); + + FT_UNUSED( sizebitmaps ); /* only used for debugging */ + + for ( i = 0; i < nbitmaps; i++ ) + { + /* rough estimate */ + if ( ( offsets[i] < 0 ) || + ( (FT_ULong)offsets[i] > size ) ) + { + FT_ERROR(( "pcf_get_bitmaps:")); + FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i )); + } + else + face->metrics[i].bits = stream->pos + offsets[i]; + } + + face->bitmapsFormat = format; + + Bail: + FT_FREE( offsets ); + return error; + } + + + static FT_Error + pcf_get_encodings( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong format, size; + int firstCol, lastCol; + int firstRow, lastRow; + int nencoding, encodingOffset; + int i, j; + PCF_Encoding tmpEncoding, encoding = 0; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BDF_ENCODINGS, + &format, + &size ); + if ( error ) + return error; + + error = FT_Stream_EnterFrame( stream, 14 ); + if ( error ) + return error; + + format = FT_GET_ULONG_LE(); + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + firstCol = FT_GET_SHORT(); + lastCol = FT_GET_SHORT(); + firstRow = FT_GET_SHORT(); + lastRow = FT_GET_SHORT(); + face->defaultChar = FT_GET_SHORT(); + } + else + { + firstCol = FT_GET_SHORT_LE(); + lastCol = FT_GET_SHORT_LE(); + firstRow = FT_GET_SHORT_LE(); + lastRow = FT_GET_SHORT_LE(); + face->defaultChar = FT_GET_SHORT_LE(); + } + + FT_Stream_ExitFrame( stream ); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return PCF_Err_Invalid_File_Format; + + FT_TRACE4(( "pdf_get_encodings:\n" )); + + FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", + firstCol, lastCol, firstRow, lastRow )); + + nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); + + if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) + return PCF_Err_Out_Of_Memory; + + error = FT_Stream_EnterFrame( stream, 2 * nencoding ); + if ( error ) + goto Bail; + + for ( i = 0, j = 0 ; i < nencoding; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + encodingOffset = FT_GET_SHORT(); + else + encodingOffset = FT_GET_SHORT_LE(); + + if ( encodingOffset != -1 ) + { + tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + + firstRow ) * 256 ) + + ( ( i % ( lastCol - firstCol + 1 ) ) + + firstCol ); + + tmpEncoding[j].glyph = (FT_Short)encodingOffset; + + FT_TRACE5(( " code %d (0x%04X): idx %d\n", + tmpEncoding[j].enc, tmpEncoding[j].enc, + tmpEncoding[j].glyph )); + + j++; + } + } + FT_Stream_ExitFrame( stream ); + + if ( FT_NEW_ARRAY( encoding, j ) ) + goto Bail; + + for ( i = 0; i < j; i++ ) + { + encoding[i].enc = tmpEncoding[i].enc; + encoding[i].glyph = tmpEncoding[i].glyph; + } + + face->nencodings = j; + face->encodings = encoding; + FT_FREE( tmpEncoding ); + + return error; + + Bail: + FT_FREE( encoding ); + FT_FREE( tmpEncoding ); + return error; + } + + + static + const FT_Frame_Field pcf_accel_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG_LE ( fontAscent ), + FT_FRAME_LONG_LE ( fontDescent ), + FT_FRAME_LONG_LE ( maxOverlap ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_accel_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG ( fontAscent ), + FT_FRAME_LONG ( fontDescent ), + FT_FRAME_LONG ( maxOverlap ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_accel( FT_Stream stream, + PCF_Face face, + FT_ULong type ) + { + FT_ULong format, size; + FT_Error error = PCF_Err_Ok; + PCF_Accel accel = &face->accel; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + type, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) + goto Bail; + } + + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->minbounds) ); + if ( error ) + goto Bail; + + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->maxbounds) ); + if ( error ) + goto Bail; + + if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + { + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_minbounds) ); + if ( error ) + goto Bail; + + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_maxbounds) ); + if ( error ) + goto Bail; + } + else + { + accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ + accel->ink_maxbounds = accel->maxbounds; + } + + Bail: + return error; + } + + + static FT_Error + pcf_interpret_style( PCF_Face pcf ) + { + FT_Error error = PCF_Err_Ok; + FT_Face face = FT_FACE( pcf ); + FT_Memory memory = face->memory; + + PCF_Property prop; + + int nn, len; + char* strings[4] = { NULL, NULL, NULL, NULL }; + int lengths[4]; + + + face->style_flags = 0; + + prop = pcf_find_property( pcf, "SLANT" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || + *(prop->value.atom) == 'o' ) ? (char *)"Oblique" + : (char *)"Italic"; + } + + prop = pcf_find_property( pcf, "WEIGHT_NAME" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = (char *)"Bold"; + } + + prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (char *)(prop->value.atom); + + prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (char *)(prop->value.atom); + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = (char *)"Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_ALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + char* src = strings[nn]; + + + len = lengths[nn]; + + if ( src == NULL ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + int mm; + + + for ( mm = 0; mm < len; mm++ ) + if (s[mm] == ' ') + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_Bool hasBDFAccelerators; + + + error = pcf_read_TOC( stream, face ); + if ( error ) + goto Exit; + + error = pcf_get_properties( stream, face ); + if ( error ) + goto Exit; + + /* Use the old accelerators if no BDF accelerators are in the file. */ + hasBDFAccelerators = pcf_has_table_type( face->toc.tables, + face->toc.count, + PCF_BDF_ACCELERATORS ); + if ( !hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* metrics */ + error = pcf_get_metrics( stream, face ); + if ( error ) + goto Exit; + + /* bitmaps */ + error = pcf_get_bitmaps( stream, face ); + if ( error ) + goto Exit; + + /* encodings */ + error = pcf_get_encodings( stream, face ); + if ( error ) + goto Exit; + + /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ + if ( hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* XXX: TO DO: inkmetrics and glyph_names are missing */ + + /* now construct the face object */ + { + FT_Face root = FT_FACE( face ); + PCF_Property prop; + + + root->num_faces = 1; + root->face_index = 0; + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_FAST_GLYPHS; + + if ( face->accel.constantWidth ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( ( error = pcf_interpret_style( face ) ) != 0 ) + goto Exit; + + prop = pcf_find_property( face, "FAMILY_NAME" ); + if ( prop && prop->isString ) + { + if ( FT_STRDUP( root->family_name, prop->value.atom ) ) + goto Exit; + } + else + root->family_name = NULL; + + /* + * Note: We shift all glyph indices by +1 since we must + * respect the convention that glyph 0 always corresponds + * to the `missing glyph'. + * + * This implies bumping the number of `available' glyphs by 1. + */ + root->num_glyphs = face->nmetrics + 1; + + root->num_fixed_sizes = 1; + if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + + + FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); + +#if 0 + bsize->height = face->accel.maxbounds.ascent << 6; +#endif + bsize->height = (FT_Short)( face->accel.fontAscent + + face->accel.fontDescent ); + + prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + if ( prop ) + bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 ); + else + bsize->width = (FT_Short)( bsize->height * 2/3 ); + + prop = pcf_find_property( face, "POINT_SIZE" ); + if ( prop ) + /* convert from 722.7 decipoints to 72 points per inch */ + bsize->size = + (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L ); + + prop = pcf_find_property( face, "PIXEL_SIZE" ); + if ( prop ) + bsize->y_ppem = (FT_Short)prop->value.integer << 6; + + prop = pcf_find_property( face, "RESOLUTION_X" ); + if ( prop ) + resolution_x = (FT_Short)prop->value.integer; + + prop = pcf_find_property( face, "RESOLUTION_Y" ); + if ( prop ) + resolution_y = (FT_Short)prop->value.integer; + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = bsize->y_ppem * resolution_y / 72; + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; + else + bsize->x_ppem = bsize->y_ppem; + } + + /* set up charset */ + { + PCF_Property charset_registry = 0, charset_encoding = 0; + + + charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); + charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); + + if ( charset_registry && charset_registry->isString && + charset_encoding && charset_encoding->isString ) + { + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + } + } + } + + Exit: + if ( error ) + { + /* This is done to respect the behaviour of the original */ + /* PCF font driver. */ + error = PCF_Err_Invalid_File_Format; + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/pcf/pcfread.h b/src/freetype2/pcf/pcfread.h new file mode 100644 index 0000000..c9524f1 --- /dev/null +++ b/src/freetype2/pcf/pcfread.h @@ -0,0 +1,45 @@ +/* pcfread.h + + FreeType font driver for pcf fonts + + Copyright 2003 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCFREAD_H__ +#define __PCFREAD_H__ + + +#include <ft2build.h> + +FT_BEGIN_HEADER + + FT_LOCAL( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ); + +FT_END_HEADER + +#endif /* __PCFREAD_H__ */ + + +/* END */ diff --git a/src/freetype2/pcf/pcfutil.c b/src/freetype2/pcf/pcfutil.c new file mode 100644 index 0000000..67ddbe8 --- /dev/null +++ b/src/freetype2/pcf/pcfutil.c @@ -0,0 +1,104 @@ +/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */ + +/* + * Author: Keith Packard, MIT X Consortium + */ + +/* Modified for use with FreeType */ + + +#include <ft2build.h> +#include "pcfutil.h" + + + /* + * Invert bit order within each BYTE of an array. + */ + + FT_LOCAL_DEF( void ) + BitOrderInvert( unsigned char* buf, + int nbytes ) + { + for ( ; --nbytes >= 0; buf++ ) + { + unsigned int val = *buf; + + + val = ( ( val >> 1 ) & 0x55 ) | ( ( val << 1 ) & 0xAA ); + val = ( ( val >> 2 ) & 0x33 ) | ( ( val << 2 ) & 0xCC ); + val = ( ( val >> 4 ) & 0x0F ) | ( ( val << 4 ) & 0xF0 ); + + *buf = (unsigned char)val; + } + } + + + /* + * Invert byte order within each 16-bits of an array. + */ + + FT_LOCAL_DEF( void ) + TwoByteSwap( unsigned char* buf, + int nbytes ) + { + unsigned char c; + + + for ( ; nbytes >= 2; nbytes -= 2, buf += 2 ) + { + c = buf[0]; + buf[0] = buf[1]; + buf[1] = c; + } + } + + /* + * Invert byte order within each 32-bits of an array. + */ + + FT_LOCAL_DEF( void ) + FourByteSwap( unsigned char* buf, + int nbytes ) + { + unsigned char c; + + + for ( ; nbytes >= 4; nbytes -= 4, buf += 4 ) + { + c = buf[0]; + buf[0] = buf[3]; + buf[3] = c; + + c = buf[1]; + buf[1] = buf[2]; + buf[2] = c; + } + } + + +/* END */ diff --git a/src/freetype2/pcf/pcfutil.h b/src/freetype2/pcf/pcfutil.h new file mode 100644 index 0000000..1557be3 --- /dev/null +++ b/src/freetype2/pcf/pcfutil.h @@ -0,0 +1,55 @@ +/* pcfutil.h + + FreeType font driver for pcf fonts + + Copyright 2000, 2001, 2004 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCFUTIL_H__ +#define __PCFUTIL_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H + + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + BitOrderInvert( unsigned char* buf, + int nbytes ); + + FT_LOCAL( void ) + TwoByteSwap( unsigned char* buf, + int nbytes ); + + FT_LOCAL( void ) + FourByteSwap( unsigned char* buf, + int nbytes ); + +FT_END_HEADER + +#endif /* __PCFUTIL_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfr.c b/src/freetype2/pfr/pfr.c new file mode 100644 index 0000000..eb2c4ed --- /dev/null +++ b/src/freetype2/pfr/pfr.c @@ -0,0 +1,29 @@ +/***************************************************************************/ +/* */ +/* pfr.c */ +/* */ +/* FreeType PFR driver component. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> + +#include "pfrload.c" +#include "pfrgload.c" +#include "pfrcmap.c" +#include "pfrobjs.c" +#include "pfrdrivr.c" +#include "pfrsbit.c" + +/* END */ diff --git a/src/freetype2/pfr/pfrcmap.c b/src/freetype2/pfr/pfrcmap.c new file mode 100644 index 0000000..c8faee0 --- /dev/null +++ b/src/freetype2/pfr/pfrcmap.c @@ -0,0 +1,163 @@ +/***************************************************************************/ +/* */ +/* pfrcmap.c */ +/* */ +/* FreeType PFR cmap handling (body). */ +/* */ +/* Copyright 2002, 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 "pfrcmap.h" +#include "pfrobjs.h" +#include FT_INTERNAL_DEBUG_H + + + FT_CALLBACK_DEF( FT_Error ) + pfr_cmap_init( PFR_CMap cmap ) + { + FT_Error error = PFR_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + + + cmap->num_chars = face->phy_font.num_chars; + cmap->chars = face->phy_font.chars; + + /* just for safety, check that the character entries are correctly */ + /* sorted in increasing character code order */ + { + FT_UInt n; + + + for ( n = 1; n < cmap->num_chars; n++ ) + { + if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code ) + { + error = PFR_Err_Invalid_Table; + goto Exit; + } + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + pfr_cmap_done( PFR_CMap cmap ) + { + cmap->chars = NULL; + cmap->num_chars = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_index( PFR_CMap cmap, + FT_UInt32 char_code ) + { + FT_UInt min = 0; + FT_UInt max = cmap->num_chars; + FT_UInt mid; + PFR_Char gchar; + + + while ( min < max ) + { + mid = min + ( max - min ) / 2; + gchar = cmap->chars + mid; + + if ( gchar->char_code == char_code ) + return mid + 1; + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_next( PFR_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + Restart: + { + FT_UInt min = 0; + FT_UInt max = cmap->num_chars; + FT_UInt mid; + PFR_Char gchar; + + + while ( min < max ) + { + mid = min + ( ( max - min ) >> 1 ); + gchar = cmap->chars + mid; + + if ( gchar->char_code == char_code ) + { + result = mid; + if ( result != 0 ) + { + result++; + goto Exit; + } + + char_code++; + goto Restart; + } + + if ( gchar->char_code < char_code ) + min = mid+1; + else + max = mid; + } + + /* we didn't find it, but we have a pair just above it */ + char_code = 0; + + if ( min < cmap->num_chars ) + { + gchar = cmap->chars + min; + result = min; + if ( result != 0 ) + { + result++; + char_code = gchar->char_code; + } + } + } + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + pfr_cmap_class_rec = + { + sizeof ( PFR_CMapRec ), + + (FT_CMap_InitFunc) pfr_cmap_init, + (FT_CMap_DoneFunc) pfr_cmap_done, + (FT_CMap_CharIndexFunc)pfr_cmap_char_index, + (FT_CMap_CharNextFunc) pfr_cmap_char_next + }; + + +/* END */ diff --git a/src/freetype2/pfr/pfrcmap.h b/src/freetype2/pfr/pfrcmap.h new file mode 100644 index 0000000..a626953 --- /dev/null +++ b/src/freetype2/pfr/pfrcmap.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* pfrcmap.h */ +/* */ +/* FreeType PFR cmap handling (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFRCMAP_H__ +#define __PFRCMAP_H__ + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_chars; + PFR_Char chars; + + } PFR_CMapRec, *PFR_CMap; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec; + +FT_END_HEADER + + +#endif /* __PFRCMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrdrivr.c b/src/freetype2/pfr/pfrdrivr.c new file mode 100644 index 0000000..4020672 --- /dev/null +++ b/src/freetype2/pfr/pfrdrivr.c @@ -0,0 +1,207 @@ +/***************************************************************************/ +/* */ +/* pfrdrivr.c */ +/* */ +/* FreeType PFR driver interface (body). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_SERVICE_PFR_H +#include FT_SERVICE_XFREE86_NAME_H +#include "pfrdrivr.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_kerning( FT_Face pfrface, /* PFR_Face */ + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + PFR_Face face = (PFR_Face)pfrface; + PFR_PhyFont phys = &face->phy_font; + + + pfr_face_get_kerning( pfrface, left, right, avector ); + + /* convert from metrics to outline units when necessary */ + if ( phys->outline_resolution != phys->metrics_resolution ) + { + if ( avector->x != 0 ) + avector->x = FT_MulDiv( avector->x, phys->outline_resolution, + phys->metrics_resolution ); + + if ( avector->y != 0 ) + avector->y = FT_MulDiv( avector->x, phys->outline_resolution, + phys->metrics_resolution ); + } + + return PFR_Err_Ok; + } + + + /* + * PFR METRICS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_advance( FT_Face pfrface, /* PFR_Face */ + FT_UInt gindex, + FT_Pos *anadvance ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = PFR_Err_Bad_Argument; + + + *anadvance = 0; + if ( face ) + { + PFR_PhyFont phys = &face->phy_font; + + + if ( gindex < phys->num_chars ) + { + *anadvance = phys->chars[gindex].advance; + error = 0; + } + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_metrics( FT_Face pfrface, /* PFR_Face */ + FT_UInt *anoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + PFR_Face face = (PFR_Face)pfrface; + PFR_PhyFont phys = &face->phy_font; + FT_Fixed x_scale, y_scale; + FT_Size size = face->root.size; + + + if ( anoutline_resolution ) + *anoutline_resolution = phys->outline_resolution; + + if ( ametrics_resolution ) + *ametrics_resolution = phys->metrics_resolution; + + x_scale = 0x10000L; + y_scale = 0x10000L; + + if ( size ) + { + x_scale = FT_DivFix( size->metrics.x_ppem << 6, + phys->metrics_resolution ); + + y_scale = FT_DivFix( size->metrics.y_ppem << 6, + phys->metrics_resolution ); + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + return PFR_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const FT_Service_PfrMetricsRec pfr_metrics_service_rec = + { + pfr_get_metrics, + pfr_face_get_kerning, + pfr_get_advance + }; + + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pfr_services[] = + { + { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PFR }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pfr_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pfr_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pfr_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE, + + sizeof( FT_DriverRec ), + + "pfr", + 0x10000L, + 0x20000L, + + NULL, + + 0, + 0, + pfr_get_service + }, + + sizeof( PFR_FaceRec ), + sizeof( PFR_SizeRec ), + sizeof( PFR_SlotRec ), + + pfr_face_init, + pfr_face_done, + 0, /* FT_Size_InitFunc */ + 0, /* FT_Size_DoneFunc */ + pfr_slot_init, + pfr_slot_done, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + pfr_slot_load, + + pfr_get_kerning, + 0, /* FT_Face_AttachFunc */ + 0, /* FT_Face_GetAdvancesFunc */ + 0, /* FT_Size_RequestFunc */ + 0, /* FT_Size_SelectFunc */ + }; + + +/* END */ diff --git a/src/freetype2/pfr/pfrdrivr.h b/src/freetype2/pfr/pfrdrivr.h new file mode 100644 index 0000000..36f1205 --- /dev/null +++ b/src/freetype2/pfr/pfrdrivr.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* pfrdrivr.h */ +/* */ +/* High-level Type PFR driver interface (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFRDRIVR_H__ +#define __PFRDRIVR_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class; + + +FT_END_HEADER + + +#endif /* __PFRDRIVR_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrerror.h b/src/freetype2/pfr/pfrerror.h new file mode 100644 index 0000000..2e1c401 --- /dev/null +++ b/src/freetype2/pfr/pfrerror.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* pfrerror.h */ +/* */ +/* PFR error codes (specification only). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the PFR error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __PFRERROR_H__ +#define __PFRERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX PFR_Err_ +#define FT_ERR_BASE FT_Mod_Err_PFR + +#include FT_ERRORS_H + +#endif /* __PFRERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrgload.c b/src/freetype2/pfr/pfrgload.c new file mode 100644 index 0000000..3bb1733 --- /dev/null +++ b/src/freetype2/pfr/pfrgload.c @@ -0,0 +1,828 @@ +/***************************************************************************/ +/* */ +/* pfrgload.c */ +/* */ +/* FreeType PFR glyph loader (body). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include "pfrgload.h" +#include "pfrsbit.h" +#include "pfrload.h" /* for macro definitions */ +#include FT_INTERNAL_DEBUG_H + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ) + { + FT_ZERO( glyph ); + + glyph->loader = loader; + glyph->path_begun = 0; + + FT_GlyphLoader_Rewind( loader ); + } + + + FT_LOCAL_DEF( void ) + pfr_glyph_done( PFR_Glyph glyph ) + { + FT_Memory memory = glyph->loader->memory; + + + FT_FREE( glyph->x_control ); + glyph->y_control = NULL; + + glyph->max_xy_control = 0; +#if 0 + glyph->num_x_control = 0; + glyph->num_y_control = 0; +#endif + + FT_FREE( glyph->subs ); + + glyph->max_subs = 0; + glyph->num_subs = 0; + + glyph->loader = NULL; + glyph->path_begun = 0; + } + + + /* close current contour, if any */ + static void + pfr_glyph_close_contour( PFR_Glyph glyph ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Int last, first; + + + if ( !glyph->path_begun ) + return; + + /* compute first and last point indices in current glyph outline */ + last = outline->n_points - 1; + first = 0; + if ( outline->n_contours > 0 ) + first = outline->contours[outline->n_contours - 1]; + + /* if the last point falls on the same location than the first one */ + /* we need to delete it */ + if ( last > first ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + last; + + + if ( p1->x == p2->x && p1->y == p2->y ) + { + outline->n_points--; + last--; + } + } + + /* don't add empty contours */ + if ( last >= first ) + outline->contours[outline->n_contours++] = (short)last; + + glyph->path_begun = 0; + } + + + /* reset glyph to start the loading of a new glyph */ + static void + pfr_glyph_start( PFR_Glyph glyph ) + { + glyph->path_begun = 0; + } + + + static FT_Error + pfr_glyph_line_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); + if ( !error ) + { + FT_UInt n = outline->n_points; + + + outline->points[n] = *to; + outline->tags [n] = FT_CURVE_TAG_ON; + + outline->n_points++; + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_curve_to( PFR_Glyph glyph, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); + if ( !error ) + { + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_CURVE_TAG_CUBIC; + tag[1] = FT_CURVE_TAG_CUBIC; + tag[2] = FT_CURVE_TAG_ON; + + outline->n_points = (FT_Short)( outline->n_points + 3 ); + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_move_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Error error; + + + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* indicate that a new contour has started */ + glyph->path_begun = 1; + + /* check that there is space for a new contour and a new point */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); + if ( !error ) + /* add new start point */ + error = pfr_glyph_line_to( glyph, to ); + + return error; + } + + + static void + pfr_glyph_end( PFR_Glyph glyph ) + { + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* merge the current glyph into the stack */ + FT_GlyphLoader_Add( glyph->loader ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH LOADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* load a simple glyph */ + static FT_Error + pfr_glyph_load_simple( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = 0; + FT_Memory memory = glyph->loader->memory; + FT_UInt flags, x_count, y_count, i, count, mask; + FT_Int x; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( flags & PFR_GLYPH_IS_COMPOUND ) + goto Failure; + + x_count = 0; + y_count = 0; + + if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) + { + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + x_count = ( count & 15 ); + y_count = ( count >> 4 ); + } + else + { + if ( flags & PFR_GLYPH_XCOUNT ) + { + PFR_CHECK( 1 ); + x_count = PFR_NEXT_BYTE( p ); + } + + if ( flags & PFR_GLYPH_YCOUNT ) + { + PFR_CHECK( 1 ); + y_count = PFR_NEXT_BYTE( p ); + } + } + + count = x_count + y_count; + + /* re-allocate array when necessary */ + if ( count > glyph->max_xy_control ) + { + FT_UInt new_max = FT_PAD_CEIL( count, 8 ); + + + if ( FT_RENEW_ARRAY( glyph->x_control, + glyph->max_xy_control, + new_max ) ) + goto Exit; + + glyph->max_xy_control = new_max; + } + + glyph->y_control = glyph->x_control + x_count; + + mask = 0; + x = 0; + + for ( i = 0; i < count; i++ ) + { + if ( ( i & 7 ) == 0 ) + { + PFR_CHECK( 1 ); + mask = PFR_NEXT_BYTE( p ); + } + + if ( mask & 1 ) + { + PFR_CHECK( 2 ); + x = PFR_NEXT_SHORT( p ); + } + else + { + PFR_CHECK( 1 ); + x += PFR_NEXT_BYTE( p ); + } + + glyph->x_control[i] = x; + + mask >>= 1; + } + + /* XXX: for now we ignore the secondary stroke and edge definitions */ + /* since we don't want to support native PFR hinting */ + /* */ + if ( flags & PFR_GLYPH_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + pfr_glyph_start( glyph ); + + /* now load a simple glyph */ + { + FT_Vector pos[4]; + FT_Vector* cur; + + + pos[0].x = pos[0].y = 0; + pos[3] = pos[0]; + + for (;;) + { + FT_UInt format, format_low, args_format = 0, args_count, n; + + + /***************************************************************/ + /* read instruction */ + /* */ + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + format_low = format & 15; + + switch ( format >> 4 ) + { + case 0: /* end glyph */ + FT_TRACE6(( "- end glyph" )); + args_count = 0; + break; + + case 1: /* general line operation */ + FT_TRACE6(( "- general line" )); + goto Line1; + + case 4: /* move to inside contour */ + FT_TRACE6(( "- move to inside" )); + goto Line1; + + case 5: /* move to outside contour */ + FT_TRACE6(( "- move to outside" )); + Line1: + args_format = format_low; + args_count = 1; + break; + + case 2: /* horizontal line to */ + FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + if ( format_low > x_count ) + goto Failure; + pos[0].x = glyph->x_control[format_low]; + pos[0].y = pos[3].y; + pos[3] = pos[0]; + args_count = 0; + break; + + case 3: /* vertical line to */ + FT_TRACE6(( "- vertical line to cy.%d", format_low )); + if ( format_low > y_count ) + goto Failure; + pos[0].x = pos[3].x; + pos[0].y = glyph->y_control[format_low]; + pos[3] = pos[0]; + args_count = 0; + break; + + case 6: /* horizontal to vertical curve */ + FT_TRACE6(( "- hv curve " )); + args_format = 0xB8E; + args_count = 3; + break; + + case 7: /* vertical to horizontal curve */ + FT_TRACE6(( "- vh curve" )); + args_format = 0xE2B; + args_count = 3; + break; + + default: /* general curve to */ + FT_TRACE6(( "- general curve" )); + args_count = 4; + args_format = format_low; + } + + /***********************************************************/ + /* now read arguments */ + /* */ + cur = pos; + for ( n = 0; n < args_count; n++ ) + { + FT_UInt idx; + FT_Int delta; + + + /* read the X argument */ + switch ( args_format & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx > x_count ) + goto Failure; + cur->x = glyph->x_control[idx]; + FT_TRACE7(( " cx#%d", idx )); + break; + + case 1: /* 16-bit value */ + PFR_CHECK( 2 ); + cur->x = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " x.%d", cur->x )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->x = pos[3].x + delta; + FT_TRACE7(( " dx.%d", delta )); + break; + + default: + FT_TRACE7(( " |" )); + cur->x = pos[3].x; + } + + /* read the Y argument */ + switch ( ( args_format >> 2 ) & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx > y_count ) + goto Failure; + cur->y = glyph->y_control[idx]; + FT_TRACE7(( " cy#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->y = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " y.%d", cur->y )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->y = pos[3].y + delta; + FT_TRACE7(( " dy.%d", delta )); + break; + + default: + FT_TRACE7(( " -" )); + cur->y = pos[3].y; + } + + /* read the additional format flag for the general curve */ + if ( n == 0 && args_count == 4 ) + { + PFR_CHECK( 1 ); + args_format = PFR_NEXT_BYTE( p ); + args_count--; + } + else + args_format >>= 4; + + /* save the previous point */ + pos[3] = cur[0]; + cur++; + } + + FT_TRACE7(( "\n" )); + + /***********************************************************/ + /* finally, execute instruction */ + /* */ + switch ( format >> 4 ) + { + case 0: /* end glyph => EXIT */ + pfr_glyph_end( glyph ); + goto Exit; + + case 1: /* line operations */ + case 2: + case 3: + error = pfr_glyph_line_to( glyph, pos ); + goto Test_Error; + + case 4: /* move to inside contour */ + case 5: /* move to outside contour */ + error = pfr_glyph_move_to( glyph, pos ); + goto Test_Error; + + default: /* curve operations */ + error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); + + Test_Error: /* test error condition */ + if ( error ) + goto Exit; + } + } /* for (;;) */ + } + + Exit: + return error; + + Failure: + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); + goto Exit; + } + + + /* load a composite/compound glyph */ + static FT_Error + pfr_glyph_load_compound( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = 0; + FT_GlyphLoader loader = glyph->loader; + FT_Memory memory = loader->memory; + PFR_SubGlyph subglyph; + FT_UInt flags, i, count, org_count; + FT_Int x_pos, y_pos; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) + goto Failure; + + count = flags & 0x3F; + + /* ignore extra items when present */ + /* */ + if ( flags & PFR_GLYPH_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if (error) goto Exit; + } + + /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ + /* the PFR format is dumb, using direct file offsets to point to the */ + /* sub-glyphs (instead of glyph indices). Sigh. */ + /* */ + /* For now, we load the list of sub-glyphs into a different array */ + /* but this will prevent us from using the auto-hinter at its best */ + /* quality. */ + /* */ + org_count = glyph->num_subs; + + if ( org_count + count > glyph->max_subs ) + { + FT_UInt new_max = ( org_count + count + 3 ) & -4; + + + if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) + goto Exit; + + glyph->max_subs = new_max; + } + + subglyph = glyph->subs + org_count; + + for ( i = 0; i < count; i++, subglyph++ ) + { + FT_UInt format; + + + x_pos = 0; + y_pos = 0; + + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + + /* read scale when available */ + subglyph->x_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_XSCALE ) + { + PFR_CHECK( 2 ); + subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4; + } + + subglyph->y_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_YSCALE ) + { + PFR_CHECK( 2 ); + subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4; + } + + /* read offset */ + switch ( format & 3 ) + { + case 1: + PFR_CHECK( 2 ); + x_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + x_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + switch ( ( format >> 2 ) & 3 ) + { + case 1: + PFR_CHECK( 2 ); + y_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + y_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + subglyph->x_delta = x_pos; + subglyph->y_delta = y_pos; + + /* read glyph position and size now */ + if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) + { + PFR_CHECK( 2 ); + subglyph->gps_size = PFR_NEXT_USHORT( p ); + } + else + { + PFR_CHECK( 1 ); + subglyph->gps_size = PFR_NEXT_BYTE( p ); + } + + if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) + { + PFR_CHECK( 3 ); + subglyph->gps_offset = PFR_NEXT_LONG( p ); + } + else + { + PFR_CHECK( 2 ); + subglyph->gps_offset = PFR_NEXT_USHORT( p ); + } + + glyph->num_subs++; + } + + Exit: + return error; + + Failure: + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_glyph_load_rec( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + FT_Error error; + FT_Byte* p; + FT_Byte* limit; + + + if ( FT_STREAM_SEEK( gps_offset + offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + limit = p + size; + + if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) + { + FT_Int n, old_count, count; + FT_GlyphLoader loader = glyph->loader; + FT_Outline* base = &loader->base.outline; + + + old_count = glyph->num_subs; + + /* this is a compound glyph - load it */ + error = pfr_glyph_load_compound( glyph, p, limit ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + count = glyph->num_subs - old_count; + + /* now, load each individual glyph */ + for ( n = 0; n < count; n++ ) + { + FT_Int i, old_points, num_points; + PFR_SubGlyph subglyph; + + + subglyph = glyph->subs + old_count + n; + old_points = base->n_points; + + error = pfr_glyph_load_rec( glyph, stream, gps_offset, + subglyph->gps_offset, + subglyph->gps_size ); + if ( error ) + goto Exit; + + /* note that `glyph->subs' might have been re-allocated */ + subglyph = glyph->subs + old_count + n; + num_points = base->n_points - old_points; + + /* translate and eventually scale the new glyph points */ + if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) + { + FT_Vector* vec = base->points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + + subglyph->x_delta; + vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + + subglyph->y_delta; + } + } + else + { + FT_Vector* vec = loader->base.outline.points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x += subglyph->x_delta; + vec->y += subglyph->y_delta; + } + } + + /* proceed to next sub-glyph */ + } + } + else + { + /* load a simple glyph */ + error = pfr_glyph_load_simple( glyph, p, limit ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + + + + FT_LOCAL_DEF( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + /* initialize glyph loader */ + FT_GlyphLoader_Rewind( glyph->loader ); + + glyph->num_subs = 0; + + /* load the glyph, recursively when needed */ + return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); + } + + +/* END */ diff --git a/src/freetype2/pfr/pfrgload.h b/src/freetype2/pfr/pfrgload.h new file mode 100644 index 0000000..7cc7a87 --- /dev/null +++ b/src/freetype2/pfr/pfrgload.h @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* pfrgload.h */ +/* */ +/* FreeType PFR glyph loader (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFRGLOAD_H__ +#define __PFRGLOAD_H__ + +#include "pfrtypes.h" + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ); + + FT_LOCAL( void ) + pfr_glyph_done( PFR_Glyph glyph ); + + + FT_LOCAL( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ); + + +FT_END_HEADER + + +#endif /* __PFRGLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrload.c b/src/freetype2/pfr/pfrload.c new file mode 100644 index 0000000..1ee2c1f --- /dev/null +++ b/src/freetype2/pfr/pfrload.c @@ -0,0 +1,938 @@ +/***************************************************************************/ +/* */ +/* pfrload.c */ +/* */ +/* FreeType PFR loader (body). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include "pfrload.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** EXTRA ITEMS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ) + { + return pfr_extra_items_parse( pp, limit, NULL, NULL ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ) + { + FT_Error error = 0; + FT_Byte* p = *pp; + FT_UInt num_items, item_type, item_size; + + + PFR_CHECK( 1 ); + num_items = PFR_NEXT_BYTE( p ); + + for ( ; num_items > 0; num_items-- ) + { + PFR_CHECK( 2 ); + item_size = PFR_NEXT_BYTE( p ); + item_type = PFR_NEXT_BYTE( p ); + + PFR_CHECK( item_size ); + + if ( item_list ) + { + PFR_ExtraItem extra = item_list; + + + for ( extra = item_list; extra->parser != NULL; extra++ ) + { + if ( extra->type == item_type ) + { + error = extra->parser( p, p + item_size, item_data ); + if ( error ) goto Exit; + + break; + } + } + } + + p += item_size; + } + + Exit: + *pp = p; + return error; + + Too_Short: + FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" )); + error = PFR_Err_Invalid_Table; + goto Exit; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR HEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static const FT_Frame_Field pfr_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PFR_HeaderRec + + FT_FRAME_START( 58 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_USHORT( version ), + FT_FRAME_USHORT( signature2 ), + FT_FRAME_USHORT( header_size ), + + FT_FRAME_USHORT( log_dir_size ), + FT_FRAME_USHORT( log_dir_offset ), + + FT_FRAME_USHORT( log_font_max_size ), + FT_FRAME_UOFF3 ( log_font_section_size ), + FT_FRAME_UOFF3 ( log_font_section_offset ), + + FT_FRAME_USHORT( phy_font_max_size ), + FT_FRAME_UOFF3 ( phy_font_section_size ), + FT_FRAME_UOFF3 ( phy_font_section_offset ), + + FT_FRAME_USHORT( gps_max_size ), + FT_FRAME_UOFF3 ( gps_section_size ), + FT_FRAME_UOFF3 ( gps_section_offset ), + + FT_FRAME_BYTE ( max_blue_values ), + FT_FRAME_BYTE ( max_x_orus ), + FT_FRAME_BYTE ( max_y_orus ), + + FT_FRAME_BYTE ( phy_font_max_size_high ), + FT_FRAME_BYTE ( color_flags ), + + FT_FRAME_UOFF3 ( bct_max_size ), + FT_FRAME_UOFF3 ( bct_set_max_size ), + FT_FRAME_UOFF3 ( phy_bct_set_max_size ), + + FT_FRAME_USHORT( num_phy_fonts ), + FT_FRAME_BYTE ( max_vert_stem_snap ), + FT_FRAME_BYTE ( max_horz_stem_snap ), + FT_FRAME_USHORT( max_chars ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ) + { + FT_Error error; + + + /* read header directly */ + if ( !FT_STREAM_SEEK( 0 ) && + !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) ) + { + /* make a few adjustments to the header */ + header->phy_font_max_size += + (FT_UInt32)header->phy_font_max_size_high << 16; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + pfr_header_check( PFR_Header header ) + { + FT_Bool result = 1; + + + /* check signature and header size */ + if ( header->signature != 0x50465230L || /* "PFR0" */ + header->version > 4 || + header->header_size < 58 || + header->signature2 != 0x0d0a ) /* CR/LF */ + { + result = 0; + } + return result; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR LOGICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 section_offset, + FT_UInt *acount ) + { + FT_Error error; + FT_UInt count; + FT_UInt result = 0; + + + if ( FT_STREAM_SEEK( section_offset ) || FT_READ_USHORT( count ) ) + goto Exit; + + result = count; + + Exit: + *acount = result; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt idx, + FT_UInt32 section_offset, + FT_Bool size_increment ) + { + FT_UInt num_log_fonts; + FT_UInt flags; + FT_UInt32 offset; + FT_UInt32 size; + FT_Error error; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( num_log_fonts ) ) + goto Exit; + + if ( idx >= num_log_fonts ) + return PFR_Err_Invalid_Argument; + + if ( FT_STREAM_SKIP( idx * 5 ) || + FT_READ_USHORT( size ) || + FT_READ_UOFF3 ( offset ) ) + goto Exit; + + /* save logical font size and offset */ + log_font->size = size; + log_font->offset = offset; + + /* now, check the rest of the table before loading it */ + { + FT_Byte* p; + FT_Byte* limit; + FT_UInt local; + + + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) + goto Exit; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK(13); + + log_font->matrix[0] = PFR_NEXT_LONG( p ); + log_font->matrix[1] = PFR_NEXT_LONG( p ); + log_font->matrix[2] = PFR_NEXT_LONG( p ); + log_font->matrix[3] = PFR_NEXT_LONG( p ); + + flags = PFR_NEXT_BYTE( p ); + + local = 0; + if ( flags & PFR_LOG_STROKE ) + { + local++; + if ( flags & PFR_LOG_2BYTE_STROKE ) + local++; + + if ( (flags & PFR_LINE_JOIN_MASK) == PFR_LINE_JOIN_MITER ) + local += 3; + } + if ( flags & PFR_LOG_BOLD ) + { + local++; + if ( flags & PFR_LOG_2BYTE_BOLD ) + local++; + } + + PFR_CHECK( local ); + + if ( flags & PFR_LOG_STROKE ) + { + log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + log_font->miter_limit = PFR_NEXT_LONG( p ); + } + + if ( flags & PFR_LOG_BOLD ) + { + log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + } + + if ( flags & PFR_LOG_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if (error) goto Fail; + } + + PFR_CHECK(5); + log_font->phys_size = PFR_NEXT_USHORT( p ); + log_font->phys_offset = PFR_NEXT_ULONG( p ); + if ( size_increment ) + { + PFR_CHECK( 1 ); + log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16; + } + } + + Fail: + FT_FRAME_EXIT(); + + Exit: + return error; + + Too_Short: + FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" )); + error = PFR_Err_Invalid_Table; + goto Fail; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR PHYSICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + /* load bitmap strikes lists */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = 0; + + + PFR_CHECK( 5 ); + + p += 3; /* skip bctSize */ + flags0 = PFR_NEXT_BYTE( p ); + count = PFR_NEXT_BYTE( p ); + + /* re-allocate when needed */ + if ( phy_font->num_strikes + count > phy_font->max_strikes ) + { + FT_UInt new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 ); + + + if ( FT_RENEW_ARRAY( phy_font->strikes, + phy_font->num_strikes, + new_max ) ) + goto Exit; + + phy_font->max_strikes = new_max; + } + + size1 = 1 + 1 + 1 + 2 + 2 + 1; + if ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + size1++; + + strike = phy_font->strikes + phy_font->num_strikes; + + PFR_CHECK( count * size1 ); + + for ( n = 0; n < count; n++, strike++ ) + { + strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->flags = PFR_NEXT_BYTE( p ); + + strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + } + + phy_font->num_strikes += count; + + Exit: + return error; + + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_extra_item_load_bitmap_info: invalid bitmap info table\n" )); + goto Exit; + } + + + /* Load font ID. This is a so-called "unique" name that is rather + * long and descriptive (like "Tiresias ScreenFont v7.51"). + * + * Note that a PFR font's family name is contained in an *undocumented* + * string of the "auxiliary data" portion of a physical font record. This + * may also contain the "real" style name! + * + * If no family name is present, the font ID is used instead for the + * family. + */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_Error error = 0; + FT_Memory memory = phy_font->memory; + FT_PtrDist len = limit - p; + + + if ( phy_font->font_id != NULL ) + goto Exit; + + if ( FT_ALLOC( phy_font->font_id, len + 1 ) ) + goto Exit; + + /* copy font ID name, and terminate it for safety */ + FT_MEM_COPY( phy_font->font_id, p, len ); + phy_font->font_id[len] = 0; + + Exit: + return error; + } + + + /* load stem snap tables */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_UInt count, num_vert, num_horz; + FT_Int* snaps; + FT_Error error = 0; + FT_Memory memory = phy_font->memory; + + + if ( phy_font->vertical.stem_snaps != NULL ) + goto Exit; + + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + + num_vert = count & 15; + num_horz = count >> 4; + count = num_vert + num_horz; + + PFR_CHECK( count * 2 ); + + if ( FT_NEW_ARRAY( snaps, count ) ) + goto Exit; + + phy_font->vertical.stem_snaps = snaps; + phy_font->horizontal.stem_snaps = snaps + num_vert; + + for ( ; count > 0; count--, snaps++ ) + *snaps = FT_NEXT_SHORT( p ); + + Exit: + return error; + + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_exta_item_load_stem_snaps: invalid stem snaps table\n" )); + goto Exit; + } + + + + /* load kerning pair data */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + PFR_KernItem item; + FT_Error error = 0; + FT_Memory memory = phy_font->memory; + + + FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" )); + + if ( FT_NEW( item ) ) + goto Exit; + + PFR_CHECK( 4 ); + + item->pair_count = PFR_NEXT_BYTE( p ); + item->base_adj = PFR_NEXT_SHORT( p ); + item->flags = PFR_NEXT_BYTE( p ); + item->offset = phy_font->offset + ( p - phy_font->cursor ); + +#ifndef PFR_CONFIG_NO_CHECKS + item->pair_size = 3; + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + item->pair_size += 2; + + if ( item->flags & PFR_KERN_2BYTE_ADJ ) + item->pair_size += 1; + + PFR_CHECK( item->pair_count * item->pair_size ); +#endif + + /* load first and last pairs into the item to speed up */ + /* lookup later... */ + if ( item->pair_count > 0 ) + { + FT_UInt char1, char2; + FT_Byte* q; + + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + { + q = p; + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + else + { + q = p; + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + + /* add new item to the current list */ + item->next = NULL; + *phy_font->kern_items_tail = item; + phy_font->kern_items_tail = &item->next; + phy_font->num_kern_pairs += item->pair_count; + } + else + { + /* empty item! */ + FT_FREE( item ); + } + + Exit: + return error; + + Too_Short: + FT_FREE( item ); + + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_extra_item_load_kerning_pairs: " + "invalid kerning pairs table\n" )); + goto Exit; + } + + + + static const PFR_ExtraItemRec pfr_phy_font_extra_items[] = + { + { 1, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info }, + { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id }, + { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps }, + { 4, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_kerning_pairs }, + { 0, NULL } + }; + + + /* Loads a name from the auxiliary data. Since this extracts undocumented + * strings from the font file, we need to be careful here. + */ + static FT_Error + pfr_aux_name_load( FT_Byte* p, + FT_UInt len, + FT_Memory memory, + FT_String* *astring ) + { + FT_Error error = 0; + FT_String* result = NULL; + FT_UInt n, ok; + + + if ( len > 0 && p[len - 1] == 0 ) + len--; + + /* check that each character is ASCII for making sure not to + load garbage + */ + ok = ( len > 0 ); + for ( n = 0; n < len; n++ ) + if ( p[n] < 32 || p[n] > 127 ) + { + ok = 0; + break; + } + + if ( ok ) + { + if ( FT_ALLOC( result, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( result, p, len ); + result[len] = 0; + } + Exit: + *astring = result; + return error; + } + + + FT_LOCAL_DEF( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ) + { + FT_FREE( phy_font->font_id ); + FT_FREE( phy_font->family_name ); + FT_FREE( phy_font->style_name ); + + FT_FREE( phy_font->vertical.stem_snaps ); + phy_font->vertical.num_stem_snaps = 0; + + phy_font->horizontal.stem_snaps = NULL; + phy_font->horizontal.num_stem_snaps = 0; + + FT_FREE( phy_font->strikes ); + phy_font->num_strikes = 0; + phy_font->max_strikes = 0; + + FT_FREE( phy_font->chars ); + phy_font->num_chars = 0; + phy_font->chars_offset = 0; + + FT_FREE( phy_font->blue_values ); + phy_font->num_blue_values = 0; + + { + PFR_KernItem item, next; + + + item = phy_font->kern_items; + while ( item ) + { + next = item->next; + FT_FREE( item ); + item = next; + } + phy_font->kern_items = NULL; + phy_font->kern_items_tail = NULL; + } + + phy_font->num_kern_pairs = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt flags, num_aux; + FT_Byte* p; + FT_Byte* limit; + + + phy_font->memory = memory; + phy_font->offset = offset; + + phy_font->kern_items = NULL; + phy_font->kern_items_tail = &phy_font->kern_items; + + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) + goto Exit; + + phy_font->cursor = stream->cursor; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 15 ); + phy_font->font_ref_number = PFR_NEXT_USHORT( p ); + phy_font->outline_resolution = PFR_NEXT_USHORT( p ); + phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); + phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); + phy_font->flags = flags = PFR_NEXT_BYTE( p ); + + /* get the standard advance for non-proportional fonts */ + if ( !(flags & PFR_PHY_PROPORTIONAL) ) + { + PFR_CHECK( 2 ); + phy_font->standard_advance = PFR_NEXT_SHORT( p ); + } + + /* load the extra items when present */ + if ( flags & PFR_PHY_EXTRA_ITEMS ) + { + error = pfr_extra_items_parse( &p, limit, + pfr_phy_font_extra_items, phy_font ); + + if ( error ) + goto Fail; + } + + /* In certain fonts, the auxiliary bytes contain interesting */ + /* information. These are not in the specification but can be */ + /* guessed by looking at the content of a few PFR0 fonts. */ + PFR_CHECK( 3 ); + num_aux = PFR_NEXT_ULONG( p ); + + if ( num_aux > 0 ) + { + FT_Byte* q = p; + FT_Byte* q2; + + + PFR_CHECK( num_aux ); + p += num_aux; + + while ( num_aux > 0 ) + { + FT_UInt length, type; + + + if ( q + 4 > p ) + break; + + length = PFR_NEXT_USHORT( q ); + if ( length < 4 || length > num_aux ) + break; + + q2 = q + length - 2; + type = PFR_NEXT_USHORT( q ); + + switch ( type ) + { + case 1: + /* this seems to correspond to the font's family name, + * padded to 16-bits with one zero when necessary + */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->family_name ); + if ( error ) + goto Exit; + break; + + case 2: + if ( q + 32 > q2 ) + break; + + q += 10; + phy_font->ascent = PFR_NEXT_SHORT( q ); + phy_font->descent = PFR_NEXT_SHORT( q ); + phy_font->leading = PFR_NEXT_SHORT( q ); + q += 16; + break; + + case 3: + /* this seems to correspond to the font's style name, + * padded to 16-bits with one zero when necessary + */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->style_name ); + if ( error ) + goto Exit; + break; + + default: + ; + } + + q = q2; + num_aux -= length; + } + } + + /* read the blue values */ + { + FT_UInt n, count; + + + PFR_CHECK( 1 ); + phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); + + PFR_CHECK( count * 2 ); + + if ( FT_NEW_ARRAY( phy_font->blue_values, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); + } + + PFR_CHECK( 8 ); + phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); + phy_font->blue_scale = PFR_NEXT_BYTE( p ); + + phy_font->vertical.standard = PFR_NEXT_USHORT( p ); + phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); + + /* read the character descriptors */ + { + FT_UInt n, count, Size; + + + phy_font->num_chars = count = PFR_NEXT_USHORT( p ); + phy_font->chars_offset = offset + ( p - stream->cursor ); + + if ( FT_NEW_ARRAY( phy_font->chars, count ) ) + goto Fail; + + Size = 1 + 1 + 2; + if ( flags & PFR_PHY_2BYTE_CHARCODE ) + Size += 1; + + if ( flags & PFR_PHY_PROPORTIONAL ) + Size += 2; + + if ( flags & PFR_PHY_ASCII_CODE ) + Size += 1; + + if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + Size += 1; + + if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + Size += 1; + + PFR_CHECK( count * Size ); + + for ( n = 0; n < count; n++ ) + { + PFR_Char cur = &phy_font->chars[n]; + + + cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) + ? PFR_NEXT_SHORT( p ) + : (FT_Int) phy_font->standard_advance; + +#if 0 + cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) + ? PFR_NEXT_BYTE( p ) + : 0; +#else + if ( flags & PFR_PHY_ASCII_CODE ) + p += 1; +#endif + cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + } + } + + /* that's it! */ + + Fail: + FT_FRAME_EXIT(); + + /* save position of bitmap info */ + phy_font->bct_offset = FT_STREAM_POS(); + phy_font->cursor = NULL; + + Exit: + return error; + + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); + goto Fail; + } + + +/* END */ diff --git a/src/freetype2/pfr/pfrload.h b/src/freetype2/pfr/pfrload.h new file mode 100644 index 0000000..ed01071 --- /dev/null +++ b/src/freetype2/pfr/pfrload.h @@ -0,0 +1,118 @@ +/***************************************************************************/ +/* */ +/* pfrload.h */ +/* */ +/* FreeType PFR loader (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFRLOAD_H__ +#define __PFRLOAD_H__ + +#include "pfrobjs.h" +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + +#ifdef PFR_CONFIG_NO_CHECKS +#define PFR_CHECK( x ) do { } while ( 0 ) +#else +#define PFR_CHECK( x ) do \ + { \ + if ( p + (x) > limit ) \ + goto Too_Short; \ + } while ( 0 ) +#endif + +#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p ) +#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p ) +#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p ) +#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p ) +#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p ) +#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p ) + + + /* handling extra items */ + + typedef FT_Error + (*PFR_ExtraItem_ParseFunc)( FT_Byte* p, + FT_Byte* limit, + FT_Pointer data ); + + typedef struct PFR_ExtraItemRec_ + { + FT_UInt type; + PFR_ExtraItem_ParseFunc parser; + + } PFR_ExtraItemRec; + + typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem; + + + FT_LOCAL( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ); + + FT_LOCAL( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ); + + + /* load a PFR header */ + FT_LOCAL( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ); + + /* check a PFR header */ + FT_LOCAL( FT_Bool ) + pfr_header_check( PFR_Header header ); + + + /* return number of logical fonts in this file */ + FT_LOCAL( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 log_section_offset, + FT_UInt *acount ); + + /* load a pfr logical font entry */ + FT_LOCAL( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt face_index, + FT_UInt32 section_offset, + FT_Bool size_increment ); + + + /* load a physical font entry */ + FT_LOCAL( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ); + + /* finalize a physical font */ + FT_LOCAL( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ); + + /* */ + +FT_END_HEADER + +#endif /* __PFRLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrobjs.c b/src/freetype2/pfr/pfrobjs.c new file mode 100644 index 0000000..180446d --- /dev/null +++ b/src/freetype2/pfr/pfrobjs.c @@ -0,0 +1,576 @@ +/***************************************************************************/ +/* */ +/* pfrobjs.c */ +/* */ +/* FreeType PFR object methods (body). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include "pfrobjs.h" +#include "pfrload.h" +#include "pfrgload.h" +#include "pfrcmap.h" +#include "pfrsbit.h" +#include FT_OUTLINE_H +#include FT_INTERNAL_DEBUG_H + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE OBJECT METHODS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + pfr_face_done( FT_Face pfrface ) /* PFR_Face */ + { + PFR_Face face = (PFR_Face)pfrface; + FT_Memory memory = pfrface->driver->root.memory; + + + /* we don't want dangling pointers */ + pfrface->family_name = NULL; + pfrface->style_name = NULL; + + /* finalize the physical font record */ + pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) ); + + /* no need to finalize the logical font or the header */ + FT_FREE( pfrface->available_sizes ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face pfrface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* load the header and check it */ + error = pfr_header_load( &face->header, stream ); + if ( error ) + goto Exit; + + if ( !pfr_header_check( &face->header ) ) + { + FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" )); + error = PFR_Err_Unknown_File_Format; + goto Exit; + } + + /* check face index */ + { + FT_UInt num_faces; + + + error = pfr_log_font_count( stream, + face->header.log_dir_offset, + &num_faces ); + if ( error ) + goto Exit; + + pfrface->num_faces = num_faces; + } + + if ( face_index < 0 ) + goto Exit; + + if ( face_index >= pfrface->num_faces ) + { + FT_ERROR(( "pfr_face_init: invalid face index\n" )); + error = PFR_Err_Invalid_Argument; + goto Exit; + } + + /* load the face */ + error = pfr_log_font_load( + &face->log_font, stream, face_index, + face->header.log_dir_offset, + FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); + if ( error ) + goto Exit; + + /* now load the physical font descriptor */ + error = pfr_phy_font_load( &face->phy_font, stream, + face->log_font.phys_offset, + face->log_font.phys_size ); + if ( error ) + goto Exit; + + /* now set up all root face fields */ + { + PFR_PhyFont phy_font = &face->phy_font; + + + pfrface->face_index = face_index; + pfrface->num_glyphs = phy_font->num_chars + 1; + pfrface->face_flags = FT_FACE_FLAG_SCALABLE; + + /* if all characters point to the same gps_offset 0, we */ + /* assume that the font only contains bitmaps */ + { + FT_UInt nn; + + + for ( nn = 0; nn < phy_font->num_chars; nn++ ) + if ( phy_font->chars[nn].gps_offset != 0 ) + break; + + if ( nn == phy_font->num_chars ) + pfrface->face_flags = 0; /* not scalable */ + } + + if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( phy_font->flags & PFR_PHY_VERTICAL ) + pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; + else + pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + + if ( phy_font->num_kern_pairs > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + + /* If no family name was found in the "undocumented" auxiliary + * data, use the font ID instead. This sucks but is better than + * nothing. + */ + pfrface->family_name = phy_font->family_name; + if ( pfrface->family_name == NULL ) + pfrface->family_name = phy_font->font_id; + + /* note that the style name can be NULL in certain PFR fonts, + * probably meaning "Regular" + */ + pfrface->style_name = phy_font->style_name; + + pfrface->num_fixed_sizes = 0; + pfrface->available_sizes = 0; + + pfrface->bbox = phy_font->bbox; + pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; + pfrface->ascender = (FT_Short) phy_font->bbox.yMax; + pfrface->descender = (FT_Short) phy_font->bbox.yMin; + + pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); + if ( pfrface->height < pfrface->ascender - pfrface->descender ) + pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender); + + if ( phy_font->num_strikes > 0 ) + { + FT_UInt n, count = phy_font->num_strikes; + FT_Bitmap_Size* size; + PFR_Strike strike; + FT_Memory memory = pfrface->stream->memory; + + + if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) + goto Exit; + + size = pfrface->available_sizes; + strike = phy_font->strikes; + for ( n = 0; n < count; n++, size++, strike++ ) + { + size->height = (FT_UShort)strike->y_ppm; + size->width = (FT_UShort)strike->x_ppm; + size->size = strike->y_ppm << 6; + size->x_ppem = strike->x_ppm << 6; + size->y_ppem = strike->y_ppm << 6; + } + pfrface->num_fixed_sizes = count; + } + + /* now compute maximum advance width */ + if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; + else + { + FT_Int max = 0; + FT_UInt count = phy_font->num_chars; + PFR_Char gchar = phy_font->chars; + + + for ( ; count > 0; count--, gchar++ ) + { + if ( max < gchar->advance ) + max = gchar->advance; + } + + pfrface->max_advance_width = (FT_Short)max; + } + + pfrface->max_advance_height = pfrface->height; + + pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); + pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); + + /* create charmap */ + { + FT_CharMapRec charmap; + + + charmap.face = pfrface; + charmap.platform_id = 3; + charmap.encoding_id = 1; + charmap.encoding = FT_ENCODING_UNICODE; + + FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); + +#if 0 + /* Select default charmap */ + if ( pfrface->num_charmaps ) + pfrface->charmap = pfrface->charmaps[0]; +#endif + } + + /* check whether we've loaded any kerning pairs */ + if ( phy_font->num_kern_pairs ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SLOT OBJECT METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + FT_GlyphLoader loader = pfrslot->internal->loader; + + + pfr_glyph_init( &slot->glyph, loader ); + + return 0; + } + + + FT_LOCAL_DEF( void ) + pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + + + pfr_glyph_done( &slot->glyph ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ + FT_Size pfrsize, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + PFR_Size size = (PFR_Size)pfrsize; + FT_Error error; + PFR_Face face = (PFR_Face)pfrslot->face; + PFR_Char gchar; + FT_Outline* outline = &pfrslot->outline; + FT_ULong gps_offset; + + + if ( gindex > 0 ) + gindex--; + + if ( !face || gindex >= face->phy_font.num_chars ) + { + error = PFR_Err_Invalid_Argument; + goto Exit; + } + + /* try to load an embedded bitmap */ + if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) + { + error = pfr_slot_load_bitmap( slot, size, gindex ); + if ( error == 0 ) + goto Exit; + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = PFR_Err_Invalid_Argument; + goto Exit; + } + + gchar = face->phy_font.chars + gindex; + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; + outline->n_points = 0; + outline->n_contours = 0; + gps_offset = face->header.gps_section_offset; + + /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ + error = pfr_glyph_load( &slot->glyph, face->root.stream, + gps_offset, gchar->gps_offset, gchar->gps_size ); + + if ( !error ) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &pfrslot->metrics; + FT_Pos advance; + FT_Int em_metrics, em_outline; + FT_Bool scaling; + + + scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + /* copy outline data */ + *outline = slot->glyph.loader->base.outline; + + outline->flags &= ~FT_OUTLINE_OWNER; + outline->flags |= FT_OUTLINE_REVERSE_FILL; + + if ( size && pfrsize->metrics.y_ppem < 24 ) + outline->flags |= FT_OUTLINE_HIGH_PRECISION; + + /* compute the advance vector */ + metrics->horiAdvance = 0; + metrics->vertAdvance = 0; + + advance = gchar->advance; + em_metrics = face->phy_font.metrics_resolution; + em_outline = face->phy_font.outline_resolution; + + if ( em_metrics != em_outline ) + advance = FT_MulDiv( advance, em_outline, em_metrics ); + + if ( face->phy_font.flags & PFR_PHY_VERTICAL ) + metrics->vertAdvance = advance; + else + metrics->horiAdvance = advance; + + pfrslot->linearHoriAdvance = metrics->horiAdvance; + pfrslot->linearVertAdvance = metrics->vertAdvance; + + /* make-up vertical metrics(?) */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + +#if 0 /* some fonts seem to be broken here! */ + + /* Apply the font matrix, if any. */ + /* TODO: Test existing fonts with unusual matrix */ + /* whether we have to adjust Units per EM. */ + { + FT_Matrix font_matrix; + + + font_matrix.xx = face->log_font.matrix[0] << 8; + font_matrix.yx = face->log_font.matrix[1] << 8; + font_matrix.xy = face->log_font.matrix[2] << 8; + font_matrix.yy = face->log_font.matrix[3] << 8; + + FT_Outline_Transform( outline, &font_matrix ); + } +#endif + + /* scale when needed */ + if ( scaling ) + { + FT_Int n; + FT_Fixed x_scale = pfrsize->metrics.x_scale; + FT_Fixed y_scale = pfrsize->metrics.y_scale; + FT_Vector* vec = outline->points; + + + /* scale outline points */ + for ( n = 0; n < outline->n_points; n++, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* scale the advance */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the rest of the metrics */ + FT_Outline_Get_CBox( outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax - metrics->height; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** KERNING METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = PFR_Err_Ok; + PFR_PhyFont phy_font = &face->phy_font; + FT_UInt32 code1, code2, pair; + + + kerning->x = 0; + kerning->y = 0; + + if ( glyph1 > 0 ) + glyph1--; + + if ( glyph2 > 0 ) + glyph2--; + + /* convert glyph indices to character codes */ + if ( glyph1 > phy_font->num_chars || + glyph2 > phy_font->num_chars ) + goto Exit; + + code1 = phy_font->chars[glyph1].char_code; + code2 = phy_font->chars[glyph2].char_code; + pair = PFR_KERN_INDEX( code1, code2 ); + + /* now search the list of kerning items */ + { + PFR_KernItem item = phy_font->kern_items; + FT_Stream stream = pfrface->stream; + + + for ( ; item; item = item->next ) + { + if ( pair >= item->pair1 && pair <= item->pair2 ) + goto FoundPair; + } + goto Exit; + + FoundPair: /* we found an item, now parse it and find the value if any */ + if ( FT_STREAM_SEEK( item->offset ) || + FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) + goto Exit; + + { + FT_UInt count = item->pair_count; + FT_UInt size = item->pair_size; + FT_UInt power = (FT_UInt)ft_highpow2( (FT_UInt32)count ); + FT_UInt probe = power * size; + FT_UInt extra = count - power; + FT_Byte* base = stream->cursor; + FT_Bool twobytes = FT_BOOL( item->flags & 1 ); + FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); + FT_Byte* p; + FT_UInt32 cpair; + + + if ( extra > 0 ) + { + p = base + extra * size; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + { + if ( twobyte_adj ) + p += 2; + else + p++; + base = p; + } + } + + while ( probe > size ) + { + probe >>= 1; + p = base + probe; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + base += probe; + } + + p = base; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + { + FT_Int value; + + + Found: + if ( twobyte_adj ) + value = FT_PEEK_SHORT( p ); + else + value = p[0]; + + kerning->x = item->base_adj + value; + } + } + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + +/* END */ diff --git a/src/freetype2/pfr/pfrobjs.h b/src/freetype2/pfr/pfrobjs.h new file mode 100644 index 0000000..f6aa8b4 --- /dev/null +++ b/src/freetype2/pfr/pfrobjs.h @@ -0,0 +1,96 @@ +/***************************************************************************/ +/* */ +/* pfrobjs.h */ +/* */ +/* FreeType PFR object methods (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFROBJS_H__ +#define __PFROBJS_H__ + +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_FaceRec_* PFR_Face; + + typedef struct PFR_SizeRec_* PFR_Size; + + typedef struct PFR_SlotRec_* PFR_Slot; + + + typedef struct PFR_FaceRec_ + { + FT_FaceRec root; + PFR_HeaderRec header; + PFR_LogFontRec log_font; + PFR_PhyFontRec phy_font; + + } PFR_FaceRec; + + + typedef struct PFR_SizeRec_ + { + FT_SizeRec root; + + } PFR_SizeRec; + + + typedef struct PFR_SlotRec_ + { + FT_GlyphSlotRec root; + PFR_GlyphRec glyph; + + } PFR_SlotRec; + + + FT_LOCAL( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face face, /* PFR_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + pfr_face_done( FT_Face face ); /* PFR_Face */ + + + FT_LOCAL( FT_Error ) + pfr_face_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + + FT_LOCAL( FT_Error ) + pfr_slot_init( FT_GlyphSlot slot ); /* PFR_Slot */ + + FT_LOCAL( void ) + pfr_slot_done( FT_GlyphSlot slot ); /* PFR_Slot */ + + + FT_LOCAL( FT_Error ) + pfr_slot_load( FT_GlyphSlot slot, /* PFR_Slot */ + FT_Size size, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* __PFROBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrsbit.c b/src/freetype2/pfr/pfrsbit.c new file mode 100644 index 0000000..45ff666 --- /dev/null +++ b/src/freetype2/pfr/pfrsbit.c @@ -0,0 +1,680 @@ +/***************************************************************************/ +/* */ +/* pfrsbit.c */ +/* */ +/* FreeType PFR bitmap loader (body). */ +/* */ +/* Copyright 2002, 2003, 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 "pfrsbit.h" +#include "pfrload.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR BIT WRITER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PFR_BitWriter_ + { + FT_Byte* line; /* current line start */ + FT_Int pitch; /* line size in bytes */ + FT_Int width; /* width in pixels/bits */ + FT_Int rows; /* number of remaining rows to scan */ + FT_Int total; /* total number of bits to draw */ + + } PFR_BitWriterRec, *PFR_BitWriter; + + + static void + pfr_bitwriter_init( PFR_BitWriter writer, + FT_Bitmap* target, + FT_Bool decreasing ) + { + writer->line = target->buffer; + writer->pitch = target->pitch; + writer->width = target->width; + writer->rows = target->rows; + writer->total = writer->width * writer->rows; + + if ( !decreasing ) + { + writer->line += writer->pitch * ( target->rows-1 ); + writer->pitch = -writer->pitch; + } + } + + + static void + pfr_bitwriter_decode_bytes( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt val = 0; + FT_UInt c = 0; + + + n = (FT_Int)( limit - p ) * 8; + if ( n > writer->total ) + n = writer->total; + + reload = n & 7; + + for ( ; n > 0; n-- ) + { + if ( ( n & 7 ) == reload ) + val = *p++; + + if ( val & 0x80 ) + c |= mask; + + val <<= 1; + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur ++; + } + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte)c; + } + + + static void + pfr_bitwriter_decode_rle1( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, phase, count, counts[2], reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + counts[0] = 0; + counts[1] = 0; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( phase ) + { + FT_Int v; + + + if ( p >= limit ) + break; + + v = *p++; + counts[0] = v >> 4; + counts[1] = v & 15; + phase = 0; + count = counts[0]; + } + else + { + phase = 1; + count = counts[1]; + } + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte) c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur ++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + static void + pfr_bitwriter_decode_rle2( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, phase, count, reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( p >= limit ) + break; + + count = *p++; + phase = phase ^ 1; + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte) c; + c = 0; + mask = 0x80; + left = writer->width; + + writer->line += writer->pitch; + cur = writer->line; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + cur ++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP DATA DECODING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + pfr_lookup_bitmap_data( FT_Byte* base, + FT_Byte* limit, + FT_UInt count, + FT_UInt flags, + FT_UInt char_code, + FT_ULong* found_offset, + FT_ULong* found_size ) + { + FT_UInt left, right, char_len; + FT_Bool two = FT_BOOL( flags & 1 ); + FT_Byte* buff; + + + char_len = 4; + if ( two ) char_len += 1; + if ( flags & 2 ) char_len += 1; + if ( flags & 4 ) char_len += 1; + + left = 0; + right = count; + + while ( left < right ) + { + FT_UInt middle, code; + + + middle = ( left + right ) >> 1; + buff = base + middle * char_len; + + /* check that we are not outside of the table -- */ + /* this is possible with broken fonts... */ + if ( buff + char_len > limit ) + goto Fail; + + if ( two ) + code = PFR_NEXT_USHORT( buff ); + else + code = PFR_NEXT_BYTE( buff ); + + if ( code == char_code ) + goto Found_It; + + if ( code < char_code ) + left = middle; + else + right = middle; + } + + Fail: + /* Not found */ + *found_size = 0; + *found_offset = 0; + return; + + Found_It: + if ( flags & 2 ) + *found_size = PFR_NEXT_USHORT( buff ); + else + *found_size = PFR_NEXT_BYTE( buff ); + + if ( flags & 4 ) + *found_offset = PFR_NEXT_ULONG( buff ); + else + *found_offset = PFR_NEXT_USHORT( buff ); + } + + + /* load bitmap metrics. "*padvance" must be set to the default value */ + /* before calling this function... */ + /* */ + static FT_Error + pfr_load_bitmap_metrics( FT_Byte** pdata, + FT_Byte* limit, + FT_Long scaled_advance, + FT_Long *axpos, + FT_Long *aypos, + FT_UInt *axsize, + FT_UInt *aysize, + FT_Long *aadvance, + FT_UInt *aformat ) + { + FT_Error error = 0; + FT_Byte flags; + FT_Char b; + FT_Byte* p = *pdata; + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + xpos = 0; + ypos = 0; + xsize = 0; + ysize = 0; + advance = 0; + + switch ( flags & 3 ) + { + case 0: + PFR_CHECK( 1 ); + b = PFR_NEXT_INT8( p ); + xpos = b >> 4; + ypos = ( (FT_Char)( b << 4 ) ) >> 4; + break; + + case 1: + PFR_CHECK( 2 ); + xpos = PFR_NEXT_INT8( p ); + ypos = PFR_NEXT_INT8( p ); + break; + + case 2: + PFR_CHECK( 4 ); + xpos = PFR_NEXT_SHORT( p ); + ypos = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 6 ); + xpos = PFR_NEXT_LONG( p ); + ypos = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + /* blank image */ + xsize = 0; + ysize = 0; + break; + + case 1: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xsize = ( b >> 4 ) & 0xF; + ysize = b & 0xF; + break; + + case 2: + PFR_CHECK( 2 ); + xsize = PFR_NEXT_BYTE( p ); + ysize = PFR_NEXT_BYTE( p ); + break; + + case 3: + PFR_CHECK( 4 ); + xsize = PFR_NEXT_USHORT( p ); + ysize = PFR_NEXT_USHORT( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + advance = scaled_advance; + break; + + case 1: + PFR_CHECK( 1 ); + advance = PFR_NEXT_INT8( p ) << 8; + break; + + case 2: + PFR_CHECK( 2 ); + advance = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 3 ); + advance = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + *axpos = xpos; + *aypos = ypos; + *axsize = xsize; + *aysize = ysize; + *aadvance = advance; + *aformat = flags >> 2; + *pdata = p; + + Exit: + return error; + + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_load_bitmap_bits( FT_Byte* p, + FT_Byte* limit, + FT_UInt format, + FT_Bool decreasing, + FT_Bitmap* target ) + { + FT_Error error = 0; + PFR_BitWriterRec writer; + + + if ( target->rows > 0 && target->width > 0 ) + { + pfr_bitwriter_init( &writer, target, decreasing ); + + switch ( format ) + { + case 0: /* packed bits */ + pfr_bitwriter_decode_bytes( &writer, p, limit ); + break; + + case 1: /* RLE1 */ + pfr_bitwriter_decode_rle1( &writer, p, limit ); + break; + + case 2: /* RLE2 */ + pfr_bitwriter_decode_rle2( &writer, p, limit ); + break; + + default: + FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" )); + error = PFR_Err_Invalid_File_Format; + } + } + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP LOADING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index ) + { + FT_Error error; + PFR_Face face = (PFR_Face) glyph->root.face; + FT_Stream stream = face->root.stream; + PFR_PhyFont phys = &face->phy_font; + FT_ULong gps_offset; + FT_ULong gps_size; + PFR_Char character; + PFR_Strike strike; + + + character = &phys->chars[glyph_index]; + + /* Look-up a bitmap strike corresponding to the current */ + /* character dimensions */ + { + FT_UInt n; + + + strike = phys->strikes; + for ( n = 0; n < phys->num_strikes; n++ ) + { + if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && + strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) + { + goto Found_Strike; + } + + strike++; + } + + /* couldn't find it */ + return PFR_Err_Invalid_Argument; + } + + Found_Strike: + + /* Now lookup the glyph's position within the file */ + { + FT_UInt char_len; + + + char_len = 4; + if ( strike->flags & 1 ) char_len += 1; + if ( strike->flags & 2 ) char_len += 1; + if ( strike->flags & 4 ) char_len += 1; + + /* Access data directly in the frame to speed lookups */ + if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || + FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) + goto Exit; + + pfr_lookup_bitmap_data( stream->cursor, + stream->limit, + strike->num_bitmaps, + strike->flags, + character->char_code, + &gps_offset, + &gps_size ); + + FT_FRAME_EXIT(); + + if ( gps_size == 0 ) + { + /* Could not find a bitmap program string for this glyph */ + error = PFR_Err_Invalid_Argument; + goto Exit; + } + } + + /* get the bitmap metrics */ + { + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize, format; + FT_Byte* p; + + + /* compute linear advance */ + advance = character->advance; + if ( phys->metrics_resolution != phys->outline_resolution ) + advance = FT_MulDiv( advance, + phys->outline_resolution, + phys->metrics_resolution ); + + glyph->root.linearHoriAdvance = advance; + + /* compute default advance, i.e., scaled advance. This can be */ + /* overridden in the bitmap header of certain glyphs. */ + advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, + character->advance, + phys->metrics_resolution ); + + if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || + FT_FRAME_ENTER( gps_size ) ) + goto Exit; + + p = stream->cursor; + error = pfr_load_bitmap_metrics( &p, stream->limit, + advance, + &xpos, &ypos, + &xsize, &ysize, + &advance, &format ); + if ( !error ) + { + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + /* Set up glyph bitmap and metrics */ + glyph->root.bitmap.width = (FT_Int)xsize; + glyph->root.bitmap.rows = (FT_Int)ysize; + glyph->root.bitmap.pitch = (FT_Long)( xsize + 7 ) >> 3; + glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->root.metrics.width = (FT_Long)xsize << 6; + glyph->root.metrics.height = (FT_Long)ysize << 6; + glyph->root.metrics.horiBearingX = xpos << 6; + glyph->root.metrics.horiBearingY = ypos << 6; + glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); + glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; + glyph->root.metrics.vertBearingY = 0; + glyph->root.metrics.vertAdvance = size->root.metrics.height; + + glyph->root.bitmap_left = xpos; + glyph->root.bitmap_top = ypos + ysize; + + /* Allocate and read bitmap data */ + { + FT_ULong len = glyph->root.bitmap.pitch * ysize; + + + error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); + if ( !error ) + { + error = pfr_load_bitmap_bits( + p, + stream->limit, + format, + FT_BOOL(face->header.color_flags & 2), + &glyph->root.bitmap ); + } + } + } + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + +/* END */ diff --git a/src/freetype2/pfr/pfrsbit.h b/src/freetype2/pfr/pfrsbit.h new file mode 100644 index 0000000..015e9e6 --- /dev/null +++ b/src/freetype2/pfr/pfrsbit.h @@ -0,0 +1,36 @@ +/***************************************************************************/ +/* */ +/* pfrsbit.h */ +/* */ +/* FreeType PFR bitmap loader (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PFRSBIT_H__ +#define __PFRSBIT_H__ + +#include "pfrobjs.h" + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index ); + +FT_END_HEADER + +#endif /* __PFR_SBIT_H__ */ + + +/* END */ diff --git a/src/freetype2/pfr/pfrtypes.h b/src/freetype2/pfr/pfrtypes.h new file mode 100644 index 0000000..c0ae042 --- /dev/null +++ b/src/freetype2/pfr/pfrtypes.h @@ -0,0 +1,362 @@ +/***************************************************************************/ +/* */ +/* pfrtypes.h */ +/* */ +/* FreeType PFR data structures (specification only). */ +/* */ +/* Copyright 2002, 2003, 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 __PFRTYPES_H__ +#define __PFRTYPES_H__ + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H + +FT_BEGIN_HEADER + + /************************************************************************/ + + /* the PFR Header structure */ + typedef struct PFR_HeaderRec_ + { + FT_UInt32 signature; + FT_UInt version; + FT_UInt signature2; + FT_UInt header_size; + + FT_UInt log_dir_size; + FT_UInt log_dir_offset; + + FT_UInt log_font_max_size; + FT_UInt32 log_font_section_size; + FT_UInt32 log_font_section_offset; + + FT_UInt32 phy_font_max_size; + FT_UInt32 phy_font_section_size; + FT_UInt32 phy_font_section_offset; + + FT_UInt gps_max_size; + FT_UInt32 gps_section_size; + FT_UInt32 gps_section_offset; + + FT_UInt max_blue_values; + FT_UInt max_x_orus; + FT_UInt max_y_orus; + + FT_UInt phy_font_max_size_high; + FT_UInt color_flags; + + FT_UInt32 bct_max_size; + FT_UInt32 bct_set_max_size; + FT_UInt32 phy_bct_set_max_size; + + FT_UInt num_phy_fonts; + FT_UInt max_vert_stem_snap; + FT_UInt max_horz_stem_snap; + FT_UInt max_chars; + + } PFR_HeaderRec, *PFR_Header; + + + /* used in `color_flags' field of the PFR_Header */ + typedef enum PFR_HeaderFlags_ + { + PFR_FLAG_BLACK_PIXEL = 1, + PFR_FLAG_INVERT_BITMAP = 2 + + } PFR_HeaderFlags; + + + /************************************************************************/ + + typedef struct PFR_LogFontRec_ + { + FT_UInt32 size; + FT_UInt32 offset; + + FT_Int32 matrix[4]; + FT_UInt stroke_flags; + FT_Int stroke_thickness; + FT_Int bold_thickness; + FT_Int32 miter_limit; + + FT_UInt32 phys_size; + FT_UInt32 phys_offset; + + } PFR_LogFontRec, *PFR_LogFont; + + + typedef enum PFR_LogFlags_ + { + PFR_LOG_EXTRA_ITEMS = 0x40, + PFR_LOG_2BYTE_BOLD = 0x20, + PFR_LOG_BOLD = 0x10, + PFR_LOG_2BYTE_STROKE = 8, + PFR_LOG_STROKE = 4, + PFR_LINE_JOIN_MASK = 3 + + } PFR_LogFlags; + + + typedef enum PFR_LineJoinFlags_ + { + PFR_LINE_JOIN_MITER = 0, + PFR_LINE_JOIN_ROUND = 1, + PFR_LINE_JOIN_BEVEL = 2 + + } PFR_LineJoinFlags; + + + /************************************************************************/ + + typedef enum PFR_BitmapFlags_ + { + PFR_BITMAP_3BYTE_OFFSET = 4, + PFR_BITMAP_2BYTE_SIZE = 2, + PFR_BITMAP_2BYTE_CHARCODE = 1 + + } PFR_BitmapFlags; + + + typedef struct PFR_BitmapCharRec_ + { + FT_UInt char_code; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_BitmapCharRec, *PFR_BitmapChar; + + + typedef enum PFR_StrikeFlags_ + { + PFR_STRIKE_2BYTE_COUNT = 0x10, + PFR_STRIKE_3BYTE_OFFSET = 0x08, + PFR_STRIKE_3BYTE_SIZE = 0x04, + PFR_STRIKE_2BYTE_YPPM = 0x02, + PFR_STRIKE_2BYTE_XPPM = 0x01 + + } PFR_StrikeFlags; + + + typedef struct PFR_StrikeRec_ + { + FT_UInt x_ppm; + FT_UInt y_ppm; + FT_UInt flags; + + FT_UInt32 gps_size; + FT_UInt32 gps_offset; + + FT_UInt32 bct_size; + FT_UInt32 bct_offset; + + /* optional */ + FT_UInt num_bitmaps; + PFR_BitmapChar bitmaps; + + } PFR_StrikeRec, *PFR_Strike; + + + /************************************************************************/ + + typedef struct PFR_CharRec_ + { + FT_UInt char_code; + FT_Int advance; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_CharRec, *PFR_Char; + + + /************************************************************************/ + + typedef struct PFR_DimensionRec_ + { + FT_UInt standard; + FT_UInt num_stem_snaps; + FT_Int* stem_snaps; + + } PFR_DimensionRec, *PFR_Dimension; + + /************************************************************************/ + + typedef struct PFR_KernItemRec_* PFR_KernItem; + + typedef struct PFR_KernItemRec_ + { + PFR_KernItem next; + FT_Byte pair_count; + FT_Byte flags; + FT_Short base_adj; + FT_UInt pair_size; + FT_UInt32 offset; + FT_UInt32 pair1; + FT_UInt32 pair2; + + } PFR_KernItemRec; + + +#define PFR_KERN_INDEX( g1, g2 ) \ + ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) ) + +#define PFR_KERN_PAIR_INDEX( pair ) \ + PFR_KERN_INDEX( (pair)->glyph1, (pair)->glyph2 ) + +#define PFR_NEXT_KPAIR( p ) ( p += 2, \ + ( (FT_UInt32)p[-2] << 16 ) | p[-1] ) + + + /************************************************************************/ + + typedef struct PFR_PhyFontRec_ + { + FT_Memory memory; + FT_UInt32 offset; + + FT_UInt font_ref_number; + FT_UInt outline_resolution; + FT_UInt metrics_resolution; + FT_BBox bbox; + FT_UInt flags; + FT_UInt standard_advance; + + FT_Int ascent; /* optional, bbox.yMax if not present */ + FT_Int descent; /* optional, bbox.yMin if not present */ + FT_Int leading; /* optional, 0 if not present */ + + PFR_DimensionRec horizontal; + PFR_DimensionRec vertical; + + FT_String* font_id; + FT_String* family_name; + FT_String* style_name; + + FT_UInt num_strikes; + FT_UInt max_strikes; + PFR_StrikeRec* strikes; + + FT_UInt num_blue_values; + FT_Int *blue_values; + FT_UInt blue_fuzz; + FT_UInt blue_scale; + + FT_UInt num_chars; + FT_UInt32 chars_offset; + PFR_Char chars; + + FT_UInt num_kern_pairs; + PFR_KernItem kern_items; + PFR_KernItem* kern_items_tail; + + /* not part of the spec, but used during load */ + FT_UInt32 bct_offset; + FT_Byte* cursor; + + } PFR_PhyFontRec, *PFR_PhyFont; + + + typedef enum PFR_PhyFlags_ + { + PFR_PHY_EXTRA_ITEMS = 0x80, + PFR_PHY_3BYTE_GPS_OFFSET = 0x20, + PFR_PHY_2BYTE_GPS_SIZE = 0x10, + PFR_PHY_ASCII_CODE = 0x08, + PFR_PHY_PROPORTIONAL = 0x04, + PFR_PHY_2BYTE_CHARCODE = 0x02, + PFR_PHY_VERTICAL = 0x01 + + } PFR_PhyFlags; + + + typedef enum PFR_KernFlags_ + { + PFR_KERN_2BYTE_CHAR = 0x01, + PFR_KERN_2BYTE_ADJ = 0x02 + + } PFR_KernFlags; + + + /************************************************************************/ + + typedef enum PFR_GlyphFlags_ + { + PFR_GLYPH_IS_COMPOUND = 0x80, + PFR_GLYPH_EXTRA_ITEMS = 0x08, + PFR_GLYPH_1BYTE_XYCOUNT = 0x04, + PFR_GLYPH_XCOUNT = 0x02, + PFR_GLYPH_YCOUNT = 0x01 + + } PFR_GlyphFlags; + + + /* controlled coordinate */ + typedef struct PFR_CoordRec_ + { + FT_UInt org; + FT_UInt cur; + + } PFR_CoordRec, *PFR_Coord; + + + typedef struct PFR_SubGlyphRec_ + { + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Int x_delta; + FT_Int y_delta; + FT_UInt32 gps_offset; + FT_UInt gps_size; + + } PFR_SubGlyphRec, *PFR_SubGlyph; + + + typedef enum PFR_SubgGlyphFlags_ + { + PFR_SUBGLYPH_3BYTE_OFFSET = 0x80, + PFR_SUBGLYPH_2BYTE_SIZE = 0x40, + PFR_SUBGLYPH_YSCALE = 0x20, + PFR_SUBGLYPH_XSCALE = 0x10 + + } PFR_SubGlyphFlags; + + + typedef struct PFR_GlyphRec_ + { + FT_Byte format; + +#if 0 + FT_UInt num_x_control; + FT_UInt num_y_control; +#endif + FT_UInt max_xy_control; + FT_Pos* x_control; + FT_Pos* y_control; + + + FT_UInt num_subs; + FT_UInt max_subs; + PFR_SubGlyphRec* subs; + + FT_GlyphLoader loader; + FT_Bool path_begun; + + } PFR_GlyphRec, *PFR_Glyph; + + +FT_END_HEADER + +#endif /* __PFRTYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/afmparse.c b/src/freetype2/psaux/afmparse.c new file mode 100644 index 0000000..0528fe6 --- /dev/null +++ b/src/freetype2/psaux/afmparse.c @@ -0,0 +1,960 @@ +/***************************************************************************/ +/* */ +/* afmparse.c */ +/* */ +/* AFM parser (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 <ft2build.h> +#include FT_FREETYPE_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_INTERNAL_DEBUG_H + +#include "afmparse.h" +#include "psconv.h" + +#include "psauxerr.h" + + +/***************************************************************************/ +/* */ +/* AFM_Stream */ +/* */ +/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. */ +/* */ +/* */ + + enum + { + AFM_STREAM_STATUS_NORMAL, + AFM_STREAM_STATUS_EOC, + AFM_STREAM_STATUS_EOL, + AFM_STREAM_STATUS_EOF + }; + + + typedef struct AFM_StreamRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + FT_Int status; + + } AFM_StreamRec; + + +#ifndef EOF +#define EOF -1 +#endif + + + /* this works because empty lines are ignored */ +#define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' ) + +#define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' ) +#define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) + + /* column separator; there is no `column' in the spec actually */ +#define AFM_IS_SEP( ch ) ( (ch) == ';' ) + +#define AFM_GETC() \ + ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ + : EOF ) + +#define AFM_STREAM_KEY_BEGIN( stream ) \ + (char*)( (stream)->cursor - 1 ) + +#define AFM_STREAM_KEY_LEN( stream, key ) \ + ( (char*)(stream)->cursor - key - 1 ) + +#define AFM_STATUS_EOC( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOC ) + +#define AFM_STATUS_EOL( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOL ) + +#define AFM_STATUS_EOF( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOF ) + + + static int + afm_stream_skip_spaces( AFM_Stream stream ) + { + int ch = 0; /* make stupid compiler happy */ + + + if ( AFM_STATUS_EOC( stream ) ) + return ';'; + + while ( 1 ) + { + ch = AFM_GETC(); + if ( !AFM_IS_SPACE( ch ) ) + break; + } + + if ( AFM_IS_NEWLINE( ch ) ) + stream->status = AFM_STREAM_STATUS_EOL; + else if ( AFM_IS_SEP( ch ) ) + stream->status = AFM_STREAM_STATUS_EOC; + else if ( AFM_IS_EOF( ch ) ) + stream->status = AFM_STREAM_STATUS_EOF; + + return ch; + } + + + /* read a key or value in current column */ + static char* + afm_stream_read_one( AFM_Stream stream ) + { + char* str; + int ch; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOC( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + while ( 1 ) + { + ch = AFM_GETC(); + if ( AFM_IS_SPACE( ch ) ) + break; + else if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_SEP( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOC; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /* read a string (i.e., read to EOL) */ + static char* + afm_stream_read_string( AFM_Stream stream ) + { + char* str; + int ch; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOL( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + /* scan to eol */ + while ( 1 ) + { + ch = AFM_GETC(); + if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /*************************************************************************/ + /* */ + /* AFM_Parser */ + /* */ + /* */ + + /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */ + typedef enum AFM_Token_ + { + AFM_TOKEN_ASCENDER, + AFM_TOKEN_AXISLABEL, + AFM_TOKEN_AXISTYPE, + AFM_TOKEN_B, + AFM_TOKEN_BLENDAXISTYPES, + AFM_TOKEN_BLENDDESIGNMAP, + AFM_TOKEN_BLENDDESIGNPOSITIONS, + AFM_TOKEN_C, + AFM_TOKEN_CC, + AFM_TOKEN_CH, + AFM_TOKEN_CAPHEIGHT, + AFM_TOKEN_CHARWIDTH, + AFM_TOKEN_CHARACTERSET, + AFM_TOKEN_CHARACTERS, + AFM_TOKEN_DESCENDER, + AFM_TOKEN_ENCODINGSCHEME, + AFM_TOKEN_ENDAXIS, + AFM_TOKEN_ENDCHARMETRICS, + AFM_TOKEN_ENDCOMPOSITES, + AFM_TOKEN_ENDDIRECTION, + AFM_TOKEN_ENDFONTMETRICS, + AFM_TOKEN_ENDKERNDATA, + AFM_TOKEN_ENDKERNPAIRS, + AFM_TOKEN_ENDTRACKKERN, + AFM_TOKEN_ESCCHAR, + AFM_TOKEN_FAMILYNAME, + AFM_TOKEN_FONTBBOX, + AFM_TOKEN_FONTNAME, + AFM_TOKEN_FULLNAME, + AFM_TOKEN_ISBASEFONT, + AFM_TOKEN_ISCIDFONT, + AFM_TOKEN_ISFIXEDPITCH, + AFM_TOKEN_ISFIXEDV, + AFM_TOKEN_ITALICANGLE, + AFM_TOKEN_KP, + AFM_TOKEN_KPH, + AFM_TOKEN_KPX, + AFM_TOKEN_KPY, + AFM_TOKEN_L, + AFM_TOKEN_MAPPINGSCHEME, + AFM_TOKEN_METRICSSETS, + AFM_TOKEN_N, + AFM_TOKEN_NOTICE, + AFM_TOKEN_PCC, + AFM_TOKEN_STARTAXIS, + AFM_TOKEN_STARTCHARMETRICS, + AFM_TOKEN_STARTCOMPOSITES, + AFM_TOKEN_STARTDIRECTION, + AFM_TOKEN_STARTFONTMETRICS, + AFM_TOKEN_STARTKERNDATA, + AFM_TOKEN_STARTKERNPAIRS, + AFM_TOKEN_STARTKERNPAIRS0, + AFM_TOKEN_STARTKERNPAIRS1, + AFM_TOKEN_STARTTRACKKERN, + AFM_TOKEN_STDHW, + AFM_TOKEN_STDVW, + AFM_TOKEN_TRACKKERN, + AFM_TOKEN_UNDERLINEPOSITION, + AFM_TOKEN_UNDERLINETHICKNESS, + AFM_TOKEN_VV, + AFM_TOKEN_VVECTOR, + AFM_TOKEN_VERSION, + AFM_TOKEN_W, + AFM_TOKEN_W0, + AFM_TOKEN_W0X, + AFM_TOKEN_W0Y, + AFM_TOKEN_W1, + AFM_TOKEN_W1X, + AFM_TOKEN_W1Y, + AFM_TOKEN_WX, + AFM_TOKEN_WY, + AFM_TOKEN_WEIGHT, + AFM_TOKEN_WEIGHTVECTOR, + AFM_TOKEN_XHEIGHT, + N_AFM_TOKENS, + AFM_TOKEN_UNKNOWN + + } AFM_Token; + + + static const char* const afm_key_table[N_AFM_TOKENS] = + { + "Ascender", + "AxisLabel", + "AxisType", + "B", + "BlendAxisTypes", + "BlendDesignMap", + "BlendDesignPositions", + "C", + "CC", + "CH", + "CapHeight", + "CharWidth", + "CharacterSet", + "Characters", + "Descender", + "EncodingScheme", + "EndAxis", + "EndCharMetrics", + "EndComposites", + "EndDirection", + "EndFontMetrics", + "EndKernData", + "EndKernPairs", + "EndTrackKern", + "EscChar", + "FamilyName", + "FontBBox", + "FontName", + "FullName", + "IsBaseFont", + "IsCIDFont", + "IsFixedPitch", + "IsFixedV", + "ItalicAngle", + "KP", + "KPH", + "KPX", + "KPY", + "L", + "MappingScheme", + "MetricsSets", + "N", + "Notice", + "PCC", + "StartAxis", + "StartCharMetrics", + "StartComposites", + "StartDirection", + "StartFontMetrics", + "StartKernData", + "StartKernPairs", + "StartKernPairs0", + "StartKernPairs1", + "StartTrackKern", + "StdHW", + "StdVW", + "TrackKern", + "UnderlinePosition", + "UnderlineThickness", + "VV", + "VVector", + "Version", + "W", + "W0", + "W0X", + "W0Y", + "W1", + "W1X", + "W1Y", + "WX", + "WY", + "Weight", + "WeightVector", + "XHeight" + }; + + + /* + * `afm_parser_read_vals' and `afm_parser_next_key' provide + * high-level operations to an AFM_Stream. The rest of the + * parser functions should use them without accessing the + * AFM_Stream directly. + */ + + FT_LOCAL_DEF( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ) + { + AFM_Stream stream = parser->stream; + char* str; + FT_Int i; + + + if ( n > AFM_MAX_ARGUMENTS ) + return 0; + + for ( i = 0; i < n; i++ ) + { + FT_UInt len; + AFM_Value val = vals + i; + + + if ( val->type == AFM_VALUE_TYPE_STRING ) + str = afm_stream_read_string( stream ); + else + str = afm_stream_read_one( stream ); + + if ( !str ) + break; + + len = AFM_STREAM_KEY_LEN( stream, str ); + + switch ( val->type ) + { + case AFM_VALUE_TYPE_STRING: + case AFM_VALUE_TYPE_NAME: + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( !FT_QALLOC( val->u.s, len + 1 ) ) + { + ft_memcpy( val->u.s, str, len ); + val->u.s[len] = '\0'; + } + } + break; + + case AFM_VALUE_TYPE_FIXED: + val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len, 0 ); + break; + + case AFM_VALUE_TYPE_INTEGER: + val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len ); + break; + + case AFM_VALUE_TYPE_BOOL: + val->u.b = FT_BOOL( len == 4 && + !ft_strncmp( str, "true", 4 ) ); + break; + + case AFM_VALUE_TYPE_INDEX: + if ( parser->get_index ) + val->u.i = parser->get_index( str, len, parser->user_data ); + else + val->u.i = 0; + break; + } + } + + return i; + } + + + FT_LOCAL_DEF( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_UInt* len ) + { + AFM_Stream stream = parser->stream; + char* key = 0; /* make stupid compiler happy */ + + + if ( line ) + { + while ( 1 ) + { + /* skip current line */ + if ( !AFM_STATUS_EOL( stream ) ) + afm_stream_read_string( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty line */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOL( stream ) ) + continue; + + break; + } + } + else + { + while ( 1 ) + { + /* skip current column */ + while ( !AFM_STATUS_EOC( stream ) ) + afm_stream_read_one( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty column */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOC( stream ) ) + continue; + + break; + } + } + + if ( len ) + *len = ( key ) ? AFM_STREAM_KEY_LEN( stream, key ) + : 0; + + return key; + } + + + static AFM_Token + afm_tokenize( const char* key, + FT_UInt len ) + { + int n; + + + for ( n = 0; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) == *key ) + { + for ( ; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) != *key ) + return AFM_TOKEN_UNKNOWN; + + if ( ft_strncmp( afm_key_table[n], key, len ) == 0 ) + return (AFM_Token) n; + } + } + } + + return AFM_TOKEN_UNKNOWN; + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ) + { + AFM_Stream stream; + FT_Error error; + + + if ( FT_NEW( stream ) ) + return error; + + stream->cursor = stream->base = base; + stream->limit = limit; + + /* don't skip the first line during the first call */ + stream->status = AFM_STREAM_STATUS_EOL; + + parser->memory = memory; + parser->stream = stream; + parser->FontInfo = NULL; + parser->get_index = NULL; + + return PSaux_Err_Ok; + } + + + FT_LOCAL( void ) + afm_parser_done( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + + + FT_FREE( parser->stream ); + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_read_int( AFM_Parser parser, + FT_Int* aint ) + { + AFM_ValueRec val; + + + val.type = AFM_VALUE_TYPE_INTEGER; + + if ( afm_parser_read_vals( parser, &val, 1 ) == 1 ) + { + *aint = val.u.i; + + return PSaux_Err_Ok; + } + else + return PSaux_Err_Syntax_Error; + } + + + static FT_Error + afm_parse_track_kern( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_TrackKern tk; + char* key; + FT_UInt len; + int n = -1; + + + if ( afm_parser_read_int( parser, &fi->NumTrackKern ) ) + goto Fail; + + if ( fi->NumTrackKern ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[5]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_TRACKKERN: + n++; + + if ( n >= fi->NumTrackKern ) + goto Fail; + + tk = fi->TrackKerns + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + shared_vals[4].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) + goto Fail; + + tk->degree = shared_vals[0].u.i; + tk->min_ptsize = shared_vals[1].u.f; + tk->min_kern = shared_vals[2].u.f; + tk->max_ptsize = shared_vals[3].u.f; + tk->max_kern = shared_vals[4].u.f; + + /* is this correct? */ + if ( tk->degree < 0 && tk->min_kern > 0 ) + tk->min_kern = -tk->min_kern; + break; + + case AFM_TOKEN_ENDTRACKKERN: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + fi->NumTrackKern = n + 1; + return PSaux_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return PSaux_Err_Syntax_Error; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + FT_CALLBACK_DEF( int ) + afm_compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair kp1 = (AFM_KernPair)a; + AFM_KernPair kp2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 ); + FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 ); + + + return (int)( index1 - index2 ); + } + + + static FT_Error + afm_parse_kern_pairs( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_KernPair kp; + char* key; + FT_UInt len; + int n = -1; + + + if ( afm_parser_read_int( parser, &fi->NumKernPair ) ) + goto Fail; + + if ( fi->NumKernPair ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + switch ( token ) + { + case AFM_TOKEN_KP: + case AFM_TOKEN_KPX: + case AFM_TOKEN_KPY: + { + FT_Int r; + AFM_ValueRec shared_vals[4]; + + + n++; + + if ( n >= fi->NumKernPair ) + goto Fail; + + kp = fi->KernPairs + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INDEX; + shared_vals[1].type = AFM_VALUE_TYPE_INDEX; + shared_vals[2].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; + r = afm_parser_read_vals( parser, shared_vals, 4 ); + if ( r < 3 ) + goto Fail; + + kp->index1 = shared_vals[0].u.i; + kp->index2 = shared_vals[1].u.i; + if ( token == AFM_TOKEN_KPY ) + { + kp->x = 0; + kp->y = shared_vals[2].u.i; + } + else + { + kp->x = shared_vals[2].u.i; + kp->y = ( token == AFM_TOKEN_KP && r == 4 ) + ? shared_vals[3].u.i : 0; + } + } + break; + + case AFM_TOKEN_ENDKERNPAIRS: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + fi->NumKernPair = n + 1; + ft_qsort( fi->KernPairs, fi->NumKernPair, + sizeof( AFM_KernPairRec ), + afm_compare_kern_pairs ); + return PSaux_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return PSaux_Err_Syntax_Error; + } + + + static FT_Error + afm_parse_kern_data( AFM_Parser parser ) + { + FT_Error error; + char* key; + FT_UInt len; + + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_STARTTRACKKERN: + error = afm_parse_track_kern( parser ); + if ( error ) + return error; + break; + + case AFM_TOKEN_STARTKERNPAIRS: + case AFM_TOKEN_STARTKERNPAIRS0: + error = afm_parse_kern_pairs( parser ); + if ( error ) + return error; + break; + + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + return PSaux_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return PSaux_Err_Syntax_Error; + } + + + static FT_Error + afm_parser_skip_section( AFM_Parser parser, + FT_UInt n, + AFM_Token end_section ) + { + char* key; + FT_UInt len; + + + while ( n-- > 0 ) + { + key = afm_parser_next_key( parser, 1, NULL ); + if ( !key ) + goto Fail; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS ) + return PSaux_Err_Ok; + } + + Fail: + return PSaux_Err_Syntax_Error; + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_parse( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + AFM_FontInfo fi = parser->FontInfo; + FT_Error error = PSaux_Err_Syntax_Error; + char* key; + FT_UInt len; + FT_Int metrics_sets = 0; + + + if ( !fi ) + return PSaux_Err_Invalid_Argument; + + key = afm_parser_next_key( parser, 1, &len ); + if ( !key || len != 16 || + ft_strncmp( key, "StartFontMetrics", 16 ) != 0 ) + return PSaux_Err_Unknown_File_Format; + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[4]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_METRICSSETS: + if ( afm_parser_read_int( parser, &metrics_sets ) ) + goto Fail; + + if ( metrics_sets != 0 && metrics_sets != 2 ) + { + error = PSaux_Err_Unimplemented_Feature; + + goto Fail; + } + break; + + case AFM_TOKEN_ISCIDFONT: + shared_vals[0].type = AFM_VALUE_TYPE_BOOL; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->IsCIDFont = shared_vals[0].u.b; + break; + + case AFM_TOKEN_FONTBBOX: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 ) + goto Fail; + + fi->FontBBox.xMin = shared_vals[0].u.f; + fi->FontBBox.yMin = shared_vals[1].u.f; + fi->FontBBox.xMax = shared_vals[2].u.f; + fi->FontBBox.yMax = shared_vals[3].u.f; + break; + + case AFM_TOKEN_ASCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Ascender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_DESCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Descender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_STARTCHARMETRICS: + { + FT_Int n = 0; + + + if ( afm_parser_read_int( parser, &n ) ) + goto Fail; + + error = afm_parser_skip_section( parser, n, + AFM_TOKEN_ENDCHARMETRICS ); + if ( error ) + return error; + } + break; + + case AFM_TOKEN_STARTKERNDATA: + error = afm_parse_kern_data( parser ); + if ( error ) + goto Fail; + /* fall through since we only support kern data */ + + case AFM_TOKEN_ENDFONTMETRICS: + return PSaux_Err_Ok; + + default: + break; + } + } + + Fail: + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + fi->IsCIDFont = 0; + + return error; + } + + +/* END */ diff --git a/src/freetype2/psaux/afmparse.h b/src/freetype2/psaux/afmparse.h new file mode 100644 index 0000000..c2fce75 --- /dev/null +++ b/src/freetype2/psaux/afmparse.h @@ -0,0 +1,87 @@ +/***************************************************************************/ +/* */ +/* afmparse.h */ +/* */ +/* AFM parser (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __AFMPARSE_H__ +#define __AFMPARSE_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_AUX_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + + FT_LOCAL( void ) + afm_parser_done( AFM_Parser parser ); + + + FT_LOCAL( FT_Error ) + afm_parser_parse( AFM_Parser parser ); + + + enum AFM_ValueType_ + { + AFM_VALUE_TYPE_STRING, + AFM_VALUE_TYPE_NAME, + AFM_VALUE_TYPE_FIXED, /* real number */ + AFM_VALUE_TYPE_INTEGER, + AFM_VALUE_TYPE_BOOL, + AFM_VALUE_TYPE_INDEX /* glyph index */ + }; + + + typedef struct AFM_ValueRec_ + { + enum AFM_ValueType_ type; + union { + char* s; + FT_Fixed f; + FT_Int i; + FT_Bool b; + + } u; + + } AFM_ValueRec, *AFM_Value; + +#define AFM_MAX_ARGUMENTS 5 + + FT_LOCAL( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ); + + /* read the next key from the next line or column */ + FT_LOCAL( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_UInt* len ); + +FT_END_HEADER + +#endif /* __AFMPARSE_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/psaux.c b/src/freetype2/psaux/psaux.c new file mode 100644 index 0000000..a4b9c5c --- /dev/null +++ b/src/freetype2/psaux/psaux.c @@ -0,0 +1,34 @@ +/***************************************************************************/ +/* */ +/* psaux.c */ +/* */ +/* FreeType auxiliary PostScript driver component (body only). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> +#include "psobjs.c" +#include "psauxmod.c" +#include "t1decode.c" +#include "t1cmap.c" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "afmparse.c" +#endif + +#include "psconv.c" + + +/* END */ diff --git a/src/freetype2/psaux/psauxerr.h b/src/freetype2/psaux/psauxerr.h new file mode 100644 index 0000000..d0baa3c --- /dev/null +++ b/src/freetype2/psaux/psauxerr.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* psauxerr.h */ +/* */ +/* PS auxiliary module error codes (specification only). */ +/* */ +/* Copyright 2001 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 PS auxiliary module error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __PSAUXERR_H__ +#define __PSAUXERR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX PSaux_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSaux + +#include FT_ERRORS_H + +#endif /* __PSAUXERR_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/psauxmod.c b/src/freetype2/psaux/psauxmod.c new file mode 100644 index 0000000..4c3579f --- /dev/null +++ b/src/freetype2/psaux/psauxmod.c @@ -0,0 +1,139 @@ +/***************************************************************************/ +/* */ +/* psauxmod.c */ +/* */ +/* FreeType auxiliary PostScript module implementation (body). */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 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 "psauxmod.h" +#include "psobjs.h" +#include "t1decode.h" +#include "t1cmap.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "afmparse.h" +#endif + + + FT_CALLBACK_TABLE_DEF + const PS_Table_FuncsRec ps_table_funcs = + { + ps_table_new, + ps_table_done, + ps_table_add, + ps_table_release + }; + + + FT_CALLBACK_TABLE_DEF + const PS_Parser_FuncsRec ps_parser_funcs = + { + ps_parser_init, + ps_parser_done, + ps_parser_skip_spaces, + ps_parser_skip_PS_token, + ps_parser_to_int, + ps_parser_to_fixed, + ps_parser_to_bytes, + ps_parser_to_coord_array, + ps_parser_to_fixed_array, + ps_parser_to_token, + ps_parser_to_token_array, + ps_parser_load_field, + ps_parser_load_field_table + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Builder_FuncsRec t1_builder_funcs = + { + t1_builder_init, + t1_builder_done, + t1_builder_check_points, + t1_builder_add_point, + t1_builder_add_point1, + t1_builder_add_contour, + t1_builder_start_point, + t1_builder_close_contour + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Decoder_FuncsRec t1_decoder_funcs = + { + t1_decoder_init, + t1_decoder_done, + t1_decoder_parse_charstrings + }; + + +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE_DEF + const AFM_Parser_FuncsRec afm_parser_funcs = + { + afm_parser_init, + afm_parser_done, + afm_parser_parse + }; +#endif + + + FT_CALLBACK_TABLE_DEF + const T1_CMap_ClassesRec t1_cmap_classes = + { + &t1_cmap_standard_class_rec, + &t1_cmap_expert_class_rec, + &t1_cmap_custom_class_rec, + &t1_cmap_unicode_class_rec + }; + + + static + const PSAux_Interface psaux_interface = + { + &ps_table_funcs, + &ps_parser_funcs, + &t1_builder_funcs, + &t1_decoder_funcs, + t1_decrypt, + + (const T1_CMap_ClassesRec*) &t1_cmap_classes, + +#ifndef T1_CONFIG_OPTION_NO_AFM + &afm_parser_funcs, +#else + 0, +#endif + }; + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class psaux_module_class = + { + 0, + sizeof( FT_ModuleRec ), + "psaux", + 0x20000L, + 0x20000L, + + &psaux_interface, /* module-specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }; + + +/* END */ diff --git a/src/freetype2/psaux/psauxmod.h b/src/freetype2/psaux/psauxmod.h new file mode 100644 index 0000000..92ac056 --- /dev/null +++ b/src/freetype2/psaux/psauxmod.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* psauxmod.h */ +/* */ +/* FreeType auxiliary PostScript module implementation (specification). */ +/* */ +/* Copyright 2000-2001 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 __PSAUXMOD_H__ +#define __PSAUXMOD_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; + + +FT_END_HEADER + +#endif /* __PSAUXMOD_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/psconv.c b/src/freetype2/psaux/psconv.c new file mode 100644 index 0000000..3bbeab6 --- /dev/null +++ b/src/freetype2/psaux/psconv.c @@ -0,0 +1,466 @@ +/***************************************************************************/ +/* */ +/* psconv.c */ +/* */ +/* Some convenience conversions (body). */ +/* */ +/* Copyright 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_POSTSCRIPT_AUX_H +#include FT_INTERNAL_DEBUG_H + +#include "psconv.h" +#include "psobjs.h" +#include "psauxerr.h" + + + /* The following array is used by various functions to quickly convert */ + /* digits (both decimal and non-decimal) into numbers. */ + +#if 'A' == 65 + /* ASCII */ + + static const FT_Char ft_char_table[128] = + { + /* 0x00 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + }; + + /* no character >= 0x80 can represent a valid number */ +#define OP >= + +#endif /* 'A' == 65 */ + +#if 'A' == 193 + /* EBCDIC */ + + static const FT_Char ft_char_table[128] = + { + /* 0x80 */ + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + }; + + /* no character < 0x80 can represent a valid number */ +#define OP < + +#endif /* 'A' == 193 */ + + + FT_LOCAL_DEF( FT_Int ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Int base ) + { + FT_Byte* p = *cursor; + FT_Int num = 0; + FT_Bool sign = 0; + + + if ( p == limit || base < 2 || base > 36 ) + return 0; + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + return 0; + } + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7f]; + + if ( c < 0 || c >= base ) + break; + + num = num * base + c; + } + + if ( sign ) + num = -num; + + *cursor = p; + + return num; + } + + + FT_LOCAL_DEF( FT_Int ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ) + + { + FT_Byte* p; + FT_Int num; + + + num = PS_Conv_Strtol( cursor, limit, 10 ); + p = *cursor; + + if ( p < limit && *p == '#' ) + { + *cursor = p + 1; + + return PS_Conv_Strtol( cursor, limit, num ); + } + else + return num; + } + + + FT_LOCAL_DEF( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Int power_ten ) + { + FT_Byte* p = *cursor; + FT_Fixed integral; + FT_Long decimal = 0, divider = 1; + FT_Bool sign = 0; + + + if ( p == limit ) + return 0; + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + return 0; + } + + if ( *p != '.' ) + integral = PS_Conv_ToInt( &p, limit ) << 16; + else + integral = 0; + + /* read the decimal part */ + if ( p < limit && *p == '.' ) + { + p++; + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7f]; + + if ( c < 0 || c >= 10 ) + break; + + if ( divider < 10000000L ) + { + decimal = decimal * 10 + c; + divider *= 10; + } + } + } + + /* read exponent, if any */ + if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) ) + { + p++; + power_ten += PS_Conv_ToInt( &p, limit ); + } + + while ( power_ten > 0 ) + { + integral *= 10; + decimal *= 10; + power_ten--; + } + + while ( power_ten < 0 ) + { + integral /= 10; + divider *= 10; + power_ten++; + } + + if ( decimal ) + integral += FT_DivFix( decimal, divider ); + + if ( sign ) + integral = -integral; + + *cursor = p; + + return integral; + } + + +#if 0 + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n ) + { + FT_Byte* p; + FT_UInt r = 0; + + + for ( p = *cursor; r < n && p < limit; p++ ) + { + FT_Byte b; + + + if ( *p != '\\' ) + { + buffer[r++] = *p; + + continue; + } + + p++; + + switch ( *p ) + { + case 'n': + b = '\n'; + break; + case 'r': + b = '\r'; + break; + case 't': + b = '\t'; + break; + case 'b': + b = '\b'; + break; + case 'f': + b = '\f'; + break; + case '\r': + p++; + if ( *p != '\n' ) + { + b = *p; + + break; + } + /* no break */ + case '\n': + continue; + break; + default: + if ( IS_PS_DIGIT( *p ) ) + { + b = *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + { + b = b * 8 + *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + b = b * 8 + *p - '0'; + else + { + buffer[r++] = b; + b = *p; + } + } + else + { + buffer[r++] = b; + b = *p; + } + } + else + b = *p; + break; + } + + buffer[r++] = b; + } + + *cursor = p; + + return r; + } +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n ) + { + FT_Byte* p; + FT_UInt r = 0; + FT_UInt w = 0; + FT_UInt pad = 0x01; + + + n *= 2; + +#if 1 + + p = *cursor; + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); + + /* we try to process two nibbles at a time to be as fast as possible */ + for ( ; r < n; r++ ) + { + FT_UInt c = p[r]; + + + if ( IS_PS_SPACE( c ) ) + continue; + + if ( c OP 0x80 ) + break; + + c = ft_char_table[c & 0x7F]; + if ( (unsigned)c >= 16 ) + break; + + pad = ( pad << 4 ) | c; + if ( pad & 0x100 ) + { + buffer[w++] = (FT_Byte)pad; + pad = 0x01; + } + } + + if ( pad != 0x01 ) + buffer[w++] = (FT_Byte)( pad << 4 ); + + *cursor = p + r; + + return w; + +#else /* 0 */ + + for ( r = 0; r < n; r++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) ) + continue; + + if ( *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7f]; + + if ( (unsigned)c >= 16 ) + break; + + if ( r & 1 ) + { + *buffer = (FT_Byte)(*buffer + c); + buffer++; + } + else + *buffer = (FT_Byte)(c << 4); + + r++; + } + + *cursor = p; + + return ( r + 1 ) / 2; + +#endif /* 0 */ + + } + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n, + FT_UShort* seed ) + { + FT_Byte* p; + FT_UInt r; + FT_UInt s = *seed; + + +#if 1 + + p = *cursor; + if ( n > (FT_UInt)(limit - p) ) + n = (FT_UInt)(limit - p); + + for ( r = 0; r < n; r++ ) + { + FT_UInt val = p[r]; + FT_UInt b = ( val ^ ( s >> 8 ) ); + + + s = ( (val + s)*52845U + 22719 ) & 0xFFFFU; + buffer[r] = (FT_Byte) b; + } + + *cursor = p + n; + *seed = (FT_UShort)s; + +#else /* 0 */ + + for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ ) + { + FT_Byte b = (FT_Byte)( *p ^ ( s >> 8 ) ); + + + s = (FT_UShort)( ( *p + s ) * 52845U + 22719 ); + *buffer++ = b; + } + *cursor = p; + *seed = s; + +#endif /* 0 */ + + return r; + } + + +/* END */ diff --git a/src/freetype2/psaux/psconv.h b/src/freetype2/psaux/psconv.h new file mode 100644 index 0000000..e511241 --- /dev/null +++ b/src/freetype2/psaux/psconv.h @@ -0,0 +1,71 @@ +/***************************************************************************/ +/* */ +/* psconv.h */ +/* */ +/* Some convenience conversions (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __PSCONV_H__ +#define __PSCONV_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_AUX_H + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Int ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Int base ); + + + FT_LOCAL( FT_Int ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ); + + FT_LOCAL( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Int power_ten ); + +#if 0 + FT_LOCAL( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n ); +#endif + + FT_LOCAL( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n ); + + FT_LOCAL( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_UInt n, + FT_UShort* seed ); + + +FT_END_HEADER + +#endif /* __PSCONV_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/psobjs.c b/src/freetype2/psaux/psobjs.c new file mode 100644 index 0000000..9570856 --- /dev/null +++ b/src/freetype2/psaux/psobjs.c @@ -0,0 +1,1698 @@ +/***************************************************************************/ +/* */ +/* psobjs.c */ +/* */ +/* Auxiliary functions for PostScript fonts (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_INTERNAL_DEBUG_H + +#include "psobjs.h" +#include "psconv.h" + +#include "psauxerr.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_psobjs + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ps_table_new */ + /* */ + /* <Description> */ + /* Initializes a PS_Table. */ + /* */ + /* <InOut> */ + /* table :: The address of the target table. */ + /* */ + /* <Input> */ + /* count :: The table size = the maximum number of elements. */ + /* */ + /* memory :: The memory object to use for all subsequent */ + /* reallocations. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + if ( FT_NEW_ARRAY( table->elements, count ) || + FT_NEW_ARRAY( table->lengths, count ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xDEADBEEFUL; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; + + Exit: + if ( error ) + FT_FREE( table->elements ); + + return error; + } + + + static void + shift_elements( PS_Table table, + FT_Byte* old_base ) + { + FT_PtrDist delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + for ( ; offset < limit; offset++ ) + { + if ( offset[0] ) + offset[0] += delta; + } + } + + + static FT_Error + reallocate_t1_table( PS_Table table, + FT_Long new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* allocate new base block */ + if ( FT_ALLOC( table->block, new_size ) ) + { + table->block = old_base; + return error; + } + + /* copy elements and shift offsets */ + if ( old_base ) + { + FT_MEM_COPY( table->block, old_base, table->capacity ); + shift_elements( table, old_base ); + FT_FREE( old_base ); + } + + table->capacity = new_size; + + return PSaux_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ps_table_add */ + /* */ + /* <Description> */ + /* Adds an object to a PS_Table, possibly growing its memory block. */ + /* */ + /* <InOut> */ + /* table :: The target table. */ + /* */ + /* <Input> */ + /* idx :: The index of the object in the table. */ + /* */ + /* object :: The address of the object to copy in memory. */ + /* */ + /* length :: The length in bytes of the source object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. An error is returned if a */ + /* reallocation fails. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ) + { + if ( idx < 0 || idx > table->max_elems ) + { + FT_ERROR(( "ps_table_add: invalid index\n" )); + return PSaux_Err_Invalid_Argument; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Offset new_size = table->capacity; + FT_Long in_offset; + + + in_offset = (FT_Long)((FT_Byte*)object - table->block); + if ( (FT_ULong)in_offset >= table->capacity ) + in_offset = -1; + + while ( new_size < table->cursor + length ) + { + /* increase size by 25% and round up to the nearest multiple + of 1024 */ + new_size += ( new_size >> 2 ) + 1; + new_size = FT_PAD_CEIL( new_size, 1024 ); + } + + error = reallocate_t1_table( table, new_size ); + if ( error ) + return error; + + if ( in_offset >= 0 ) + object = table->block + in_offset; + } + + /* add the object to the base block and adjust offset */ + table->elements[idx] = table->block + table->cursor; + table->lengths [idx] = length; + FT_MEM_COPY( table->block + table->cursor, object, length ); + + table->cursor += length; + return PSaux_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ps_table_done */ + /* */ + /* <Description> */ + /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ + /* cursor). */ + /* */ + /* <InOut> */ + /* table :: The target table. */ + /* */ + /* <Note> */ + /* This function does NOT release the heap's memory block. It is up */ + /* to the caller to clean it, or reference it in its own structures. */ + /* */ + FT_LOCAL_DEF( void ) + ps_table_done( PS_Table table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base = table->block; + + + /* should never fail, because rec.cursor <= rec.size */ + if ( !old_base ) + return; + + if ( FT_ALLOC( table->block, table->cursor ) ) + return; + FT_MEM_COPY( table->block, old_base, table->cursor ); + shift_elements( table, old_base ); + + table->capacity = table->cursor; + FT_FREE( old_base ); + + FT_UNUSED( error ); + } + + + FT_LOCAL_DEF( void ) + ps_table_release( PS_Table table ) + { + FT_Memory memory = table->memory; + + + if ( (FT_ULong)table->init == 0xDEADBEEFUL ) + { + FT_FREE( table->block ); + FT_FREE( table->elements ); + FT_FREE( table->lengths ); + table->init = 0; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* first character must be already part of the comment */ + + static void + skip_comment( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( IS_PS_NEWLINE( *cur ) ) + break; + cur++; + } + + *acur = cur; + } + + + static void + skip_spaces( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( !IS_PS_SPACE( *cur ) ) + { + if ( *cur == '%' ) + /* According to the PLRM, a comment is equal to a space. */ + skip_comment( &cur, limit ); + else + break; + } + cur++; + } + + *acur = cur; + } + + +#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) + + + /* first character must be `('; */ + /* *acur is positioned at the character after the closing `)' */ + + static FT_Error + skip_literal_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Int embed = 0; + FT_Error error = PSaux_Err_Invalid_File_Format; + unsigned int i; + + + while ( cur < limit ) + { + FT_Byte c = *cur; + + + ++cur; + + if ( c == '\\' ) + { + /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ + /* A backslash can introduce three different types */ + /* of escape sequences: */ + /* - a special escaped char like \r, \n, etc. */ + /* - a one-, two-, or three-digit octal number */ + /* - none of the above in which case the backslash is ignored */ + + if ( cur == limit ) + /* error (or to be ignored?) */ + break; + + switch ( *cur ) + { + /* skip `special' escape */ + case 'n': + case 'r': + case 't': + case 'b': + case 'f': + case '\\': + case '(': + case ')': + ++cur; + break; + + default: + /* skip octal escape or ignore backslash */ + for ( i = 0; i < 3 && cur < limit; ++i ) + { + if ( ! IS_OCTAL_DIGIT( *cur ) ) + break; + + ++cur; + } + } + } + else if ( c == '(' ) + embed++; + else if ( c == ')' ) + { + embed--; + if ( embed == 0 ) + { + error = PSaux_Err_Ok; + break; + } + } + } + + *acur = cur; + + return error; + } + + + /* first character must be `<' */ + + static FT_Error + skip_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Error err = PSaux_Err_Ok; + + + while ( ++cur < limit ) + { + /* All whitespace characters are ignored. */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; + + if ( !IS_PS_XDIGIT( *cur ) ) + break; + } + + if ( cur < limit && *cur != '>' ) + { + FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); + err = PSaux_Err_Invalid_File_Format; + } + else + cur++; + + *acur = cur; + return err; + } + + + /* first character must be the opening brace that */ + /* starts the procedure */ + + /* NB: [ and ] need not match: */ + /* `/foo {[} def' is a valid PostScript fragment, */ + /* even within a Type1 font */ + + static FT_Error + skip_procedure( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur; + FT_Int embed = 0; + FT_Error error = PSaux_Err_Ok; + + + FT_ASSERT( **acur == '{' ); + + for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur ) + { + switch ( *cur ) + { + case '{': + ++embed; + break; + + case '}': + --embed; + if ( embed == 0 ) + { + ++cur; + goto end; + } + break; + + case '(': + error = skip_literal_string( &cur, limit ); + break; + + case '<': + error = skip_string( &cur, limit ); + break; + + case '%': + skip_comment( &cur, limit ); + break; + } + } + + end: + if ( embed != 0 ) + error = PSaux_Err_Invalid_File_Format; + + *acur = cur; + + return error; + } + + + /***********************************************************************/ + /* */ + /* All exported parsing routines handle leading whitespace and stop at */ + /* the first character which isn't part of the just handled token. */ + /* */ + /***********************************************************************/ + + + FT_LOCAL_DEF( void ) + ps_parser_skip_PS_token( PS_Parser parser ) + { + /* Note: PostScript allows any non-delimiting, non-whitespace */ + /* character in a name (PS Ref Manual, 3rd ed, p31). */ + /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ + + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + FT_Error error = PSaux_Err_Ok; + + + skip_spaces( &cur, limit ); /* this also skips comments */ + if ( cur >= limit ) + goto Exit; + + /* self-delimiting, single-character tokens */ + if ( *cur == '[' || *cur == ']' ) + { + cur++; + goto Exit; + } + + /* skip balanced expressions (procedures and strings) */ + + if ( *cur == '{' ) /* {...} */ + { + error = skip_procedure( &cur, limit ); + goto Exit; + } + + if ( *cur == '(' ) /* (...) */ + { + error = skip_literal_string( &cur, limit ); + goto Exit; + } + + if ( *cur == '<' ) /* <...> */ + { + if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ + { + cur++; + cur++; + } + else + error = skip_string( &cur, limit ); + + goto Exit; + } + + if ( *cur == '>' ) + { + cur++; + if ( cur >= limit || *cur != '>' ) /* >> */ + { + FT_ERROR(( "ps_parser_skip_PS_token: " + "unexpected closing delimiter `>'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + cur++; + goto Exit; + } + + if ( *cur == '/' ) + cur++; + + /* anything else */ + while ( cur < limit ) + { + /* *cur might be invalid (e.g., ')' or '}'), but this */ + /* is handled by the test `cur == parser->cursor' below */ + if ( IS_PS_DELIM( *cur ) ) + break; + + cur++; + } + + Exit: + if ( cur == parser->cursor ) + { + FT_ERROR(( "ps_parser_skip_PS_token: " + "current token is `%c', which is self-delimiting " + "but invalid at this point\n", + *cur )); + + error = PSaux_Err_Invalid_File_Format; + } + + parser->error = error; + parser->cursor = cur; + } + + + FT_LOCAL_DEF( void ) + ps_parser_skip_spaces( PS_Parser parser ) + { + skip_spaces( &parser->cursor, parser->limit ); + } + + + /* `token' here means either something between balanced delimiters */ + /* or the next token; the delimiters are not removed. */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Int embed; + + + token->type = T1_TOKEN_TYPE_NONE; + token->start = 0; + token->limit = 0; + + /* first of all, skip leading whitespace */ + ps_parser_skip_spaces( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur >= limit ) + return; + + switch ( *cur ) + { + /************* check for literal string *****************/ + case '(': + token->type = T1_TOKEN_TYPE_STRING; + token->start = cur; + + if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok ) + token->limit = cur; + break; + + /************* check for programs/array *****************/ + case '{': + token->type = T1_TOKEN_TYPE_ARRAY; + token->start = cur; + + if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok ) + token->limit = cur; + break; + + /************* check for table/array ********************/ + /* XXX: in theory we should also look for "<<" */ + /* since this is semantically equivalent to "["; */ + /* in practice it doesn't matter (?) */ + case '[': + token->type = T1_TOKEN_TYPE_ARRAY; + embed = 1; + token->start = cur++; + + /* we need this to catch `[ ]' */ + parser->cursor = cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + while ( cur < limit && !parser->error ) + { + /* XXX: this is wrong because it does not */ + /* skip comments, procedures, and strings */ + if ( *cur == '[' ) + embed++; + else if ( *cur == ']' ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = ++cur; + break; + } + } + + parser->cursor = cur; + ps_parser_skip_PS_token( parser ); + /* we need this to catch `[XXX ]' */ + ps_parser_skip_spaces ( parser ); + cur = parser->cursor; + } + break; + + /* ************ otherwise, it is any token **************/ + default: + token->start = cur; + token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); + ps_parser_skip_PS_token( parser ); + cur = parser->cursor; + if ( !parser->error ) + token->limit = cur; + } + + if ( !token->limit ) + { + token->start = 0; + token->type = T1_TOKEN_TYPE_NONE; + } + + parser->cursor = cur; + } + + + /* NB: `tokens' can be NULL if we only want to count */ + /* the number of array elements */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + T1_TokenRec master; + + + *pnum_tokens = -1; + + /* this also handles leading whitespace */ + ps_parser_to_token( parser, &master ); + + if ( master.type == T1_TOKEN_TYPE_ARRAY ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + T1_Token cur = tokens; + T1_Token limit = cur + max_tokens; + + + /* don't include outermost delimiters */ + parser->cursor = master.start + 1; + parser->limit = master.limit - 1; + + while ( parser->cursor < parser->limit ) + { + T1_TokenRec token; + + + ps_parser_to_token( parser, &token ); + if ( !token.type ) + break; + + if ( tokens != NULL && cur < limit ) + *cur = token; + + cur++; + } + + *pnum_tokens = (FT_Int)( cur - tokens ); + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `coords' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_coords' */ + + static FT_Int + ps_tocoordarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array; otherwise, only one number */ + /* will be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the coordinates */ + while ( cur < limit ) + { + FT_Short dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( coords != NULL && count >= max_coords ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( coords != NULL ? &coords[count] : &dummy ) = + (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `values' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_values' */ + + static FT_Int + ps_tofixedarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* Check for the beginning of an array. Otherwise, only one number */ + /* will be read. */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the values */ + while ( cur < limit ) + { + FT_Fixed dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( values != NULL && count >= max_values ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( values != NULL ? &values[count] : &dummy ) = + PS_Conv_ToFixed( &cur, limit, power_ten ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + +#if 0 + + static FT_String* + ps_tostring( FT_Byte** cursor, + FT_Byte* limit, + FT_Memory memory ) + { + FT_Byte* cur = *cursor; + FT_PtrDist len = 0; + FT_Int count; + FT_String* result; + FT_Error error; + + + /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ + /* that simply doesn't begin with an opening parenthesis, even */ + /* though they have a closing one! E.g. "amuncial.pfb" */ + /* */ + /* We must deal with these ill-fated cases there. Note that */ + /* these fonts didn't work with the old Type 1 driver as the */ + /* notice/copyright was not recognized as a valid string token */ + /* and made the old token parser commit errors. */ + + while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) + cur++; + if ( cur + 1 >= limit ) + return 0; + + if ( *cur == '(' ) + cur++; /* skip the opening parenthesis, if there is one */ + + *cursor = cur; + count = 0; + + /* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if ( *cur == '(' ) + count++; + + else if ( *cur == ')' ) + { + count--; + if ( count < 0 ) + break; + } + } + + len = cur - *cursor; + if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) + return 0; + + /* now copy the string */ + FT_MEM_COPY( result, *cursor, len ); + result[len] = '\0'; + *cursor = cur; + return result; + } + +#endif /* 0 */ + + + static int + ps_tobool( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Bool result = 0; + + + /* return 1 if we find `true', 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + + *acur = cur; + return result; + } + + + /* load a simple field (i.e. non-table) into the current list of objects */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt idx; + FT_Error error; + + + /* this also skips leading whitespace */ + ps_parser_to_token( parser, &token ); + if ( !token.type ) + goto Fail; + + count = 1; + idx = 0; + cur = token.start; + limit = token.limit; + + /* we must detect arrays in /FontBBox */ + if ( field->type == T1_FIELD_TYPE_BBOX ) + { + T1_TokenRec token2; + FT_Byte* old_cur = parser->cursor; + FT_Byte* old_limit = parser->limit; + + + /* don't include delimiters */ + parser->cursor = token.start + 1; + parser->limit = token.limit - 1; + + ps_parser_to_token( parser, &token2 ); + parser->cursor = old_cur; + parser->limit = old_limit; + + if ( token2.type == T1_TOKEN_TYPE_ARRAY ) + goto FieldArray; + } + else if ( token.type == T1_TOKEN_TYPE_ARRAY ) + { + FieldArray: + /* if this is an array and we have no blend, an error occurs */ + if ( max_objects == 0 ) + goto Fail; + + count = max_objects; + idx = 1; + + /* don't include delimiters */ + cur++; + limit--; + } + + for ( ; count > 0; count--, idx++ ) + { + FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; + FT_Long val; + FT_String* string; + + + skip_spaces( &cur, limit ); + + switch ( field->type ) + { + case T1_FIELD_TYPE_BOOL: + val = ps_tobool( &cur, limit ); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED: + val = PS_Conv_ToFixed( &cur, limit, 0 ); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED_1000: + val = PS_Conv_ToFixed( &cur, limit, 3 ); + goto Store_Integer; + + case T1_FIELD_TYPE_INTEGER: + val = PS_Conv_ToInt( &cur, limit ); + /* fall through */ + + Store_Integer: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_UShort*)q = (FT_UShort)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)q = (FT_UInt32)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case T1_FIELD_TYPE_STRING: + case T1_FIELD_TYPE_KEY: + { + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + + + if ( cur >= limit ) + break; + + /* we allow both a string or a name */ + /* for cases like /FontName (foo) def */ + if ( token.type == T1_TOKEN_TYPE_KEY ) + { + /* don't include leading `/' */ + len--; + cur++; + } + else if ( token.type == T1_TOKEN_TYPE_STRING ) + { + /* don't include delimiting parentheses */ + /* XXX we don't handle <<...>> here */ + /* XXX should we convert octal escapes? */ + /* if so, what encoding should we use? */ + cur++; + len -= 2; + } + else + { + FT_ERROR(( "ps_parser_load_field: expected a name or string " + "but found token of type %d instead\n", + token.type )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + /* for this to work (FT_String**)q must have been */ + /* initialized to NULL */ + if ( *(FT_String**)q != NULL ) + { + FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", + field->ident )); + FT_FREE( *(FT_String**)q ); + *(FT_String**)q = NULL; + } + + if ( FT_ALLOC( string, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( string, cur, len ); + string[len] = 0; + + *(FT_String**)q = string; + } + break; + + case T1_FIELD_TYPE_BBOX: + { + FT_Fixed temp[4]; + FT_BBox* bbox = (FT_BBox*)q; + FT_Int result; + + + result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); + + if ( result < 0 ) + { + FT_ERROR(( "ps_parser_load_field: " + "expected four integers in bounding box\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + bbox->xMin = FT_RoundFix( temp[0] ); + bbox->yMin = FT_RoundFix( temp[1] ); + bbox->xMax = FT_RoundFix( temp[2] ); + bbox->yMax = FT_RoundFix( temp[3] ); + } + break; + + default: + /* an error occurred */ + goto Fail; + } + } + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + error = PSaux_Err_Ok; + + Exit: + return error; + + Fail: + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; + T1_Token token; + FT_Int num_elements; + FT_Error error = PSaux_Err_Ok; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_FieldRec fieldrec = *(T1_Field)field; + + + fieldrec.type = T1_FIELD_TYPE_INTEGER; + if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || + field->type == T1_FIELD_TYPE_BBOX ) + fieldrec.type = T1_FIELD_TYPE_FIXED; + + ps_parser_to_token_array( parser, elements, + T1_MAX_TABLE_ELEMENTS, &num_elements ); + if ( num_elements < 0 ) + { + error = PSaux_Err_Ignore; + goto Exit; + } + if ( (FT_UInt)num_elements > field->array_max ) + num_elements = field->array_max; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count if necessary */ + if ( field->type != T1_FIELD_TYPE_BBOX ) + *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = + (FT_Byte)num_elements; + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); + fieldrec.offset += fieldrec.size; + } + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Long ) + ps_parser_to_int( PS_Parser parser ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToInt( &parser->cursor, parser->limit ); + } + + + /* first character must be `<' if `delimiters' is non-zero */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ) + { + FT_Error error = PSaux_Err_Ok; + FT_Byte* cur; + + + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + if ( cur >= parser->limit ) + goto Exit; + + if ( delimiters ) + { + if ( *cur != '<' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + cur++; + } + + *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, + parser->limit, + bytes, + max_bytes ); + + if ( delimiters ) + { + if ( cur < parser->limit && *cur != '>' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + cur++; + } + + parser->cursor = cur; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ) + { + ps_parser_skip_spaces( parser ); + return ps_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return ps_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } + + +#if 0 + + FT_LOCAL_DEF( FT_String* ) + T1_ToString( PS_Parser parser ) + { + return ps_tostring( &parser->cursor, parser->limit, parser->memory ); + } + + + FT_LOCAL_DEF( FT_Bool ) + T1_ToBool( PS_Parser parser ) + { + return ps_tobool( &parser->cursor, parser->limit ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ) + { + parser->error = PSaux_Err_Ok; + parser->base = base; + parser->limit = limit; + parser->cursor = base; + parser->memory = memory; + parser->funcs = ps_parser_funcs; + } + + + FT_LOCAL_DEF( void ) + ps_parser_done( PS_Parser parser ) + { + FT_UNUSED( parser ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Function> */ + /* t1_builder_init */ + /* */ + /* <Description> */ + /* Initializes a given glyph builder. */ + /* */ + /* <InOut> */ + /* builder :: A pointer to the glyph builder to initialize. */ + /* */ + /* <Input> */ + /* face :: The current face object. */ + /* */ + /* size :: The current size object. */ + /* */ + /* glyph :: The current glyph object. */ + /* */ + /* hinting :: Whether hinting should be applied. */ + /* */ + FT_LOCAL_DEF( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->parse_state = T1_Parse_Start; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = size->internal; + builder->hints_funcs = 0; + + if ( hinting ) + builder->hints_funcs = glyph->internal->glyph_hints; + } + + if ( size ) + { + builder->scale_x = size->metrics.x_scale; + builder->scale_y = size->metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->funcs = t1_builder_funcs; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* t1_builder_done */ + /* */ + /* <Description> */ + /* Finalizes a given glyph builder. Its contents can still be used */ + /* after the call, but the function saves important information */ + /* within the corresponding glyph slot. */ + /* */ + /* <Input> */ + /* builder :: A pointer to the glyph builder to finalize. */ + /* */ + FT_LOCAL_DEF( void ) + t1_builder_done( T1_Builder builder ) + { + FT_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + if ( builder->shift ) + { + x >>= 16; + y >>= 16; + } + point->x = x; + point->y = y; + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + + builder->last = *point; + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = t1_builder_check_points( builder, 1 ); + if ( !error ) + t1_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return PSaux_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = PSaux_Err_Invalid_File_Format; + + + /* test whether we are building a new contour */ + + if ( builder->parse_state == T1_Parse_Have_Path ) + error = PSaux_Err_Ok; + else if ( builder->parse_state == T1_Parse_Have_Moveto ) + { + builder->parse_state = T1_Parse_Have_Path; + error = t1_builder_add_contour( builder ); + if ( !error ) + error = t1_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + t1_builder_close_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + + + if ( !outline ) + return; + + /* XXXX: We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Int first = 0; + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + + + if ( outline->n_contours > 1 ) + { + first = outline->contours[outline->n_contours - 2] + 1; + p1 = outline->points + first; + } + + /* `delete' last point only if it coincides with the first */ + /* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ) + { + PS_Conv_EexecDecode( &buffer, + buffer + length, + buffer, + length, + &seed ); + } + + +/* END */ diff --git a/src/freetype2/psaux/psobjs.h b/src/freetype2/psaux/psobjs.h new file mode 100644 index 0000000..c2cbf2c --- /dev/null +++ b/src/freetype2/psaux/psobjs.h @@ -0,0 +1,212 @@ +/***************************************************************************/ +/* */ +/* psobjs.h */ +/* */ +/* Auxiliary functions for PostScript fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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 __PSOBJS_H__ +#define __PSOBJS_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_AUX_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_TABLE + const PS_Table_FuncsRec ps_table_funcs; + + FT_CALLBACK_TABLE + const PS_Parser_FuncsRec ps_parser_funcs; + + FT_CALLBACK_TABLE + const T1_Builder_FuncsRec t1_builder_funcs; + + + FT_LOCAL( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ); + + FT_LOCAL( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ); + + FT_LOCAL( void ) + ps_table_done( PS_Table table ); + + + FT_LOCAL( void ) + ps_table_release( PS_Table table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL( void ) + ps_parser_skip_spaces( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_skip_PS_token( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ); + + FT_LOCAL( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Long ) + ps_parser_to_int( PS_Parser parser ); + + + FT_LOCAL( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); + + + FT_LOCAL( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ); + + + FT_LOCAL( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + + FT_LOCAL( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + + FT_LOCAL( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + FT_LOCAL( void ) + ps_parser_done( PS_Parser parser ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ); + + FT_LOCAL( void ) + t1_builder_done( T1_Builder builder ); + + FT_LOCAL( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ); + + FT_LOCAL( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + FT_LOCAL( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( FT_Error ) + t1_builder_add_contour( T1_Builder builder ); + + + FT_LOCAL( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + + FT_LOCAL( void ) + t1_builder_close_contour( T1_Builder builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + +FT_END_HEADER + +#endif /* __PSOBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/t1cmap.c b/src/freetype2/psaux/t1cmap.c new file mode 100644 index 0000000..2934686 --- /dev/null +++ b/src/freetype2/psaux/t1cmap.c @@ -0,0 +1,333 @@ +/***************************************************************************/ +/* */ +/* t1cmap.c */ +/* */ +/* Type 1 character map support (body). */ +/* */ +/* Copyright 2002, 2003, 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 "t1cmap.h" + +#include FT_INTERNAL_DEBUG_H + +#include "psauxerr.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_cmap_std_init( T1_CMapStd cmap, + FT_Int is_expert ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + cmap->num_glyphs = face->type1.num_glyphs; + cmap->glyph_names = (const char* const*)face->type1.glyph_names; + cmap->sid_to_string = psnames->adobe_std_strings; + cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding + : psnames->adobe_std_encoding; + + FT_ASSERT( cmap->code_to_sid != NULL ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_std_done( T1_CMapStd cmap ) + { + cmap->num_glyphs = 0; + cmap->glyph_names = NULL; + cmap->sid_to_string = NULL; + cmap->code_to_sid = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_index( T1_CMapStd cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + + + if ( char_code < 256 ) + { + FT_UInt code, n; + const char* glyph_name; + + + /* convert character code to Adobe SID string */ + code = cmap->code_to_sid[char_code]; + glyph_name = cmap->sid_to_string( code ); + + /* look for the corresponding glyph name */ + for ( n = 0; n < cmap->num_glyphs; n++ ) + { + const char* gname = cmap->glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + ft_strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_next( T1_CMapStd cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + while ( char_code < 256 ) + { + result = t1_cmap_std_char_index( cmap, char_code ); + if ( result != 0 ) + goto Exit; + + char_code++; + } + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_standard_init( T1_CMapStd cmap ) + { + t1_cmap_std_init( cmap, 0 ); + return 0; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_standard_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_standard_init, + (FT_CMap_DoneFunc) t1_cmap_std_done, + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, + (FT_CMap_CharNextFunc) t1_cmap_std_char_next + }; + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_expert_init( T1_CMapStd cmap ) + { + t1_cmap_std_init( cmap, 1 ); + return 0; + } + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_expert_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_expert_init, + (FT_CMap_DoneFunc) t1_cmap_std_done, + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, + (FT_CMap_CharNextFunc) t1_cmap_std_char_next + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_custom_init( T1_CMapCustom cmap ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + T1_Encoding encoding = &face->type1.encoding; + + + cmap->first = encoding->code_first; + cmap->count = (FT_UInt)( encoding->code_last - cmap->first + 1 ); + cmap->indices = encoding->char_index; + + FT_ASSERT( cmap->indices != NULL ); + FT_ASSERT( encoding->code_first <= encoding->code_last ); + + return 0; + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_custom_done( T1_CMapCustom cmap ) + { + cmap->indices = NULL; + cmap->first = 0; + cmap->count = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_index( T1_CMapCustom cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + + + if ( ( char_code >= cmap->first ) && + ( char_code < ( cmap->first + cmap->count ) ) ) + result = cmap->indices[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_next( T1_CMapCustom cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + ++char_code; + + if ( char_code < cmap->first ) + char_code = cmap->first; + + for ( ; char_code < ( cmap->first + cmap->count ); char_code++ ) + { + result = cmap->indices[char_code]; + if ( result != 0 ) + goto Exit; + } + + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_custom_class_rec = + { + sizeof ( T1_CMapCustomRec ), + + (FT_CMap_InitFunc) t1_cmap_custom_init, + (FT_CMap_DoneFunc) t1_cmap_custom_done, + (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, + (FT_CMap_CharNextFunc) t1_cmap_custom_char_next + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char * ) + t1_get_glyph_name( T1_Face face, + FT_UInt idx ) + { + return face->type1.glyph_names[idx]; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_unicode_init( PS_Unicodes unicodes ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_init( memory, + unicodes, + face->type1.num_glyphs, + (PS_GetGlyphNameFunc)&t1_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_unicode_done( PS_Unicodes unicodes ) + { + FT_Face face = FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_index( PS_Unicodes unicodes, + FT_UInt32 char_code ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_next( PS_Unicodes unicodes, + FT_UInt32 *pchar_code ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_unicode_class_rec = + { + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) t1_cmap_unicode_init, + (FT_CMap_DoneFunc) t1_cmap_unicode_done, + (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, + (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next + }; + + +/* END */ diff --git a/src/freetype2/psaux/t1cmap.h b/src/freetype2/psaux/t1cmap.h new file mode 100644 index 0000000..7ae65d2 --- /dev/null +++ b/src/freetype2/psaux/t1cmap.h @@ -0,0 +1,105 @@ +/***************************************************************************/ +/* */ +/* t1cmap.h */ +/* */ +/* Type 1 character map support (specification). */ +/* */ +/* Copyright 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1CMAP_H__ +#define __T1CMAP_H__ + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_TYPE1_TYPES_H + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct T1_CMapStdRec_* T1_CMapStd; + + typedef struct T1_CMapStdRec_ + { + FT_CMapRec cmap; + + const FT_UShort* code_to_sid; + PS_Adobe_Std_StringsFunc sid_to_string; + + FT_UInt num_glyphs; + const char* const* glyph_names; + + } T1_CMapStdRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_standard_class_rec; + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_expert_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct T1_CMapCustomRec_* T1_CMapCustom; + + typedef struct T1_CMapCustomRec_ + { + FT_CMapRec cmap; + FT_UInt first; + FT_UInt count; + FT_UShort* indices; + + } T1_CMapCustomRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_custom_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_unicode_class_rec; + + /* */ + + +FT_END_HEADER + +#endif /* __T1CMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/psaux/t1decode.c b/src/freetype2/psaux/t1decode.c new file mode 100644 index 0000000..f790643 --- /dev/null +++ b/src/freetype2/psaux/t1decode.c @@ -0,0 +1,1474 @@ +/***************************************************************************/ +/* */ +/* t1decode.c */ +/* */ +/* PostScript Type 1 decoding routines (body). */ +/* */ +/* Copyright 2000-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include FT_OUTLINE_H + +#include "t1decode.h" +#include "psobjs.h" + +#include "psauxerr.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_t1decode + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + op_unknown15, + + op_max /* never remove this one */ + + } T1_Operator; + + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2, /* setcurrentpoint */ + 2 /* opcode 15 (undocumented and obsolete) */ + }; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* t1_lookup_glyph_by_stdcharcode */ + /* */ + /* <Description> */ + /* Looks up a given glyph by its StandardEncoding charcode. Used to */ + /* implement the SEAC Type 1 operator. */ + /* */ + /* <Input> */ + /* face :: The current face object. */ + /* */ + /* charcode :: The character code to look for. */ + /* */ + /* <Return> */ + /* A glyph index in the font face. Returns -1 if the corresponding */ + /* glyph wasn't found. */ + /* */ + static FT_Int + t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return n; + } + + return -1; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* t1operator_seac */ + /* */ + /* <Description> */ + /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ + /* */ + /* <Input> */ + /* decoder :: The current CID decoder. */ + /* */ + /* asb :: The accent's side bearing. */ + /* */ + /* adx :: The horizontal offset of the accent. */ + /* */ + /* ady :: The vertical offset of the accent. */ + /* */ + /* bchar :: The base character's StandardEncoding charcode. */ + /* */ + /* achar :: The accent character's StandardEncoding charcode. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + t1operator_seac( T1_Decoder decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index; +#if 0 + FT_Int n_base_points; + FT_Outline* base = decoder->builder.base; +#endif + FT_Vector left_bearing, advance; + + + /* seac weirdness */ + adx += decoder->builder.left_bearing.x; + + /* `glyph_names' is set to 0 for CID fonts which do not */ + /* include an encoding. How can we deal with these? */ + if ( decoder->glyph_names == 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " glyph names table not available in this font!\n" )); + return PSaux_Err_Syntax_Error; + } + + bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return PSaux_Err_Syntax_Error; + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)( adx - asb ); + subg->arg2 = (FT_Int)ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + goto Exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + error = t1_decoder_parse_glyph( decoder, bchar_index ); + if ( error ) + goto Exit; + + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + decoder->builder.pos_x = adx - asb; + decoder->builder.pos_y = ady; + + /* Now load `achar' on top of */ + /* the base outline */ + error = t1_decoder_parse_glyph( decoder, achar_index ); + if ( error ) + goto Exit; + + /* restore the left side bearing and */ + /* advance width of the base character */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + decoder->builder.pos_x = 0; + decoder->builder.pos_y = 0; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* t1_decoder_parse_charstrings */ + /* */ + /* <Description> */ + /* Parses a given Type 1 charstrings program. */ + /* */ + /* <Input> */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* charstring_base :: The base address of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + FT_Error error; + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Pos x, y, orig_x, orig_y; + FT_Int known_othersubr_result_cnt = 0; + FT_Int unknown_othersubr_result_cnt = 0; + + T1_Hints_Funcs hinter; + + + /* we don't want to touch the source code -- use macro trick */ +#define start_point t1_builder_start_point +#define check_points t1_builder_check_points +#define add_point t1_builder_add_point +#define add_point1 t1_builder_add_point1 +#define add_contour t1_builder_add_contour +#define close_contour t1_builder_close_contour + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->parse_state = T1_Parse_Start; + + hinter = (T1_Hints_Funcs)builder->hints_funcs; + + /* a font that reads BuildCharArray without setting */ + /* its values first is buggy, but ... */ + FT_ASSERT( ( decoder->len_buildchar == 0 ) == + ( decoder->buildchar == NULL ) ); + + if ( decoder->len_buildchar > 0 ) + memset( &decoder->buildchar[0], + 0, + sizeof( decoder->buildchar[0] ) * + decoder->len_buildchar ); + + FT_TRACE4(( "\nStart charstring\n" )); + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = PSaux_Err_Ok; + + x = orig_x = builder->pos_x; + y = orig_y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Long value = 0; + + + FT_ASSERT( known_othersubr_result_cnt == 0 || + unknown_othersubr_result_cnt == 0 ); + + FT_TRACE5(( " (%d)", decoder->top - decoder->stack )); + + /*********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + /* */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 15: /* undocumented, obsolete operator */ + op = op_unknown15; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = (FT_Int32)( ((FT_Long)ip[0] << 24) | + ((FT_Long)ip[1] << 16) | + ((FT_Long)ip[2] << 8 ) | + ip[3] ); + ip += 4; + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Long)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " )); + FT_ERROR(( "unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + + if ( unknown_othersubr_result_cnt > 0 ) + { + switch ( op ) + { + case op_callsubr: + case op_return: + case op_none: + case op_pop: + break; + + default: + /* all operands have been transferred by previous pops */ + unknown_othersubr_result_cnt = 0; + break; + } + } + + /*********************************************************************/ + /* */ + /* Push value on stack, or process operator */ + /* */ + /* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" )); + goto Syntax_Error; + } + + FT_TRACE4(( " %ld", value )); + + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_Int subr_no; + FT_Int arg_cnt; + + + FT_TRACE4(( " callothersubr" )); + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + + subr_no = (FT_Int)top[1]; + arg_cnt = (FT_Int)top[0]; + + /***********************************************************/ + /* */ + /* remove all operands to callothersubr from the stack */ + /* */ + /* for handled othersubrs, where we know the number of */ + /* arguments, we increase the stack by the value of */ + /* known_othersubr_result_cnt */ + /* */ + /* for unhandled othersubrs the following pops adjust the */ + /* stack pointer as necessary */ + + if ( arg_cnt > top - decoder->stack ) + goto Stack_Underflow; + + top -= arg_cnt; + + known_othersubr_result_cnt = 0; + unknown_othersubr_result_cnt = 0; + + /* XXX TODO: The checks to `arg_count == <whatever>' */ + /* might not be correct; an othersubr expects a certain */ + /* number of operands on the PostScript stack (as opposed */ + /* to the T1 stack) but it doesn't have to put them there */ + /* by itself; previous othersubrs might have left the */ + /* operands there if they were not followed by an */ + /* appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ + /* accept a font that contains charstrings like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray exists. */ + + switch ( subr_no ) + { + case 1: /* start flex feature */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + break; + + case 2: /* add flex vectors */ + { + FT_Int idx; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + /* note that we should not add a point for index 0; */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + add_point( builder, + x, + y, + (FT_Byte)( idx == 3 || idx == 6 ) ); + } + break; + + case 0: /* end flex feature */ + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "unexpected flex end\n" )); + goto Syntax_Error; + } + + /* the two `results' are popped by the following setcurrentpoint */ + known_othersubr_result_cnt = 2; + break; + + case 3: /* change hints */ + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + + known_othersubr_result_cnt = 1; + + if ( hinter ) + hinter->reset( hinter->hints, builder->current->n_points ); + + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + top = decoder->stack; + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Long* delta; + FT_Long* values; + + + if ( !blend ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " )); + FT_ERROR(( "unexpected multiple masters operator!\n" )); + goto Syntax_Error; + } + + num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " )); + FT_ERROR(( "incorrect number of mm arguments\n" )); + goto Syntax_Error; + } + + /* we want to compute: */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */ + /* however, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as: */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1 */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Long tmp = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); + + *values++ = tmp; + } + + known_othersubr_result_cnt = num_points; + break; + } + +#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS + + /* We cannot yet enable these since currently */ + /* our T1 stack stores integers which lack the */ + /* precision to express the values */ + + case 19: + /* <idx> 1 19 callothersubr */ + /* => replace elements starting from index cvi( <idx> ) */ + /* of BuildCharArray with WeightVector */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[0]; + + if ( idx < 0 || + idx + blend->num_designs > decoder->face->len_buildchar ) + goto Unexpected_OtherSubr; + + memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof( blend->weight_vector[ 0 ] ) ); + } + break; + + case 20: + /* <arg1> <arg2> 2 20 callothersubr pop */ + /* ==> push <arg1> + <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] += top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 21: + /* <arg1> <arg2> 2 21 callothersubr pop */ + /* ==> push <arg1> - <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] -= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 22: + /* <arg1> <arg2> 2 22 callothersubr pop */ + /* ==> push <arg1> * <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] *= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 23: + /* <arg1> <arg2> 2 23 callothersubr pop */ + /* ==> push <arg1> / <arg2> onto T1 stack */ + if ( arg_cnt != 2 || top[1] == 0 ) + goto Unexpected_OtherSubr; + + top[0] /= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + +#endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */ + + case 24: + /* <val> <idx> 2 24 callothersubr */ + /* => set BuildCharArray[cvi( <idx> )] = <val> */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + if ( arg_cnt != 2 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[1]; + + if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = top[0]; + } + break; + + case 25: + /* <idx> 1 25 callothersubr pop */ + /* => push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[0]; + + if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + top[0] = decoder->buildchar[idx]; + } + + known_othersubr_result_cnt = 1; + break; + +#if 0 + case 26: + /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */ + /* leave mark on T1 stack */ + /* <val> <idx> ==> set BuildCharArray[cvi( <idx> )] = <val> */ + XXX who has left his mark on the (PostScript) stack ?; + break; +#endif + + case 27: + /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */ + /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */ + /* otherwise push <res2> */ + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + if ( top[2] > top[3] ) + top[0] = top[1]; + + known_othersubr_result_cnt = 1; + break; + +#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS + case 28: + /* 0 28 callothersubr pop */ + /* => push random value from interval [0, 1) onto stack */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + top[0] = FT_rand(); + known_othersubr_result_cnt = 1; + break; +#endif + + default: + FT_ERROR(( "t1_decoder_parse_charstrings: " + "unknown othersubr [%d %d], wish me luck!\n", + arg_cnt, subr_no )); + unknown_othersubr_result_cnt = arg_cnt; + break; + + Unexpected_OtherSubr: + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invalid othersubr [%d %d]!\n", arg_cnt, subr_no )); + goto Syntax_Error; + } + + top += known_othersubr_result_cnt; + + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + FT_ASSERT( num_args >= 0 ); + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + /* XXX Operators usually take their operands from the */ + /* bottom of the stack, i.e., the operands are */ + /* decoder->stack[0], ..., decoder->stack[num_args - 1]; */ + /* only div, callsubr, and callothersubr are different. */ + /* In practice it doesn't matter (?). */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + switch ( op ) + { + case op_callsubr: + case op_div: + case op_callothersubr: + case op_pop: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_charstrings: " + "too much operands on the stack " + "(seen %d, expected %d)\n", + top - decoder->stack, num_args )); + break; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar" )); + + close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if (hinter->close( hinter->hints, builder->current->n_points )) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + hinter->apply( hinter->hints, + builder->current, + (PSH_Globals) builder->hints_globals, + decoder->hint_mode ); + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + FT_TRACE4(( "\n" )); + + /* the compiler should optimize away this empty loop but ... */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + if ( decoder->len_buildchar > 0 ) + { + FT_UInt i; + + + FT_TRACE4(( "BuildCharArray = [ " )); + + for ( i = 0; i < decoder->len_buildchar; ++i ) + FT_TRACE4(( "%d ", decoder->buildchar[ i ] )); + + FT_TRACE4(( "]\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + FT_TRACE4(( "\n" )); + + /* return now! */ + return PSaux_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + + orig_x = builder->last.x = x = builder->pos_x + top[0]; + orig_y = builder->last.y = y = builder->pos_y; + + FT_UNUSED( orig_y ); + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return PSaux_Err_Ok; + + break; + + case op_seac: + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], top[2], + (FT_Int)top[3], (FT_Int)top[4] ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + builder->last.x = x = builder->pos_x + top[0]; + builder->last.y = y = builder->pos_y + top[1]; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return PSaux_Err_Ok; + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + close_contour( builder ); + if ( !( builder->parse_state == T1_Parse_Have_Path || + builder->parse_state == T1_Parse_Have_Moveto ) ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Width; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( start_point( builder, x, y ) ) + goto Fail; + + x += top[0]; + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x += top[0]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Fail; + + x += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + y += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( start_point( builder, x, y ) ) + goto Fail; + + x += top[0]; + y += top[1]; + + Add_Line: + if ( add_point1( builder, x, y ) ) + goto Fail; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x += top[0]; + y += top[1]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_rrcurveto: + FT_TRACE4(( " rcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Fail; + + x += top[0]; + y += top[1]; + add_point( builder, x, y, 0 ); + + x += top[2]; + y += top[3]; + add_point( builder, x, y, 0 ); + + x += top[4]; + y += top[5]; + add_point( builder, x, y, 1 ); + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Fail; + + y += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + x += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( start_point( builder, x, y ) ) + goto Fail; + + y += top[0]; + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y += top[0]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_div: + FT_TRACE4(( " div" )); + + if ( top[1] ) + { + *top = top[0] / top[1]; + ++top; + } + else + { + FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = (FT_Int)top[0]; + if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_pop: + FT_TRACE4(( " pop" )); + + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; + /* ignore, we pushed the operands ourselves */ + break; + } + + if ( unknown_othersubr_result_cnt == 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " + "no more operands for othersubr!\n" )); + goto Syntax_Error; + } + + unknown_othersubr_result_cnt--; + top++; /* `push' the operand to callothersubr onto the stack */ + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + /* record horizontal hint */ + if ( hinter ) + { + /* top[0] += builder->left_bearing.y; */ + hinter->stem( hinter->hints, 1, top ); + } + + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + /* record horizontal counter-controlled hints */ + if ( hinter ) + hinter->stem3( hinter->hints, 1, top ); + + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + /* record vertical hint */ + if ( hinter ) + { + top[0] += orig_x; + hinter->stem( hinter->hints, 0, top ); + } + + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + /* record vertical counter-controlled hints */ + if ( hinter ) + { + FT_Pos dx = orig_x; + + + top[0] += dx; + top[2] += dx; + top[4] += dx; + hinter->stem3( hinter->hints, 0, top ); + } + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + /* From the T1 specs, section 6.4: */ + /* */ + /* The setcurrentpoint command is used only in */ + /* conjunction with results from OtherSubrs procedures. */ + + /* known_othersubr_result_cnt != 0 is already handled above */ + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: " )); + FT_ERROR(( "unexpected `setcurrentpoint'\n" )); + + goto Syntax_Error; + } + else + decoder->flex_state = 0; + break; + + case op_unknown15: + FT_TRACE4(( " opcode_15" )); + /* nothing to do except to pop the two arguments */ + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings: " + "unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + /* XXX Operators usually clear the operand stack; */ + /* only div, callsubr, callothersubr, pop, and */ + /* return are different. */ + /* In practice it doesn't matter (?). */ + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + + Fail: + return error; + + Syntax_Error: + return PSaux_Err_Syntax_Error; + + Stack_Underflow: + return PSaux_Err_Stack_Underflow; + } + + + /* parse a single Type 1 glyph */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph ) + { + return decoder->parse_callback( decoder, glyph ); + } + + + /* initialize T1 decoder */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_callback ) + { + FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); + + /* retrieve PSNames interface from list of current modules */ + { + FT_Service_PsCMaps psnames = 0; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + { + FT_ERROR(( "t1_decoder_init: " )); + FT_ERROR(( "the `psnames' module is not available\n" )); + return PSaux_Err_Unimplemented_Feature; + } + + decoder->psnames = psnames; + } + + t1_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* decoder->buildchar and decoder->len_buildchar have to be */ + /* initialized by the caller since we cannot know the length */ + /* of the BuildCharArray */ + + decoder->num_glyphs = (FT_UInt)face->num_glyphs; + decoder->glyph_names = glyph_names; + decoder->hint_mode = hint_mode; + decoder->blend = blend; + decoder->parse_callback = parse_callback; + + decoder->funcs = t1_decoder_funcs; + + return PSaux_Err_Ok; + } + + + /* finalize T1 decoder */ + FT_LOCAL_DEF( void ) + t1_decoder_done( T1_Decoder decoder ) + { + t1_builder_done( &decoder->builder ); + } + + +/* END */ diff --git a/src/freetype2/psaux/t1decode.h b/src/freetype2/psaux/t1decode.h new file mode 100644 index 0000000..00728db --- /dev/null +++ b/src/freetype2/psaux/t1decode.h @@ -0,0 +1,64 @@ +/***************************************************************************/ +/* */ +/* t1decode.h */ +/* */ +/* PostScript Type 1 decoding routines (specification). */ +/* */ +/* Copyright 2000-2001, 2002, 2003 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 __T1DECODE_H__ +#define __T1DECODE_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_INTERNAL_TYPE1_TYPES_H + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const T1_Decoder_FuncsRec t1_decoder_funcs; + + + FT_LOCAL( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph_index ); + + FT_LOCAL( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); + + FT_LOCAL( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_glyph ); + + FT_LOCAL( void ) + t1_decoder_done( T1_Decoder decoder ); + + +FT_END_HEADER + +#endif /* __T1DECODE_H__ */ + + +/* END */ diff --git a/src/freetype2/pshinter/pshalgo.c b/src/freetype2/pshinter/pshalgo.c new file mode 100644 index 0000000..505d95c --- /dev/null +++ b/src/freetype2/pshinter/pshalgo.c @@ -0,0 +1,2291 @@ +/***************************************************************************/ +/* */ +/* pshalgo.c */ +/* */ +/* PostScript hinting algorithm (body). */ +/* */ +/* Copyright 2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include "pshalgo.h" + +#include "pshnterr.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pshalgo2 + + +#ifdef DEBUG_HINTER + PSH_Hint_Table ps_debug_hint_table = 0; + PSH_HintFunc ps_debug_hint_func = 0; + PSH_Glyph ps_debug_glyph = 0; +#endif + + +#define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */ + /* and similar glyphs */ +#define STRONGER /* slightly increase the contrast of smooth */ + /* hinting */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC HINTS RECORDINGS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* return true if two stem hints overlap */ + static FT_Int + psh_hint_overlap( PSH_Hint hint1, + PSH_Hint hint2 ) + { + return hint1->org_pos + hint1->org_len >= hint2->org_pos && + hint2->org_pos + hint2->org_len >= hint1->org_pos; + } + + + /* destroy hints table */ + static void + psh_hint_table_done( PSH_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->zones ); + table->num_zones = 0; + table->zone = 0; + + FT_FREE( table->sort ); + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + table->sort_global = 0; + } + + + /* deactivate all hints in a table */ + static void + psh_hint_table_deactivate( PSH_Hint_Table table ) + { + FT_UInt count = table->max_hints; + PSH_Hint hint = table->hints; + + + for ( ; count > 0; count--, hint++ ) + { + psh_hint_deactivate( hint ); + hint->order = -1; + } + } + + + /* internal function to record a new hint */ + static void + psh_hint_table_record( PSH_Hint_Table table, + FT_UInt idx ) + { + PSH_Hint hint = table->hints + idx; + + + if ( idx >= table->max_hints ) + { + FT_ERROR(( "psh_hint_table_record: invalid hint index %d\n", idx )); + return; + } + + /* ignore active hints */ + if ( psh_hint_is_active( hint ) ) + return; + + psh_hint_activate( hint ); + + /* now scan the current active hint set to check */ + /* whether `hint' overlaps with another hint */ + { + PSH_Hint* sorted = table->sort_global; + FT_UInt count = table->num_hints; + PSH_Hint hint2; + + + hint->parent = 0; + for ( ; count > 0; count--, sorted++ ) + { + hint2 = sorted[0]; + + if ( psh_hint_overlap( hint, hint2 ) ) + { + hint->parent = hint2; + break; + } + } + } + + if ( table->num_hints < table->max_hints ) + table->sort_global[table->num_hints++] = hint; + else + FT_ERROR(( "psh_hint_table_record: too many sorted hints! BUG!\n" )); + } + + + static void + psh_hint_table_record_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit; + + + limit = hint_mask->num_bits; + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + psh_hint_table_record( table, idx ); + + mask >>= 1; + } + } + + + /* create hints table */ + static FT_Error + psh_hint_table_init( PSH_Hint_Table table, + PS_Hint_Table hints, + PS_Mask_Table hint_masks, + PS_Mask_Table counter_masks, + FT_Memory memory ) + { + FT_UInt count; + FT_Error error; + + FT_UNUSED( counter_masks ); + + + count = hints->num_hints; + + /* allocate our tables */ + if ( FT_NEW_ARRAY( table->sort, 2 * count ) || + FT_NEW_ARRAY( table->hints, count ) || + FT_NEW_ARRAY( table->zones, 2 * count + 1 ) ) + goto Exit; + + table->max_hints = count; + table->sort_global = table->sort + count; + table->num_hints = 0; + table->num_zones = 0; + table->zone = 0; + + /* initialize the `table->hints' array */ + { + PSH_Hint write = table->hints; + PS_Hint read = hints->hints; + + + for ( ; count > 0; count--, write++, read++ ) + { + write->org_pos = read->pos; + write->org_len = read->len; + write->flags = read->flags; + } + } + + /* we now need to determine the initial `parent' stems; first */ + /* activate the hints that are given by the initial hint masks */ + if ( hint_masks ) + { + PS_Mask mask = hint_masks->masks; + + + count = hint_masks->num_masks; + table->hint_masks = hint_masks; + + for ( ; count > 0; count--, mask++ ) + psh_hint_table_record_mask( table, mask ); + } + + /* finally, do a linear parse in case some hints were left alone */ + if ( table->num_hints != table->max_hints ) + { + FT_UInt idx; + + + FT_ERROR(( "psh_hint_table_init: missing/incorrect hint masks!\n" )); + + count = table->max_hints; + for ( idx = 0; idx < count; idx++ ) + psh_hint_table_record( table, idx ); + } + + Exit: + return error; + } + + + static void + psh_hint_table_activate_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit, count; + + + limit = hint_mask->num_bits; + count = 0; + + psh_hint_table_deactivate( table ); + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + { + PSH_Hint hint = &table->hints[idx]; + + + if ( !psh_hint_is_active( hint ) ) + { + FT_UInt count2; + +#if 0 + PSH_Hint* sort = table->sort; + PSH_Hint hint2; + + + for ( count2 = count; count2 > 0; count2--, sort++ ) + { + hint2 = sort[0]; + if ( psh_hint_overlap( hint, hint2 ) ) + FT_ERROR(( "psh_hint_table_activate_mask:" + " found overlapping hints\n" )) + } +#else + count2 = 0; +#endif + + if ( count2 == 0 ) + { + psh_hint_activate( hint ); + if ( count < table->max_hints ) + table->sort[count++] = hint; + else + FT_ERROR(( "psh_hint_tableactivate_mask:" + " too many active hints\n" )); + } + } + } + + mask >>= 1; + } + table->num_hints = count; + + /* now, sort the hints; they are guaranteed to not overlap */ + /* so we can compare their "org_pos" field directly */ + { + FT_Int i1, i2; + PSH_Hint hint1, hint2; + PSH_Hint* sort = table->sort; + + + /* a simple bubble sort will do, since in 99% of cases, the hints */ + /* will be already sorted -- and the sort will be linear */ + for ( i1 = 1; i1 < (FT_Int)count; i1++ ) + { + hint1 = sort[i1]; + for ( i2 = i1 - 1; i2 >= 0; i2-- ) + { + hint2 = sort[i2]; + + if ( hint2->org_pos < hint1->org_pos ) + break; + + sort[i2 + 1] = hint2; + sort[i2] = hint1; + } + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTS GRID-FITTING AND OPTIMIZATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 1 + static FT_Pos + psh_dimension_quantize_len( PSH_Dimension dim, + FT_Pos len, + FT_Bool do_snapping ) + { + if ( len <= 64 ) + len = 64; + else + { + FT_Pos delta = len - dim->stdw.widths[0].cur; + + + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + len = dim->stdw.widths[0].cur; + if ( len < 48 ) + len = 48; + } + + if ( len < 3 * 64 ) + { + delta = ( len & 63 ); + len &= -64; + + if ( delta < 10 ) + len += delta; + + else if ( delta < 32 ) + len += 10; + + else if ( delta < 54 ) + len += 54; + + else + len += delta; + } + else + len = FT_PIX_ROUND( len ); + } + + if ( do_snapping ) + len = FT_PIX_ROUND( len ); + + return len; + } +#endif /* 0 */ + + +#ifdef DEBUG_HINTER + + static void + ps_simple_scale( PSH_Hint_Table table, + FT_Fixed scale, + FT_Fixed delta, + FT_Int dimension ) + { + PSH_Hint hint; + FT_UInt count; + + + for ( count = 0; count < table->max_hints; count++ ) + { + hint = table->hints + count; + + hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta; + hint->cur_len = FT_MulFix( hint->org_len, scale ); + + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); + } + } + +#endif /* DEBUG_HINTER */ + + + static FT_Fixed + psh_hint_snap_stem_side_delta( FT_Fixed pos, + FT_Fixed len ) + { + FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos; + FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len; + + + if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) ) + return delta1; + else + return delta2; + } + + + static void + psh_hint_align( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Int do_snapping; + FT_Pos fit_len; + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + /* perform stem snapping when requested - this is necessary + * for monochrome and LCD hinting modes only + */ + do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) || + ( dimension == 1 && glyph->do_vert_snapping ); + + hint->cur_len = fit_len = len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + hint->org_pos + hint->org_len, + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align( parent, globals, dimension, glyph ); + + /* keep original relation between hints, this is, use the */ + /* scaled distance between the centers of the hints to */ + /* compute the new position */ + par_org_center = parent->org_pos + ( parent->org_len >> 1 ); + par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 ); + cur_org_center = hint->org_pos + ( hint->org_len >> 1 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + hint->cur_pos = pos; + hint->cur_len = fit_len; + + /* Stem adjustment tries to snap stem widths to standard + * ones. This is important to prevent unpleasant rounding + * artefacts. + */ + if ( glyph->do_stem_adjust ) + { + if ( len <= 64 ) + { + /* the stem is less than one pixel; we will center it + * around the nearest pixel center + */ + if ( len >= 32 ) + { + /* This is a special case where we also widen the stem + * and align it to the pixel grid. + * + * stem_center = pos + (len/2) + * nearest_pixel_center = FT_ROUND(stem_center-32)+32 + * new_pos = nearest_pixel_center-32 + * = FT_ROUND(stem_center-32) + * = FT_FLOOR(stem_center-32+32) + * = FT_FLOOR(stem_center) + * new_len = 64 + */ + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ); + len = 64; + } + else if ( len > 0 ) + { + /* This is a very small stem; we simply align it to the + * pixel grid, trying to find the minimal displacement. + * + * left = pos + * right = pos + len + * left_nearest_edge = ROUND(pos) + * right_nearest_edge = ROUND(right) + * + * if ( ABS(left_nearest_edge - left) <= + * ABS(right_nearest_edge - right) ) + * new_pos = left + * else + * new_pos = right + */ + FT_Pos left_nearest = FT_PIX_ROUND( pos ); + FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); + FT_Pos left_disp = left_nearest - pos; + FT_Pos right_disp = right_nearest - ( pos + len ); + + + if ( left_disp < 0 ) + left_disp = -left_disp; + if ( right_disp < 0 ) + right_disp = -right_disp; + if ( left_disp <= right_disp ) + pos = left_nearest; + else + pos = right_nearest; + } + else + { + /* this is a ghost stem; we simply round it */ + pos = FT_PIX_ROUND( pos ); + } + } + else + { + len = psh_dimension_quantize_len( dim, len, 0 ); + } + } + + /* now that we have a good hinted stem width, try to position */ + /* the stem along a pixel grid integer coordinate */ + hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); + hint->cur_len = len; + } + } + + if ( do_snapping ) + { + pos = hint->cur_pos; + len = hint->cur_len; + + if ( len < 64 ) + len = 64; + else + len = FT_PIX_ROUND( len ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + hint->cur_pos = align.align_top - len; + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT: + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: + /* don't touch */ + break; + + + default: + hint->cur_len = len; + if ( len & 64 ) + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; + else + pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); + + hint->cur_pos = pos - ( len >> 1 ); + hint->cur_len = len; + } + } + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + + +#if 0 /* not used for now, experimental */ + + /* + * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) + * of stems + */ + static void + psh_hint_align_light( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Pos fit_len; + + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + fit_len = len; + + hint->cur_len = fit_len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + hint->org_pos + hint->org_len, + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align_light( parent, globals, dimension, glyph ); + + par_org_center = parent->org_pos + ( parent->org_len / 2 ); + par_cur_center = parent->cur_pos + ( parent->cur_len / 2 ); + cur_org_center = hint->org_pos + ( hint->org_len / 2 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + /* Stems less than one pixel wide are easy -- we want to + * make them as dark as possible, so they must fall within + * one pixel. If the stem is split between two pixels + * then snap the edge that is nearer to the pixel boundary + * to the pixel boundary. + */ + if ( len <= 64 ) + { + if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + + /* Position stems other to minimize the amount of mid-grays. + * There are, in general, two positions that do this, + * illustrated as A) and B) below. + * + * + + + + + * + * A) |--------------------------------| + * B) |--------------------------------| + * C) |--------------------------------| + * + * Position A) (split the excess stem equally) should be better + * for stems of width N + f where f < 0.5. + * + * Position B) (split the deficiency equally) should be better + * for stems of width N + f where f > 0.5. + * + * It turns out though that minimizing the total number of lit + * pixels is also important, so position C), with one edge + * aligned with a pixel boundary is actually preferable + * to A). There are also more possibile positions for C) than + * for A) or B), so it involves less distortion of the overall + * character shape. + */ + else /* len > 64 */ + { + FT_Fixed frac_len = len & 63; + FT_Fixed center = pos + ( len >> 1 ); + FT_Fixed delta_a, delta_b; + + + if ( ( len / 64 ) & 1 ) + { + delta_a = FT_PIX_FLOOR( center ) + 32 - center; + delta_b = FT_PIX_ROUND( center ) - center; + } + else + { + delta_a = FT_PIX_ROUND( center ) - center; + delta_b = FT_PIX_FLOOR( center ) + 32 - center; + } + + /* We choose between B) and C) above based on the amount + * of fractinal stem width; for small amounts, choose + * C) always, for large amounts, B) always, and inbetween, + * pick whichever one involves less stem movement. + */ + if ( frac_len < 32 ) + { + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + else if ( frac_len < 48 ) + { + FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, + len ); + + if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) + pos += side_delta; + else + pos += delta_b; + } + else + { + pos += delta_b; + } + } + + hint->cur_pos = pos; + } + } /* switch */ + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + +#endif /* 0 */ + + + static void + psh_hint_table_align_hints( PSH_Hint_Table table, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Hint hint; + FT_UInt count; + +#ifdef DEBUG_HINTER + + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( ps_debug_no_vert_hints && dimension == 0 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + + if ( ps_debug_no_horz_hints && dimension == 1 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + +#endif /* DEBUG_HINTER*/ + + hint = table->hints; + count = table->max_hints; + + for ( ; count > 0; count--, hint++ ) + psh_hint_align( hint, globals, dimension, glyph ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** POINTS INTERPOLATION ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define PSH_ZONE_MIN -3200000L +#define PSH_ZONE_MAX +3200000L + +#define xxDEBUG_ZONES + + +#ifdef DEBUG_ZONES + +#include <stdio.h> + + static void + psh_print_zone( PSH_Zone zone ) + { + printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n", + zone->scale / 65536.0, + zone->delta / 64.0, + zone->min, + zone->max ); + } + +#else + +#define psh_print_zone( x ) do { } while ( 0 ) + +#endif /* DEBUG_ZONES */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTER GLYPH MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 1 + +#define psh_corner_is_flat ft_corner_is_flat +#define psh_corner_orientation ft_corner_orientation + +#else + + FT_LOCAL_DEF( FT_Int ) + psh_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 ); + } + + static FT_Int + psh_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 */ + { + long long delta = (long long)in_x * out_y - (long long)in_y * out_x; + + if ( delta == 0 ) + result = 0; + else + result = 1 - 2 * ( delta < 0 ); + } + + return result; + } + +#endif /* !1 */ + + +#ifdef COMPUTE_INFLEXS + + /* compute all inflex points in a given glyph */ + static void + psh_glyph_compute_inflections( PSH_Glyph glyph ) + { + FT_UInt n; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first, start, end, before, after; + FT_Pos in_x, in_y, out_x, out_y; + FT_Int orient_prev, orient_cur; + FT_Int finished = 0; + + + /* we need at least 4 points to create an inflection point */ + if ( glyph->contours[n].count < 4 ) + continue; + + /* compute first segment in contour */ + first = glyph->contours[n].start; + + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + + in_x = end->org_u - start->org_u; + in_y = end->org_v - start->org_v; + + } 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->org_u - before->org_u; + out_y = start->org_v - before->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_prev = psh_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->org_u - end->org_u; + out_y = after->org_v - end->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_cur == 0 ); + + if ( ( orient_cur ^ orient_prev ) < 0 ) + { + do + { + psh_point_set_inflex( start ); + start = start->next; + } + while ( start != end ); + + psh_point_set_inflex( start ); + } + + start = end; + end = after; + orient_prev = orient_cur; + in_x = out_x; + in_y = out_y; + + } while ( !finished ); + + Skip: + ; + } + } + +#endif /* COMPUTE_INFLEXS */ + + + static void + psh_glyph_done( PSH_Glyph glyph ) + { + FT_Memory memory = glyph->memory; + + + psh_hint_table_done( &glyph->hint_tables[1], memory ); + psh_hint_table_done( &glyph->hint_tables[0], memory ); + + FT_FREE( glyph->points ); + FT_FREE( glyph->contours ); + + glyph->num_points = 0; + glyph->num_contours = 0; + + glyph->memory = 0; + } + + + static int + psh_compute_dir( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ax, ay; + int result = PSH_DIR_NONE; + + + ax = ( dx >= 0 ) ? dx : -dx; + ay = ( dy >= 0 ) ? dy : -dy; + + if ( ay * 12 < ax ) + { + /* |dy| <<< |dx| means a near-horizontal segment */ + result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; + } + else if ( ax * 12 < ay ) + { + /* |dx| <<< |dy| means a near-vertical segment */ + result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; + } + + return result; + } + + + /* load outline point coordinates into hinter glyph */ + static void + psh_glyph_load_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_Vector* vec = glyph->outline->points; + PSH_Point point = glyph->points; + FT_UInt count = glyph->num_points; + + + for ( ; count > 0; count--, point++, vec++ ) + { + point->flags2 = 0; + point->hint = NULL; + if ( dimension == 0 ) + { + point->org_u = vec->x; + point->org_v = vec->y; + } + else + { + point->org_u = vec->y; + point->org_v = vec->x; + } + +#ifdef DEBUG_HINTER + point->org_x = vec->x; + point->org_y = vec->y; +#endif + + } + } + + + /* save hinted point coordinates back to outline */ + static void + psh_glyph_save_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_UInt n; + PSH_Point point = glyph->points; + FT_Vector* vec = glyph->outline->points; + char* tags = glyph->outline->tags; + + + for ( n = 0; n < glyph->num_points; n++ ) + { + if ( dimension == 0 ) + vec[n].x = point->cur_u; + else + vec[n].y = point->cur_u; + + if ( psh_point_is_strong( point ) ) + tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 ); + +#ifdef DEBUG_HINTER + + if ( dimension == 0 ) + { + point->cur_x = point->cur_u; + point->flags_x = point->flags2 | point->flags; + } + else + { + point->cur_y = point->cur_u; + point->flags_y = point->flags2 | point->flags; + } + +#endif + + point++; + } + } + + + static FT_Error + psh_glyph_init( PSH_Glyph glyph, + FT_Outline* outline, + PS_Hints ps_hints, + PSH_Globals globals ) + { + FT_Error error; + FT_Memory memory; + + + /* clear all fields */ + FT_MEM_ZERO( glyph, sizeof ( *glyph ) ); + + memory = glyph->memory = globals->memory; + + /* allocate and setup points + contours arrays */ + if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) || + FT_NEW_ARRAY( glyph->contours, outline->n_contours ) ) + goto Exit; + + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; + + { + FT_UInt first = 0, next, n; + PSH_Point points = glyph->points; + PSH_Contour contour = glyph->contours; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + FT_Int count; + PSH_Point point; + + + next = outline->contours[n] + 1; + count = next - first; + + contour->start = points + first; + contour->count = (FT_UInt)count; + + if ( count > 0 ) + { + point = points + first; + + point->prev = points + next - 1; + point->contour = contour; + + for ( ; count > 1; count-- ) + { + point[0].next = point + 1; + point[1].prev = point; + point++; + point->contour = contour; + } + point->next = points + first; + } + + contour++; + first = next; + } + } + + { + PSH_Point points = glyph->points; + PSH_Point point = points; + FT_Vector* vec = outline->points; + FT_UInt n; + + + for ( n = 0; n < glyph->num_points; n++, point++ ) + { + FT_Int n_prev = (FT_Int)( point->prev - points ); + FT_Int n_next = (FT_Int)( point->next - points ); + FT_Pos dxi, dyi, dxo, dyo; + + + if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) + point->flags = PSH_POINT_OFF; + + dxi = vec[n].x - vec[n_prev].x; + dyi = vec[n].y - vec[n_prev].y; + + point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi ); + + dxo = vec[n_next].x - vec[n].x; + dyo = vec[n_next].y - vec[n].y; + + point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo ); + + /* detect smooth points */ + if ( point->flags & PSH_POINT_OFF ) + point->flags |= PSH_POINT_SMOOTH; + + else if ( point->dir_in == point->dir_out ) + { + if ( point->dir_out != PSH_DIR_NONE || + psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) + point->flags |= PSH_POINT_SMOOTH; + } + } + } + + glyph->outline = outline; + glyph->globals = globals; + +#ifdef COMPUTE_INFLEXS + psh_glyph_load_points( glyph, 0 ); + psh_glyph_compute_inflections( glyph ); +#endif /* COMPUTE_INFLEXS */ + + /* now deal with hints tables */ + error = psh_hint_table_init( &glyph->hint_tables [0], + &ps_hints->dimension[0].hints, + &ps_hints->dimension[0].masks, + &ps_hints->dimension[0].counters, + memory ); + if ( error ) + goto Exit; + + error = psh_hint_table_init( &glyph->hint_tables [1], + &ps_hints->dimension[1].hints, + &ps_hints->dimension[1].masks, + &ps_hints->dimension[1].counters, + memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* compute all extrema in a glyph for a given dimension */ + static void + psh_glyph_compute_extrema( PSH_Glyph glyph ) + { + FT_UInt n; + + + /* first of all, compute all local extrema */ + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first = glyph->contours[n].start; + PSH_Point point, before, after; + + + if ( glyph->contours[n].count == 0 ) + continue; + + point = first; + before = point; + after = point; + + do + { + before = before->prev; + if ( before == first ) + goto Skip; + + } while ( before->org_u == point->org_u ); + + first = point = before->next; + + for (;;) + { + after = point; + do + { + after = after->next; + if ( after == first ) + goto Next; + + } while ( after->org_u == point->org_u ); + + if ( before->org_u < point->org_u ) + { + if ( after->org_u < point->org_u ) + { + /* local maximum */ + goto Extremum; + } + } + else /* before->org_u > point->org_u */ + { + if ( after->org_u > point->org_u ) + { + /* local minimum */ + Extremum: + do + { + psh_point_set_extremum( point ); + point = point->next; + + } while ( point != after ); + } + } + + before = after->prev; + point = after; + + } /* for */ + + Next: + ; + } + + /* for each extremum, determine its direction along the */ + /* orthogonal axis */ + for ( n = 0; n < glyph->num_points; n++ ) + { + PSH_Point point, before, after; + + + point = &glyph->points[n]; + before = point; + after = point; + + if ( psh_point_is_extremum( point ) ) + { + do + { + before = before->prev; + if ( before == point ) + goto Skip; + + } while ( before->org_v == point->org_v ); + + do + { + after = after->next; + if ( after == point ) + goto Skip; + + } while ( after->org_v == point->org_v ); + } + + if ( before->org_v < point->org_v && + after->org_v > point->org_v ) + { + psh_point_set_positive( point ); + } + else if ( before->org_v > point->org_v && + after->org_v < point->org_v ) + { + psh_point_set_negative( point ); + } + + Skip: + ; + } + } + + + /* major_dir is the direction for points on the bottom/left of the stem; */ + /* Points on the top/right of the stem will have a direction of */ + /* -major_dir. */ + + static void + psh_hint_table_find_strong_points( PSH_Hint_Table table, + PSH_Point point, + FT_UInt count, + FT_Int threshold, + FT_Int major_dir ) + { + PSH_Hint* sort = table->sort; + FT_UInt num_hints = table->num_hints; + + + for ( ; count > 0; count--, point++ ) + { + FT_Int point_dir = 0; + FT_Pos org_u = point->org_u; + + + if ( psh_point_is_strong( point ) ) + continue; + + if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) ) + point_dir = point->dir_in; + + else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) + point_dir = point->dir_out; + + if ( point_dir ) + { + if ( point_dir == major_dir ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; + } + } + } + else if ( point_dir == -major_dir ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; + } + } + } + } + +#if 1 + else if ( psh_point_is_extremum( point ) ) + { + /* treat extrema as special cases for stem edge alignment */ + FT_UInt nn, min_flag, max_flag; + + + if ( major_dir == PSH_DIR_HORIZONTAL ) + { + min_flag = PSH_POINT_POSITIVE; + max_flag = PSH_POINT_NEGATIVE; + } + else + { + min_flag = PSH_POINT_NEGATIVE; + max_flag = PSH_POINT_POSITIVE; + } + + if ( point->flags2 & min_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + else if ( point->flags2 & max_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + + if ( point->hint == NULL ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + + + if ( org_u >= hint->org_pos && + org_u <= hint->org_pos + hint->org_len ) + { + point->hint = hint; + break; + } + } + } + } + +#endif /* 1 */ + } + } + + + /* the accepted shift for strong points in fractional pixels */ +#define PSH_STRONG_THRESHOLD 32 + + /* the maximum shift value in font units */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 30 + + + /* find strong points in a glyph */ + static void + psh_glyph_find_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + /* a point is `strong' if it is located on a stem edge and */ + /* has an `in' or `out' tangent parallel to the hint's direction */ + + PSH_Hint_Table table = &glyph->hint_tables[dimension]; + PS_Mask mask = table->hint_masks->masks; + FT_UInt num_masks = table->hint_masks->num_masks; + FT_UInt first = 0; + FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL + : PSH_DIR_HORIZONTAL; + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Int threshold; + + + threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); + if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) + threshold = PSH_STRONG_THRESHOLD_MAXIMUM; + + /* process secondary hints to `selected' points */ + if ( num_masks > 1 && glyph->num_points > 0 ) + { + first = mask->end_point; + mask++; + for ( ; num_masks > 1; num_masks--, mask++ ) + { + FT_UInt next; + FT_Int count; + + + next = mask->end_point; + count = next - first; + if ( count > 0 ) + { + PSH_Point point = glyph->points + first; + + + psh_hint_table_activate_mask( table, mask ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + first = next; + } + } + + /* process primary hints for all points */ + if ( num_masks == 1 ) + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + psh_hint_table_activate_mask( table, table->hint_masks->masks ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + + /* now, certain points may have been attached to a hint and */ + /* not marked as strong; update their flags then */ + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + if ( point->hint && !psh_point_is_strong( point ) ) + psh_point_set_strong( point ); + } + } + + + /* find points in a glyph which are in a blue zone and have `in' or */ + /* `out' tangents parallel to the horizontal axis */ + static void + psh_glyph_find_blue_points( PSH_Blues blues, + PSH_Glyph glyph ) + { + PSH_Blue_Table table; + PSH_Blue_Zone zone; + FT_UInt glyph_count = glyph->num_points; + FT_UInt blue_count; + PSH_Point point = glyph->points; + + + for ( ; glyph_count > 0; glyph_count--, point++ ) + { + FT_Pos y; + + + /* check tangents */ + if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && + !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) + continue; + + /* skip strong points */ + if ( psh_point_is_strong( point ) ) + continue; + + y = point->org_u; + + /* look up top zones */ + table = &blues->normal_top; + blue_count = table->count; + zone = table->zones; + + for ( ; blue_count > 0; blue_count--, zone++ ) + { + FT_Pos delta = y - zone->org_bottom; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y <= zone->org_top + blues->blue_fuzz ) + if ( blues->no_overshoots || delta <= blues->blue_threshold ) + { + point->cur_u = zone->cur_bottom; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + + /* look up bottom zones */ + table = &blues->normal_bottom; + blue_count = table->count; + zone = table->zones + blue_count - 1; + + for ( ; blue_count > 0; blue_count--, zone-- ) + { + FT_Pos delta = zone->org_top - y; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y >= zone->org_bottom - blues->blue_fuzz ) + if ( blues->no_overshoots || delta < blues->blue_threshold ) + { + point->cur_u = zone->cur_top; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + } + } + + + /* interpolate strong points with the help of hinted coordinates */ + static void + psh_glyph_interpolate_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + { + PSH_Hint hint = point->hint; + + + if ( hint ) + { + FT_Pos delta; + + + if ( psh_point_is_edge_min( point ) ) + point->cur_u = hint->cur_pos; + + else if ( psh_point_is_edge_max( point ) ) + point->cur_u = hint->cur_pos + hint->cur_len; + + else + { + delta = point->org_u - hint->org_pos; + + if ( delta <= 0 ) + point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); + + else if ( delta >= hint->org_len ) + point->cur_u = hint->cur_pos + hint->cur_len + + FT_MulFix( delta - hint->org_len, scale ); + + else if ( hint->org_len > 0 ) + point->cur_u = hint->cur_pos + + FT_MulDiv( delta, hint->cur_len, + hint->org_len ); + else + point->cur_u = hint->cur_pos; + } + psh_point_set_fitted( point ); + } + } + } + + +#define PSH_MAX_STRONG_INTERNAL 16 + + static void + psh_glyph_interpolate_normal_points( PSH_Glyph glyph, + FT_Int dimension ) + { + +#if 1 + /* first technique: a point is strong if it is a local extremum */ + + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Memory memory = glyph->memory; + + PSH_Point* strongs = NULL; + PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; + FT_UInt num_strongs = 0; + + PSH_Point points = glyph->points; + PSH_Point points_end = points + glyph->num_points; + PSH_Point point; + + + /* first count the number of strong points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + num_strongs++; + } + + if ( num_strongs == 0 ) /* nothing to do here */ + return; + + /* allocate an array to store a list of points, */ + /* stored in increasing org_u order */ + if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) + strongs = strongs_0; + else + { + FT_Error error; + + + if ( FT_NEW_ARRAY( strongs, num_strongs ) ) + return; + } + + num_strongs = 0; + for ( point = points; point < points_end; point++ ) + { + PSH_Point* insert; + + + if ( !psh_point_is_strong( point ) ) + continue; + + for ( insert = strongs + num_strongs; insert > strongs; insert-- ) + { + if ( insert[-1]->org_u <= point->org_u ) + break; + + insert[0] = insert[-1]; + } + insert[0] = point; + num_strongs++; + } + + /* now try to interpolate all normal points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + continue; + + /* sometimes, some local extrema are smooth points */ + if ( psh_point_is_smooth( point ) ) + { + if ( point->dir_in == PSH_DIR_NONE || + point->dir_in != point->dir_out ) + continue; + + if ( !psh_point_is_extremum( point ) && + !psh_point_is_inflex( point ) ) + continue; + + point->flags &= ~PSH_POINT_SMOOTH; + } + + /* find best enclosing point coordinates then interpolate */ + { + PSH_Point before, after; + FT_UInt nn; + + + for ( nn = 0; nn < num_strongs; nn++ ) + if ( strongs[nn]->org_u > point->org_u ) + break; + + if ( nn == 0 ) /* point before the first strong point */ + { + after = strongs[0]; + + point->cur_u = after->cur_u + + FT_MulFix( point->org_u - after->org_u, + scale ); + } + else + { + before = strongs[nn - 1]; + + for ( nn = num_strongs; nn > 0; nn-- ) + if ( strongs[nn - 1]->org_u < point->org_u ) + break; + + if ( nn == num_strongs ) /* point is after last strong point */ + { + before = strongs[nn - 1]; + + point->cur_u = before->cur_u + + FT_MulFix( point->org_u - before->org_u, + scale ); + } + else + { + FT_Pos u; + + + after = strongs[nn]; + + /* now interpolate point between before and after */ + u = point->org_u; + + if ( u == before->org_u ) + point->cur_u = before->cur_u; + + else if ( u == after->org_u ) + point->cur_u = after->cur_u; + + else + point->cur_u = before->cur_u + + FT_MulDiv( u - before->org_u, + after->cur_u - before->cur_u, + after->org_u - before->org_u ); + } + } + psh_point_set_fitted( point ); + } + } + + if ( strongs != strongs_0 ) + FT_FREE( strongs ); + +#endif /* 1 */ + + } + + + /* interpolate other points */ + static void + psh_glyph_interpolate_other_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + PSH_Contour contour = glyph->contours; + FT_UInt num_contours = glyph->num_contours; + + + for ( ; num_contours > 0; num_contours--, contour++ ) + { + PSH_Point start = contour->start; + PSH_Point first, next, point; + FT_UInt fit_count; + + + /* count the number of strong points in this contour */ + next = start + contour->count; + fit_count = 0; + first = 0; + + for ( point = start; point < next; point++ ) + if ( psh_point_is_fitted( point ) ) + { + if ( !first ) + first = point; + + fit_count++; + } + + /* if there are less than 2 fitted points in the contour, we */ + /* simply scale and eventually translate the contour points */ + if ( fit_count < 2 ) + { + if ( fit_count == 1 ) + delta = first->cur_u - FT_MulFix( first->org_u, scale ); + + for ( point = start; point < next; point++ ) + if ( point != first ) + point->cur_u = FT_MulFix( point->org_u, scale ) + delta; + + goto Next_Contour; + } + + /* there are more than 2 strong points in this contour; we */ + /* need to interpolate weak points between them */ + start = first; + do + { + point = first; + + /* skip consecutive fitted points */ + for (;;) + { + next = first->next; + if ( next == start ) + goto Next_Contour; + + if ( !psh_point_is_fitted( next ) ) + break; + + first = next; + } + + /* find next fitted point after unfitted one */ + for (;;) + { + next = next->next; + if ( psh_point_is_fitted( next ) ) + break; + } + + /* now interpolate between them */ + { + FT_Pos org_a, org_ab, cur_a, cur_ab; + FT_Pos org_c, org_ac, cur_c; + FT_Fixed scale_ab; + + + if ( first->org_u <= next->org_u ) + { + org_a = first->org_u; + cur_a = first->cur_u; + org_ab = next->org_u - org_a; + cur_ab = next->cur_u - cur_a; + } + else + { + org_a = next->org_u; + cur_a = next->cur_u; + org_ab = first->org_u - org_a; + cur_ab = first->cur_u - cur_a; + } + + scale_ab = 0x10000L; + if ( org_ab > 0 ) + scale_ab = FT_DivFix( cur_ab, org_ab ); + + point = first->next; + do + { + org_c = point->org_u; + org_ac = org_c - org_a; + + if ( org_ac <= 0 ) + { + /* on the left of the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale ); + } + else if ( org_ac >= org_ab ) + { + /* on the right on the interpolation zone */ + cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); + } + else + { + /* within the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); + } + + point->cur_u = cur_c; + + point = point->next; + + } while ( point != next ); + } + + /* keep going until all points in the contours have been processed */ + first = next; + + } while ( first != start ); + + Next_Contour: + ; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HIGH-LEVEL INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + PSH_GlyphRec glyphrec; + PSH_Glyph glyph = &glyphrec; + FT_Error error; +#ifdef DEBUG_HINTER + FT_Memory memory; +#endif + FT_Int dimension; + + + /* something to do? */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return PSH_Err_Ok; + +#ifdef DEBUG_HINTER + + memory = globals->memory; + + if ( ps_debug_glyph ) + { + psh_glyph_done( ps_debug_glyph ); + FT_FREE( ps_debug_glyph ); + } + + if ( FT_NEW( glyph ) ) + return error; + + ps_debug_glyph = glyph; + +#endif /* DEBUG_HINTER */ + + error = psh_glyph_init( glyph, outline, ps_hints, globals ); + if ( error ) + goto Exit; + + /* try to optimize the y_scale so that the top of non-capital letters + * is aligned on a pixel boundary whenever possible + */ + { + PSH_Dimension dim_x = &glyph->globals->dimension[0]; + PSH_Dimension dim_y = &glyph->globals->dimension[1]; + + FT_Fixed x_scale = dim_x->scale_mult; + FT_Fixed y_scale = dim_y->scale_mult; + + FT_Fixed scaled; + FT_Fixed fitted; + + + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + + if ( fitted != 0 && scaled != fitted ) + { + y_scale = FT_MulDiv( y_scale, fitted, scaled ); + + if ( fitted < scaled ) + x_scale -= x_scale / 50; + + psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); + } + } + + glyph->do_horz_hints = 1; + glyph->do_vert_hints = 1; + + glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD ); + + glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD_V ); + + glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + + for ( dimension = 0; dimension < 2; dimension++ ) + { + /* load outline coordinates into glyph */ + psh_glyph_load_points( glyph, dimension ); + + /* compute local extrema */ + psh_glyph_compute_extrema( glyph ); + + /* compute aligned stem/hints positions */ + psh_hint_table_align_hints( &glyph->hint_tables[dimension], + glyph->globals, + dimension, + glyph ); + + /* find strong points, align them, then interpolate others */ + psh_glyph_find_strong_points( glyph, dimension ); + if ( dimension == 1 ) + psh_glyph_find_blue_points( &globals->blues, glyph ); + psh_glyph_interpolate_strong_points( glyph, dimension ); + psh_glyph_interpolate_normal_points( glyph, dimension ); + psh_glyph_interpolate_other_points( glyph, dimension ); + + /* save hinted coordinates back to outline */ + psh_glyph_save_points( glyph, dimension ); + } + + Exit: + +#ifndef DEBUG_HINTER + psh_glyph_done( glyph ); +#endif + + return error; + } + + +/* END */ diff --git a/src/freetype2/pshinter/pshalgo.h b/src/freetype2/pshinter/pshalgo.h new file mode 100644 index 0000000..f68de71 --- /dev/null +++ b/src/freetype2/pshinter/pshalgo.h @@ -0,0 +1,255 @@ +/***************************************************************************/ +/* */ +/* pshalgo.h */ +/* */ +/* PostScript hinting algorithm (specification). */ +/* */ +/* Copyright 2001, 2002, 2003 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 __PSHALGO_H__ +#define __PSHALGO_H__ + + +#include "pshrec.h" +#include "pshglob.h" +#include FT_TRIGONOMETRY_H + + +FT_BEGIN_HEADER + + + /* handle to Hint structure */ + typedef struct PSH_HintRec_* PSH_Hint; + + /* hint bit-flags */ + typedef enum + { + PSH_HINT_GHOST = PS_HINT_FLAG_GHOST, + PSH_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM, + PSH_HINT_ACTIVE = 4, + PSH_HINT_FITTED = 8 + + } PSH_Hint_Flags; + + +#define psh_hint_is_active( x ) ( ( (x)->flags & PSH_HINT_ACTIVE ) != 0 ) +#define psh_hint_is_ghost( x ) ( ( (x)->flags & PSH_HINT_GHOST ) != 0 ) +#define psh_hint_is_fitted( x ) ( ( (x)->flags & PSH_HINT_FITTED ) != 0 ) + +#define psh_hint_activate( x ) (x)->flags |= PSH_HINT_ACTIVE +#define psh_hint_deactivate( x ) (x)->flags &= ~PSH_HINT_ACTIVE +#define psh_hint_set_fitted( x ) (x)->flags |= PSH_HINT_FITTED + + /* hint structure */ + typedef struct PSH_HintRec_ + { + FT_Int org_pos; + FT_Int org_len; + FT_Pos cur_pos; + FT_Pos cur_len; + FT_UInt flags; + PSH_Hint parent; + FT_Int order; + + } PSH_HintRec; + + + /* this is an interpolation zone used for strong points; */ + /* weak points are interpolated according to their strong */ + /* neighbours */ + typedef struct PSH_ZoneRec_ + { + FT_Fixed scale; + FT_Fixed delta; + FT_Pos min; + FT_Pos max; + + } PSH_ZoneRec, *PSH_Zone; + + + typedef struct PSH_Hint_TableRec_ + { + FT_UInt max_hints; + FT_UInt num_hints; + PSH_Hint hints; + PSH_Hint* sort; + PSH_Hint* sort_global; + FT_UInt num_zones; + PSH_ZoneRec* zones; + PSH_Zone zone; + PS_Mask_Table hint_masks; + PS_Mask_Table counter_masks; + + } PSH_Hint_TableRec, *PSH_Hint_Table; + + + typedef struct PSH_PointRec_* PSH_Point; + typedef struct PSH_ContourRec_* PSH_Contour; + + enum + { + PSH_DIR_NONE = 4, + PSH_DIR_UP = -1, + PSH_DIR_DOWN = 1, + PSH_DIR_LEFT = -2, + PSH_DIR_RIGHT = 2 + }; + +#define PSH_DIR_HORIZONTAL 2 +#define PSH_DIR_VERTICAL 1 + +#define PSH_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) ) +#define PSH_DIR_IS_HORIZONTAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_HORIZONTAL ) +#define PSH_DIR_IS_VERTICAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_VERTICAL ) + + + /* the following bit-flags are computed once by the glyph */ + /* analyzer, for both dimensions */ + enum + { + PSH_POINT_OFF = 1, /* point is off the curve */ + PSH_POINT_SMOOTH = 2, /* point is smooth */ + PSH_POINT_INFLEX = 4 /* point is inflection */ + }; + +#define psh_point_is_smooth( p ) ( (p)->flags & PSH_POINT_SMOOTH ) +#define psh_point_is_off( p ) ( (p)->flags & PSH_POINT_OFF ) +#define psh_point_is_inflex( p ) ( (p)->flags & PSH_POINT_INFLEX ) + +#define psh_point_set_smooth( p ) (p)->flags |= PSH_POINT_SMOOTH +#define psh_point_set_off( p ) (p)->flags |= PSH_POINT_OFF +#define psh_point_set_inflex( p ) (p)->flags |= PSH_POINT_INFLEX + + /* the following bit-flags are re-computed for each dimension */ + enum + { + PSH_POINT_STRONG = 16, /* point is strong */ + PSH_POINT_FITTED = 32, /* point is already fitted */ + PSH_POINT_EXTREMUM = 64, /* point is local extremum */ + PSH_POINT_POSITIVE = 128, /* extremum has positive contour flow */ + PSH_POINT_NEGATIVE = 256, /* extremum has negative contour flow */ + PSH_POINT_EDGE_MIN = 512, /* point is aligned to left/bottom stem edge */ + PSH_POINT_EDGE_MAX = 1024 /* point is aligned to top/right stem edge */ + }; + +#define psh_point_is_strong( p ) ( (p)->flags2 & PSH_POINT_STRONG ) +#define psh_point_is_fitted( p ) ( (p)->flags2 & PSH_POINT_FITTED ) +#define psh_point_is_extremum( p ) ( (p)->flags2 & PSH_POINT_EXTREMUM ) +#define psh_point_is_positive( p ) ( (p)->flags2 & PSH_POINT_POSITIVE ) +#define psh_point_is_negative( p ) ( (p)->flags2 & PSH_POINT_NEGATIVE ) +#define psh_point_is_edge_min( p ) ( (p)->flags2 & PSH_POINT_EDGE_MIN ) +#define psh_point_is_edge_max( p ) ( (p)->flags2 & PSH_POINT_EDGE_MAX ) + +#define psh_point_set_strong( p ) (p)->flags2 |= PSH_POINT_STRONG +#define psh_point_set_fitted( p ) (p)->flags2 |= PSH_POINT_FITTED +#define psh_point_set_extremum( p ) (p)->flags2 |= PSH_POINT_EXTREMUM +#define psh_point_set_positive( p ) (p)->flags2 |= PSH_POINT_POSITIVE +#define psh_point_set_negative( p ) (p)->flags2 |= PSH_POINT_NEGATIVE +#define psh_point_set_edge_min( p ) (p)->flags2 |= PSH_POINT_EDGE_MIN +#define psh_point_set_edge_max( p ) (p)->flags2 |= PSH_POINT_EDGE_MAX + + + typedef struct PSH_PointRec_ + { + PSH_Point prev; + PSH_Point next; + PSH_Contour contour; + FT_UInt flags; + FT_UInt flags2; + FT_Char dir_in; + FT_Char dir_out; + FT_Angle angle_in; + FT_Angle angle_out; + PSH_Hint hint; + FT_Pos org_u; + FT_Pos org_v; + FT_Pos cur_u; +#ifdef DEBUG_HINTER + FT_Pos org_x; + FT_Pos cur_x; + FT_Pos org_y; + FT_Pos cur_y; + FT_UInt flags_x; + FT_UInt flags_y; +#endif + + } PSH_PointRec; + + +#define PSH_POINT_EQUAL_ORG( a, b ) ( (a)->org_u == (b)->org_u && \ + (a)->org_v == (b)->org_v ) + +#define PSH_POINT_ANGLE( a, b ) FT_Atan2( (b)->org_u - (a)->org_u, \ + (b)->org_v - (a)->org_v ) + + typedef struct PSH_ContourRec_ + { + PSH_Point start; + FT_UInt count; + + } PSH_ContourRec; + + + typedef struct PSH_GlyphRec_ + { + FT_UInt num_points; + FT_UInt num_contours; + + PSH_Point points; + PSH_Contour contours; + + FT_Memory memory; + FT_Outline* outline; + PSH_Globals globals; + PSH_Hint_TableRec hint_tables[2]; + + FT_Bool vertical; + FT_Int major_dir; + FT_Int minor_dir; + + FT_Bool do_horz_hints; + FT_Bool do_vert_hints; + FT_Bool do_horz_snapping; + FT_Bool do_vert_snapping; + FT_Bool do_stem_adjust; + + } PSH_GlyphRec, *PSH_Glyph; + + +#ifdef DEBUG_HINTER + extern PSH_Hint_Table ps_debug_hint_table; + + typedef void + (*PSH_HintFunc)( PSH_Hint hint, + FT_Bool vertical ); + + extern PSH_HintFunc ps_debug_hint_func; + + extern PSH_Glyph ps_debug_glyph; +#endif + + + extern FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + +FT_END_HEADER + + +#endif /* __PSHALGO_H__ */ + + +/* END */ diff --git a/src/freetype2/pshinter/pshglob.c b/src/freetype2/pshinter/pshglob.c new file mode 100644 index 0000000..8a69aa1 --- /dev/null +++ b/src/freetype2/pshinter/pshglob.c @@ -0,0 +1,750 @@ +/***************************************************************************/ +/* */ +/* pshglob.c */ +/* */ +/* PostScript hinter global hinting management (body). */ +/* Inspired by the new auto-hinter module. */ +/* */ +/* Copyright 2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_INTERNAL_OBJECTS_H +#include "pshglob.h" + +#ifdef DEBUG_HINTER + PSH_Globals ps_debug_globals = 0; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STANDARD WIDTHS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* scale the widths/heights table */ + static void + psh_globals_scale_widths( PSH_Globals globals, + FT_UInt direction ) + { + PSH_Dimension dim = &globals->dimension[direction]; + PSH_Widths stdw = &dim->stdw; + FT_UInt count = stdw->count; + PSH_Width width = stdw->widths; + PSH_Width stand = width; /* standard width/height */ + FT_Fixed scale = dim->scale_mult; + + + if ( count > 0 ) + { + width->cur = FT_MulFix( width->org, scale ); + width->fit = FT_PIX_ROUND( width->cur ); + + width++; + count--; + + for ( ; count > 0; count--, width++ ) + { + FT_Pos w, dist; + + + w = FT_MulFix( width->org, scale ); + dist = w - stand->cur; + + if ( dist < 0 ) + dist = -dist; + + if ( dist < 128 ) + w = stand->cur; + + width->cur = w; + width->fit = FT_PIX_ROUND( w ); + } + } + } + + +#if 0 + + /* org_width is is font units, result in device pixels, 26.6 format */ + FT_LOCAL_DEF( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ) + { + FT_UInt n; + FT_Pos width = FT_MulFix( org_width, dimension->scale_mult ); + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + + + for ( n = 0; n < dimension->stdw.count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = dimension->stdw.widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + if ( width >= reference ) + { + width -= 0x21; + if ( width < reference ) + width = reference; + } + else + { + width += 0x21; + if ( width > reference ) + width = reference; + } + + return width; + } + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BLUE ZONES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_blues_set_zones_0( PSH_Blues target, + FT_Bool is_others, + FT_UInt read_count, + FT_Short* read, + PSH_Blue_Table top_table, + PSH_Blue_Table bot_table ) + { + FT_UInt count_top = top_table->count; + FT_UInt count_bot = bot_table->count; + FT_Bool first = 1; + + FT_UNUSED( target ); + + + for ( ; read_count > 1; read_count -= 2 ) + { + FT_Int reference, delta; + FT_UInt count; + PSH_Blue_Zone zones, zone; + FT_Bool top; + + + /* read blue zone entry, and select target top/bottom zone */ + top = 0; + if ( first || is_others ) + { + reference = read[1]; + delta = read[0] - reference; + + zones = bot_table->zones; + count = count_bot; + first = 0; + } + else + { + reference = read[0]; + delta = read[1] - reference; + + zones = top_table->zones; + count = count_top; + top = 1; + } + + /* insert into sorted table */ + zone = zones; + for ( ; count > 0; count--, zone++ ) + { + if ( reference < zone->org_ref ) + break; + + if ( reference == zone->org_ref ) + { + FT_Int delta0 = zone->org_delta; + + + /* we have two zones on the same reference position -- */ + /* only keep the largest one */ + if ( delta < 0 ) + { + if ( delta < delta0 ) + zone->org_delta = delta; + } + else + { + if ( delta > delta0 ) + zone->org_delta = delta; + } + goto Skip; + } + } + + for ( ; count > 0; count-- ) + zone[count] = zone[count-1]; + + zone->org_ref = reference; + zone->org_delta = delta; + + if ( top ) + count_top++; + else + count_bot++; + + Skip: + read += 2; + } + + top_table->count = count_top; + bot_table->count = count_bot; + } + + + /* Re-read blue zones from the original fonts and store them into out */ + /* private structure. This function re-orders, sanitizes and */ + /* fuzz-expands the zones as well. */ + static void + psh_blues_set_zones( PSH_Blues target, + FT_UInt count, + FT_Short* blues, + FT_UInt count_others, + FT_Short* other_blues, + FT_Int fuzz, + FT_Int family ) + { + PSH_Blue_Table top_table, bot_table; + FT_Int count_top, count_bot; + + + if ( family ) + { + top_table = &target->family_top; + bot_table = &target->family_bottom; + } + else + { + top_table = &target->normal_top; + bot_table = &target->normal_bottom; + } + + /* read the input blue zones, and build two sorted tables */ + /* (one for the top zones, the other for the bottom zones) */ + top_table->count = 0; + bot_table->count = 0; + + /* first, the blues */ + psh_blues_set_zones_0( target, 0, + count, blues, top_table, bot_table ); + psh_blues_set_zones_0( target, 1, + count_others, other_blues, top_table, bot_table ); + + count_top = top_table->count; + count_bot = bot_table->count; + + /* sanitize top table */ + if ( count_top > 0 ) + { + PSH_Blue_Zone zone = top_table->zones; + + + for ( count = count_top; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[1].org_ref - zone[0].org_ref; + if ( zone->org_delta > delta ) + zone->org_delta = delta; + } + + zone->org_bottom = zone->org_ref; + zone->org_top = zone->org_delta + zone->org_ref; + } + } + + /* sanitize bottom table */ + if ( count_bot > 0 ) + { + PSH_Blue_Zone zone = bot_table->zones; + + + for ( count = count_bot; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[0].org_ref - zone[1].org_ref; + if ( zone->org_delta < delta ) + zone->org_delta = delta; + } + + zone->org_top = zone->org_ref; + zone->org_bottom = zone->org_delta + zone->org_ref; + } + } + + /* expand top and bottom tables with blue fuzz */ + { + FT_Int dim, top, bot, delta; + PSH_Blue_Zone zone; + + + zone = top_table->zones; + count = count_top; + + for ( dim = 1; dim >= 0; dim-- ) + { + if ( count > 0 ) + { + /* expand the bottom of the lowest zone normally */ + zone->org_bottom -= fuzz; + + /* expand the top and bottom of intermediate zones; */ + /* checking that the interval is smaller than the fuzz */ + top = zone->org_top; + + for ( count--; count > 0; count-- ) + { + bot = zone[1].org_bottom; + delta = bot - top; + + if ( delta < 2 * fuzz ) + zone[0].org_top = zone[1].org_bottom = top + delta / 2; + else + { + zone[0].org_top = top + fuzz; + zone[1].org_bottom = bot - fuzz; + } + + zone++; + top = zone->org_top; + } + + /* expand the top of the highest zone normally */ + zone->org_top = top + fuzz; + } + zone = bot_table->zones; + count = count_bot; + } + } + } + + + /* reset the blues table when the device transform changes */ + static void + psh_blues_scale_zones( PSH_Blues blues, + FT_Fixed scale, + FT_Pos delta ) + { + FT_UInt count; + FT_UInt num; + PSH_Blue_Table table = 0; + + /* */ + /* Determine whether we need to suppress overshoots or */ + /* not. We simply need to compare the vertical scale */ + /* parameter to the raw bluescale value. Here is why: */ + /* */ + /* We need to suppress overshoots for all pointsizes. */ + /* At 300dpi that satisfies: */ + /* */ + /* pointsize < 240*bluescale + 0.49 */ + /* */ + /* This corresponds to: */ + /* */ + /* pixelsize < 1000*bluescale + 49/24 */ + /* */ + /* scale*EM_Size < 1000*bluescale + 49/24 */ + /* */ + /* However, for normal Type 1 fonts, EM_Size is 1000! */ + /* We thus only check: */ + /* */ + /* scale < bluescale + 49/24000 */ + /* */ + /* which we shorten to */ + /* */ + /* "scale < bluescale" */ + /* */ + /* Note that `blue_scale' is stored 1000 times its real */ + /* value, and that `scale' converts from font units to */ + /* fractional pixels. */ + /* */ + + /* 1000 / 64 = 125 / 8 */ + if ( scale >= 0x20C49BAL ) + blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 ); + else + blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 ); + + /* */ + /* The blue threshold is the font units distance under */ + /* which overshoots are suppressed due to the BlueShift */ + /* even if the scale is greater than BlueScale. */ + /* */ + /* It is the smallest distance such that */ + /* */ + /* dist <= BlueShift && dist*scale <= 0.5 pixels */ + /* */ + { + FT_Int threshold = blues->blue_shift; + + + while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 ) + threshold--; + + blues->blue_threshold = threshold; + } + + for ( num = 0; num < 4; num++ ) + { + PSH_Blue_Zone zone; + + + switch ( num ) + { + case 0: + table = &blues->normal_top; + break; + case 1: + table = &blues->normal_bottom; + break; + case 2: + table = &blues->family_top; + break; + default: + table = &blues->family_bottom; + break; + } + + zone = table->zones; + count = table->count; + for ( ; count > 0; count--, zone++ ) + { + zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta; + zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta; + zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta; + zone->cur_delta = FT_MulFix( zone->org_delta, scale ); + + /* round scaled reference position */ + zone->cur_ref = FT_PIX_ROUND( zone->cur_ref ); + +#if 0 + if ( zone->cur_ref > zone->cur_top ) + zone->cur_ref -= 64; + else if ( zone->cur_ref < zone->cur_bottom ) + zone->cur_ref += 64; +#endif + } + } + + /* process the families now */ + + for ( num = 0; num < 2; num++ ) + { + PSH_Blue_Zone zone1, zone2; + FT_UInt count1, count2; + PSH_Blue_Table normal, family; + + + switch ( num ) + { + case 0: + normal = &blues->normal_top; + family = &blues->family_top; + break; + + default: + normal = &blues->normal_bottom; + family = &blues->family_bottom; + } + + zone1 = normal->zones; + count1 = normal->count; + + for ( ; count1 > 0; count1--, zone1++ ) + { + /* try to find a family zone whose reference position is less */ + /* than 1 pixel far from the current zone */ + zone2 = family->zones; + count2 = family->count; + + for ( ; count2 > 0; count2--, zone2++ ) + { + FT_Pos Delta; + + + Delta = zone1->org_ref - zone2->org_ref; + if ( Delta < 0 ) + Delta = -Delta; + + if ( FT_MulFix( Delta, scale ) < 64 ) + { + zone1->cur_top = zone2->cur_top; + zone1->cur_bottom = zone2->cur_bottom; + zone1->cur_ref = zone2->cur_ref; + zone1->cur_delta = zone2->cur_delta; + break; + } + } + } + } + } + + + FT_LOCAL_DEF( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ) + { + PSH_Blue_Table table; + FT_UInt count; + FT_Pos delta; + PSH_Blue_Zone zone; + FT_Int no_shoots; + + + alignment->align = PSH_BLUE_ALIGN_NONE; + + no_shoots = blues->no_overshoots; + + /* look up stem top in top zones table */ + table = &blues->normal_top; + count = table->count; + zone = table->zones; + + for ( ; count > 0; count--, zone++ ) + { + delta = stem_top - zone->org_bottom; + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_top <= zone->org_top + blues->blue_fuzz ) + { + if ( no_shoots || delta <= blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_TOP; + alignment->align_top = zone->cur_ref; + } + break; + } + } + + /* look up stem bottom in bottom zones table */ + table = &blues->normal_bottom; + count = table->count; + zone = table->zones + count-1; + + for ( ; count > 0; count--, zone-- ) + { + delta = zone->org_top - stem_bot; + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_bot >= zone->org_bottom - blues->blue_fuzz ) + { + if ( no_shoots || delta < blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_BOT; + alignment->align_bot = zone->cur_ref; + } + break; + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_globals_destroy( PSH_Globals globals ) + { + if ( globals ) + { + FT_Memory memory; + + + memory = globals->memory; + globals->dimension[0].stdw.count = 0; + globals->dimension[1].stdw.count = 0; + + globals->blues.normal_top.count = 0; + globals->blues.normal_bottom.count = 0; + globals->blues.family_top.count = 0; + globals->blues.family_bottom.count = 0; + + FT_FREE( globals ); + +#ifdef DEBUG_HINTER + ps_debug_globals = 0; +#endif + } + } + + + static FT_Error + psh_globals_new( FT_Memory memory, + T1_Private* priv, + PSH_Globals *aglobals ) + { + PSH_Globals globals; + FT_Error error; + + + if ( !FT_NEW( globals ) ) + { + FT_UInt count; + FT_Short* read; + + + globals->memory = memory; + + /* copy standard widths */ + { + PSH_Dimension dim = &globals->dimension[1]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_width[0]; + write++; + + read = priv->snap_widths; + for ( count = priv->num_snap_widths; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_widths + 1; + } + + /* copy standard heights */ + { + PSH_Dimension dim = &globals->dimension[0]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_height[0]; + write++; + read = priv->snap_heights; + for ( count = priv->num_snap_heights; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_heights + 1; + } + + /* copy blue zones */ + psh_blues_set_zones( &globals->blues, priv->num_blue_values, + priv->blue_values, priv->num_other_blues, + priv->other_blues, priv->blue_fuzz, 0 ); + + psh_blues_set_zones( &globals->blues, priv->num_family_blues, + priv->family_blues, priv->num_family_other_blues, + priv->family_other_blues, priv->blue_fuzz, 1 ); + + globals->blues.blue_scale = priv->blue_scale; + globals->blues.blue_shift = priv->blue_shift; + globals->blues.blue_fuzz = priv->blue_fuzz; + + globals->dimension[0].scale_mult = 0; + globals->dimension[0].scale_delta = 0; + globals->dimension[1].scale_mult = 0; + globals->dimension[1].scale_delta = 0; + +#ifdef DEBUG_HINTER + ps_debug_globals = globals; +#endif + } + + *aglobals = globals; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ) + { + PSH_Dimension dim = &globals->dimension[0]; + + + dim = &globals->dimension[0]; + if ( x_scale != dim->scale_mult || + x_delta != dim->scale_delta ) + { + dim->scale_mult = x_scale; + dim->scale_delta = x_delta; + + psh_globals_scale_widths( globals, 0 ); + } + + dim = &globals->dimension[1]; + if ( y_scale != dim->scale_mult || + y_delta != dim->scale_delta ) + { + dim->scale_mult = y_scale; + dim->scale_delta = y_delta; + + psh_globals_scale_widths( globals, 1 ); + psh_blues_scale_zones( &globals->blues, y_scale, y_delta ); + } + + return 0; + } + + + FT_LOCAL_DEF( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ) + { + funcs->create = psh_globals_new; + funcs->set_scale = psh_globals_set_scale; + funcs->destroy = psh_globals_destroy; + } + + +/* END */ diff --git a/src/freetype2/pshinter/pshglob.h b/src/freetype2/pshinter/pshglob.h new file mode 100644 index 0000000..c511626 --- /dev/null +++ b/src/freetype2/pshinter/pshglob.h @@ -0,0 +1,196 @@ +/***************************************************************************/ +/* */ +/* pshglob.h */ +/* */ +/* PostScript hinter global hinting management. */ +/* */ +/* Copyright 2001, 2002, 2003 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 __PSHGLOB_H__ +#define __PSHGLOB_H__ + + +#include FT_FREETYPE_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* @constant: */ + /* PS_GLOBALS_MAX_BLUE_ZONES */ + /* */ + /* @description: */ + /* The maximum number of blue zones in a font global hints structure. */ + /* See @PS_Globals_BluesRec. */ + /* */ +#define PS_GLOBALS_MAX_BLUE_ZONES 16 + + + /*************************************************************************/ + /* */ + /* @constant: */ + /* PS_GLOBALS_MAX_STD_WIDTHS */ + /* */ + /* @description: */ + /* The maximum number of standard and snap widths in either the */ + /* horizontal or vertical direction. See @PS_Globals_WidthsRec. */ + /* */ +#define PS_GLOBALS_MAX_STD_WIDTHS 16 + + + /* standard and snap width */ + typedef struct PSH_WidthRec_ + { + FT_Int org; + FT_Pos cur; + FT_Pos fit; + + } PSH_WidthRec, *PSH_Width; + + + /* standard and snap widths table */ + typedef struct PSH_WidthsRec_ + { + FT_UInt count; + PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS]; + + } PSH_WidthsRec, *PSH_Widths; + + + typedef struct PSH_DimensionRec_ + { + PSH_WidthsRec stdw; + FT_Fixed scale_mult; + FT_Fixed scale_delta; + + } PSH_DimensionRec, *PSH_Dimension; + + + /* blue zone descriptor */ + typedef struct PSH_Blue_ZoneRec_ + { + FT_Int org_ref; + FT_Int org_delta; + FT_Int org_top; + FT_Int org_bottom; + + FT_Pos cur_ref; + FT_Pos cur_delta; + FT_Pos cur_bottom; + FT_Pos cur_top; + + } PSH_Blue_ZoneRec, *PSH_Blue_Zone; + + + typedef struct PSH_Blue_TableRec_ + { + FT_UInt count; + PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES]; + + } PSH_Blue_TableRec, *PSH_Blue_Table; + + + /* blue zones table */ + typedef struct PSH_BluesRec_ + { + PSH_Blue_TableRec normal_top; + PSH_Blue_TableRec normal_bottom; + PSH_Blue_TableRec family_top; + PSH_Blue_TableRec family_bottom; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_threshold; + FT_Int blue_fuzz; + FT_Bool no_overshoots; + + } PSH_BluesRec, *PSH_Blues; + + + /* font globals. */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PSH_GlobalsRec_ + { + FT_Memory memory; + PSH_DimensionRec dimension[2]; + PSH_BluesRec blues; + + } PSH_GlobalsRec; + + +#define PSH_BLUE_ALIGN_NONE 0 +#define PSH_BLUE_ALIGN_TOP 1 +#define PSH_BLUE_ALIGN_BOT 2 + + + typedef struct PSH_AlignmentRec_ + { + int align; + FT_Pos align_top; + FT_Pos align_bot; + + } PSH_AlignmentRec, *PSH_Alignment; + + + FT_LOCAL( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ); + + +#if 0 + /* snap a stem width to fitter coordinates. `org_width' is in font */ + /* units. The result is in device pixels (26.6 format). */ + FT_LOCAL( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ); +#endif + + FT_LOCAL( FT_Error ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + /* snap a stem to one or two blue zones */ + FT_LOCAL( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ); + /* */ + +#ifdef DEBUG_HINTER + extern PSH_Globals ps_debug_globals; +#endif + + +FT_END_HEADER + + +#endif /* __PSHGLOB_H__ */ + + +/* END */ diff --git a/src/freetype2/pshinter/pshinter.c b/src/freetype2/pshinter/pshinter.c new file mode 100644 index 0000000..8e3f193 --- /dev/null +++ b/src/freetype2/pshinter/pshinter.c @@ -0,0 +1,28 @@ +/***************************************************************************/ +/* */ +/* pshinter.c */ +/* */ +/* FreeType PostScript Hinting module */ +/* */ +/* Copyright 2001, 2003 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 "pshrec.c" +#include "pshglob.c" +#include "pshalgo.c" +#include "pshmod.c" + + +/* END */ diff --git a/src/freetype2/pshinter/pshmod.c b/src/freetype2/pshinter/pshmod.c new file mode 100644 index 0000000..4eb3d91 --- /dev/null +++ b/src/freetype2/pshinter/pshmod.c @@ -0,0 +1,121 @@ +/***************************************************************************/ +/* */ +/* pshmod.c */ +/* */ +/* FreeType PostScript hinter module implementation (body). */ +/* */ +/* Copyright 2001, 2002, 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_INTERNAL_OBJECTS_H +#include "pshrec.h" +#include "pshalgo.h" + + + /* the Postscript Hinter module structure */ + typedef struct PS_Hinter_Module_Rec_ + { + FT_ModuleRec root; + PS_HintsRec ps_hints; + + PSH_Globals_FuncsRec globals_funcs; + T1_Hints_FuncsRec t1_funcs; + T2_Hints_FuncsRec t2_funcs; + + } PS_Hinter_ModuleRec, *PS_Hinter_Module; + + + /* finalize module */ + FT_CALLBACK_DEF( void ) + ps_hinter_done( PS_Hinter_Module module ) + { + module->t1_funcs.hints = NULL; + module->t2_funcs.hints = NULL; + + ps_hints_done( &module->ps_hints ); + } + + + /* initialize module, create hints recorder and the interface */ + FT_CALLBACK_DEF( FT_Error ) + ps_hinter_init( PS_Hinter_Module module ) + { + FT_Memory memory = module->root.memory; + void* ph = &module->ps_hints; + + + ps_hints_init( &module->ps_hints, memory ); + + psh_globals_funcs_init( &module->globals_funcs ); + + t1_hints_funcs_init( &module->t1_funcs ); + module->t1_funcs.hints = (T1_Hints)ph; + + t2_hints_funcs_init( &module->t2_funcs ); + module->t2_funcs.hints = (T2_Hints)ph; + + return 0; + } + + + /* returns global hints interface */ + FT_CALLBACK_DEF( PSH_Globals_Funcs ) + pshinter_get_globals_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->globals_funcs; + } + + + /* return Type 1 hints interface */ + FT_CALLBACK_DEF( T1_Hints_Funcs ) + pshinter_get_t1_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t1_funcs; + } + + + /* return Type 2 hints interface */ + FT_CALLBACK_DEF( T2_Hints_Funcs ) + pshinter_get_t2_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t2_funcs; + } + + + static + const PSHinter_Interface pshinter_interface = + { + pshinter_get_globals_funcs, + pshinter_get_t1_funcs, + pshinter_get_t2_funcs + }; + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class pshinter_module_class = + { + 0, + sizeof ( PS_Hinter_ModuleRec ), + "pshinter", + 0x10000L, + 0x20000L, + + &pshinter_interface, /* module-specific interface */ + + (FT_Module_Constructor)ps_hinter_init, + (FT_Module_Destructor) ps_hinter_done, + (FT_Module_Requester) 0 /* no additional interface for now */ + }; + + +/* END */ diff --git a/src/freetype2/pshinter/pshmod.h b/src/freetype2/pshinter/pshmod.h new file mode 100644 index 0000000..1a91025 --- /dev/null +++ b/src/freetype2/pshinter/pshmod.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* pshmod.h */ +/* */ +/* PostScript hinter module interface (specification). */ +/* */ +/* Copyright 2001 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 __PSHMOD_H__ +#define __PSHMOD_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) pshinter_module_class; + + +FT_END_HEADER + + +#endif /* __PSHMOD_H__ */ + + +/* END */ diff --git a/src/freetype2/pshinter/pshnterr.h b/src/freetype2/pshinter/pshnterr.h new file mode 100644 index 0000000..3c0029f --- /dev/null +++ b/src/freetype2/pshinter/pshnterr.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* pshnterr.h */ +/* */ +/* PS Hinter error codes (specification only). */ +/* */ +/* Copyright 2003 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 PSHinter error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __PSHNTERR_H__ +#define __PSHNTERR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX PSH_Err_ +#define FT_ERR_BASE FT_Mod_Err_PShinter + +#include FT_ERRORS_H + +#endif /* __PSHNTERR_H__ */ + + +/* END */ diff --git a/src/freetype2/pshinter/pshrec.c b/src/freetype2/pshinter/pshrec.c new file mode 100644 index 0000000..2a885ef --- /dev/null +++ b/src/freetype2/pshinter/pshrec.c @@ -0,0 +1,1215 @@ +/***************************************************************************/ +/* */ +/* pshrec.c */ +/* */ +/* FreeType PostScript hints recorder (body). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 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_FREETYPE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include "pshrec.h" +#include "pshalgo.h" + +#include "pshnterr.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_pshrec + +#ifdef DEBUG_HINTER + PS_Hints ps_debug_hints = 0; + int ps_debug_no_horz_hints = 0; + int ps_debug_no_vert_hints = 0; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_HINT MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy hints table */ + static void + ps_hint_table_done( PS_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + } + + + /* ensure that a table can contain "count" elements */ + static FT_Error + ps_hint_table_ensure( PS_Hint_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_hints; + FT_UInt new_max = count; + FT_Error error = 0; + + + if ( new_max > old_max ) + { + /* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + } + return error; + } + + + static FT_Error + ps_hint_table_alloc( PS_Hint_Table table, + FT_Memory memory, + PS_Hint *ahint ) + { + FT_Error error = 0; + FT_UInt count; + PS_Hint hint = 0; + + + count = table->num_hints; + count++; + + if ( count >= table->max_hints ) + { + error = ps_hint_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + hint = table->hints + count - 1; + hint->pos = 0; + hint->len = 0; + hint->flags = 0; + + table->num_hints = count; + + Exit: + *ahint = hint; + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_MASK MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy mask */ + static void + ps_mask_done( PS_Mask mask, + FT_Memory memory ) + { + FT_FREE( mask->bytes ); + mask->num_bits = 0; + mask->max_bits = 0; + mask->end_point = 0; + } + + + /* ensure that a mask can contain "count" bits */ + static FT_Error + ps_mask_ensure( PS_Mask mask, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; + FT_Error error = 0; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) + mask->max_bits = new_max * 8; + } + return error; + } + + + /* test a bit value in a given mask */ + static FT_Int + ps_mask_test_bit( PS_Mask mask, + FT_Int idx ) + { + if ( (FT_UInt)idx >= mask->num_bits ) + return 0; + + return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); + } + + + /* clear a given bit */ + static void + ps_mask_clear_bit( PS_Mask mask, + FT_Int idx ) + { + FT_Byte* p; + + + if ( (FT_UInt)idx >= mask->num_bits ) + return; + + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) ); + } + + + /* set a given bit, possibly grow the mask */ + static FT_Error + ps_mask_set_bit( PS_Mask mask, + FT_Int idx, + FT_Memory memory ) + { + FT_Error error = 0; + FT_Byte* p; + + + if ( idx < 0 ) + goto Exit; + + if ( (FT_UInt)idx >= mask->num_bits ) + { + error = ps_mask_ensure( mask, idx + 1, memory ); + if ( error ) + goto Exit; + + mask->num_bits = idx + 1; + } + + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); + + Exit: + return error; + } + + + /* destroy mask table */ + static void + ps_mask_table_done( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt count = table->max_masks; + PS_Mask mask = table->masks; + + + for ( ; count > 0; count--, mask++ ) + ps_mask_done( mask, memory ); + + FT_FREE( table->masks ); + table->num_masks = 0; + table->max_masks = 0; + } + + + /* ensure that a mask table can contain "count" masks */ + static FT_Error + ps_mask_table_ensure( PS_Mask_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_masks; + FT_UInt new_max = count; + FT_Error error = 0; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) + table->max_masks = new_max; + } + return error; + } + + + /* allocate a new mask in a table */ + static FT_Error + ps_mask_table_alloc( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_UInt count; + FT_Error error = 0; + PS_Mask mask = 0; + + + count = table->num_masks; + count++; + + if ( count > table->max_masks ) + { + error = ps_mask_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + mask = table->masks + count - 1; + mask->num_bits = 0; + mask->end_point = 0; + table->num_masks = count; + + Exit: + *amask = mask; + return error; + } + + + /* return last hint mask in a table, create one if the table is empty */ + static FT_Error + ps_mask_table_last( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_Error error = 0; + FT_UInt count; + PS_Mask mask; + + + count = table->num_masks; + if ( count == 0 ) + { + error = ps_mask_table_alloc( table, memory, &mask ); + if ( error ) + goto Exit; + } + else + mask = table->masks + count - 1; + + Exit: + *amask = mask; + return error; + } + + + /* set a new mask to a given bit range */ + static FT_Error + ps_mask_table_set_bits( PS_Mask_Table table, + const FT_Byte* source, + FT_UInt bit_pos, + FT_UInt bit_count, + FT_Memory memory ) + { + FT_Error error = 0; + PS_Mask mask; + + + error = ps_mask_table_last( table, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_ensure( mask, bit_count, memory ); + if ( error ) + goto Exit; + + mask->num_bits = bit_count; + + /* now, copy bits */ + { + FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); + FT_Int rmask = 0x80 >> ( bit_pos & 7 ); + FT_Byte* write = mask->bytes; + FT_Int wmask = 0x80; + FT_Int val; + + + for ( ; bit_count > 0; bit_count-- ) + { + val = write[0] & ~wmask; + + if ( read[0] & rmask ) + val |= wmask; + + write[0] = (FT_Byte)val; + + rmask >>= 1; + if ( rmask == 0 ) + { + read++; + rmask = 0x80; + } + + wmask >>= 1; + if ( wmask == 0 ) + { + write++; + wmask = 0x80; + } + } + } + + Exit: + return error; + } + + + /* test whether two masks in a table intersect */ + static FT_Int + ps_mask_table_test_intersect( PS_Mask_Table table, + FT_Int index1, + FT_Int index2 ) + { + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_Byte* p1 = mask1->bytes; + FT_Byte* p2 = mask2->bytes; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt count; + + + count = ( count1 <= count2 ) ? count1 : count2; + for ( ; count >= 8; count -= 8 ) + { + if ( p1[0] & p2[0] ) + return 1; + + p1++; + p2++; + } + + if ( count == 0 ) + return 0; + + return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); + } + + + /* merge two masks, used by ps_mask_table_merge_all */ + static FT_Error + ps_mask_table_merge( PS_Mask_Table table, + FT_Int index1, + FT_Int index2, + FT_Memory memory ) + { + FT_UInt temp; + FT_Error error = 0; + + + /* swap index1 and index2 so that index1 < index2 */ + if ( index1 > index2 ) + { + temp = index1; + index1 = index2; + index2 = temp; + } + + if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks ) + { + /* we need to merge the bitsets of index1 and index2 with a */ + /* simple union */ + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_Int delta; + + + if ( count2 > 0 ) + { + FT_UInt pos; + FT_Byte* read; + FT_Byte* write; + + + /* if "count2" is greater than "count1", we need to grow the */ + /* first bitset, and clear the highest bits */ + if ( count2 > count1 ) + { + error = ps_mask_ensure( mask1, count2, memory ); + if ( error ) + goto Exit; + + for ( pos = count1; pos < count2; pos++ ) + ps_mask_clear_bit( mask1, pos ); + } + + /* merge (unite) the bitsets */ + read = mask2->bytes; + write = mask1->bytes; + pos = (FT_UInt)( ( count2 + 7 ) >> 3 ); + + for ( ; pos > 0; pos-- ) + { + write[0] = (FT_Byte)( write[0] | read[0] ); + write++; + read++; + } + } + + /* Now, remove "mask2" from the list. We need to keep the masks */ + /* sorted in order of importance, so move table elements. */ + mask2->num_bits = 0; + mask2->end_point = 0; + + delta = table->num_masks - 1 - index2; /* number of masks to move */ + if ( delta > 0 ) + { + /* move to end of table for reuse */ + PS_MaskRec dummy = *mask2; + + + ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) ); + + mask2[delta] = dummy; + } + + table->num_masks--; + } + else + FT_ERROR(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + index1, index2 )); + + Exit: + return error; + } + + + /* Try to merge all masks in a given table. This is used to merge */ + /* all counter masks into independent counter "paths". */ + /* */ + static FT_Error + ps_mask_table_merge_all( PS_Mask_Table table, + FT_Memory memory ) + { + FT_Int index1, index2; + FT_Error error = 0; + + + for ( index1 = table->num_masks - 1; index1 > 0; index1-- ) + { + for ( index2 = index1 - 1; index2 >= 0; index2-- ) + { + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) + { + error = ps_mask_table_merge( table, index2, index1, memory ); + if ( error ) + goto Exit; + + break; + } + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_DIMENSION MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* finalize a given dimension */ + static void + ps_dimension_done( PS_Dimension dimension, + FT_Memory memory ) + { + ps_mask_table_done( &dimension->counters, memory ); + ps_mask_table_done( &dimension->masks, memory ); + ps_hint_table_done( &dimension->hints, memory ); + } + + + /* initialize a given dimension */ + static void + ps_dimension_init( PS_Dimension dimension ) + { + dimension->hints.num_hints = 0; + dimension->masks.num_masks = 0; + dimension->counters.num_masks = 0; + } + + +#if 0 + + /* set a bit at a given index in the current hint mask */ + static FT_Error + ps_dimension_set_mask_bit( PS_Dimension dim, + FT_UInt idx, + FT_Memory memory ) + { + PS_Mask mask; + FT_Error error = 0; + + + /* get last hint mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + + Exit: + return error; + } + +#endif + + /* set the end point in a mask, called from "End" & "Reset" methods */ + static void + ps_dimension_end_mask( PS_Dimension dim, + FT_UInt end_point ) + { + FT_UInt count = dim->masks.num_masks; + PS_Mask mask; + + + if ( count > 0 ) + { + mask = dim->masks.masks + count - 1; + mask->end_point = end_point; + } + } + + + /* set the end point in the current mask, then create a new empty one */ + /* (called by "Reset" method) */ + static FT_Error + ps_dimension_reset_mask( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + PS_Mask mask; + + + /* end current mask */ + ps_dimension_end_mask( dim, end_point ); + + /* allocate new one */ + return ps_mask_table_alloc( &dim->masks, memory, &mask ); + } + + + /* set a new mask, called from the "T2Stem" method */ + static FT_Error + ps_dimension_set_mask_bits( PS_Dimension dim, + const FT_Byte* source, + FT_UInt source_pos, + FT_UInt source_bits, + FT_UInt end_point, + FT_Memory memory ) + { + FT_Error error = 0; + + + /* reset current mask, if any */ + error = ps_dimension_reset_mask( dim, end_point, memory ); + if ( error ) + goto Exit; + + /* set bits in new mask */ + error = ps_mask_table_set_bits( &dim->masks, source, + source_pos, source_bits, memory ); + + Exit: + return error; + } + + + /* add a new single stem (called from "T1Stem" method) */ + static FT_Error + ps_dimension_add_t1stem( PS_Dimension dim, + FT_Int pos, + FT_Int len, + FT_Memory memory, + FT_Int *aindex ) + { + FT_Error error = 0; + FT_UInt flags = 0; + + + /* detect ghost stem */ + if ( len < 0 ) + { + flags |= PS_HINT_FLAG_GHOST; + if ( len == -21 ) + { + flags |= PS_HINT_FLAG_BOTTOM; + pos += len; + } + len = 0; + } + + if ( aindex ) + *aindex = -1; + + /* now, lookup stem in the current hints table */ + { + PS_Mask mask; + FT_UInt idx; + FT_UInt max = dim->hints.num_hints; + PS_Hint hint = dim->hints.hints; + + + for ( idx = 0; idx < max; idx++, hint++ ) + { + if ( hint->pos == pos && hint->len == len ) + break; + } + + /* we need to create a new hint in the table */ + if ( idx >= max ) + { + error = ps_hint_table_alloc( &dim->hints, memory, &hint ); + if ( error ) + goto Exit; + + hint->pos = pos; + hint->len = len; + hint->flags = flags; + } + + /* now, store the hint in the current mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + if ( error ) + goto Exit; + + if ( aindex ) + *aindex = (FT_Int)idx; + } + + Exit: + return error; + } + + + /* add a "hstem3/vstem3" counter to our dimension table */ + static FT_Error + ps_dimension_add_counter( PS_Dimension dim, + FT_Int hint1, + FT_Int hint2, + FT_Int hint3, + FT_Memory memory ) + { + FT_Error error = 0; + FT_UInt count = dim->counters.num_masks; + PS_Mask counter = dim->counters.masks; + + + /* try to find an existing counter mask that already uses */ + /* one of these stems here */ + for ( ; count > 0; count--, counter++ ) + { + if ( ps_mask_test_bit( counter, hint1 ) || + ps_mask_test_bit( counter, hint2 ) || + ps_mask_test_bit( counter, hint3 ) ) + break; + } + + /* create a new counter when needed */ + if ( count == 0 ) + { + error = ps_mask_table_alloc( &dim->counters, memory, &counter ); + if ( error ) + goto Exit; + } + + /* now, set the bits for our hints in the counter mask */ + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* end of recording session for a given dimension */ + static FT_Error + ps_dimension_end( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + /* end hint mask table */ + ps_dimension_end_mask( dim, end_point ); + + /* merge all counter masks into independent "paths" */ + return ps_mask_table_merge_all( &dim->counters, memory ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_RECORDER MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* destroy hints */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ) + { + FT_Memory memory = hints->memory; + + + ps_dimension_done( &hints->dimension[0], memory ); + ps_dimension_done( &hints->dimension[1], memory ); + + hints->error = 0; + hints->memory = 0; + } + + + FT_LOCAL( FT_Error ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ) + { + FT_MEM_ZERO( hints, sizeof ( *hints ) ); + hints->memory = memory; + return 0; + } + + + /* initialize a hints for a new session */ + static void + ps_hints_open( PS_Hints hints, + PS_Hint_Type hint_type ) + { + switch ( hint_type ) + { + case PS_HINT_TYPE_1: + case PS_HINT_TYPE_2: + hints->error = 0; + hints->hint_type = hint_type; + + ps_dimension_init( &hints->dimension[0] ); + ps_dimension_init( &hints->dimension[1] ); + break; + + default: + hints->error = PSH_Err_Invalid_Argument; + hints->hint_type = hint_type; + + FT_ERROR(( "ps_hints_open: invalid charstring type!\n" )); + break; + } + } + + + /* add one or more stems to the current hints table */ + static void + ps_hints_stem( PS_Hints hints, + FT_Int dimension, + FT_UInt count, + FT_Long* stems ) + { + if ( !hints->error ) + { + /* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_ERROR(( "ps_hints_stem: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + /* record the stems in the current hints/masks table */ + switch ( hints->hint_type ) + { + case PS_HINT_TYPE_1: /* Type 1 "hstem" or "vstem" operator */ + case PS_HINT_TYPE_2: /* Type 2 "hstem" or "vstem" operator */ + { + PS_Dimension dim = &hints->dimension[dimension]; + + + for ( ; count > 0; count--, stems += 2 ) + { + FT_Error error; + FT_Memory memory = hints->memory; + + + error = ps_dimension_add_t1stem( + dim, (FT_Int)stems[0], (FT_Int)stems[1], + memory, NULL ); + if ( error ) + { + FT_ERROR(( "ps_hints_stem: could not add stem" + " (%d,%d) to hints table\n", stems[0], stems[1] )); + + hints->error = error; + return; + } + } + break; + } + + default: + FT_ERROR(( "ps_hints_stem: called with invalid hint type (%d)\n", + hints->hint_type )); + break; + } + } + } + + + /* add one Type1 counter stem to the current hints table */ + static void + ps_hints_t1stem3( PS_Hints hints, + FT_Int dimension, + FT_Long* stems ) + { + FT_Error error = 0; + + + if ( !hints->error ) + { + PS_Dimension dim; + FT_Memory memory = hints->memory; + FT_Int count; + FT_Int idx[3]; + + + /* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_ERROR(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + dim = &hints->dimension[dimension]; + + /* there must be 6 elements in the 'stem' array */ + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + /* add the three stems to our hints/masks table */ + for ( count = 0; count < 3; count++, stems += 2 ) + { + error = ps_dimension_add_t1stem( + dim, (FT_Int)stems[0], (FT_Int)stems[1], + memory, &idx[count] ); + if ( error ) + goto Fail; + } + + /* now, add the hints to the counters table */ + error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], + memory ); + if ( error ) + goto Fail; + } + else + { + FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type!\n" )); + error = PSH_Err_Invalid_Argument; + goto Fail; + } + } + + return; + + Fail: + FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); + hints->error = error; + } + + + /* reset hints (only with Type 1 hints) */ + static void + ps_hints_t1reset( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error = 0; + + + if ( !hints->error ) + { + FT_Memory memory = hints->memory; + + + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + error = ps_dimension_reset_mask( &hints->dimension[0], + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_reset_mask( &hints->dimension[1], + end_point, memory ); + if ( error ) + goto Fail; + } + else + { + /* invalid hint type */ + error = PSH_Err_Invalid_Argument; + goto Fail; + } + } + return; + + Fail: + hints->error = error; + } + + + /* Type2 "hintmask" operator, add a new hintmask to each direction */ + static void + ps_hints_t2mask( PS_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count; must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_ERROR(( "ps_hints_t2mask: " + "called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, + end_point, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + static void + ps_hints_t2counter( PS_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count, must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_ERROR(( "ps_hints_t2counter: " + "called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, + 0, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, + 0, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + /* end recording session */ + static FT_Error + ps_hints_close( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error; + + + error = hints->error; + if ( !error ) + { + FT_Memory memory = hints->memory; + PS_Dimension dim = hints->dimension; + + + error = ps_dimension_end( &dim[0], end_point, memory ); + if ( !error ) + { + error = ps_dimension_end( &dim[1], end_point, memory ); + } + } + +#ifdef DEBUG_HINTER + if ( !error ) + ps_debug_hints = hints; +#endif + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_hints_open( T1_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); + } + + static void + t1_hints_stem( T1_Hints hints, + FT_Int dimension, + FT_Long* coords ) + { + ps_hints_stem( (PS_Hints)hints, dimension, 1, coords ); + } + + + FT_LOCAL_DEF( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) + { + FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) ); + + funcs->open = (T1_Hints_OpenFunc) t1_hints_open; + funcs->close = (T1_Hints_CloseFunc) ps_hints_close; + funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; + funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; + funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; + funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 2 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t2_hints_open( T2_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); + } + + + static void + t2_hints_stems( T2_Hints hints, + FT_Int dimension, + FT_Int count, + FT_Fixed* coords ) + { + FT_Pos stems[32], y, n; + FT_Int total = count; + + + y = 0; + while ( total > 0 ) + { + /* determine number of stems to write */ + count = total; + if ( count > 16 ) + count = 16; + + /* compute integer stem positions in font units */ + for ( n = 0; n < count * 2; n++ ) + { + y += coords[n]; + stems[n] = ( y + 0x8000L ) >> 16; + } + + /* compute lengths */ + for ( n = 0; n < count * 2; n += 2 ) + stems[n + 1] = stems[n + 1] - stems[n]; + + /* add them to the current dimension */ + ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); + + total -= count; + } + } + + + FT_LOCAL_DEF( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) + { + FT_MEM_ZERO( funcs, sizeof ( *funcs ) ); + + funcs->open = (T2_Hints_OpenFunc) t2_hints_open; + funcs->close = (T2_Hints_CloseFunc) ps_hints_close; + funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; + funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask; + funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; + funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply; + } + + +/* END */ diff --git a/src/freetype2/pshinter/pshrec.h b/src/freetype2/pshinter/pshrec.h new file mode 100644 index 0000000..f7ef900 --- /dev/null +++ b/src/freetype2/pshinter/pshrec.h @@ -0,0 +1,176 @@ +/***************************************************************************/ +/* */ +/* pshrec.h */ +/* */ +/* Postscript (Type1/Type2) hints recorder (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + + /**************************************************************************/ + /* */ + /* The functions defined here are called from the Type 1, CID and CFF */ + /* font drivers to record the hints of a given character/glyph. */ + /* */ + /* The hints are recorded in a unified format, and are later processed */ + /* by the `optimizer' and `fitter' to adjust the outlines to the pixel */ + /* grid. */ + /* */ + /**************************************************************************/ + + +#ifndef __PSHREC_H__ +#define __PSHREC_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include "pshglob.h" + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH HINTS RECORDER INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to hint record */ + typedef struct PS_HintRec_* PS_Hint; + + /* hint types */ + typedef enum + { + PS_HINT_TYPE_1 = 1, + PS_HINT_TYPE_2 = 2 + + } PS_Hint_Type; + + + /* hint flags */ + typedef enum + { + PS_HINT_FLAG_GHOST = 1, + PS_HINT_FLAG_BOTTOM = 2 + + } PS_Hint_Flags; + + + /* hint descriptor */ + typedef struct PS_HintRec_ + { + FT_Int pos; + FT_Int len; + FT_UInt flags; + + } PS_HintRec; + + +#define ps_hint_is_active( x ) ( (x)->flags & PS_HINT_FLAG_ACTIVE ) +#define ps_hint_is_ghost( x ) ( (x)->flags & PS_HINT_FLAG_GHOST ) +#define ps_hint_is_bottom( x ) ( (x)->flags & PS_HINT_FLAG_BOTTOM ) + + + /* hints table descriptor */ + typedef struct PS_Hint_TableRec_ + { + FT_UInt num_hints; + FT_UInt max_hints; + PS_Hint hints; + + } PS_Hint_TableRec, *PS_Hint_Table; + + + /* hint and counter mask descriptor */ + typedef struct PS_MaskRec_ + { + FT_UInt num_bits; + FT_UInt max_bits; + FT_Byte* bytes; + FT_UInt end_point; + + } PS_MaskRec, *PS_Mask; + + + /* masks and counters table descriptor */ + typedef struct PS_Mask_TableRec_ + { + FT_UInt num_masks; + FT_UInt max_masks; + PS_Mask masks; + + } PS_Mask_TableRec, *PS_Mask_Table; + + + /* dimension-specific hints descriptor */ + typedef struct PS_DimensionRec_ + { + PS_Hint_TableRec hints; + PS_Mask_TableRec masks; + PS_Mask_TableRec counters; + + } PS_DimensionRec, *PS_Dimension; + + + /* glyph hints descriptor */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PS_HintsRec_ + { + FT_Memory memory; + FT_Error error; + FT_UInt32 magic; + PS_Hint_Type hint_type; + PS_DimensionRec dimension[2]; + + } PS_HintsRec, *PS_Hints; + + /* */ + + /* initialize hints recorder */ + FT_LOCAL( FT_Error ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ); + + /* finalize hints recorder */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ); + + /* initialize Type1 hints recorder interface */ + FT_LOCAL( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ); + + /* initialize Type2 hints recorder interface */ + FT_LOCAL( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ); + + +#ifdef DEBUG_HINTER + extern PS_Hints ps_debug_hints; + extern int ps_debug_no_horz_hints; + extern int ps_debug_no_vert_hints; +#endif + + /* */ + + +FT_END_HEADER + + +#endif /* __PS_HINTER_RECORD_H__ */ + + +/* END */ diff --git a/src/freetype2/psnames/psmodule.c b/src/freetype2/psnames/psmodule.c new file mode 100644 index 0000000..8d8c476 --- /dev/null +++ b/src/freetype2/psnames/psmodule.c @@ -0,0 +1,458 @@ +/***************************************************************************/ +/* */ +/* psmodule.c */ +/* */ +/* PSNames module implementation (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + +#include "psmodule.h" +#include "pstables.h" + +#include "psnamerr.h" + + +#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + +#define VARIANT_BIT 0x80000000UL +#define BASE_GLYPH( code ) ( (code) & ~VARIANT_BIT ) + + + /* Return the Unicode value corresponding to a given glyph. Note that */ + /* we do deal with glyph variants by detecting a non-initial dot in */ + /* the name, as in `A.swash' or `e.final'; in this case, the */ + /* VARIANT_BIT is set in the return value. */ + /* */ + static FT_UInt32 + ps_unicode_value( const char* glyph_name ) + { + /* If the name begins with `uni', then the glyph name may be a */ + /* hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' && + glyph_name[1] == 'n' && + glyph_name[2] == 'i' ) + { + /* determine whether the next four characters following are */ + /* hexadecimal. */ + + /* XXX: Add code to deal with ligatures, i.e. glyph names like */ + /* `uniXXXXYYYYZZZZ'... */ + + FT_Int count; + FT_ULong value = 0; + const char* p = glyph_name + 3; + + + for ( count = 4; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + /* Exit if a non-uppercase hexadecimal character was found */ + /* -- this also catches character codes below `0' since such */ + /* negative numbers cast to `unsigned int' are far too big. */ + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + /* there must be exactly four hex digits */ + if ( count == 0 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return value | VARIANT_BIT; + } + } + + /* If the name begins with `u', followed by four to six uppercase */ + /* hexadecimal digits, it is a hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' ) + { + FT_Int count; + FT_ULong value = 0; + const char* p = glyph_name + 1; + + + for ( count = 6; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + if ( count <= 2 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return value | VARIANT_BIT; + } + } + + /* Look for a non-initial dot in the glyph name in order to */ + /* find variants like `A.swash', `e.final', etc. */ + { + const char* p = glyph_name; + const char* dot = NULL; + + + for ( ; *p; p++ ) + { + if ( *p == '.' && p > glyph_name ) + { + dot = p; + break; + } + } + + /* now look up the glyph in the Adobe Glyph List */ + if ( !dot ) + return ft_get_adobe_glyph_index( glyph_name, p ); + else + return ft_get_adobe_glyph_index( glyph_name, dot ) | VARIANT_BIT; + } + } + + + /* ft_qsort callback to sort the unicode map */ + FT_CALLBACK_DEF( int ) + compare_uni_maps( const void* a, + const void* b ) + { + PS_UniMap* map1 = (PS_UniMap*)a; + PS_UniMap* map2 = (PS_UniMap*)b; + FT_UInt32 unicode1 = BASE_GLYPH( map1->unicode ); + FT_UInt32 unicode2 = BASE_GLYPH( map2->unicode ); + + + /* sort base glyphs before glyph variants */ + if ( unicode1 == unicode2 ) + return map1->unicode - map2->unicode; + else + return unicode1 - unicode2; + } + + + /* Build a table that maps Unicode values to glyph indices. */ + static FT_Error + ps_unicodes_init( FT_Memory memory, + PS_Unicodes table, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ) + { + FT_Error error; + + + /* we first allocate the table */ + table->num_maps = 0; + table->maps = 0; + + if ( !FT_NEW_ARRAY( table->maps, num_glyphs ) ) + { + FT_UInt n; + FT_UInt count; + PS_UniMap* map; + FT_UInt32 uni_char; + + + map = table->maps; + + for ( n = 0; n < num_glyphs; n++ ) + { + const char* gname = get_glyph_name( glyph_data, n ); + + + if ( gname ) + { + uni_char = ps_unicode_value( gname ); + + if ( BASE_GLYPH( uni_char ) != 0 ) + { + map->unicode = uni_char; + map->glyph_index = n; + map++; + } + + if ( free_glyph_name ) + free_glyph_name( glyph_data, gname ); + } + } + + /* now compress the table a bit */ + count = (FT_UInt)( map - table->maps ); + + if ( count == 0 ) + { + FT_FREE( table->maps ); + if ( !error ) + error = PSnames_Err_Invalid_Argument; /* No unicode chars here! */ + } + else { + /* Reallocate if the number of used entries is much smaller. */ + if ( count < num_glyphs / 2 ) + { + (void)FT_RENEW_ARRAY( table->maps, num_glyphs, count ); + error = PSnames_Err_Ok; + } + + /* Sort the table in increasing order of unicode values, */ + /* taking care of glyph variants. */ + ft_qsort( table->maps, count, sizeof ( PS_UniMap ), + compare_uni_maps ); + } + + table->num_maps = count; + } + + return error; + } + + + static FT_UInt + ps_unicodes_char_index( PS_Unicodes table, + FT_UInt32 unicode ) + { + PS_UniMap *min, *max, *mid, *result = NULL; + + + /* Perform a binary search on the table. */ + + min = table->maps; + max = min + table->num_maps - 1; + + while ( min <= max ) + { + FT_UInt32 base_glyph; + + + mid = min + ( ( max - min ) >> 1 ); + + if ( mid->unicode == unicode ) + { + result = mid; + break; + } + + base_glyph = BASE_GLYPH( mid->unicode ); + + if ( base_glyph == unicode ) + result = mid; /* remember match but continue search for base glyph */ + + if ( min == max ) + break; + + if ( base_glyph < unicode ) + min = mid + 1; + else + max = mid - 1; + } + + if ( result ) + return result->glyph_index; + else + return 0; + } + + + static FT_ULong + ps_unicodes_char_next( PS_Unicodes table, + FT_UInt32 *unicode ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *unicode + 1; + + + { + FT_UInt min = 0; + FT_UInt max = table->num_maps; + FT_UInt mid; + PS_UniMap* map; + FT_UInt32 base_glyph; + + + while ( min < max ) + { + mid = min + ( ( max - min ) >> 1 ); + map = table->maps + mid; + + if ( map->unicode == char_code ) + { + result = map->glyph_index; + goto Exit; + } + + base_glyph = BASE_GLYPH( map->unicode ); + + if ( base_glyph == char_code ) + result = map->glyph_index; + + if ( base_glyph < char_code ) + min = mid + 1; + else + max = mid; + } + + if ( result ) + goto Exit; /* we have a variant glyph */ + + /* we didn't find it; check whether we have a map just above it */ + char_code = 0; + + if ( min < table->num_maps ) + { + map = table->maps + min; + result = map->glyph_index; + char_code = BASE_GLYPH( map->unicode ); + } + } + + Exit: + *unicode = char_code; + return result; + } + + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + static const char* + ps_get_macintosh_name( FT_UInt name_index ) + { + if ( name_index >= FT_NUM_MAC_NAMES ) + name_index = 0; + + return ft_standard_glyph_names + ft_mac_names[name_index]; + } + + + static const char* + ps_get_standard_strings( FT_UInt sid ) + { + if ( sid >= FT_NUM_SID_NAMES ) + return 0; + + return ft_standard_glyph_names + ft_sid_names[sid]; + } + + + static + const FT_Service_PsCMapsRec pscmaps_interface = + { +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + (PS_Unicode_ValueFunc) ps_unicode_value, + (PS_Unicodes_InitFunc) ps_unicodes_init, + (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, + (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, + +#else + + 0, + 0, + 0, + 0, + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + (PS_Macintosh_NameFunc) ps_get_macintosh_name, + (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, + + t1_standard_encoding, + t1_expert_encoding + }; + + + static const FT_ServiceDescRec pscmaps_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_CMAPS, &pscmaps_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + psnames_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pscmaps_services, service_id ); + } + +#endif /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */ + + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class psnames_module_class = + { + 0, /* this is not a font driver, nor a renderer */ + sizeof ( FT_ModuleRec ), + + "psnames", /* driver name */ + 0x10000L, /* driver version */ + 0x20000L, /* driver requires FreeType 2 or above */ + +#ifdef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES + 0, + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 +#else + (void*)&pscmaps_interface, /* module specific interface */ + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) psnames_get_service +#endif + }; + + +/* END */ diff --git a/src/freetype2/psnames/psmodule.h b/src/freetype2/psnames/psmodule.h new file mode 100644 index 0000000..232fdfb --- /dev/null +++ b/src/freetype2/psnames/psmodule.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* psmodule.h */ +/* */ +/* High-level PSNames module interface (specification). */ +/* */ +/* Copyright 1996-2001 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 __PSMODULE_H__ +#define __PSMODULE_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) psnames_module_class; + + +FT_END_HEADER + +#endif /* __PSMODULE_H__ */ + + +/* END */ diff --git a/src/freetype2/psnames/psnamerr.h b/src/freetype2/psnames/psnamerr.h new file mode 100644 index 0000000..ae1541d --- /dev/null +++ b/src/freetype2/psnames/psnamerr.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* psnamerr.h */ +/* */ +/* PS names module error codes (specification only). */ +/* */ +/* Copyright 2001 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 PS names module error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __PSNAMERR_H__ +#define __PSNAMERR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX PSnames_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSnames + +#include FT_ERRORS_H + +#endif /* __PSNAMERR_H__ */ + + +/* END */ diff --git a/src/freetype2/psnames/psnames.c b/src/freetype2/psnames/psnames.c new file mode 100644 index 0000000..d6ed998 --- /dev/null +++ b/src/freetype2/psnames/psnames.c @@ -0,0 +1,25 @@ +/***************************************************************************/ +/* */ +/* psnames.c */ +/* */ +/* FreeType PSNames module component (body only). */ +/* */ +/* Copyright 1996-2001 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 "psmodule.c" + + +/* END */ diff --git a/src/freetype2/psnames/pstables.h b/src/freetype2/psnames/pstables.h new file mode 100644 index 0000000..cc40ef7 --- /dev/null +++ b/src/freetype2/psnames/pstables.h @@ -0,0 +1,4090 @@ +/***************************************************************************/ +/* */ +/* pstables.h */ +/* */ +/* PostScript glyph names. */ +/* */ +/* 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 has been generated automatically -- do not edit! */ + + + static const char ft_standard_glyph_names[3696] = + { + '.','n','u','l','l', 0, + 'n','o','n','m','a','r','k','i','n','g','r','e','t','u','r','n', 0, + 'n','o','t','e','q','u','a','l', 0, + 'i','n','f','i','n','i','t','y', 0, + 'l','e','s','s','e','q','u','a','l', 0, + 'g','r','e','a','t','e','r','e','q','u','a','l', 0, + 'p','a','r','t','i','a','l','d','i','f','f', 0, + 's','u','m','m','a','t','i','o','n', 0, + 'p','r','o','d','u','c','t', 0, + 'p','i', 0, + 'i','n','t','e','g','r','a','l', 0, + 'O','m','e','g','a', 0, + 'r','a','d','i','c','a','l', 0, + 'a','p','p','r','o','x','e','q','u','a','l', 0, + 'D','e','l','t','a', 0, + 'n','o','n','b','r','e','a','k','i','n','g','s','p','a','c','e', 0, + 'l','o','z','e','n','g','e', 0, + 'a','p','p','l','e', 0, + 'f','r','a','n','c', 0, + 'G','b','r','e','v','e', 0, + 'g','b','r','e','v','e', 0, + 'I','d','o','t','a','c','c','e','n','t', 0, + 'S','c','e','d','i','l','l','a', 0, + 's','c','e','d','i','l','l','a', 0, + 'C','a','c','u','t','e', 0, + 'c','a','c','u','t','e', 0, + 'C','c','a','r','o','n', 0, + 'c','c','a','r','o','n', 0, + 'd','c','r','o','a','t', 0, + '.','n','o','t','d','e','f', 0, + 's','p','a','c','e', 0, + 'e','x','c','l','a','m', 0, + 'q','u','o','t','e','d','b','l', 0, + 'n','u','m','b','e','r','s','i','g','n', 0, + 'd','o','l','l','a','r', 0, + 'p','e','r','c','e','n','t', 0, + 'a','m','p','e','r','s','a','n','d', 0, + 'q','u','o','t','e','r','i','g','h','t', 0, + 'p','a','r','e','n','l','e','f','t', 0, + 'p','a','r','e','n','r','i','g','h','t', 0, + 'a','s','t','e','r','i','s','k', 0, + 'p','l','u','s', 0, + 'c','o','m','m','a', 0, + 'h','y','p','h','e','n', 0, + 'p','e','r','i','o','d', 0, + 's','l','a','s','h', 0, + 'z','e','r','o', 0, + 'o','n','e', 0, + 't','w','o', 0, + 't','h','r','e','e', 0, + 'f','o','u','r', 0, + 'f','i','v','e', 0, + 's','i','x', 0, + 's','e','v','e','n', 0, + 'e','i','g','h','t', 0, + 'n','i','n','e', 0, + 'c','o','l','o','n', 0, + 's','e','m','i','c','o','l','o','n', 0, + 'l','e','s','s', 0, + 'e','q','u','a','l', 0, + 'g','r','e','a','t','e','r', 0, + 'q','u','e','s','t','i','o','n', 0, + 'a','t', 0, + 'A', 0, + 'B', 0, + 'C', 0, + 'D', 0, + 'E', 0, + 'F', 0, + 'G', 0, + 'H', 0, + 'I', 0, + 'J', 0, + 'K', 0, + 'L', 0, + 'M', 0, + 'N', 0, + 'O', 0, + 'P', 0, + 'Q', 0, + 'R', 0, + 'S', 0, + 'T', 0, + 'U', 0, + 'V', 0, + 'W', 0, + 'X', 0, + 'Y', 0, + 'Z', 0, + 'b','r','a','c','k','e','t','l','e','f','t', 0, + 'b','a','c','k','s','l','a','s','h', 0, + 'b','r','a','c','k','e','t','r','i','g','h','t', 0, + 'a','s','c','i','i','c','i','r','c','u','m', 0, + 'u','n','d','e','r','s','c','o','r','e', 0, + 'q','u','o','t','e','l','e','f','t', 0, + 'a', 0, + 'b', 0, + 'c', 0, + 'd', 0, + 'e', 0, + 'f', 0, + 'g', 0, + 'h', 0, + 'i', 0, + 'j', 0, + 'k', 0, + 'l', 0, + 'm', 0, + 'n', 0, + 'o', 0, + 'p', 0, + 'q', 0, + 'r', 0, + 's', 0, + 't', 0, + 'u', 0, + 'v', 0, + 'w', 0, + 'x', 0, + 'y', 0, + 'z', 0, + 'b','r','a','c','e','l','e','f','t', 0, + 'b','a','r', 0, + 'b','r','a','c','e','r','i','g','h','t', 0, + 'a','s','c','i','i','t','i','l','d','e', 0, + 'e','x','c','l','a','m','d','o','w','n', 0, + 'c','e','n','t', 0, + 's','t','e','r','l','i','n','g', 0, + 'f','r','a','c','t','i','o','n', 0, + 'y','e','n', 0, + 'f','l','o','r','i','n', 0, + 's','e','c','t','i','o','n', 0, + 'c','u','r','r','e','n','c','y', 0, + 'q','u','o','t','e','s','i','n','g','l','e', 0, + 'q','u','o','t','e','d','b','l','l','e','f','t', 0, + 'g','u','i','l','l','e','m','o','t','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','r','i','g','h','t', 0, + 'f','i', 0, + 'f','l', 0, + 'e','n','d','a','s','h', 0, + 'd','a','g','g','e','r', 0, + 'd','a','g','g','e','r','d','b','l', 0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d', 0, + 'p','a','r','a','g','r','a','p','h', 0, + 'b','u','l','l','e','t', 0, + 'q','u','o','t','e','s','i','n','g','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','r','i','g','h','t', 0, + 'g','u','i','l','l','e','m','o','t','r','i','g','h','t', 0, + 'e','l','l','i','p','s','i','s', 0, + 'p','e','r','t','h','o','u','s','a','n','d', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n', 0, + 'g','r','a','v','e', 0, + 'a','c','u','t','e', 0, + 'c','i','r','c','u','m','f','l','e','x', 0, + 't','i','l','d','e', 0, + 'm','a','c','r','o','n', 0, + 'b','r','e','v','e', 0, + 'd','o','t','a','c','c','e','n','t', 0, + 'd','i','e','r','e','s','i','s', 0, + 'r','i','n','g', 0, + 'c','e','d','i','l','l','a', 0, + 'h','u','n','g','a','r','u','m','l','a','u','t', 0, + 'o','g','o','n','e','k', 0, + 'c','a','r','o','n', 0, + 'e','m','d','a','s','h', 0, + 'A','E', 0, + 'o','r','d','f','e','m','i','n','i','n','e', 0, + 'L','s','l','a','s','h', 0, + 'O','s','l','a','s','h', 0, + 'O','E', 0, + 'o','r','d','m','a','s','c','u','l','i','n','e', 0, + 'a','e', 0, + 'd','o','t','l','e','s','s','i', 0, + 'l','s','l','a','s','h', 0, + 'o','s','l','a','s','h', 0, + 'o','e', 0, + 'g','e','r','m','a','n','d','b','l','s', 0, + 'o','n','e','s','u','p','e','r','i','o','r', 0, + 'l','o','g','i','c','a','l','n','o','t', 0, + 'm','u', 0, + 't','r','a','d','e','m','a','r','k', 0, + 'E','t','h', 0, + 'o','n','e','h','a','l','f', 0, + 'p','l','u','s','m','i','n','u','s', 0, + 'T','h','o','r','n', 0, + 'o','n','e','q','u','a','r','t','e','r', 0, + 'd','i','v','i','d','e', 0, + 'b','r','o','k','e','n','b','a','r', 0, + 'd','e','g','r','e','e', 0, + 't','h','o','r','n', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s', 0, + 't','w','o','s','u','p','e','r','i','o','r', 0, + 'r','e','g','i','s','t','e','r','e','d', 0, + 'm','i','n','u','s', 0, + 'e','t','h', 0, + 'm','u','l','t','i','p','l','y', 0, + 't','h','r','e','e','s','u','p','e','r','i','o','r', 0, + 'c','o','p','y','r','i','g','h','t', 0, + 'A','a','c','u','t','e', 0, + 'A','c','i','r','c','u','m','f','l','e','x', 0, + 'A','d','i','e','r','e','s','i','s', 0, + 'A','g','r','a','v','e', 0, + 'A','r','i','n','g', 0, + 'A','t','i','l','d','e', 0, + 'C','c','e','d','i','l','l','a', 0, + 'E','a','c','u','t','e', 0, + 'E','c','i','r','c','u','m','f','l','e','x', 0, + 'E','d','i','e','r','e','s','i','s', 0, + 'E','g','r','a','v','e', 0, + 'I','a','c','u','t','e', 0, + 'I','c','i','r','c','u','m','f','l','e','x', 0, + 'I','d','i','e','r','e','s','i','s', 0, + 'I','g','r','a','v','e', 0, + 'N','t','i','l','d','e', 0, + 'O','a','c','u','t','e', 0, + 'O','c','i','r','c','u','m','f','l','e','x', 0, + 'O','d','i','e','r','e','s','i','s', 0, + 'O','g','r','a','v','e', 0, + 'O','t','i','l','d','e', 0, + 'S','c','a','r','o','n', 0, + 'U','a','c','u','t','e', 0, + 'U','c','i','r','c','u','m','f','l','e','x', 0, + 'U','d','i','e','r','e','s','i','s', 0, + 'U','g','r','a','v','e', 0, + 'Y','a','c','u','t','e', 0, + 'Y','d','i','e','r','e','s','i','s', 0, + 'Z','c','a','r','o','n', 0, + 'a','a','c','u','t','e', 0, + 'a','c','i','r','c','u','m','f','l','e','x', 0, + 'a','d','i','e','r','e','s','i','s', 0, + 'a','g','r','a','v','e', 0, + 'a','r','i','n','g', 0, + 'a','t','i','l','d','e', 0, + 'c','c','e','d','i','l','l','a', 0, + 'e','a','c','u','t','e', 0, + 'e','c','i','r','c','u','m','f','l','e','x', 0, + 'e','d','i','e','r','e','s','i','s', 0, + 'e','g','r','a','v','e', 0, + 'i','a','c','u','t','e', 0, + 'i','c','i','r','c','u','m','f','l','e','x', 0, + 'i','d','i','e','r','e','s','i','s', 0, + 'i','g','r','a','v','e', 0, + 'n','t','i','l','d','e', 0, + 'o','a','c','u','t','e', 0, + 'o','c','i','r','c','u','m','f','l','e','x', 0, + 'o','d','i','e','r','e','s','i','s', 0, + 'o','g','r','a','v','e', 0, + 'o','t','i','l','d','e', 0, + 's','c','a','r','o','n', 0, + 'u','a','c','u','t','e', 0, + 'u','c','i','r','c','u','m','f','l','e','x', 0, + 'u','d','i','e','r','e','s','i','s', 0, + 'u','g','r','a','v','e', 0, + 'y','a','c','u','t','e', 0, + 'y','d','i','e','r','e','s','i','s', 0, + 'z','c','a','r','o','n', 0, + 'e','x','c','l','a','m','s','m','a','l','l', 0, + 'H','u','n','g','a','r','u','m','l','a','u','t','s','m','a','l','l', 0, + 'd','o','l','l','a','r','o','l','d','s','t','y','l','e', 0, + 'd','o','l','l','a','r','s','u','p','e','r','i','o','r', 0, + 'a','m','p','e','r','s','a','n','d','s','m','a','l','l', 0, + 'A','c','u','t','e','s','m','a','l','l', 0, + 'p','a','r','e','n','l','e','f','t','s','u','p','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 't','w','o','d','o','t','e','n','l','e','a','d','e','r', 0, + 'o','n','e','d','o','t','e','n','l','e','a','d','e','r', 0, + 'z','e','r','o','o','l','d','s','t','y','l','e', 0, + 'o','n','e','o','l','d','s','t','y','l','e', 0, + 't','w','o','o','l','d','s','t','y','l','e', 0, + 't','h','r','e','e','o','l','d','s','t','y','l','e', 0, + 'f','o','u','r','o','l','d','s','t','y','l','e', 0, + 'f','i','v','e','o','l','d','s','t','y','l','e', 0, + 's','i','x','o','l','d','s','t','y','l','e', 0, + 's','e','v','e','n','o','l','d','s','t','y','l','e', 0, + 'e','i','g','h','t','o','l','d','s','t','y','l','e', 0, + 'n','i','n','e','o','l','d','s','t','y','l','e', 0, + 'c','o','m','m','a','s','u','p','e','r','i','o','r', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s','e','m','d','a','s','h', 0, + 'p','e','r','i','o','d','s','u','p','e','r','i','o','r', 0, + 'q','u','e','s','t','i','o','n','s','m','a','l','l', 0, + 'a','s','u','p','e','r','i','o','r', 0, + 'b','s','u','p','e','r','i','o','r', 0, + 'c','e','n','t','s','u','p','e','r','i','o','r', 0, + 'd','s','u','p','e','r','i','o','r', 0, + 'e','s','u','p','e','r','i','o','r', 0, + 'i','s','u','p','e','r','i','o','r', 0, + 'l','s','u','p','e','r','i','o','r', 0, + 'm','s','u','p','e','r','i','o','r', 0, + 'n','s','u','p','e','r','i','o','r', 0, + 'o','s','u','p','e','r','i','o','r', 0, + 'r','s','u','p','e','r','i','o','r', 0, + 's','s','u','p','e','r','i','o','r', 0, + 't','s','u','p','e','r','i','o','r', 0, + 'f','f', 0, + 'f','f','i', 0, + 'f','f','l', 0, + 'p','a','r','e','n','l','e','f','t','i','n','f','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'C','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'h','y','p','h','e','n','s','u','p','e','r','i','o','r', 0, + 'G','r','a','v','e','s','m','a','l','l', 0, + 'A','s','m','a','l','l', 0, + 'B','s','m','a','l','l', 0, + 'C','s','m','a','l','l', 0, + 'D','s','m','a','l','l', 0, + 'E','s','m','a','l','l', 0, + 'F','s','m','a','l','l', 0, + 'G','s','m','a','l','l', 0, + 'H','s','m','a','l','l', 0, + 'I','s','m','a','l','l', 0, + 'J','s','m','a','l','l', 0, + 'K','s','m','a','l','l', 0, + 'L','s','m','a','l','l', 0, + 'M','s','m','a','l','l', 0, + 'N','s','m','a','l','l', 0, + 'O','s','m','a','l','l', 0, + 'P','s','m','a','l','l', 0, + 'Q','s','m','a','l','l', 0, + 'R','s','m','a','l','l', 0, + 'S','s','m','a','l','l', 0, + 'T','s','m','a','l','l', 0, + 'U','s','m','a','l','l', 0, + 'V','s','m','a','l','l', 0, + 'W','s','m','a','l','l', 0, + 'X','s','m','a','l','l', 0, + 'Y','s','m','a','l','l', 0, + 'Z','s','m','a','l','l', 0, + 'c','o','l','o','n','m','o','n','e','t','a','r','y', 0, + 'o','n','e','f','i','t','t','e','d', 0, + 'r','u','p','i','a','h', 0, + 'T','i','l','d','e','s','m','a','l','l', 0, + 'e','x','c','l','a','m','d','o','w','n','s','m','a','l','l', 0, + 'c','e','n','t','o','l','d','s','t','y','l','e', 0, + 'L','s','l','a','s','h','s','m','a','l','l', 0, + 'S','c','a','r','o','n','s','m','a','l','l', 0, + 'Z','c','a','r','o','n','s','m','a','l','l', 0, + 'D','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'B','r','e','v','e','s','m','a','l','l', 0, + 'C','a','r','o','n','s','m','a','l','l', 0, + 'D','o','t','a','c','c','e','n','t','s','m','a','l','l', 0, + 'M','a','c','r','o','n','s','m','a','l','l', 0, + 'f','i','g','u','r','e','d','a','s','h', 0, + 'h','y','p','h','e','n','i','n','f','e','r','i','o','r', 0, + 'O','g','o','n','e','k','s','m','a','l','l', 0, + 'R','i','n','g','s','m','a','l','l', 0, + 'C','e','d','i','l','l','a','s','m','a','l','l', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n','s','m','a','l','l', 0, + 'o','n','e','e','i','g','h','t','h', 0, + 't','h','r','e','e','e','i','g','h','t','h','s', 0, + 'f','i','v','e','e','i','g','h','t','h','s', 0, + 's','e','v','e','n','e','i','g','h','t','h','s', 0, + 'o','n','e','t','h','i','r','d', 0, + 't','w','o','t','h','i','r','d','s', 0, + 'z','e','r','o','s','u','p','e','r','i','o','r', 0, + 'f','o','u','r','s','u','p','e','r','i','o','r', 0, + 'f','i','v','e','s','u','p','e','r','i','o','r', 0, + 's','i','x','s','u','p','e','r','i','o','r', 0, + 's','e','v','e','n','s','u','p','e','r','i','o','r', 0, + 'e','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 'n','i','n','e','s','u','p','e','r','i','o','r', 0, + 'z','e','r','o','i','n','f','e','r','i','o','r', 0, + 'o','n','e','i','n','f','e','r','i','o','r', 0, + 't','w','o','i','n','f','e','r','i','o','r', 0, + 't','h','r','e','e','i','n','f','e','r','i','o','r', 0, + 'f','o','u','r','i','n','f','e','r','i','o','r', 0, + 'f','i','v','e','i','n','f','e','r','i','o','r', 0, + 's','i','x','i','n','f','e','r','i','o','r', 0, + 's','e','v','e','n','i','n','f','e','r','i','o','r', 0, + 'e','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'n','i','n','e','i','n','f','e','r','i','o','r', 0, + 'c','e','n','t','i','n','f','e','r','i','o','r', 0, + 'd','o','l','l','a','r','i','n','f','e','r','i','o','r', 0, + 'p','e','r','i','o','d','i','n','f','e','r','i','o','r', 0, + 'c','o','m','m','a','i','n','f','e','r','i','o','r', 0, + 'A','g','r','a','v','e','s','m','a','l','l', 0, + 'A','a','c','u','t','e','s','m','a','l','l', 0, + 'A','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'A','t','i','l','d','e','s','m','a','l','l', 0, + 'A','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'A','r','i','n','g','s','m','a','l','l', 0, + 'A','E','s','m','a','l','l', 0, + 'C','c','e','d','i','l','l','a','s','m','a','l','l', 0, + 'E','g','r','a','v','e','s','m','a','l','l', 0, + 'E','a','c','u','t','e','s','m','a','l','l', 0, + 'E','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'E','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'I','g','r','a','v','e','s','m','a','l','l', 0, + 'I','a','c','u','t','e','s','m','a','l','l', 0, + 'I','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'I','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'E','t','h','s','m','a','l','l', 0, + 'N','t','i','l','d','e','s','m','a','l','l', 0, + 'O','g','r','a','v','e','s','m','a','l','l', 0, + 'O','a','c','u','t','e','s','m','a','l','l', 0, + 'O','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'O','t','i','l','d','e','s','m','a','l','l', 0, + 'O','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'O','E','s','m','a','l','l', 0, + 'O','s','l','a','s','h','s','m','a','l','l', 0, + 'U','g','r','a','v','e','s','m','a','l','l', 0, + 'U','a','c','u','t','e','s','m','a','l','l', 0, + 'U','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'U','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'Y','a','c','u','t','e','s','m','a','l','l', 0, + 'T','h','o','r','n','s','m','a','l','l', 0, + 'Y','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + '0','0','1','.','0','0','0', 0, + '0','0','1','.','0','0','1', 0, + '0','0','1','.','0','0','2', 0, + '0','0','1','.','0','0','3', 0, + 'B','l','a','c','k', 0, + 'B','o','l','d', 0, + 'B','o','o','k', 0, + 'L','i','g','h','t', 0, + 'M','e','d','i','u','m', 0, + 'R','e','g','u','l','a','r', 0, + 'R','o','m','a','n', 0, + 'S','e','m','i','b','o','l','d', 0, + }; + + +#define FT_NUM_MAC_NAMES 258 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + + static const short ft_mac_names[FT_NUM_MAC_NAMES] = + { + 253, 0, 6, 261, 267, 274, 283, 294, 301, 309, 758, 330, 340, 351, + 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, + 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, + 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, + 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 979, 608, 610, + 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, + 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, + 1375,1392,1405,1414,1486,1512,1562,1603,1632,1610,1622,1645,1639,1652, + 1661,1690,1668,1680,1697,1726,1704,1716,1733,1740,1769,1747,1759,1776, + 1790,1819,1797,1809, 839,1263, 707, 712, 741, 881, 871,1160,1302,1346, + 1197, 985,1031, 23,1086,1108, 32,1219, 41, 51, 730,1194, 64, 76, + 86, 94, 97,1089,1118, 106,1131,1150, 966, 696,1183, 112, 734, 120, + 132, 783, 930, 945, 138,1385,1398,1529,1115,1157, 832,1079, 770, 916, + 598, 319,1246, 155,1833,1586, 721, 749, 797, 811, 826, 829, 846, 856, + 888, 903, 954,1363,1421,1356,1433,1443,1450,1457,1469,1479,1493,1500, + 163,1522,1543,1550,1572,1134, 991,1002,1008,1015,1021,1040,1045,1053, + 1066,1073,1101,1143,1536,1783,1596,1843,1253,1207,1319,1579,1826,1229, + 1270,1313,1323,1171,1290,1332,1211,1235,1276, 169, 175, 182, 189, 200, + 209, 218, 225, 232, 239, 246 + }; + + +#define FT_NUM_SID_NAMES 391 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + + static const short ft_sid_names[FT_NUM_SID_NAMES] = + { + 253, 261, 267, 274, 283, 294, 301, 309, 319, 330, 340, 351, 360, 365, + 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, + 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, + 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, + 532, 534, 536, 538, 540, 552, 562, 575, 587, 598, 608, 610, 612, 614, + 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, + 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 696, 707, + 712, 721, 730, 734, 741, 749, 758, 770, 783, 797, 811, 826, 829, 832, + 839, 846, 856, 871, 881, 888, 903, 916, 930, 945, 954, 966, 979, 985, + 991,1002,1008,1015,1021,1031,1040,1045,1053,1066,1073,1079,1086,1089, + 1101,1108,1115,1118,1131,1134,1143,1150,1157,1160,1171,1183,1194,1197, + 1207,1211,1219,1229,1235,1246,1253,1263,1270,1276,1290,1302,1313,1319, + 1323,1332,1346,1356,1363,1375,1385,1392,1398,1405,1414,1421,1433,1443, + 1450,1457,1469,1479,1486,1493,1500,1512,1522,1529,1536,1543,1550,1562, + 1572,1579,1586,1596,1603,1610,1622,1632,1639,1645,1652,1661,1668,1680, + 1690,1697,1704,1716,1726,1733,1740,1747,1759,1769,1776,1783,1790,1797, + 1809,1819,1826,1833,1843,1850,1862,1880,1895,1910,1925,1936,1954,1973, + 1988,2003,2016,2028,2040,2054,2067,2080,2092,2106,2120,2133,2147,2167, + 2182,2196,2206,2216,2229,2239,2249,2259,2269,2279,2289,2299,2309,2319, + 2329,2332,2336,2340,2358,2377,2393,2408,2419,2426,2433,2440,2447,2454, + 2461,2468,2475,2482,2489,2496,2503,2510,2517,2524,2531,2538,2545,2552, + 2559,2566,2573,2580,2587,2594,2601,2615,2625,2632,2643,2659,2672,2684, + 2696,2708,2722,2733,2744,2759,2771,2782,2797,2809,2819,2832,2850,2860, + 2873,2885,2898,2907,2917,2930,2943,2956,2968,2982,2996,3009,3022,3034, + 3046,3060,3073,3086,3098,3112,3126,3139,3152,3167,3182,3196,3208,3220, + 3237,3249,3264,3275,3283,3297,3309,3321,3338,3353,3365,3377,3394,3409, + 3418,3430,3442,3454,3471,3483,3498,3506,3518,3530,3542,3559,3574,3586, + 3597,3612,3620,3628,3636,3644,3650,3655,3660,3666,3673,3681,3687 + }; + + + /* the following are indices into the SID name table */ + static const unsigned short t1_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110, + 0,111,112,113,114, 0,115,116,117,118,119,120,121,122, 0,123, + 0,124,125,126,127,128,129,130,131, 0,132,133, 0,134,135,136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,138, 0,139, 0, 0, 0, 0,140,141,142,143, 0, 0, 0, 0, + 0,144, 0, 0, 0,145, 0, 0,146,147,148,149, 0, 0, 0, 0 + }; + + + /* the following are indices into the SID name table */ + static const unsigned short t1_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1,229,230, 0,231,232,233,234,235,236,237,238, 13, 14, 15, 99, + 239,240,241,242,243,244,245,246,247,248, 27, 28,249,250,251,252, + 0,253,254,255,256,257, 0, 0, 0,258, 0, 0,259,260,261,262, + 0, 0,263,264,265, 0,266,109,110,267,268,269, 0,270,271,272, + 273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, + 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,304,305,306, 0, 0,307,308,309,310,311, 0,312, 0, 0,313, + 0, 0,314,315, 0, 0,316,317,318, 0, 0, 0,158,155,163,319, + 320,321,322,323,324,325, 0, 0,326,150,164,169,327,328,329,330, + 331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346, + 347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362, + 363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378 + }; + + + /* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + static const unsigned char ft_adobe_glyph_list[54791] = + { + 0, 52, 0,106, 2,167, 3, 63, 4,220, 6,125, 9,143, 10, 23, + 11,137, 12,199, 14,246, 15, 87, 16,233, 17,219, 18,104, 19, 88, + 22,110, 23, 32, 23, 71, 24, 77, 27,156, 29, 73, 31,247, 32,107, + 32,222, 33, 55, 34,154, 35,218, 53, 84, 59,196, 68, 6, 75,183, + 83,178, 88,135, 93,242,101,165,109,185,111, 55,117,254,123, 73, + 130,238,138,206,145, 31,153,182,156,189,163,249,178,221,193, 17, + 197, 99,199,240,204, 27,204,155,210,100, 65,143, 0, 65, 0,140, + 0,175, 0,193, 1, 15, 1,147, 1,233, 1,251, 2, 7, 2, 40, + 2, 57, 2, 82, 2, 91, 2,128, 2,136, 2,154, 69,131, 0,198, + 0,150, 0,158, 0,167,225,227,245,244,101,128, 1,252,237,225, + 227,242,239,110,128, 1,226,243,237,225,236,108,128,247,230,225, + 227,245,244,101,129, 0,193, 0,185,243,237,225,236,108,128,247, + 225,226,242,229,246,101,134, 1, 2, 0,213, 0,221, 0,232, 0, + 243, 0,251, 1, 7,225,227,245,244,101,128, 30,174,227,249,242, + 233,236,236,233, 99,128, 4,208,228,239,244,226,229,236,239,119, + 128, 30,182,231,242,225,246,101,128, 30,176,232,239,239,235,225, + 226,239,246,101,128, 30,178,244,233,236,228,101,128, 30,180, 99, + 4, 1, 25, 1, 32, 1,121, 1,137,225,242,239,110,128, 1,205, + 233,242, 99, 2, 1, 40, 1, 45,236,101,128, 36,182,245,237,230, + 236,229,120,134, 0,194, 1, 66, 1, 74, 1, 85, 1, 93, 1,105, + 1,113,225,227,245,244,101,128, 30,164,228,239,244,226,229,236, + 239,119,128, 30,172,231,242,225,246,101,128, 30,166,232,239,239, + 235,225,226,239,246,101,128, 30,168,243,237,225,236,108,128,247, + 226,244,233,236,228,101,128, 30,170,245,244,101,129,246,201, 1, + 129,243,237,225,236,108,128,247,180,249,242,233,236,236,233, 99, + 128, 4, 16,100, 3, 1,155, 1,165, 1,209,226,236,231,242,225, + 246,101,128, 2, 0,233,229,242,229,243,233,115,131, 0,196, 1, + 181, 1,192, 1,201,227,249,242,233,236,236,233, 99,128, 4,210, + 237,225,227,242,239,110,128, 1,222,243,237,225,236,108,128,247, + 228,239,116, 2, 1,216, 1,224,226,229,236,239,119,128, 30,160, + 237,225,227,242,239,110,128, 1,224,231,242,225,246,101,129, 0, + 192, 1,243,243,237,225,236,108,128,247,224,232,239,239,235,225, + 226,239,246,101,128, 30,162,105, 2, 2, 13, 2, 25,229,227,249, + 242,233,236,236,233, 99,128, 4,212,238,246,229,242,244,229,228, + 226,242,229,246,101,128, 2, 2,236,240,232, 97,129, 3,145, 2, + 49,244,239,238,239,115,128, 3,134,109, 2, 2, 63, 2, 71,225, + 227,242,239,110,128, 1, 0,239,238,239,243,240,225,227,101,128, + 255, 33,239,231,239,238,229,107,128, 1, 4,242,233,238,103,131, + 0,197, 2,104, 2,112, 2,120,225,227,245,244,101,128, 1,250, + 226,229,236,239,119,128, 30, 0,243,237,225,236,108,128,247,229, + 243,237,225,236,108,128,247, 97,244,233,236,228,101,129, 0,195, + 2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229, + 238,233,225,110,128, 5, 49, 66,137, 0, 66, 2,189, 2,198, 2, + 223, 3, 3, 3, 10, 3, 22, 3, 34, 3, 46, 3, 54,227,233,242, + 227,236,101,128, 36,183,228,239,116, 2, 2,206, 2,215,225,227, + 227,229,238,116,128, 30, 2,226,229,236,239,119,128, 30, 4,101, + 3, 2,231, 2,242, 2,254,227,249,242,233,236,236,233, 99,128, + 4, 17,238,225,242,237,229,238,233,225,110,128, 5, 50,244, 97, + 128, 3,146,232,239,239,107,128, 1,129,236,233,238,229,226,229, + 236,239,119,128, 30, 6,237,239,238,239,243,240,225,227,101,128, + 255, 34,242,229,246,229,243,237,225,236,108,128,246,244,243,237, + 225,236,108,128,247, 98,244,239,240,226,225,114,128, 1,130, 67, + 137, 0, 67, 3, 85, 3,127, 3,193, 3,210, 3,224, 4,171, 4, + 188, 4,200, 4,212, 97, 3, 3, 93, 3,104, 3,111,225,242,237, + 229,238,233,225,110,128, 5, 62,227,245,244,101,128, 1, 6,242, + 239,110,129,246,202, 3,119,243,237,225,236,108,128,246,245, 99, + 3, 3,135, 3,142, 3,171,225,242,239,110,128, 1, 12,229,228, + 233,236,236, 97,130, 0,199, 3,155, 3,163,225,227,245,244,101, + 128, 30, 8,243,237,225,236,108,128,247,231,233,242, 99, 2, 3, + 179, 3,184,236,101,128, 36,184,245,237,230,236,229,120,128, 1, + 8,228,239,116,129, 1, 10, 3,201,225,227,227,229,238,116,128, + 1, 10,229,228,233,236,236,225,243,237,225,236,108,128,247,184, + 104, 4, 3,234, 3,246, 4,161, 4,165,225,225,242,237,229,238, + 233,225,110,128, 5, 73,101, 6, 4, 4, 4, 24, 4, 35, 4,103, + 4,115, 4,136,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,188,227,249,242,233,236,236,233, 99, + 128, 4, 39,100, 2, 4, 41, 4, 85,229,243,227,229,238,228,229, + 114, 2, 4, 54, 4, 74,225,226,235,232,225,243,233,225,238,227, + 249,242,233,236,236,233, 99,128, 4,190,227,249,242,233,236,236, + 233, 99,128, 4,182,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,244,232,225,242,237,229,238,233,225,110, + 128, 5, 67,235,232,225,235,225,243,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,203,246,229,242,244,233,227,225,236, + 243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4, + 184,105,128, 3,167,239,239,107,128, 1,135,233,242,227,245,237, + 230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239, + 243,240,225,227,101,128,255, 35,239,225,242,237,229,238,233,225, + 110,128, 5, 81,243,237,225,236,108,128,247, 99, 68,142, 0, 68, + 4,252, 5, 10, 5, 36, 5, 96, 5,121, 5,166, 5,173, 5,231, + 5,244, 6, 0, 6, 12, 6, 28, 6, 48, 6, 57, 90,129, 1,241, + 5, 2,227,225,242,239,110,128, 1,196, 97, 2, 5, 16, 5, 27, + 225,242,237,229,238,233,225,110,128, 5, 52,230,242,233,227,225, + 110,128, 1,137, 99, 4, 5, 46, 5, 53, 5, 62, 5, 89,225,242, + 239,110,128, 1, 14,229,228,233,236,236, 97,128, 30, 16,233,242, + 99, 2, 5, 70, 5, 75,236,101,128, 36,185,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 18,242,239,225,116,128, 1, 16, + 228,239,116, 2, 5,104, 5,113,225,227,227,229,238,116,128, 30, + 10,226,229,236,239,119,128, 30, 12,101, 3, 5,129, 5,140, 5, + 150,227,249,242,233,236,236,233, 99,128, 4, 20,233,227,239,240, + 244,233, 99,128, 3,238,236,244, 97,129, 34, 6, 5,158,231,242, + 229,229,107,128, 3,148,232,239,239,107,128, 1,138,105, 2, 5, + 179, 5,218,229,242,229,243,233,115,131,246,203, 5,194, 5,202, + 5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128, + 246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231, + 242,229,229,107,128, 3,220,234,229,227,249,242,233,236,236,233, + 99,128, 4, 2,236,233,238,229,226,229,236,239,119,128, 30, 14, + 237,239,238,239,243,240,225,227,101,128,255, 36,239,244,225,227, + 227,229,238,244,243,237,225,236,108,128,246,247,115, 2, 6, 34, + 6, 41,236,225,243,104,128, 1, 16,237,225,236,108,128,247,100, + 244,239,240,226,225,114,128, 1,139,122,131, 1,242, 6, 67, 6, + 75, 6,112,227,225,242,239,110,128, 1,197,101, 2, 6, 81, 6, + 101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,224,227,249,242,233,236,236,233, 99,128, 4, 5, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 15, 69,146, 0, + 69, 6,165, 6,183, 6,191, 7, 89, 7,153, 7,165, 7,183, 7, + 211, 8, 7, 8, 36, 8, 94, 8,169, 8,189, 8,208, 8,248, 9, + 44, 9,109, 9,115,225,227,245,244,101,129, 0,201, 6,175,243, + 237,225,236,108,128,247,233,226,242,229,246,101,128, 1, 20, 99, + 5, 6,203, 6,210, 6,224, 6,236, 7, 79,225,242,239,110,128, + 1, 26,229,228,233,236,236,225,226,242,229,246,101,128, 30, 28, + 232,225,242,237,229,238,233,225,110,128, 5, 53,233,242, 99, 2, + 6,244, 6,249,236,101,128, 36,186,245,237,230,236,229,120,135, + 0,202, 7, 16, 7, 24, 7, 32, 7, 43, 7, 51, 7, 63, 7, 71, + 225,227,245,244,101,128, 30,190,226,229,236,239,119,128, 30, 24, + 228,239,244,226,229,236,239,119,128, 30,198,231,242,225,246,101, + 128, 30,192,232,239,239,235,225,226,239,246,101,128, 30,194,243, + 237,225,236,108,128,247,234,244,233,236,228,101,128, 30,196,249, + 242,233,236,236,233, 99,128, 4, 4,100, 3, 7, 97, 7,107, 7, + 127,226,236,231,242,225,246,101,128, 2, 4,233,229,242,229,243, + 233,115,129, 0,203, 7,119,243,237,225,236,108,128,247,235,239, + 116,130, 1, 22, 7,136, 7,145,225,227,227,229,238,116,128, 1, + 22,226,229,236,239,119,128, 30,184,230,227,249,242,233,236,236, + 233, 99,128, 4, 36,231,242,225,246,101,129, 0,200, 7,175,243, + 237,225,236,108,128,247,232,104, 2, 7,189, 7,200,225,242,237, + 229,238,233,225,110,128, 5, 55,239,239,235,225,226,239,246,101, + 128, 30,186,105, 3, 7,219, 7,230, 7,245,231,232,244,242,239, + 237,225,110,128, 33,103,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 6,239,244,233,230,233,229,228,227,249,242,233, + 236,236,233, 99,128, 4,100,108, 2, 8, 13, 8, 24,227,249,242, + 233,236,236,233, 99,128, 4, 27,229,246,229,238,242,239,237,225, + 110,128, 33,106,109, 3, 8, 44, 8, 72, 8, 83,225,227,242,239, + 110,130, 1, 18, 8, 56, 8, 64,225,227,245,244,101,128, 30, 22, + 231,242,225,246,101,128, 30, 20,227,249,242,233,236,236,233, 99, + 128, 4, 28,239,238,239,243,240,225,227,101,128,255, 37,110, 4, + 8,104, 8,115, 8,135, 8,154,227,249,242,233,236,236,233, 99, + 128, 4, 29,228,229,243,227,229,238,228,229,242,227,249,242,233, + 236,236,233, 99,128, 4,162,103,129, 1, 74, 8,141,232,229,227, + 249,242,233,236,236,233, 99,128, 4,164,232,239,239,235,227,249, + 242,233,236,236,233, 99,128, 4,199,111, 2, 8,175, 8,183,231, + 239,238,229,107,128, 1, 24,240,229,110,128, 1,144,240,243,233, + 236,239,110,129, 3,149, 8,200,244,239,238,239,115,128, 3,136, + 114, 2, 8,214, 8,225,227,249,242,233,236,236,233, 99,128, 4, + 32,229,246,229,242,243,229,100,129, 1,142, 8,237,227,249,242, + 233,236,236,233, 99,128, 4, 45,115, 4, 9, 2, 9, 13, 9, 33, + 9, 37,227,249,242,233,236,236,233, 99,128, 4, 33,228,229,243, + 227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4, + 170,104,128, 1,169,237,225,236,108,128,247,101,116, 3, 9, 52, + 9, 78, 9, 92, 97,130, 3,151, 9, 60, 9, 70,242,237,229,238, + 233,225,110,128, 5, 56,244,239,238,239,115,128, 3,137,104,129, + 0,208, 9, 84,243,237,225,236,108,128,247,240,233,236,228,101, + 129, 30,188, 9,101,226,229,236,239,119,128, 30, 26,245,242,111, + 128, 32,172,250,104,130, 1,183, 9,124, 9,132,227,225,242,239, + 110,128, 1,238,242,229,246,229,242,243,229,100,128, 1,184, 70, + 136, 0, 70, 9,163, 9,172, 9,184, 9,212, 9,219, 9,248, 10, + 4, 10, 15,227,233,242,227,236,101,128, 36,187,228,239,244,225, + 227,227,229,238,116,128, 30, 30,101, 2, 9,190, 9,202,232,225, + 242,237,229,238,233,225,110,128, 5, 86,233,227,239,240,244,233, + 99,128, 3,228,232,239,239,107,128, 1,145,105, 2, 9,225, 9, + 238,244,225,227,249,242,233,236,236,233, 99,128, 4,114,246,229, + 242,239,237,225,110,128, 33,100,237,239,238,239,243,240,225,227, + 101,128,255, 38,239,245,242,242,239,237,225,110,128, 33, 99,243, + 237,225,236,108,128,247,102, 71,140, 0, 71, 10, 51, 10, 61, 10, + 107, 10,115, 10,176, 10,193, 10,205, 11, 39, 11, 52, 11, 65, 11, + 90, 11,107,194,243,241,245,225,242,101,128, 51,135, 97, 3, 10, + 69, 10, 76, 10, 94,227,245,244,101,128, 1,244,237,237, 97,129, + 3,147, 10, 84,225,230,242,233,227,225,110,128, 1,148,238,231, + 233,225,227,239,240,244,233, 99,128, 3,234,226,242,229,246,101, + 128, 1, 30, 99, 4, 10,125, 10,132, 10,141, 10,163,225,242,239, + 110,128, 1,230,229,228,233,236,236, 97,128, 1, 34,233,242, 99, + 2, 10,149, 10,154,236,101,128, 36,188,245,237,230,236,229,120, + 128, 1, 28,239,237,237,225,225,227,227,229,238,116,128, 1, 34, + 228,239,116,129, 1, 32, 10,184,225,227,227,229,238,116,128, 1, + 32,229,227,249,242,233,236,236,233, 99,128, 4, 19,104, 3, 10, + 213, 10,226, 11, 33,225,228,225,242,237,229,238,233,225,110,128, + 5, 66,101, 3, 10,234, 10,255, 11, 16,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,148,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,146, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 144,239,239,107,128, 1,147,233,237,225,242,237,229,238,233,225, + 110,128, 5, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, + 3,109, 2, 11, 71, 11, 79,225,227,242,239,110,128, 30, 32,239, + 238,239,243,240,225,227,101,128,255, 39,242,225,246,101,129,246, + 206, 11, 99,243,237,225,236,108,128,247, 96,115, 2, 11,113, 11, + 129,237,225,236,108,129,247,103, 11,122,232,239,239,107,128, 2, + 155,244,242,239,235,101,128, 1,228, 72,140, 0, 72, 11,165, 11, + 190, 11,198, 11,208, 12, 17, 12, 40, 12, 77, 12,117, 12,129, 12, + 157, 12,165, 12,189,177,184, 53, 3, 11,175, 11,180, 11,185,179, + 51,128, 37,207,180, 51,128, 37,170,181, 49,128, 37,171,178,178, + 176,183, 51,128, 37,161,208,243,241,245,225,242,101,128, 51,203, + 97, 3, 11,216, 11,236, 12, 0,225,226,235,232,225,243,233,225, + 238,227,249,242,233,236,236,233, 99,128, 4,168,228,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,178, + 242,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, + 42, 98, 2, 12, 23, 12, 28,225,114,128, 1, 38,242,229,246,229, + 226,229,236,239,119,128, 30, 42, 99, 2, 12, 46, 12, 55,229,228, + 233,236,236, 97,128, 30, 40,233,242, 99, 2, 12, 63, 12, 68,236, + 101,128, 36,189,245,237,230,236,229,120,128, 1, 36,100, 2, 12, + 83, 12, 93,233,229,242,229,243,233,115,128, 30, 38,239,116, 2, + 12,100, 12,109,225,227,227,229,238,116,128, 30, 34,226,229,236, + 239,119,128, 30, 36,237,239,238,239,243,240,225,227,101,128,255, + 40,111, 2, 12,135, 12,146,225,242,237,229,238,233,225,110,128, + 5, 64,242,233,227,239,240,244,233, 99,128, 3,232,243,237,225, + 236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116, + 129,246,207, 12,181,243,237,225,236,108,128,246,248,250,243,241, + 245,225,242,101,128, 51,144, 73,146, 0, 73, 12,239, 12,251, 12, + 255, 13, 11, 13, 29, 13, 37, 13, 94, 13,181, 13,214, 13,224, 13, + 242, 13,254, 14, 48, 14, 86, 14, 99, 14,166, 14,187, 14,205,193, + 227,249,242,233,236,236,233, 99,128, 4, 47, 74,128, 1, 50,213, + 227,249,242,233,236,236,233, 99,128, 4, 46,225,227,245,244,101, + 129, 0,205, 13, 21,243,237,225,236,108,128,247,237,226,242,229, + 246,101,128, 1, 44, 99, 3, 13, 45, 13, 52, 13, 84,225,242,239, + 110,128, 1,207,233,242, 99, 2, 13, 60, 13, 65,236,101,128, 36, + 190,245,237,230,236,229,120,129, 0,206, 13, 76,243,237,225,236, + 108,128,247,238,249,242,233,236,236,233, 99,128, 4, 6,100, 3, + 13,102, 13,112, 13,155,226,236,231,242,225,246,101,128, 2, 8, + 233,229,242,229,243,233,115,131, 0,207, 13,128, 13,136, 13,147, + 225,227,245,244,101,128, 30, 46,227,249,242,233,236,236,233, 99, + 128, 4,228,243,237,225,236,108,128,247,239,239,116,130, 1, 48, + 13,164, 13,173,225,227,227,229,238,116,128, 1, 48,226,229,236, + 239,119,128, 30,202,101, 2, 13,187, 13,203,226,242,229,246,229, + 227,249,242,233,236,236,233, 99,128, 4,214,227,249,242,233,236, + 236,233, 99,128, 4, 21,230,242,225,235,244,245,114,128, 33, 17, + 231,242,225,246,101,129, 0,204, 13,234,243,237,225,236,108,128, + 247,236,232,239,239,235,225,226,239,246,101,128, 30,200,105, 3, + 14, 6, 14, 17, 14, 32,227,249,242,233,236,236,233, 99,128, 4, + 24,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 10, + 243,232,239,242,244,227,249,242,233,236,236,233, 99,128, 4, 25, + 109, 2, 14, 54, 14, 75,225,227,242,239,110,129, 1, 42, 14, 64, + 227,249,242,233,236,236,233, 99,128, 4,226,239,238,239,243,240, + 225,227,101,128,255, 41,238,233,225,242,237,229,238,233,225,110, + 128, 5, 59,111, 3, 14,107, 14,118, 14,126,227,249,242,233,236, + 236,233, 99,128, 4, 1,231,239,238,229,107,128, 1, 46,244, 97, + 131, 3,153, 14,137, 14,147, 14,158,225,230,242,233,227,225,110, + 128, 1,150,228,233,229,242,229,243,233,115,128, 3,170,244,239, + 238,239,115,128, 3,138,115, 2, 14,172, 14,179,237,225,236,108, + 128,247,105,244,242,239,235,101,128, 1,151,244,233,236,228,101, + 129, 1, 40, 14,197,226,229,236,239,119,128, 30, 44,250,232,233, + 244,243, 97, 2, 14,216, 14,227,227,249,242,233,236,236,233, 99, + 128, 4,116,228,226,236,231,242,225,246,229,227,249,242,233,236, + 236,233, 99,128, 4,118, 74,134, 0, 74, 15, 6, 15, 18, 15, 41, + 15, 53, 15, 67, 15, 79,225,225,242,237,229,238,233,225,110,128, + 5, 65,227,233,242, 99, 2, 15, 27, 15, 32,236,101,128, 36,191, + 245,237,230,236,229,120,128, 1, 52,229,227,249,242,233,236,236, + 233, 99,128, 4, 8,232,229,232,225,242,237,229,238,233,225,110, + 128, 5, 75,237,239,238,239,243,240,225,227,101,128,255, 42,243, + 237,225,236,108,128,247,106, 75,140, 0, 75, 15,115, 15,125, 15, + 135, 16, 18, 16, 65, 16, 76, 16,106, 16,143, 16,156, 16,168, 16, + 180, 16,208,194,243,241,245,225,242,101,128, 51,133,203,243,241, + 245,225,242,101,128, 51,205, 97, 7, 15,151, 15,169, 15,191, 15, + 211, 15,226, 15,232, 15,249,226,225,243,232,235,233,242,227,249, + 242,233,236,236,233, 99,128, 4,160, 99, 2, 15,175, 15,181,245, + 244,101,128, 30, 48,249,242,233,236,236,233, 99,128, 4, 26,228, + 229,243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99, + 128, 4,154,232,239,239,235,227,249,242,233,236,236,233, 99,128, + 4,195,240,240, 97,128, 3,154,243,244,242,239,235,229,227,249, + 242,233,236,236,233, 99,128, 4,158,246,229,242,244,233,227,225, + 236,243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, + 4,156, 99, 4, 16, 28, 16, 35, 16, 44, 16, 52,225,242,239,110, + 128, 1,232,229,228,233,236,236, 97,128, 1, 54,233,242,227,236, + 101,128, 36,192,239,237,237,225,225,227,227,229,238,116,128, 1, + 54,228,239,244,226,229,236,239,119,128, 30, 50,101, 2, 16, 82, + 16, 94,232,225,242,237,229,238,233,225,110,128, 5, 84,238,225, + 242,237,229,238,233,225,110,128, 5, 63,104, 3, 16,114, 16,126, + 16,137,225,227,249,242,233,236,236,233, 99,128, 4, 37,229,233, + 227,239,240,244,233, 99,128, 3,230,239,239,107,128, 1,152,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 12,236,233,238,229, + 226,229,236,239,119,128, 30, 52,237,239,238,239,243,240,225,227, + 101,128,255, 43,239,240,240, 97, 2, 16,189, 16,200,227,249,242, + 233,236,236,233, 99,128, 4,128,231,242,229,229,107,128, 3,222, + 115, 2, 16,214, 16,226,233,227,249,242,233,236,236,233, 99,128, + 4,110,237,225,236,108,128,247,107, 76,138, 0, 76, 17, 1, 17, + 5, 17, 9, 17, 29, 17, 95, 17,133, 17,147, 17,165, 17,177, 17, + 189, 74,128, 1,199, 76,128,246,191, 97, 2, 17, 15, 17, 22,227, + 245,244,101,128, 1, 57,237,226,228, 97,128, 3,155, 99, 4, 17, + 39, 17, 46, 17, 55, 17, 82,225,242,239,110,128, 1, 61,229,228, + 233,236,236, 97,128, 1, 59,233,242, 99, 2, 17, 63, 17, 68,236, + 101,128, 36,193,245,237,230,236,229,248,226,229,236,239,119,128, + 30, 60,239,237,237,225,225,227,227,229,238,116,128, 1, 59,228, + 239,116,130, 1, 63, 17,105, 17,114,225,227,227,229,238,116,128, + 1, 63,226,229,236,239,119,129, 30, 54, 17,124,237,225,227,242, + 239,110,128, 30, 56,233,247,238,225,242,237,229,238,233,225,110, + 128, 5, 60,106,129, 1,200, 17,153,229,227,249,242,233,236,236, + 233, 99,128, 4, 9,236,233,238,229,226,229,236,239,119,128, 30, + 58,237,239,238,239,243,240,225,227,101,128,255, 44,115, 2, 17, + 195, 17,212,236,225,243,104,129, 1, 65, 17,204,243,237,225,236, + 108,128,246,249,237,225,236,108,128,247,108, 77,137, 0, 77, 17, + 241, 17,251, 18, 24, 18, 33, 18, 58, 18, 71, 18, 83, 18, 91, 18, + 100,194,243,241,245,225,242,101,128, 51,134,225, 99, 2, 18, 2, + 18, 18,242,239,110,129,246,208, 18, 10,243,237,225,236,108,128, + 247,175,245,244,101,128, 30, 62,227,233,242,227,236,101,128, 36, + 194,228,239,116, 2, 18, 41, 18, 50,225,227,227,229,238,116,128, + 30, 64,226,229,236,239,119,128, 30, 66,229,238,225,242,237,229, + 238,233,225,110,128, 5, 68,237,239,238,239,243,240,225,227,101, + 128,255, 45,243,237,225,236,108,128,247,109,244,245,242,238,229, + 100,128, 1,156,117,128, 3,156, 78,141, 0, 78, 18,134, 18,138, + 18,146, 18,212, 18,237, 18,248, 19, 3, 19, 21, 19, 33, 19, 45, + 19, 58, 19, 66, 19, 84, 74,128, 1,202,225,227,245,244,101,128, + 1, 67, 99, 4, 18,156, 18,163, 18,172, 18,199,225,242,239,110, + 128, 1, 71,229,228,233,236,236, 97,128, 1, 69,233,242, 99, 2, + 18,180, 18,185,236,101,128, 36,195,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 74,239,237,237,225,225,227,227,229,238, + 116,128, 1, 69,228,239,116, 2, 18,220, 18,229,225,227,227,229, + 238,116,128, 30, 68,226,229,236,239,119,128, 30, 70,232,239,239, + 235,236,229,230,116,128, 1,157,233,238,229,242,239,237,225,110, + 128, 33,104,106,129, 1,203, 19, 9,229,227,249,242,233,236,236, + 233, 99,128, 4, 10,236,233,238,229,226,229,236,239,119,128, 30, + 72,237,239,238,239,243,240,225,227,101,128,255, 46,239,247,225, + 242,237,229,238,233,225,110,128, 5, 70,243,237,225,236,108,128, + 247,110,244,233,236,228,101,129, 0,209, 19, 76,243,237,225,236, + 108,128,247,241,117,128, 3,157, 79,141, 0, 79, 19,118, 19,132, + 19,150, 19,203, 20, 78, 20,152, 20,187, 21, 48, 21, 69, 21,213, + 21,223, 21,254, 22, 53, 69,129, 1, 82, 19,124,243,237,225,236, + 108,128,246,250,225,227,245,244,101,129, 0,211, 19,142,243,237, + 225,236,108,128,247,243, 98, 2, 19,156, 19,196,225,242,242,229, + 100, 2, 19,166, 19,177,227,249,242,233,236,236,233, 99,128, 4, + 232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,234,242,229,246,101,128, 1, 78, 99, 4, 19,213, 19, + 220, 19,235, 20, 68,225,242,239,110,128, 1,209,229,238,244,229, + 242,229,228,244,233,236,228,101,128, 1,159,233,242, 99, 2, 19, + 243, 19,248,236,101,128, 36,196,245,237,230,236,229,120,134, 0, + 212, 20, 13, 20, 21, 20, 32, 20, 40, 20, 52, 20, 60,225,227,245, + 244,101,128, 30,208,228,239,244,226,229,236,239,119,128, 30,216, + 231,242,225,246,101,128, 30,210,232,239,239,235,225,226,239,246, + 101,128, 30,212,243,237,225,236,108,128,247,244,244,233,236,228, + 101,128, 30,214,249,242,233,236,236,233, 99,128, 4, 30,100, 3, + 20, 86, 20,109, 20,142,226,108, 2, 20, 93, 20,101,225,227,245, + 244,101,128, 1, 80,231,242,225,246,101,128, 2, 12,233,229,242, + 229,243,233,115,130, 0,214, 20,123, 20,134,227,249,242,233,236, + 236,233, 99,128, 4,230,243,237,225,236,108,128,247,246,239,244, + 226,229,236,239,119,128, 30,204,103, 2, 20,158, 20,170,239,238, + 229,235,243,237,225,236,108,128,246,251,242,225,246,101,129, 0, + 210, 20,179,243,237,225,236,108,128,247,242,104, 4, 20,197, 20, + 208, 20,212, 21, 34,225,242,237,229,238,233,225,110,128, 5, 85, + 109,128, 33, 38,111, 2, 20,218, 20,228,239,235,225,226,239,246, + 101,128, 30,206,242,110,133, 1,160, 20,243, 20,251, 21, 6, 21, + 14, 21, 26,225,227,245,244,101,128, 30,218,228,239,244,226,229, + 236,239,119,128, 30,226,231,242,225,246,101,128, 30,220,232,239, + 239,235,225,226,239,246,101,128, 30,222,244,233,236,228,101,128, + 30,224,245,238,231,225,242,245,237,236,225,245,116,128, 1, 80, + 105,129, 1,162, 21, 54,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 14,109, 4, 21, 79, 21,107, 21,184, 21,202,225, + 227,242,239,110,130, 1, 76, 21, 91, 21, 99,225,227,245,244,101, + 128, 30, 82,231,242,225,246,101,128, 30, 80,229,231, 97,132, 33, + 38, 21,121, 21,132, 21,140, 21,156,227,249,242,233,236,236,233, + 99,128, 4, 96,231,242,229,229,107,128, 3,169,242,239,245,238, + 228,227,249,242,233,236,236,233, 99,128, 4,122,116, 2, 21,162, + 21,177,233,244,236,239,227,249,242,233,236,236,233, 99,128, 4, + 124,239,238,239,115,128, 3,143,233,227,242,239,110,129, 3,159, + 21,194,244,239,238,239,115,128, 3,140,239,238,239,243,240,225, + 227,101,128,255, 47,238,229,242,239,237,225,110,128, 33, 96,111, + 2, 21,229, 21,248,231,239,238,229,107,129, 1,234, 21,239,237, + 225,227,242,239,110,128, 1,236,240,229,110,128, 1,134,115, 3, + 22, 6, 22, 33, 22, 40,236,225,243,104,130, 0,216, 22, 17, 22, + 25,225,227,245,244,101,128, 1,254,243,237,225,236,108,128,247, + 248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245, + 244,101,128, 1,254,116, 2, 22, 59, 22, 70,227,249,242,233,236, + 236,233, 99,128, 4,126,233,236,228,101,131, 0,213, 22, 83, 22, + 91, 22,102,225,227,245,244,101,128, 30, 76,228,233,229,242,229, + 243,233,115,128, 30, 78,243,237,225,236,108,128,247,245, 80,136, + 0, 80, 22,130, 22,138, 22,147, 22,159, 22,211, 22,227, 22,246, + 23, 2,225,227,245,244,101,128, 30, 84,227,233,242,227,236,101, + 128, 36,197,228,239,244,225,227,227,229,238,116,128, 30, 86,101, + 3, 22,167, 22,178, 22,190,227,249,242,233,236,236,233, 99,128, + 4, 31,232,225,242,237,229,238,233,225,110,128, 5, 74,237,233, + 228,228,236,229,232,239,239,235,227,249,242,233,236,236,233, 99, + 128, 4,166,104, 2, 22,217, 22,221,105,128, 3,166,239,239,107, + 128, 1,164,105,129, 3,160, 22,233,247,242,225,242,237,229,238, + 233,225,110,128, 5, 83,237,239,238,239,243,240,225,227,101,128, + 255, 48,115, 2, 23, 8, 23, 25,105,129, 3,168, 23, 14,227,249, + 242,233,236,236,233, 99,128, 4,112,237,225,236,108,128,247,112, + 81,131, 0, 81, 23, 42, 23, 51, 23, 63,227,233,242,227,236,101, + 128, 36,198,237,239,238,239,243,240,225,227,101,128,255, 49,243, + 237,225,236,108,128,247,113, 82,138, 0, 82, 23, 95, 23,119, 23, + 166, 23,217, 23,230, 23,240, 23,245, 24, 19, 24, 31, 24, 43, 97, + 2, 23,101, 23,112,225,242,237,229,238,233,225,110,128, 5, 76, + 227,245,244,101,128, 1, 84, 99, 4, 23,129, 23,136, 23,145, 23, + 153,225,242,239,110,128, 1, 88,229,228,233,236,236, 97,128, 1, + 86,233,242,227,236,101,128, 36,199,239,237,237,225,225,227,227, + 229,238,116,128, 1, 86,100, 2, 23,172, 23,182,226,236,231,242, + 225,246,101,128, 2, 16,239,116, 2, 23,189, 23,198,225,227,227, + 229,238,116,128, 30, 88,226,229,236,239,119,129, 30, 90, 23,208, + 237,225,227,242,239,110,128, 30, 92,229,232,225,242,237,229,238, + 233,225,110,128, 5, 80,230,242,225,235,244,245,114,128, 33, 28, + 232,111,128, 3,161,233,110, 2, 23,252, 24, 5,231,243,237,225, + 236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101, + 128, 2, 18,236,233,238,229,226,229,236,239,119,128, 30, 94,237, + 239,238,239,243,240,225,227,101,128,255, 50,243,237,225,236,108, + 129,247,114, 24, 53,233,238,246,229,242,244,229,100,129, 2,129, + 24, 66,243,245,240,229,242,233,239,114,128, 2,182, 83,139, 0, + 83, 24,103, 26, 17, 26, 55, 26,182, 26,221, 26,250, 27, 84, 27, + 105, 27,117, 27,135, 27,143, 70, 6, 24,117, 24,209, 24,241, 25, + 77, 25,119, 25,221, 48, 9, 24,137, 24,145, 24,153, 24,161, 24, + 169, 24,177, 24,185, 24,193, 24,201,177,176,176,176, 48,128, 37, + 12,178,176,176,176, 48,128, 37, 20,179,176,176,176, 48,128, 37, + 16,180,176,176,176, 48,128, 37, 24,181,176,176,176, 48,128, 37, + 60,182,176,176,176, 48,128, 37, 44,183,176,176,176, 48,128, 37, + 52,184,176,176,176, 48,128, 37, 28,185,176,176,176, 48,128, 37, + 36, 49, 3, 24,217, 24,225, 24,233,176,176,176,176, 48,128, 37, + 0,177,176,176,176, 48,128, 37, 2,185,176,176,176, 48,128, 37, + 97, 50, 9, 25, 5, 25, 13, 25, 21, 25, 29, 25, 37, 25, 45, 25, + 53, 25, 61, 25, 69,176,176,176,176, 48,128, 37, 98,177,176,176, + 176, 48,128, 37, 86,178,176,176,176, 48,128, 37, 85,179,176,176, + 176, 48,128, 37, 99,180,176,176,176, 48,128, 37, 81,181,176,176, + 176, 48,128, 37, 87,182,176,176,176, 48,128, 37, 93,183,176,176, + 176, 48,128, 37, 92,184,176,176,176, 48,128, 37, 91, 51, 4, 25, + 87, 25, 95, 25,103, 25,111,182,176,176,176, 48,128, 37, 94,183, + 176,176,176, 48,128, 37, 95,184,176,176,176, 48,128, 37, 90,185, + 176,176,176, 48,128, 37, 84, 52, 10, 25,141, 25,149, 25,157, 25, + 165, 25,173, 25,181, 25,189, 25,197, 25,205, 25,213,176,176,176, + 176, 48,128, 37,105,177,176,176,176, 48,128, 37,102,178,176,176, + 176, 48,128, 37, 96,179,176,176,176, 48,128, 37, 80,180,176,176, + 176, 48,128, 37,108,181,176,176,176, 48,128, 37,103,182,176,176, + 176, 48,128, 37,104,183,176,176,176, 48,128, 37,100,184,176,176, + 176, 48,128, 37,101,185,176,176,176, 48,128, 37, 89, 53, 5, 25, + 233, 25,241, 25,249, 26, 1, 26, 9,176,176,176,176, 48,128, 37, + 88,177,176,176,176, 48,128, 37, 82,178,176,176,176, 48,128, 37, + 83,179,176,176,176, 48,128, 37,107,180,176,176,176, 48,128, 37, + 106, 97, 2, 26, 23, 26, 44,227,245,244,101,129, 1, 90, 26, 32, + 228,239,244,225,227,227,229,238,116,128, 30,100,237,240,233,231, + 242,229,229,107,128, 3,224, 99, 5, 26, 67, 26, 98, 26,107, 26, + 147, 26,169,225,242,239,110,130, 1, 96, 26, 78, 26, 90,228,239, + 244,225,227,227,229,238,116,128, 30,102,243,237,225,236,108,128, + 246,253,229,228,233,236,236, 97,128, 1, 94,232,247, 97,130, 1, + 143, 26,117, 26,128,227,249,242,233,236,236,233, 99,128, 4,216, + 228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99, + 128, 4,218,233,242, 99, 2, 26,155, 26,160,236,101,128, 36,200, + 245,237,230,236,229,120,128, 1, 92,239,237,237,225,225,227,227, + 229,238,116,128, 2, 24,228,239,116, 2, 26,190, 26,199,225,227, + 227,229,238,116,128, 30, 96,226,229,236,239,119,129, 30, 98, 26, + 209,228,239,244,225,227,227,229,238,116,128, 30,104,101, 2, 26, + 227, 26,239,232,225,242,237,229,238,233,225,110,128, 5, 77,246, + 229,238,242,239,237,225,110,128, 33,102,104, 5, 27, 6, 27, 34, + 27, 48, 27, 59, 27, 72, 97, 2, 27, 12, 27, 23,225,242,237,229, + 238,233,225,110,128, 5, 71,227,249,242,233,236,236,233, 99,128, + 4, 40,227,232,225,227,249,242,233,236,236,233, 99,128, 4, 41, + 229,233,227,239,240,244,233, 99,128, 3,226,232,225,227,249,242, + 233,236,236,233, 99,128, 4,186,233,237,225,227,239,240,244,233, + 99,128, 3,236,105, 2, 27, 90, 27, 96,231,237, 97,128, 3,163, + 248,242,239,237,225,110,128, 33,101,237,239,238,239,243,240,225, + 227,101,128,255, 51,239,230,244,243,233,231,238,227,249,242,233, + 236,236,233, 99,128, 4, 44,243,237,225,236,108,128,247,115,244, + 233,231,237,225,231,242,229,229,107,128, 3,218, 84,141, 0, 84, + 27,186, 27,191, 27,197, 28, 7, 28, 32, 28, 96, 28,147, 28,177, + 28,189, 28,201, 28,246, 29, 6, 29, 46,225,117,128, 3,164,226, + 225,114,128, 1,102, 99, 4, 27,207, 27,214, 27,223, 27,250,225, + 242,239,110,128, 1,100,229,228,233,236,236, 97,128, 1, 98,233, + 242, 99, 2, 27,231, 27,236,236,101,128, 36,201,245,237,230,236, + 229,248,226,229,236,239,119,128, 30,112,239,237,237,225,225,227, + 227,229,238,116,128, 1, 98,228,239,116, 2, 28, 15, 28, 24,225, + 227,227,229,238,116,128, 30,106,226,229,236,239,119,128, 30,108, + 101, 4, 28, 42, 28, 53, 28, 73, 28, 82,227,249,242,233,236,236, + 233, 99,128, 4, 34,228,229,243,227,229,238,228,229,242,227,249, + 242,233,236,236,233, 99,128, 4,172,238,242,239,237,225,110,128, + 33,105,244,243,229,227,249,242,233,236,236,233, 99,128, 4,180, + 104, 3, 28,104, 28,110, 28,136,229,244, 97,128, 3,152,111, 2, + 28,116, 28,121,239,107,128, 1,172,242,110,129, 0,222, 28,128, + 243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110, + 128, 33, 98,105, 2, 28,153, 28,164,236,228,229,243,237,225,236, + 108,128,246,254,247,238,225,242,237,229,238,233,225,110,128, 5, + 79,236,233,238,229,226,229,236,239,119,128, 30,110,237,239,238, + 239,243,240,225,227,101,128,255, 52,111, 2, 28,207, 28,218,225, + 242,237,229,238,233,225,110,128, 5, 57,238,101, 3, 28,227, 28, + 234, 28,240,230,233,246,101,128, 1,188,243,233,120,128, 1,132, + 244,247,111,128, 1,167,242,229,244,242,239,230,236,229,248,232, + 239,239,107,128, 1,174,115, 3, 29, 14, 29, 26, 29, 39,229,227, + 249,242,233,236,236,233, 99,128, 4, 38,232,229,227,249,242,233, + 236,236,233, 99,128, 4, 11,237,225,236,108,128,247,116,119, 2, + 29, 52, 29, 64,229,236,246,229,242,239,237,225,110,128, 33,107, + 239,242,239,237,225,110,128, 33, 97, 85,142, 0, 85, 29,105, 29, + 123, 29,131, 29,198, 30, 69, 30, 87, 30,198, 30,214, 30,226, 31, + 21, 31, 30, 31,142, 31,149, 31,219,225,227,245,244,101,129, 0, + 218, 29,115,243,237,225,236,108,128,247,250,226,242,229,246,101, + 128, 1,108, 99, 3, 29,139, 29,146, 29,188,225,242,239,110,128, + 1,211,233,242, 99, 2, 29,154, 29,159,236,101,128, 36,202,245, + 237,230,236,229,120,130, 0,219, 29,172, 29,180,226,229,236,239, + 119,128, 30,118,243,237,225,236,108,128,247,251,249,242,233,236, + 236,233, 99,128, 4, 35,100, 3, 29,206, 29,229, 30, 59,226,108, + 2, 29,213, 29,221,225,227,245,244,101,128, 1,112,231,242,225, + 246,101,128, 2, 20,233,229,242,229,243,233,115,134, 0,220, 29, + 251, 30, 3, 30, 11, 30, 34, 30, 42, 30, 51,225,227,245,244,101, + 128, 1,215,226,229,236,239,119,128, 30,114, 99, 2, 30, 17, 30, + 24,225,242,239,110,128, 1,217,249,242,233,236,236,233, 99,128, + 4,240,231,242,225,246,101,128, 1,219,237,225,227,242,239,110, + 128, 1,213,243,237,225,236,108,128,247,252,239,244,226,229,236, + 239,119,128, 30,228,231,242,225,246,101,129, 0,217, 30, 79,243, + 237,225,236,108,128,247,249,104, 2, 30, 93, 30,171,111, 2, 30, + 99, 30,109,239,235,225,226,239,246,101,128, 30,230,242,110,133, + 1,175, 30,124, 30,132, 30,143, 30,151, 30,163,225,227,245,244, + 101,128, 30,232,228,239,244,226,229,236,239,119,128, 30,240,231, + 242,225,246,101,128, 30,234,232,239,239,235,225,226,239,246,101, + 128, 30,236,244,233,236,228,101,128, 30,238,245,238,231,225,242, + 245,237,236,225,245,116,129, 1,112, 30,187,227,249,242,233,236, + 236,233, 99,128, 4,242,233,238,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 22,235,227,249,242,233,236,236,233, 99,128, + 4,120,109, 2, 30,232, 31, 10,225,227,242,239,110,130, 1,106, + 30,244, 30,255,227,249,242,233,236,236,233, 99,128, 4,238,228, + 233,229,242,229,243,233,115,128, 30,122,239,238,239,243,240,225, + 227,101,128,255, 53,239,231,239,238,229,107,128, 1,114,240,243, + 233,236,239,110,133, 3,165, 31, 49, 31, 53, 31, 90, 31,121, 31, + 134, 49,128, 3,210, 97, 2, 31, 59, 31, 81,227,245,244,229,232, + 239,239,235,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 211,230,242,233,227,225,110,128, 1,177,228,233,229,242,229,243, + 233,115,129, 3,171, 31,103,232,239,239,235,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,212,232,239,239,235,243,249,237, + 226,239,108,128, 3,210,244,239,238,239,115,128, 3,142,242,233, + 238,103,128, 1,110,115, 3, 31,157, 31,172, 31,179,232,239,242, + 244,227,249,242,233,236,236,233, 99,128, 4, 14,237,225,236,108, + 128,247,117,244,242,225,233,231,232,116, 2, 31,191, 31,202,227, + 249,242,233,236,236,233, 99,128, 4,174,243,244,242,239,235,229, + 227,249,242,233,236,236,233, 99,128, 4,176,244,233,236,228,101, + 130, 1,104, 31,231, 31,239,225,227,245,244,101,128, 30,120,226, + 229,236,239,119,128, 30,116, 86,136, 0, 86, 32, 11, 32, 20, 32, + 31, 32, 60, 32, 67, 32, 79, 32, 91, 32, 99,227,233,242,227,236, + 101,128, 36,203,228,239,244,226,229,236,239,119,128, 30,126,101, + 2, 32, 37, 32, 48,227,249,242,233,236,236,233, 99,128, 4, 18, + 247,225,242,237,229,238,233,225,110,128, 5, 78,232,239,239,107, + 128, 1,178,237,239,238,239,243,240,225,227,101,128,255, 54,239, + 225,242,237,229,238,233,225,110,128, 5, 72,243,237,225,236,108, + 128,247,118,244,233,236,228,101,128, 30,124, 87,134, 0, 87, 32, + 123, 32,131, 32,154, 32,194, 32,202, 32,214,225,227,245,244,101, + 128, 30,130,227,233,242, 99, 2, 32,140, 32,145,236,101,128, 36, + 204,245,237,230,236,229,120,128, 1,116,100, 2, 32,160, 32,170, + 233,229,242,229,243,233,115,128, 30,132,239,116, 2, 32,177, 32, + 186,225,227,227,229,238,116,128, 30,134,226,229,236,239,119,128, + 30,136,231,242,225,246,101,128, 30,128,237,239,238,239,243,240, + 225,227,101,128,255, 55,243,237,225,236,108,128,247,119, 88,134, + 0, 88, 32,238, 32,247, 33, 18, 33, 31, 33, 35, 33, 47,227,233, + 242,227,236,101,128, 36,205,100, 2, 32,253, 33, 7,233,229,242, + 229,243,233,115,128, 30,140,239,244,225,227,227,229,238,116,128, + 30,138,229,232,225,242,237,229,238,233,225,110,128, 5, 61,105, + 128, 3,158,237,239,238,239,243,240,225,227,101,128,255, 56,243, + 237,225,236,108,128,247,120, 89,139, 0, 89, 33, 81, 33,116, 33, + 139, 33,189, 33,228, 33,236, 33,253, 34, 40, 34, 52, 34, 60, 34, + 68, 97, 2, 33, 87, 33,104,227,245,244,101,129, 0,221, 33, 96, + 243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233, + 99,128, 4, 98,227,233,242, 99, 2, 33,125, 33,130,236,101,128, + 36,206,245,237,230,236,229,120,128, 1,118,100, 2, 33,145, 33, + 165,233,229,242,229,243,233,115,129, 1,120, 33,157,243,237,225, + 236,108,128,247,255,239,116, 2, 33,172, 33,181,225,227,227,229, + 238,116,128, 30,142,226,229,236,239,119,128, 30,244,229,114, 2, + 33,196, 33,208,233,227,249,242,233,236,236,233, 99,128, 4, 43, + 245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,248,231,242,225,246,101,128, 30,242,232,239,239,107, + 129, 1,179, 33,245,225,226,239,246,101,128, 30,246,105, 3, 34, + 5, 34, 16, 34, 27,225,242,237,229,238,233,225,110,128, 5, 69, + 227,249,242,233,236,236,233, 99,128, 4, 7,247,238,225,242,237, + 229,238,233,225,110,128, 5, 82,237,239,238,239,243,240,225,227, + 101,128,255, 57,243,237,225,236,108,128,247,121,244,233,236,228, + 101,128, 30,248,245,115, 2, 34, 75, 34,113,226,233,103, 2, 34, + 83, 34, 94,227,249,242,233,236,236,233, 99,128, 4,106,233,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 108,236,233,244,244,236,101, 2, 34,124, 34,135,227,249,242,233, + 236,236,233, 99,128, 4,102,233,239,244,233,230,233,229,228,227, + 249,242,233,236,236,233, 99,128, 4,104, 90,136, 0, 90, 34,174, + 34,198, 34,243, 35, 14, 35, 81, 35,173, 35,185, 35,197, 97, 2, + 34,180, 34,191,225,242,237,229,238,233,225,110,128, 5, 54,227, + 245,244,101,128, 1,121, 99, 2, 34,204, 34,221,225,242,239,110, + 129, 1,125, 34,213,243,237,225,236,108,128,246,255,233,242, 99, + 2, 34,229, 34,234,236,101,128, 36,207,245,237,230,236,229,120, + 128, 30,144,228,239,116,130, 1,123, 34,253, 35, 6,225,227,227, + 229,238,116,128, 1,123,226,229,236,239,119,128, 30,146,101, 3, + 35, 22, 35, 33, 35, 76,227,249,242,233,236,236,233, 99,128, 4, + 23,100, 2, 35, 39, 35, 58,229,243,227,229,238,228,229,242,227, + 249,242,233,236,236,233, 99,128, 4,152,233,229,242,229,243,233, + 243,227,249,242,233,236,236,233, 99,128, 4,222,244, 97,128, 3, + 150,232,101, 4, 35, 92, 35,103, 35,119, 35,130,225,242,237,229, + 238,233,225,110,128, 5, 58,226,242,229,246,229,227,249,242,233, + 236,236,233, 99,128, 4,193,227,249,242,233,236,236,233, 99,128, + 4, 22,100, 2, 35,136, 35,155,229,243,227,229,238,228,229,242, + 227,249,242,233,236,236,233, 99,128, 4,150,233,229,242,229,243, + 233,243,227,249,242,233,236,236,233, 99,128, 4,220,236,233,238, + 229,226,229,236,239,119,128, 30,148,237,239,238,239,243,240,225, + 227,101,128,255, 58,115, 2, 35,203, 35,210,237,225,236,108,128, + 247,122,244,242,239,235,101,128, 1,181, 97,149, 0, 97, 36, 8, + 36,144, 37, 35, 37,211, 38, 55, 38, 91, 45, 10, 45, 47, 45, 74, + 46, 43, 46, 81, 47,170, 47,242, 48,197, 48,206, 49, 79, 51, 87, + 52, 77, 52,124, 53, 19, 53, 33, 97, 7, 36, 24, 36, 34, 36, 41, + 36, 48, 36, 73, 36, 89, 36,100,226,229,238,231,225,236,105,128, + 9,134,227,245,244,101,128, 0,225,228,229,246, 97,128, 9, 6, + 231,117, 2, 36, 55, 36, 64,234,225,242,225,244,105,128, 10,134, + 242,237,245,235,232,105,128, 10, 6,237,225,244,242,225,231,245, + 242,237,245,235,232,105,128, 10, 62,242,245,243,241,245,225,242, + 101,128, 51, 3,246,239,247,229,236,243,233,231,110, 3, 36,116, + 36,126, 36,133,226,229,238,231,225,236,105,128, 9,190,228,229, + 246, 97,128, 9, 62,231,245,234,225,242,225,244,105,128, 10,190, + 98, 4, 36,154, 36,195, 36,204, 36,214,226,242,229,246,233,225, + 244,233,239,110, 2, 36,169, 36,184,237,225,242,235,225,242,237, + 229,238,233,225,110,128, 5, 95,243,233,231,238,228,229,246, 97, + 128, 9,112,229,238,231,225,236,105,128, 9,133,239,240,239,237, + 239,230,111,128, 49, 26,242,229,246,101,134, 1, 3, 36,233, 36, + 241, 36,252, 37, 7, 37, 15, 37, 27,225,227,245,244,101,128, 30, + 175,227,249,242,233,236,236,233, 99,128, 4,209,228,239,244,226, + 229,236,239,119,128, 30,183,231,242,225,246,101,128, 30,177,232, + 239,239,235,225,226,239,246,101,128, 30,179,244,233,236,228,101, + 128, 30,181, 99, 4, 37, 45, 37, 52, 37,131, 37,201,225,242,239, + 110,128, 1,206,233,242, 99, 2, 37, 60, 37, 65,236,101,128, 36, + 208,245,237,230,236,229,120,133, 0,226, 37, 84, 37, 92, 37,103, + 37,111, 37,123,225,227,245,244,101,128, 30,165,228,239,244,226, + 229,236,239,119,128, 30,173,231,242,225,246,101,128, 30,167,232, + 239,239,235,225,226,239,246,101,128, 30,169,244,233,236,228,101, + 128, 30,171,245,244,101,133, 0,180, 37,147, 37,158, 37,175, 37, + 182, 37,191,226,229,236,239,247,227,237, 98,128, 3, 23, 99, 2, + 37,164, 37,169,237, 98,128, 3, 1,239,237, 98,128, 3, 1,228, + 229,246, 97,128, 9, 84,236,239,247,237,239,100,128, 2,207,244, + 239,238,229,227,237, 98,128, 3, 65,249,242,233,236,236,233, 99, + 128, 4, 48,100, 5, 37,223, 37,233, 37,247, 37,253, 38, 31,226, + 236,231,242,225,246,101,128, 2, 1,228,225,235,231,245,242,237, + 245,235,232,105,128, 10,113,229,246, 97,128, 9, 5,233,229,242, + 229,243,233,115,130, 0,228, 38, 11, 38, 22,227,249,242,233,236, + 236,233, 99,128, 4,211,237,225,227,242,239,110,128, 1,223,239, + 116, 2, 38, 38, 38, 46,226,229,236,239,119,128, 30,161,237,225, + 227,242,239,110,128, 1,225,101,131, 0,230, 38, 65, 38, 73, 38, + 82,225,227,245,244,101,128, 1,253,235,239,242,229,225,110,128, + 49, 80,237,225,227,242,239,110,128, 1,227,230,233,105, 6, 38, + 107, 38,127, 41, 64, 41, 70, 41, 85, 44,185, 48, 2, 38,113, 38, + 120,176,178,176, 56,128, 32, 21,184,185,180, 49,128, 32,164,177, + 48, 3, 38,136, 40,160, 41, 39, 48, 9, 38,156, 38,176, 38,238, + 39, 44, 39,106, 39,168, 39,230, 40, 36, 40, 98, 49, 3, 38,164, + 38,168, 38,172, 55,128, 4, 16, 56,128, 4, 17, 57,128, 4, 18, + 50, 10, 38,198, 38,202, 38,206, 38,210, 38,214, 38,218, 38,222, + 38,226, 38,230, 38,234, 48,128, 4, 19, 49,128, 4, 20, 50,128, + 4, 21, 51,128, 4, 1, 52,128, 4, 22, 53,128, 4, 23, 54,128, + 4, 24, 55,128, 4, 25, 56,128, 4, 26, 57,128, 4, 27, 51, 10, + 39, 4, 39, 8, 39, 12, 39, 16, 39, 20, 39, 24, 39, 28, 39, 32, + 39, 36, 39, 40, 48,128, 4, 28, 49,128, 4, 29, 50,128, 4, 30, + 51,128, 4, 31, 52,128, 4, 32, 53,128, 4, 33, 54,128, 4, 34, + 55,128, 4, 35, 56,128, 4, 36, 57,128, 4, 37, 52, 10, 39, 66, + 39, 70, 39, 74, 39, 78, 39, 82, 39, 86, 39, 90, 39, 94, 39, 98, + 39,102, 48,128, 4, 38, 49,128, 4, 39, 50,128, 4, 40, 51,128, + 4, 41, 52,128, 4, 42, 53,128, 4, 43, 54,128, 4, 44, 55,128, + 4, 45, 56,128, 4, 46, 57,128, 4, 47, 53, 10, 39,128, 39,132, + 39,136, 39,140, 39,144, 39,148, 39,152, 39,156, 39,160, 39,164, + 48,128, 4,144, 49,128, 4, 2, 50,128, 4, 3, 51,128, 4, 4, + 52,128, 4, 5, 53,128, 4, 6, 54,128, 4, 7, 55,128, 4, 8, + 56,128, 4, 9, 57,128, 4, 10, 54, 10, 39,190, 39,194, 39,198, + 39,202, 39,206, 39,210, 39,214, 39,218, 39,222, 39,226, 48,128, + 4, 11, 49,128, 4, 12, 50,128, 4, 14, 51,128,246,196, 52,128, + 246,197, 53,128, 4, 48, 54,128, 4, 49, 55,128, 4, 50, 56,128, + 4, 51, 57,128, 4, 52, 55, 10, 39,252, 40, 0, 40, 4, 40, 8, + 40, 12, 40, 16, 40, 20, 40, 24, 40, 28, 40, 32, 48,128, 4, 53, + 49,128, 4, 81, 50,128, 4, 54, 51,128, 4, 55, 52,128, 4, 56, + 53,128, 4, 57, 54,128, 4, 58, 55,128, 4, 59, 56,128, 4, 60, + 57,128, 4, 61, 56, 10, 40, 58, 40, 62, 40, 66, 40, 70, 40, 74, + 40, 78, 40, 82, 40, 86, 40, 90, 40, 94, 48,128, 4, 62, 49,128, + 4, 63, 50,128, 4, 64, 51,128, 4, 65, 52,128, 4, 66, 53,128, + 4, 67, 54,128, 4, 68, 55,128, 4, 69, 56,128, 4, 70, 57,128, + 4, 71, 57, 10, 40,120, 40,124, 40,128, 40,132, 40,136, 40,140, + 40,144, 40,148, 40,152, 40,156, 48,128, 4, 72, 49,128, 4, 73, + 50,128, 4, 74, 51,128, 4, 75, 52,128, 4, 76, 53,128, 4, 77, + 54,128, 4, 78, 55,128, 4, 79, 56,128, 4,145, 57,128, 4, 82, + 49, 4, 40,170, 40,232, 40,237, 41, 7, 48, 10, 40,192, 40,196, + 40,200, 40,204, 40,208, 40,212, 40,216, 40,220, 40,224, 40,228, + 48,128, 4, 83, 49,128, 4, 84, 50,128, 4, 85, 51,128, 4, 86, + 52,128, 4, 87, 53,128, 4, 88, 54,128, 4, 89, 55,128, 4, 90, + 56,128, 4, 91, 57,128, 4, 92,177, 48,128, 4, 94, 52, 4, 40, + 247, 40,251, 40,255, 41, 3, 53,128, 4, 15, 54,128, 4, 98, 55, + 128, 4,114, 56,128, 4,116, 57, 5, 41, 19, 41, 23, 41, 27, 41, + 31, 41, 35, 50,128,246,198, 51,128, 4, 95, 52,128, 4, 99, 53, + 128, 4,115, 54,128, 4,117, 56, 2, 41, 45, 41, 59, 51, 2, 41, + 51, 41, 55, 49,128,246,199, 50,128,246,200,180, 54,128, 4,217, + 178,185, 57,128, 32, 14,179, 48, 2, 41, 77, 41, 81, 48,128, 32, + 15, 49,128, 32, 13,181, 55, 7, 41,102, 41,172, 42,237, 43, 58, + 44, 15, 44,108, 44,179, 51, 2, 41,108, 41,122, 56, 2, 41,114, + 41,118, 49,128, 6,106, 56,128, 6, 12, 57, 8, 41,140, 41,144, + 41,148, 41,152, 41,156, 41,160, 41,164, 41,168, 50,128, 6, 96, + 51,128, 6, 97, 52,128, 6, 98, 53,128, 6, 99, 54,128, 6,100, + 55,128, 6,101, 56,128, 6,102, 57,128, 6,103, 52, 7, 41,188, + 41,220, 42, 26, 42, 88, 42,120, 42,176, 42,232, 48, 5, 41,200, + 41,204, 41,208, 41,212, 41,216, 48,128, 6,104, 49,128, 6,105, + 51,128, 6, 27, 55,128, 6, 31, 57,128, 6, 33, 49, 10, 41,242, + 41,246, 41,250, 41,254, 42, 2, 42, 6, 42, 10, 42, 14, 42, 18, + 42, 22, 48,128, 6, 34, 49,128, 6, 35, 50,128, 6, 36, 51,128, + 6, 37, 52,128, 6, 38, 53,128, 6, 39, 54,128, 6, 40, 55,128, + 6, 41, 56,128, 6, 42, 57,128, 6, 43, 50, 10, 42, 48, 42, 52, + 42, 56, 42, 60, 42, 64, 42, 68, 42, 72, 42, 76, 42, 80, 42, 84, + 48,128, 6, 44, 49,128, 6, 45, 50,128, 6, 46, 51,128, 6, 47, + 52,128, 6, 48, 53,128, 6, 49, 54,128, 6, 50, 55,128, 6, 51, + 56,128, 6, 52, 57,128, 6, 53, 51, 5, 42,100, 42,104, 42,108, + 42,112, 42,116, 48,128, 6, 54, 49,128, 6, 55, 50,128, 6, 56, + 51,128, 6, 57, 52,128, 6, 58, 52, 9, 42,140, 42,144, 42,148, + 42,152, 42,156, 42,160, 42,164, 42,168, 42,172, 48,128, 6, 64, + 49,128, 6, 65, 50,128, 6, 66, 51,128, 6, 67, 52,128, 6, 68, + 53,128, 6, 69, 54,128, 6, 70, 56,128, 6, 72, 57,128, 6, 73, + 53, 9, 42,196, 42,200, 42,204, 42,208, 42,212, 42,216, 42,220, + 42,224, 42,228, 48,128, 6, 74, 49,128, 6, 75, 50,128, 6, 76, + 51,128, 6, 77, 52,128, 6, 78, 53,128, 6, 79, 54,128, 6, 80, + 55,128, 6, 81, 56,128, 6, 82,183, 48,128, 6, 71, 53, 3, 42, + 245, 43, 21, 43, 53, 48, 5, 43, 1, 43, 5, 43, 9, 43, 13, 43, + 17, 53,128, 6,164, 54,128, 6,126, 55,128, 6,134, 56,128, 6, + 152, 57,128, 6,175, 49, 5, 43, 33, 43, 37, 43, 41, 43, 45, 43, + 49, 49,128, 6,121, 50,128, 6,136, 51,128, 6,145, 52,128, 6, + 186, 57,128, 6,210,179, 52,128, 6,213, 54, 7, 43, 74, 43, 79, + 43, 84, 43, 89, 43,127, 43,189, 43,251,179, 54,128, 32,170,180, + 53,128, 5,190,181, 56,128, 5,195, 54, 6, 43,103, 43,107, 43, + 111, 43,115, 43,119, 43,123, 52,128, 5,208, 53,128, 5,209, 54, + 128, 5,210, 55,128, 5,211, 56,128, 5,212, 57,128, 5,213, 55, + 10, 43,149, 43,153, 43,157, 43,161, 43,165, 43,169, 43,173, 43, + 177, 43,181, 43,185, 48,128, 5,214, 49,128, 5,215, 50,128, 5, + 216, 51,128, 5,217, 52,128, 5,218, 53,128, 5,219, 54,128, 5, + 220, 55,128, 5,221, 56,128, 5,222, 57,128, 5,223, 56, 10, 43, + 211, 43,215, 43,219, 43,223, 43,227, 43,231, 43,235, 43,239, 43, + 243, 43,247, 48,128, 5,224, 49,128, 5,225, 50,128, 5,226, 51, + 128, 5,227, 52,128, 5,228, 53,128, 5,229, 54,128, 5,230, 55, + 128, 5,231, 56,128, 5,232, 57,128, 5,233, 57, 3, 44, 3, 44, + 7, 44, 11, 48,128, 5,234, 52,128,251, 42, 53,128,251, 43, 55, + 4, 44, 25, 44, 39, 44, 59, 44, 64, 48, 2, 44, 31, 44, 35, 48, + 128,251, 75, 53,128,251, 31, 49, 3, 44, 47, 44, 51, 44, 55, 54, + 128, 5,240, 55,128, 5,241, 56,128, 5,242,178, 51,128,251, 53, + 57, 7, 44, 80, 44, 84, 44, 88, 44, 92, 44, 96, 44,100, 44,104, + 51,128, 5,180, 52,128, 5,181, 53,128, 5,182, 54,128, 5,187, + 55,128, 5,184, 56,128, 5,183, 57,128, 5,176, 56, 3, 44,116, + 44,160, 44,165, 48, 7, 44,132, 44,136, 44,140, 44,144, 44,148, + 44,152, 44,156, 48,128, 5,178, 49,128, 5,177, 50,128, 5,179, + 51,128, 5,194, 52,128, 5,193, 54,128, 5,185, 55,128, 5,188, + 179, 57,128, 5,189, 52, 2, 44,171, 44,175, 49,128, 5,191, 50, + 128, 5,192,185,178, 57,128, 2,188, 54, 3, 44,193, 44,252, 45, + 3, 49, 4, 44,203, 44,219, 44,225, 44,246, 50, 2, 44,209, 44, + 214,180, 56,128, 33, 5,184, 57,128, 33, 19,179,181, 50,128, 33, + 22,181, 55, 3, 44,234, 44,238, 44,242, 51,128, 32, 44, 52,128, + 32, 45, 53,128, 32, 46,182,182, 52,128, 32, 12,179,177,182, 55, + 128, 6,109,180,185,179, 55,128, 2,189,103, 2, 45, 16, 45, 23, + 242,225,246,101,128, 0,224,117, 2, 45, 29, 45, 38,234,225,242, + 225,244,105,128, 10,133,242,237,245,235,232,105,128, 10, 5,104, + 2, 45, 53, 45, 63,233,242,225,231,225,238, 97,128, 48, 66,239, + 239,235,225,226,239,246,101,128, 30,163,105, 7, 45, 90, 45,115, + 45,122, 45,134, 45,159, 45,175, 45,255, 98, 2, 45, 96, 45,105, + 229,238,231,225,236,105,128, 9,144,239,240,239,237,239,230,111, + 128, 49, 30,228,229,246, 97,128, 9, 16,229,227,249,242,233,236, + 236,233, 99,128, 4,213,231,117, 2, 45,141, 45,150,234,225,242, + 225,244,105,128, 10,144,242,237,245,235,232,105,128, 10, 16,237, + 225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 72,110, + 5, 45,187, 45,196, 45,210, 45,226, 45,241,225,242,225,226,233, + 99,128, 6, 57,230,233,238,225,236,225,242,225,226,233, 99,128, + 254,202,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,203,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, + 204,246,229,242,244,229,228,226,242,229,246,101,128, 2, 3,246, + 239,247,229,236,243,233,231,110, 3, 46, 15, 46, 25, 46, 32,226, + 229,238,231,225,236,105,128, 9,200,228,229,246, 97,128, 9, 72, + 231,245,234,225,242,225,244,105,128, 10,200,107, 2, 46, 49, 46, + 73,225,244,225,235,225,238, 97,129, 48,162, 46, 61,232,225,236, + 230,247,233,228,244,104,128,255,113,239,242,229,225,110,128, 49, + 79,108, 3, 46, 89, 47,145, 47,154,101, 2, 46, 95, 47,140,102, + 136, 5,208, 46,115, 46,124, 46,139, 46,153, 46,242, 47, 0, 47, + 111, 47,125,225,242,225,226,233, 99,128, 6, 39,228,225,231,229, + 243,232,232,229,226,242,229,119,128,251, 48,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,142,104, 2, 46,159, 46,234,225, + 237,250, 97, 2, 46,168, 46,201,225,226,239,246,101, 2, 46,178, + 46,187,225,242,225,226,233, 99,128, 6, 35,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,132,226,229,236,239,119, 2, 46, + 211, 46,220,225,242,225,226,233, 99,128, 6, 37,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,136,229,226,242,229,119,128, + 5,208,236,225,237,229,228,232,229,226,242,229,119,128,251, 79, + 237, 97, 2, 47, 7, 47, 43,228,228,225,225,226,239,246,101, 2, + 47, 20, 47, 29,225,242,225,226,233, 99,128, 6, 34,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,130,235,243,245,242, 97, + 4, 47, 57, 47, 66, 47, 80, 47, 96,225,242,225,226,233, 99,128, + 6, 73,230,233,238,225,236,225,242,225,226,233, 99,128,254,240, + 233,238,233,244,233,225,236,225,242,225,226,233, 99,128,254,243, + 237,229,228,233,225,236,225,242,225,226,233, 99,128,254,244,240, + 225,244,225,232,232,229,226,242,229,119,128,251, 46,241,225,237, + 225,244,243,232,229,226,242,229,119,128,251, 47,240,104,128, 33, + 53,236,229,241,245,225,108,128, 34, 76,240,232, 97,129, 3,177, + 47,162,244,239,238,239,115,128, 3,172,109, 4, 47,180, 47,188, + 47,199, 47,233,225,227,242,239,110,128, 1, 1,239,238,239,243, + 240,225,227,101,128,255, 65,240,229,242,243,225,238,100,130, 0, + 38, 47,213, 47,225,237,239,238,239,243,240,225,227,101,128,255, + 6,243,237,225,236,108,128,247, 38,243,241,245,225,242,101,128, + 51,194,110, 4, 47,252, 48, 7, 48,129, 48,139,226,239,240,239, + 237,239,230,111,128, 49, 34,103, 4, 48, 17, 48, 28, 48, 42, 48, + 121,226,239,240,239,237,239,230,111,128, 49, 36,235,232,225,238, + 235,232,245,244,232,225,105,128, 14, 90,236,101,131, 34, 32, 48, + 53, 48,106, 48,113,226,242,225,227,235,229,116, 2, 48, 65, 48, + 85,236,229,230,116,129, 48, 8, 48, 74,246,229,242,244,233,227, + 225,108,128,254, 63,242,233,231,232,116,129, 48, 9, 48, 95,246, + 229,242,244,233,227,225,108,128,254, 64,236,229,230,116,128, 35, + 41,242,233,231,232,116,128, 35, 42,243,244,242,239,109,128, 33, + 43,239,244,229,236,229,233, 97,128, 3,135,117, 2, 48,145, 48, + 157,228,225,244,244,225,228,229,246, 97,128, 9, 82,243,246,225, + 242, 97, 3, 48,169, 48,179, 48,186,226,229,238,231,225,236,105, + 128, 9,130,228,229,246, 97,128, 9, 2,231,245,234,225,242,225, + 244,105,128, 10,130,239,231,239,238,229,107,128, 1, 5,112, 3, + 48,214, 48,238, 49, 12, 97, 2, 48,220, 48,232,225,244,239,243, + 241,245,225,242,101,128, 51, 0,242,229,110,128, 36,156,239,243, + 244,242,239,240,232,101, 2, 48,251, 49, 6,225,242,237,229,238, + 233,225,110,128, 5, 90,237,239,100,128, 2,188,112, 2, 49, 18, + 49, 23,236,101,128,248,255,242,111, 2, 49, 30, 49, 38,225,227, + 232,229,115,128, 34, 80,120, 2, 49, 44, 49, 64,229,241,245,225, + 108,129, 34, 72, 49, 54,239,242,233,237,225,231,101,128, 34, 82, + 233,237,225,244,229,236,249,229,241,245,225,108,128, 34, 69,114, + 4, 49, 89, 49,116, 49,120, 49,165,225,229, 97, 2, 49, 97, 49, + 107,229,235,239,242,229,225,110,128, 49,142,235,239,242,229,225, + 110,128, 49,141, 99,128, 35, 18,105, 2, 49,126, 49,140,231,232, + 244,232,225,236,230,242,233,238,103,128, 30,154,238,103,130, 0, + 229, 49,149, 49,157,225,227,245,244,101,128, 1,251,226,229,236, + 239,119,128, 30, 1,242,239,119, 8, 49,185, 49,192, 50, 65, 50, + 131, 50,181, 50,236, 51, 3, 51, 78,226,239,244,104,128, 33,148, + 100, 3, 49,200, 49,239, 50, 30,225,243,104, 4, 49,212, 49,219, + 49,226, 49,234,228,239,247,110,128, 33,227,236,229,230,116,128, + 33,224,242,233,231,232,116,128, 33,226,245,112,128, 33,225,226, + 108, 5, 49,252, 50, 3, 50, 10, 50, 17, 50, 25,226,239,244,104, + 128, 33,212,228,239,247,110,128, 33,211,236,229,230,116,128, 33, + 208,242,233,231,232,116,128, 33,210,245,112,128, 33,209,239,247, + 110,131, 33,147, 50, 42, 50, 49, 50, 57,236,229,230,116,128, 33, + 153,242,233,231,232,116,128, 33,152,247,232,233,244,101,128, 33, + 233,104, 2, 50, 71, 50,122,229,225,100, 4, 50, 83, 50, 93, 50, + 103, 50,114,228,239,247,238,237,239,100,128, 2,197,236,229,230, + 244,237,239,100,128, 2,194,242,233,231,232,244,237,239,100,128, + 2,195,245,240,237,239,100,128, 2,196,239,242,233,250,229,120, + 128,248,231,236,229,230,116,131, 33,144, 50,144, 50,161, 50,173, + 228,226,108,129, 33,208, 50,152,243,244,242,239,235,101,128, 33, + 205,239,246,229,242,242,233,231,232,116,128, 33,198,247,232,233, + 244,101,128, 33,230,242,233,231,232,116,132, 33,146, 50,197, 50, + 209, 50,217, 50,228,228,226,236,243,244,242,239,235,101,128, 33, + 207,232,229,225,246,121,128, 39,158,239,246,229,242,236,229,230, + 116,128, 33,196,247,232,233,244,101,128, 33,232,244,225, 98, 2, + 50,244, 50,251,236,229,230,116,128, 33,228,242,233,231,232,116, + 128, 33,229,245,112,132, 33,145, 51, 16, 51, 44, 51, 62, 51, 70, + 100, 2, 51, 22, 51, 34,110,129, 33,149, 51, 28,226,243,101,128, + 33,168,239,247,238,226,225,243,101,128, 33,168,236,229,230,116, + 129, 33,150, 51, 53,239,230,228,239,247,110,128, 33,197,242,233, + 231,232,116,128, 33,151,247,232,233,244,101,128, 33,231,246,229, + 242,244,229,120,128,248,230,115, 5, 51, 99, 51,175, 51,220, 52, + 47, 52, 57, 99, 2, 51,105, 51,157,233,105, 2, 51,112, 51,135, + 227,233,242,227,245,109,129, 0, 94, 51,123,237,239,238,239,243, + 240,225,227,101,128,255, 62,244,233,236,228,101,129, 0,126, 51, + 145,237,239,238,239,243,240,225,227,101,128,255, 94,242,233,240, + 116,129, 2, 81, 51,166,244,245,242,238,229,100,128, 2, 82,237, + 225,236,108, 2, 51,184, 51,195,232,233,242,225,231,225,238, 97, + 128, 48, 65,235,225,244,225,235,225,238, 97,129, 48,161, 51,208, + 232,225,236,230,247,233,228,244,104,128,255,103,244,229,242,233, + 115, 2, 51,230, 52, 43,107,131, 0, 42, 51,240, 52, 12, 52, 35, + 97, 2, 51,246, 52, 4,236,244,239,238,229,225,242,225,226,233, + 99,128, 6,109,242,225,226,233, 99,128, 6,109,109, 2, 52, 18, + 52, 24,225,244,104,128, 34, 23,239,238,239,243,240,225,227,101, + 128,255, 10,243,237,225,236,108,128,254, 97,109,128, 32, 66,245, + 240,229,242,233,239,114,128,246,233,249,237,240,244,239,244,233, + 227,225,236,236,249,229,241,245,225,108,128, 34, 67,116,132, 0, + 64, 52, 89, 52, 96, 52,108, 52,116,233,236,228,101,128, 0,227, + 237,239,238,239,243,240,225,227,101,128,255, 32,243,237,225,236, + 108,128,254,107,245,242,238,229,100,128, 2, 80,117, 6, 52,138, + 52,163, 52,170, 52,195, 52,215, 52,231, 98, 2, 52,144, 52,153, + 229,238,231,225,236,105,128, 9,148,239,240,239,237,239,230,111, + 128, 49, 32,228,229,246, 97,128, 9, 20,231,117, 2, 52,177, 52, + 186,234,225,242,225,244,105,128, 10,148,242,237,245,235,232,105, + 128, 10, 20,236,229,238,231,244,232,237,225,242,235,226,229,238, + 231,225,236,105,128, 9,215,237,225,244,242,225,231,245,242,237, + 245,235,232,105,128, 10, 76,246,239,247,229,236,243,233,231,110, + 3, 52,247, 53, 1, 53, 8,226,229,238,231,225,236,105,128, 9, + 204,228,229,246, 97,128, 9, 76,231,245,234,225,242,225,244,105, + 128, 10,204,246,225,231,242,225,232,225,228,229,246, 97,128, 9, + 61,121, 2, 53, 39, 53, 51,226,225,242,237,229,238,233,225,110, + 128, 5, 97,233,110,130, 5,226, 53, 60, 53, 75,225,236,244,239, + 238,229,232,229,226,242,229,119,128,251, 32,232,229,226,242,229, + 119,128, 5,226, 98,144, 0, 98, 53,120, 53,255, 54, 10, 54, 19, + 54, 44, 55, 85, 55,147, 55,220, 57,146, 57,158, 57,201, 57,209, + 57,219, 59, 89, 59,113, 59,122, 97, 7, 53,136, 53,146, 53,170, + 53,177, 53,202, 53,226, 53,237,226,229,238,231,225,236,105,128, + 9,172,227,235,243,236,225,243,104,129, 0, 92, 53,158,237,239, + 238,239,243,240,225,227,101,128,255, 60,228,229,246, 97,128, 9, + 44,231,117, 2, 53,184, 53,193,234,225,242,225,244,105,128, 10, + 172,242,237,245,235,232,105,128, 10, 44,104, 2, 53,208, 53,218, + 233,242,225,231,225,238, 97,128, 48,112,244,244,232,225,105,128, + 14, 63,235,225,244,225,235,225,238, 97,128, 48,208,114,129, 0, + 124, 53,243,237,239,238,239,243,240,225,227,101,128,255, 92,226, + 239,240,239,237,239,230,111,128, 49, 5,227,233,242,227,236,101, + 128, 36,209,228,239,116, 2, 54, 27, 54, 36,225,227,227,229,238, + 116,128, 30, 3,226,229,236,239,119,128, 30, 5,101, 6, 54, 58, + 54, 79, 54,102, 54,244, 54,255, 55, 11,225,237,229,228,243,233, + 248,244,229,229,238,244,232,238,239,244,229,115,128, 38,108, 99, + 2, 54, 85, 54, 92,225,245,243,101,128, 34, 53,249,242,233,236, + 236,233, 99,128, 4, 49,104, 5, 54,114, 54,123, 54,137, 54,167, + 54,226,225,242,225,226,233, 99,128, 6, 40,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,144,105, 2, 54,143, 54,158,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,145,242,225, + 231,225,238, 97,128, 48,121,237,101, 2, 54,174, 54,187,228,233, + 225,236,225,242,225,226,233, 99,128,254,146,229,237,105, 2, 54, + 195, 54,210,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 252,159,243,239,236,225,244,229,228,225,242,225,226,233, 99,128, + 252, 8,238,239,239,238,230,233,238,225,236,225,242,225,226,233, + 99,128,252,109,235,225,244,225,235,225,238, 97,128, 48,217,238, + 225,242,237,229,238,233,225,110,128, 5, 98,116,132, 5,209, 55, + 23, 55, 43, 55, 63, 55, 72, 97,129, 3,178, 55, 29,243,249,237, + 226,239,236,231,242,229,229,107,128, 3,208,228,225,231,229,243, + 104,129,251, 49, 55, 54,232,229,226,242,229,119,128,251, 49,232, + 229,226,242,229,119,128, 5,209,242,225,230,229,232,229,226,242, + 229,119,128,251, 76,104, 2, 55, 91, 55,141, 97, 3, 55, 99, 55, + 109, 55,116,226,229,238,231,225,236,105,128, 9,173,228,229,246, + 97,128, 9, 45,231,117, 2, 55,123, 55,132,234,225,242,225,244, + 105,128, 10,173,242,237,245,235,232,105,128, 10, 45,239,239,107, + 128, 2, 83,105, 5, 55,159, 55,170, 55,181, 55,195, 55,209,232, + 233,242,225,231,225,238, 97,128, 48,115,235,225,244,225,235,225, + 238, 97,128, 48,211,236,225,226,233,225,236,227,236,233,227,107, + 128, 2,152,238,228,233,231,245,242,237,245,235,232,105,128, 10, + 2,242,245,243,241,245,225,242,101,128, 51, 49,108, 3, 55,228, + 57,129, 57,140, 97, 2, 55,234, 57,124,227,107, 6, 55,249, 56, + 2, 56, 39, 56,188, 56,243, 57, 39,227,233,242,227,236,101,128, + 37,207,100, 2, 56, 8, 56, 17,233,225,237,239,238,100,128, 37, + 198,239,247,238,240,239,233,238,244,233,238,231,244,242,233,225, + 238,231,236,101,128, 37,188,108, 2, 56, 45, 56,148,101, 2, 56, + 51, 56, 87,230,244,240,239,233,238,244,233,238,103, 2, 56, 66, + 56, 76,240,239,233,238,244,229,114,128, 37,196,244,242,233,225, + 238,231,236,101,128, 37,192,238,244,233,227,245,236,225,242,226, + 242,225,227,235,229,116, 2, 56,107, 56,127,236,229,230,116,129, + 48, 16, 56,116,246,229,242,244,233,227,225,108,128,254, 59,242, + 233,231,232,116,129, 48, 17, 56,137,246,229,242,244,233,227,225, + 108,128,254, 60,239,247,229,114, 2, 56,157, 56,172,236,229,230, + 244,244,242,233,225,238,231,236,101,128, 37,227,242,233,231,232, + 244,244,242,233,225,238,231,236,101,128, 37,226,114, 2, 56,194, + 56,205,229,227,244,225,238,231,236,101,128, 37,172,233,231,232, + 244,240,239,233,238,244,233,238,103, 2, 56,222, 56,232,240,239, + 233,238,244,229,114,128, 37,186,244,242,233,225,238,231,236,101, + 128, 37,182,115, 3, 56,251, 57, 25, 57, 33,109, 2, 57, 1, 57, + 13,225,236,236,243,241,245,225,242,101,128, 37,170,233,236,233, + 238,231,230,225,227,101,128, 38, 59,241,245,225,242,101,128, 37, + 160,244,225,114,128, 38, 5,245,240,112, 2, 57, 47, 57, 85,229, + 114, 2, 57, 54, 57, 69,236,229,230,244,244,242,233,225,238,231, + 236,101,128, 37,228,242,233,231,232,244,244,242,233,225,238,231, + 236,101,128, 37,229,239,233,238,244,233,238,103, 2, 57, 97, 57, + 113,243,237,225,236,236,244,242,233,225,238,231,236,101,128, 37, + 180,244,242,233,225,238,231,236,101,128, 37,178,238,107,128, 36, + 35,233,238,229,226,229,236,239,119,128, 30, 7,239,227,107,128, + 37,136,237,239,238,239,243,240,225,227,101,128,255, 66,111, 3, + 57,166, 57,179, 57,190,226,225,233,237,225,233,244,232,225,105, + 128, 14, 26,232,233,242,225,231,225,238, 97,128, 48,124,235,225, + 244,225,235,225,238, 97,128, 48,220,240,225,242,229,110,128, 36, + 157,241,243,241,245,225,242,101,128, 51,195,114, 4, 57,229, 58, + 223, 59, 40, 59, 79,225, 99, 2, 57,236, 58,130,101, 3, 57,244, + 57,249, 58, 61,229,120,128,248,244,236,229,230,116,133, 0,123, + 58, 10, 58, 15, 58, 37, 58, 45, 58, 50,226,116,128,248,243,109, + 2, 58, 21, 58, 26,233,100,128,248,242,239,238,239,243,240,225, + 227,101,128,255, 91,243,237,225,236,108,128,254, 91,244,112,128, + 248,241,246,229,242,244,233,227,225,108,128,254, 55,242,233,231, + 232,116,133, 0,125, 58, 79, 58, 84, 58,106, 58,114, 58,119,226, + 116,128,248,254,109, 2, 58, 90, 58, 95,233,100,128,248,253,239, + 238,239,243,240,225,227,101,128,255, 93,243,237,225,236,108,128, + 254, 92,244,112,128,248,252,246,229,242,244,233,227,225,108,128, + 254, 56,235,229,116, 2, 58,138, 58,180,236,229,230,116,132, 0, + 91, 58,153, 58,158, 58,163, 58,175,226,116,128,248,240,229,120, + 128,248,239,237,239,238,239,243,240,225,227,101,128,255, 59,244, + 112,128,248,238,242,233,231,232,116,132, 0, 93, 58,196, 58,201, + 58,206, 58,218,226,116,128,248,251,229,120,128,248,250,237,239, + 238,239,243,240,225,227,101,128,255, 61,244,112,128,248,249,229, + 246,101,131, 2,216, 58,235, 58,246, 58,252,226,229,236,239,247, + 227,237, 98,128, 3, 46,227,237, 98,128, 3, 6,233,238,246,229, + 242,244,229,100, 3, 59, 11, 59, 22, 59, 28,226,229,236,239,247, + 227,237, 98,128, 3, 47,227,237, 98,128, 3, 17,228,239,245,226, + 236,229,227,237, 98,128, 3, 97,233,228,231,101, 2, 59, 49, 59, + 60,226,229,236,239,247,227,237, 98,128, 3, 42,233,238,246,229, + 242,244,229,228,226,229,236,239,247,227,237, 98,128, 3, 58,239, + 235,229,238,226,225,114,128, 0,166,115, 2, 59, 95, 59,103,244, + 242,239,235,101,128, 1,128,245,240,229,242,233,239,114,128,246, + 234,244,239,240,226,225,114,128, 1,131,117, 3, 59,130, 59,141, + 59,152,232,233,242,225,231,225,238, 97,128, 48,118,235,225,244, + 225,235,225,238, 97,128, 48,214,236,108, 2, 59,159, 59,189,229, + 116,130, 32, 34, 59,168, 59,178,233,238,246,229,242,243,101,128, + 37,216,239,240,229,242,225,244,239,114,128, 34, 25,243,229,249, + 101,128, 37,206, 99,143, 0, 99, 59,230, 60,179, 60,190, 60,254, + 61, 29, 61,122, 63, 33, 64, 17, 64,117, 64,166, 67,158, 67,166, + 67,176, 67,188, 67,221, 97, 9, 59,250, 60, 5, 60, 15, 60, 22, + 60, 29, 60, 54, 60, 64, 60,116, 60,125,225,242,237,229,238,233, + 225,110,128, 5,110,226,229,238,231,225,236,105,128, 9,154,227, + 245,244,101,128, 1, 7,228,229,246, 97,128, 9, 26,231,117, 2, + 60, 36, 60, 45,234,225,242,225,244,105,128, 10,154,242,237,245, + 235,232,105,128, 10, 26,236,243,241,245,225,242,101,128, 51,136, + 238,228,242,225,226,233,238,228,117, 4, 60, 82, 60, 92, 60, 98, + 60,105,226,229,238,231,225,236,105,128, 9,129,227,237, 98,128, + 3, 16,228,229,246, 97,128, 9, 1,231,245,234,225,242,225,244, + 105,128, 10,129,240,243,236,239,227,107,128, 33,234,114, 3, 60, + 133, 60,139, 60,165,229,239,102,128, 33, 5,239,110,130, 2,199, + 60,148, 60,159,226,229,236,239,247,227,237, 98,128, 3, 44,227, + 237, 98,128, 3, 12,242,233,225,231,229,242,229,244,245,242,110, + 128, 33,181,226,239,240,239,237,239,230,111,128, 49, 24, 99, 4, + 60,200, 60,207, 60,226, 60,248,225,242,239,110,128, 1, 13,229, + 228,233,236,236, 97,129, 0,231, 60,218,225,227,245,244,101,128, + 30, 9,233,242, 99, 2, 60,234, 60,239,236,101,128, 36,210,245, + 237,230,236,229,120,128, 1, 9,245,242,108,128, 2, 85,100, 2, + 61, 4, 61, 20,239,116,129, 1, 11, 61, 11,225,227,227,229,238, + 116,128, 1, 11,243,241,245,225,242,101,128, 51,197,101, 2, 61, + 35, 61, 51,228,233,236,236, 97,129, 0,184, 61, 45,227,237, 98, + 128, 3, 39,238,116,132, 0,162, 61, 64, 61, 88, 61,100, 61,111, + 105, 2, 61, 70, 61, 78,231,242,225,228,101,128, 33, 3,238,230, + 229,242,233,239,114,128,246,223,237,239,238,239,243,240,225,227, + 101,128,255,224,239,236,228,243,244,249,236,101,128,247,162,243, + 245,240,229,242,233,239,114,128,246,224,104, 5, 61,134, 61,197, + 61,208, 62,136, 62,228, 97, 4, 61,144, 61,155, 61,165, 61,172, + 225,242,237,229,238,233,225,110,128, 5,121,226,229,238,231,225, + 236,105,128, 9,155,228,229,246, 97,128, 9, 27,231,117, 2, 61, + 179, 61,188,234,225,242,225,244,105,128, 10,155,242,237,245,235, + 232,105,128, 10, 27,226,239,240,239,237,239,230,111,128, 49, 20, + 101, 6, 61,222, 61,242, 62, 10, 62, 78, 62, 90, 62,111,225,226, + 235,232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, + 4,189, 99, 2, 61,248, 62, 0,235,237,225,242,107,128, 39, 19, + 249,242,233,236,236,233, 99,128, 4, 71,100, 2, 62, 16, 62, 60, + 229,243,227,229,238,228,229,114, 2, 62, 29, 62, 49,225,226,235, + 232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, 4, + 191,227,249,242,233,236,236,233, 99,128, 4,183,233,229,242,229, + 243,233,243,227,249,242,233,236,236,233, 99,128, 4,245,232,225, + 242,237,229,238,233,225,110,128, 5,115,235,232,225,235,225,243, + 243,233,225,238,227,249,242,233,236,236,233, 99,128, 4,204,246, + 229,242,244,233,227,225,236,243,244,242,239,235,229,227,249,242, + 233,236,236,233, 99,128, 4,185,105,129, 3,199, 62,142,229,245, + 227,104, 4, 62,155, 62,190, 62,205, 62,214, 97, 2, 62,161, 62, + 176,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,119, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 23,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,105,235,239,242, + 229,225,110,128, 49, 74,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 9,111, 2, 62,234, 63, 28,227,104, 3, 62,243, 63, + 9, 63, 19,225,110, 2, 62,250, 63, 2,231,244,232,225,105,128, + 14, 10,244,232,225,105,128, 14, 8,233,238,231,244,232,225,105, + 128, 14, 9,239,229,244,232,225,105,128, 14, 12,239,107,128, 1, + 136,105, 2, 63, 39, 63,141,229,245, 99, 5, 63, 53, 63, 88, 63, + 103, 63,112, 63,126, 97, 2, 63, 59, 63, 74,227,233,242,227,236, + 229,235,239,242,229,225,110,128, 50,118,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 22,227,233,242,227,236,229,235,239, + 242,229,225,110,128, 50,104,235,239,242,229,225,110,128, 49, 72, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 8,245,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 28,242, 99, 2, + 63,148, 63,243,236,101,132, 37,203, 63,161, 63,172, 63,177, 63, + 201,237,245,236,244,233,240,236,121,128, 34,151,239,116,128, 34, + 153,112, 2, 63,183, 63,189,236,245,115,128, 34,149,239,243,244, + 225,236,237,225,242,107,128, 48, 54,247,233,244,104, 2, 63,210, + 63,226,236,229,230,244,232,225,236,230,226,236,225,227,107,128, + 37,208,242,233,231,232,244,232,225,236,230,226,236,225,227,107, + 128, 37,209,245,237,230,236,229,120,130, 2,198, 64, 0, 64, 11, + 226,229,236,239,247,227,237, 98,128, 3, 45,227,237, 98,128, 3, + 2,108, 3, 64, 25, 64, 31, 64, 85,229,225,114,128, 35, 39,233, + 227,107, 4, 64, 43, 64, 54, 64, 63, 64, 73,225,236,246,229,239, + 236,225,114,128, 1,194,228,229,238,244,225,108,128, 1,192,236, + 225,244,229,242,225,108,128, 1,193,242,229,244,242,239,230,236, + 229,120,128, 1,195,245, 98,129, 38, 99, 64, 92,243,245,233,116, + 2, 64,101, 64,109,226,236,225,227,107,128, 38, 99,247,232,233, + 244,101,128, 38,103,109, 3, 64,125, 64,139, 64,150,227,245,226, + 229,228,243,241,245,225,242,101,128, 51,164,239,238,239,243,240, + 225,227,101,128,255, 67,243,241,245,225,242,229,228,243,241,245, + 225,242,101,128, 51,160,111, 8, 64,184, 64,195, 65, 26, 65,224, + 66,253, 67, 28, 67,135, 67,144,225,242,237,229,238,233,225,110, + 128, 5,129,236,239,110,131, 0, 58, 64,207, 64,232, 64,251,237, + 239,110, 2, 64,215, 64,223,229,244,225,242,121,128, 32,161,239, + 243,240,225,227,101,128,255, 26,115, 2, 64,238, 64,244,233,231, + 110,128, 32,161,237,225,236,108,128,254, 85,244,242,233,225,238, + 231,245,236,225,114, 2, 65, 10, 65, 20,232,225,236,230,237,239, + 100,128, 2,209,237,239,100,128, 2,208,109, 2, 65, 32, 65,217, + 237, 97,134, 0, 44, 65, 49, 65,113, 65,124, 65,136, 65,166, 65, + 189, 97, 3, 65, 57, 65, 83, 65, 91,226,239,246,101, 2, 65, 66, + 65, 72,227,237, 98,128, 3, 19,242,233,231,232,244,227,237, 98, + 128, 3, 21,227,227,229,238,116,128,246,195,114, 2, 65, 97, 65, + 104,225,226,233, 99,128, 6, 12,237,229,238,233,225,110,128, 5, + 93,233,238,230,229,242,233,239,114,128,246,225,237,239,238,239, + 243,240,225,227,101,128,255, 12,242,229,246,229,242,243,229,100, + 2, 65,149, 65,160,225,226,239,246,229,227,237, 98,128, 3, 20, + 237,239,100,128, 2,189,115, 2, 65,172, 65,179,237,225,236,108, + 128,254, 80,245,240,229,242,233,239,114,128,246,226,244,245,242, + 238,229,100, 2, 65,200, 65,211,225,226,239,246,229,227,237, 98, + 128, 3, 18,237,239,100,128, 2,187,240,225,243,115,128, 38, 60, + 110, 2, 65,230, 65,239,231,242,245,229,238,116,128, 34, 69,116, + 2, 65,245, 66, 3,239,245,242,233,238,244,229,231,242,225,108, + 128, 34, 46,242,239,108,142, 35, 3, 66, 37, 66, 43, 66, 58, 66, + 73, 66,117, 66,162, 66,176, 66,181, 66,186, 66,191, 66,197, 66, + 202, 66,243, 66,248,193,195, 75,128, 0, 6, 66, 2, 66, 49, 66, + 54,197, 76,128, 0, 7, 83,128, 0, 8, 67, 2, 66, 64, 66, 69, + 193, 78,128, 0, 24, 82,128, 0, 13, 68, 3, 66, 81, 66,107, 66, + 112, 67, 4, 66, 91, 66, 95, 66, 99, 66,103, 49,128, 0, 17, 50, + 128, 0, 18, 51,128, 0, 19, 52,128, 0, 20,197, 76,128, 0,127, + 204, 69,128, 0, 16, 69, 5, 66,129, 66,133, 66,138, 66,143, 66, + 148, 77,128, 0, 25,206, 81,128, 0, 5,207, 84,128, 0, 4,211, + 67,128, 0, 27, 84, 2, 66,154, 66,158, 66,128, 0, 23, 88,128, + 0, 3, 70, 2, 66,168, 66,172, 70,128, 0, 12, 83,128, 0, 28, + 199, 83,128, 0, 29,200, 84,128, 0, 9,204, 70,128, 0, 10,206, + 193, 75,128, 0, 21,210, 83,128, 0, 30, 83, 5, 66,214, 66,218, + 66,228, 66,233, 66,238, 73,128, 0, 15, 79,129, 0, 14, 66,224, + 84,128, 0, 2,212, 88,128, 0, 1,213, 66,128, 0, 26,217, 78, + 128, 0, 22,213, 83,128, 0, 31,214, 84,128, 0, 11,240,249,242, + 233,231,232,116,129, 0,169, 67, 9,115, 2, 67, 15, 67, 21,225, + 238,115,128,248,233,229,242,233,102,128,246,217,114, 2, 67, 34, + 67,118,238,229,242,226,242,225,227,235,229,116, 2, 67, 49, 67, + 83,236,229,230,116,130, 48, 12, 67, 60, 67, 72,232,225,236,230, + 247,233,228,244,104,128,255, 98,246,229,242,244,233,227,225,108, + 128,254, 65,242,233,231,232,116,130, 48, 13, 67, 95, 67,107,232, + 225,236,230,247,233,228,244,104,128,255, 99,246,229,242,244,233, + 227,225,108,128,254, 66,240,239,242,225,244,233,239,238,243,241, + 245,225,242,101,128, 51,127,243,241,245,225,242,101,128, 51,199, + 246,229,242,235,231,243,241,245,225,242,101,128, 51,198,240,225, + 242,229,110,128, 36,158,242,245,250,229,233,242,111,128, 32,162, + 243,244,242,229,244,227,232,229,100,128, 2,151,245,114, 2, 67, + 195, 67,213,236,121, 2, 67,202, 67,208,225,238,100,128, 34,207, + 239,114,128, 34,206,242,229,238,227,121,128, 0,164,249,114, 4, + 67,232, 67,240, 67,247, 67,255,194,242,229,246,101,128,246,209, + 198,236,229,120,128,246,210,226,242,229,246,101,128,246,212,230, + 236,229,120,128,246,213,100,146, 0,100, 68, 46, 69,184, 70,208, + 71, 12, 71,188, 72,142, 72,204, 73,133, 73,146, 73,155, 73,181, + 73,206, 73,215, 75, 26, 75, 34, 75, 45, 75, 65, 75, 93, 97, 11, + 68, 70, 68, 81, 68, 91, 68,163, 68,226, 68,237, 68,248, 69, 61, + 69,123, 69,129, 69,159,225,242,237,229,238,233,225,110,128, 5, + 100,226,229,238,231,225,236,105,128, 9,166,100, 5, 68,103, 68, + 112, 68,118, 68,132, 68,148,225,242,225,226,233, 99,128, 6, 54, + 229,246, 97,128, 9, 38,230,233,238,225,236,225,242,225,226,233, + 99,128,254,190,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,191,237,229,228,233,225,236,225,242,225,226,233, 99, + 128,254,192,103, 3, 68,171, 68,188, 68,202,229,243,104,129, 5, + 188, 68,179,232,229,226,242,229,119,128, 5,188,231,229,114,129, + 32, 32, 68,196,228,226,108,128, 32, 33,117, 2, 68,208, 68,217, + 234,225,242,225,244,105,128, 10,166,242,237,245,235,232,105,128, + 10, 38,232,233,242,225,231,225,238, 97,128, 48, 96,235,225,244, + 225,235,225,238, 97,128, 48,192,108, 3, 69, 0, 69, 9, 69, 47, + 225,242,225,226,233, 99,128, 6, 47,229,116,130, 5,211, 69, 18, + 69, 38,228,225,231,229,243,104,129,251, 51, 69, 29,232,229,226, + 242,229,119,128,251, 51,232,229,226,242,229,119,128, 5,211,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,170,237,237, 97, + 3, 69, 71, 69, 80, 69, 92,225,242,225,226,233, 99,128, 6, 79, + 236,239,247,225,242,225,226,233, 99,128, 6, 79,244,225,238, 97, + 2, 69,101, 69,115,236,244,239,238,229,225,242,225,226,233, 99, + 128, 6, 76,242,225,226,233, 99,128, 6, 76,238,228, 97,128, 9, + 100,242,231, 97, 2, 69,137, 69,146,232,229,226,242,229,119,128, + 5,167,236,229,230,244,232,229,226,242,229,119,128, 5,167,243, + 233,225,240,238,229,245,237,225,244,225,227,249,242,233,236,236, + 233,227,227,237, 98,128, 4,133, 98, 3, 69,192, 70,189, 70,199, + 108, 9, 69,212, 69,220, 70, 77, 70, 85, 70,101, 70,112, 70,130, + 70,144, 70,155,199,242,225,246,101,128,246,211, 97, 2, 69,226, + 70, 27,238,231,236,229,226,242,225,227,235,229,116, 2, 69,242, + 70, 6,236,229,230,116,129, 48, 10, 69,251,246,229,242,244,233, + 227,225,108,128,254, 61,242,233,231,232,116,129, 48, 11, 70, 16, + 246,229,242,244,233,227,225,108,128,254, 62,114, 2, 70, 33, 70, + 54,227,232,233,238,246,229,242,244,229,228,226,229,236,239,247, + 227,237, 98,128, 3, 43,242,239,119, 2, 70, 62, 70, 69,236,229, + 230,116,128, 33,212,242,233,231,232,116,128, 33,210,228,225,238, + 228, 97,128, 9,101,231,242,225,246,101,129,246,214, 70, 95,227, + 237, 98,128, 3, 15,233,238,244,229,231,242,225,108,128, 34, 44, + 236,239,247,236,233,238,101,129, 32, 23, 70,124,227,237, 98,128, + 3, 51,239,246,229,242,236,233,238,229,227,237, 98,128, 3, 63, + 240,242,233,237,229,237,239,100,128, 2,186,246,229,242,244,233, + 227,225,108, 2, 70,168, 70,174,226,225,114,128, 32, 22,236,233, + 238,229,225,226,239,246,229,227,237, 98,128, 3, 14,239,240,239, + 237,239,230,111,128, 49, 9,243,241,245,225,242,101,128, 51,200, + 99, 4, 70,218, 70,225, 70,234, 71, 5,225,242,239,110,128, 1, + 15,229,228,233,236,236, 97,128, 30, 17,233,242, 99, 2, 70,242, + 70,247,236,101,128, 36,211,245,237,230,236,229,248,226,229,236, + 239,119,128, 30, 19,242,239,225,116,128, 1, 17,100, 4, 71, 22, + 71,103, 71,113, 71,164, 97, 4, 71, 32, 71, 42, 71, 49, 71, 74, + 226,229,238,231,225,236,105,128, 9,161,228,229,246, 97,128, 9, + 33,231,117, 2, 71, 56, 71, 65,234,225,242,225,244,105,128, 10, + 161,242,237,245,235,232,105,128, 10, 33,108, 2, 71, 80, 71, 89, + 225,242,225,226,233, 99,128, 6,136,230,233,238,225,236,225,242, + 225,226,233, 99,128,251,137,228,232,225,228,229,246, 97,128, 9, + 92,232, 97, 3, 71,122, 71,132, 71,139,226,229,238,231,225,236, + 105,128, 9,162,228,229,246, 97,128, 9, 34,231,117, 2, 71,146, + 71,155,234,225,242,225,244,105,128, 10,162,242,237,245,235,232, + 105,128, 10, 34,239,116, 2, 71,171, 71,180,225,227,227,229,238, + 116,128, 30, 11,226,229,236,239,119,128, 30, 13,101, 8, 71,206, + 72, 3, 72, 10, 72, 35, 72, 45, 72, 56, 72,101, 72,137, 99, 2, + 71,212, 71,249,233,237,225,236,243,229,240,225,242,225,244,239, + 114, 2, 71,230, 71,239,225,242,225,226,233, 99,128, 6,107,240, + 229,242,243,233,225,110,128, 6,107,249,242,233,236,236,233, 99, + 128, 4, 52,231,242,229,101,128, 0,176,232,105, 2, 72, 17, 72, + 26,232,229,226,242,229,119,128, 5,173,242,225,231,225,238, 97, + 128, 48,103,233,227,239,240,244,233, 99,128, 3,239,235,225,244, + 225,235,225,238, 97,128, 48,199,108, 2, 72, 62, 72, 85,229,244, + 101, 2, 72, 70, 72, 77,236,229,230,116,128, 35, 43,242,233,231, + 232,116,128, 35, 38,244, 97,129, 3,180, 72, 92,244,245,242,238, + 229,100,128, 1,141,238,239,237,233,238,225,244,239,242,237,233, + 238,245,243,239,238,229,238,245,237,229,242,225,244,239,242,226, + 229,238,231,225,236,105,128, 9,248,250,104,128, 2,164,104, 2, + 72,148, 72,198, 97, 3, 72,156, 72,166, 72,173,226,229,238,231, + 225,236,105,128, 9,167,228,229,246, 97,128, 9, 39,231,117, 2, + 72,180, 72,189,234,225,242,225,244,105,128, 10,167,242,237,245, + 235,232,105,128, 10, 39,239,239,107,128, 2, 87,105, 6, 72,218, + 73, 11, 73, 71, 73, 82, 73, 93, 73,103, 97, 2, 72,224, 72,246, + 236,249,244,233,235,225,244,239,238,239,115,129, 3,133, 72,240, + 227,237, 98,128, 3, 68,237,239,238,100,129, 38,102, 72,255,243, + 245,233,244,247,232,233,244,101,128, 38, 98,229,242,229,243,233, + 115,133, 0,168, 73, 30, 73, 38, 73, 49, 73, 55, 73, 63,225,227, + 245,244,101,128,246,215,226,229,236,239,247,227,237, 98,128, 3, + 36,227,237, 98,128, 3, 8,231,242,225,246,101,128,246,216,244, + 239,238,239,115,128, 3,133,232,233,242,225,231,225,238, 97,128, + 48, 98,235,225,244,225,235,225,238, 97,128, 48,194,244,244,239, + 237,225,242,107,128, 48, 3,246,105, 2, 73,110, 73,121,228,101, + 129, 0,247, 73,117,115,128, 34, 35,243,233,239,238,243,236,225, + 243,104,128, 34, 21,234,229,227,249,242,233,236,236,233, 99,128, + 4, 82,235,243,232,225,228,101,128, 37,147,108, 2, 73,161, 73, + 172,233,238,229,226,229,236,239,119,128, 30, 15,243,241,245,225, + 242,101,128, 51,151,109, 2, 73,187, 73,195,225,227,242,239,110, + 128, 1, 17,239,238,239,243,240,225,227,101,128,255, 68,238,226, + 236,239,227,107,128, 37,132,111, 10, 73,237, 73,249, 74, 3, 74, + 14, 74, 25, 74, 97, 74,102, 74,113, 74,228, 74,254,227,232,225, + 228,225,244,232,225,105,128, 14, 14,228,229,235,244,232,225,105, + 128, 14, 20,232,233,242,225,231,225,238, 97,128, 48,105,235,225, + 244,225,235,225,238, 97,128, 48,201,236,236,225,114,132, 0, 36, + 74, 40, 74, 51, 74, 63, 74, 74,233,238,230,229,242,233,239,114, + 128,246,227,237,239,238,239,243,240,225,227,101,128,255, 4,239, + 236,228,243,244,249,236,101,128,247, 36,115, 2, 74, 80, 74, 87, + 237,225,236,108,128,254,105,245,240,229,242,233,239,114,128,246, + 228,238,103,128, 32,171,242,245,243,241,245,225,242,101,128, 51, + 38,116, 6, 74,127, 74,144, 74,166, 74,177, 74,209, 74,216,225, + 227,227,229,238,116,129, 2,217, 74,138,227,237, 98,128, 3, 7, + 226,229,236,239,247, 99, 2, 74,155, 74,160,237, 98,128, 3, 35, + 239,237, 98,128, 3, 35,235,225,244,225,235,225,238, 97,128, 48, + 251,236,229,243,115, 2, 74,186, 74,190,105,128, 1, 49,106,129, + 246,190, 74,196,243,244,242,239,235,229,232,239,239,107,128, 2, + 132,237,225,244,104,128, 34,197,244,229,228,227,233,242,227,236, + 101,128, 37,204,245,226,236,229,249,239,228,240,225,244,225,104, + 129,251, 31, 74,245,232,229,226,242,229,119,128,251, 31,247,238, + 244,225,227,107, 2, 75, 9, 75, 20,226,229,236,239,247,227,237, + 98,128, 3, 30,237,239,100,128, 2,213,240,225,242,229,110,128, + 36,159,243,245,240,229,242,233,239,114,128,246,235,116, 2, 75, + 51, 75, 57,225,233,108,128, 2, 86,239,240,226,225,114,128, 1, + 140,117, 2, 75, 71, 75, 82,232,233,242,225,231,225,238, 97,128, + 48,101,235,225,244,225,235,225,238, 97,128, 48,197,122,132, 1, + 243, 75,105, 75,114, 75,133, 75,170,225,236,244,239,238,101,128, + 2,163, 99, 2, 75,120, 75,127,225,242,239,110,128, 1,198,245, + 242,108,128, 2,165,101, 2, 75,139, 75,159,225,226,235,232,225, + 243,233,225,238,227,249,242,233,236,236,233, 99,128, 4,225,227, + 249,242,233,236,236,233, 99,128, 4, 85,232,229,227,249,242,233, + 236,236,233, 99,128, 4, 95,101,151, 0,101, 75,233, 75,252, 76, + 30, 77, 4, 77, 66, 77, 99, 77,111, 77,134, 77,187, 79, 43, 79, + 101, 79,203, 80, 63, 80,198, 81, 17, 81, 48, 81,110, 81,163, 82, + 98, 82,231, 82,251, 83, 39, 83,130, 97, 2, 75,239, 75,246,227, + 245,244,101,128, 0,233,242,244,104,128, 38, 65, 98, 3, 76, 4, + 76, 13, 76, 23,229,238,231,225,236,105,128, 9,143,239,240,239, + 237,239,230,111,128, 49, 28,242,229,246,101,128, 1, 21, 99, 5, + 76, 42, 76,115, 76,129, 76,161, 76,250, 97, 2, 76, 48, 76,109, + 238,228,242, 97, 3, 76, 59, 76, 66, 76, 77,228,229,246, 97,128, + 9, 13,231,245,234,225,242,225,244,105,128, 10,141,246,239,247, + 229,236,243,233,231,110, 2, 76, 91, 76, 98,228,229,246, 97,128, + 9, 69,231,245,234,225,242,225,244,105,128, 10,197,242,239,110, + 128, 1, 27,229,228,233,236,236,225,226,242,229,246,101,128, 30, + 29,104, 2, 76,135, 76,146,225,242,237,229,238,233,225,110,128, + 5,101,249,233,247,238,225,242,237,229,238,233,225,110,128, 5, + 135,233,242, 99, 2, 76,169, 76,174,236,101,128, 36,212,245,237, + 230,236,229,120,134, 0,234, 76,195, 76,203, 76,211, 76,222, 76, + 230, 76,242,225,227,245,244,101,128, 30,191,226,229,236,239,119, + 128, 30, 25,228,239,244,226,229,236,239,119,128, 30,199,231,242, + 225,246,101,128, 30,193,232,239,239,235,225,226,239,246,101,128, + 30,195,244,233,236,228,101,128, 30,197,249,242,233,236,236,233, + 99,128, 4, 84,100, 4, 77, 14, 77, 24, 77, 30, 77, 40,226,236, + 231,242,225,246,101,128, 2, 5,229,246, 97,128, 9, 15,233,229, + 242,229,243,233,115,128, 0,235,239,116,130, 1, 23, 77, 49, 77, + 58,225,227,227,229,238,116,128, 1, 23,226,229,236,239,119,128, + 30,185,101, 2, 77, 72, 77, 83,231,245,242,237,245,235,232,105, + 128, 10, 15,237,225,244,242,225,231,245,242,237,245,235,232,105, + 128, 10, 71,230,227,249,242,233,236,236,233, 99,128, 4, 68,103, + 2, 77,117, 77,124,242,225,246,101,128, 0,232,245,234,225,242, + 225,244,105,128, 10,143,104, 4, 77,144, 77,155, 77,166, 77,176, + 225,242,237,229,238,233,225,110,128, 5,103,226,239,240,239,237, + 239,230,111,128, 49, 29,233,242,225,231,225,238, 97,128, 48, 72, + 239,239,235,225,226,239,246,101,128, 30,187,105, 4, 77,197, 77, + 208, 79, 10, 79, 25,226,239,240,239,237,239,230,111,128, 49, 31, + 231,232,116,142, 0, 56, 77,242, 77,251, 78, 5, 78, 35, 78, 42, + 78, 80, 78,105, 78,150, 78,184, 78,196, 78,207, 78,240, 78,248, + 79, 3,225,242,225,226,233, 99,128, 6,104,226,229,238,231,225, + 236,105,128, 9,238,227,233,242,227,236,101,129, 36,103, 78, 16, + 233,238,246,229,242,243,229,243,225,238,243,243,229,242,233,102, + 128, 39,145,228,229,246, 97,128, 9,110,229,229,110, 2, 78, 50, + 78, 59,227,233,242,227,236,101,128, 36,113,112, 2, 78, 65, 78, + 72,225,242,229,110,128, 36,133,229,242,233,239,100,128, 36,153, + 231,117, 2, 78, 87, 78, 96,234,225,242,225,244,105,128, 10,238, + 242,237,245,235,232,105,128, 10,110,104, 2, 78,111, 78,137, 97, + 2, 78,117, 78,128,227,235,225,242,225,226,233, 99,128, 6,104, + 238,231,250,232,239,117,128, 48, 40,238,239,244,229,226,229,225, + 237,229,100,128, 38,107,105, 2, 78,156, 78,174,228,229,239,231, + 242,225,240,232,233,227,240,225,242,229,110,128, 50, 39,238,230, + 229,242,233,239,114,128, 32,136,237,239,238,239,243,240,225,227, + 101,128,255, 24,239,236,228,243,244,249,236,101,128,247, 56,112, + 2, 78,213, 78,220,225,242,229,110,128, 36,123,229,114, 2, 78, + 227, 78,233,233,239,100,128, 36,143,243,233,225,110,128, 6,248, + 242,239,237,225,110,128, 33,119,243,245,240,229,242,233,239,114, + 128, 32,120,244,232,225,105,128, 14, 88,238,246,229,242,244,229, + 228,226,242,229,246,101,128, 2, 7,239,244,233,230,233,229,228, + 227,249,242,233,236,236,233, 99,128, 4,101,107, 2, 79, 49, 79, + 73,225,244,225,235,225,238, 97,129, 48,168, 79, 61,232,225,236, + 230,247,233,228,244,104,128,255,116,111, 2, 79, 79, 79, 94,238, + 235,225,242,231,245,242,237,245,235,232,105,128, 10,116,242,229, + 225,110,128, 49, 84,108, 3, 79,109, 79,120, 79,181,227,249,242, + 233,236,236,233, 99,128, 4, 59,101, 2, 79,126, 79,133,237,229, + 238,116,128, 34, 8,246,229,110, 3, 79,143, 79,152, 79,173,227, + 233,242,227,236,101,128, 36,106,112, 2, 79,158, 79,165,225,242, + 229,110,128, 36,126,229,242,233,239,100,128, 36,146,242,239,237, + 225,110,128, 33,122,236,233,240,243,233,115,129, 32, 38, 79,192, + 246,229,242,244,233,227,225,108,128, 34,238,109, 5, 79,215, 79, + 243, 79,254, 80, 18, 80, 29,225,227,242,239,110,130, 1, 19, 79, + 227, 79,235,225,227,245,244,101,128, 30, 23,231,242,225,246,101, + 128, 30, 21,227,249,242,233,236,236,233, 99,128, 4, 60,228,225, + 243,104,129, 32, 20, 80, 7,246,229,242,244,233,227,225,108,128, + 254, 49,239,238,239,243,240,225,227,101,128,255, 69,112, 2, 80, + 35, 80, 55,232,225,243,233,243,237,225,242,235,225,242,237,229, + 238,233,225,110,128, 5, 91,244,249,243,229,116,128, 34, 5,110, + 6, 80, 77, 80, 88, 80, 99, 80,143, 80,175, 80,190,226,239,240, + 239,237,239,230,111,128, 49, 35,227,249,242,233,236,236,233, 99, + 128, 4, 61,100, 2, 80,105, 80,124,225,243,104,129, 32, 19, 80, + 113,246,229,242,244,233,227,225,108,128,254, 50,229,243,227,229, + 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,163,103, + 130, 1, 75, 80,151, 80,162,226,239,240,239,237,239,230,111,128, + 49, 37,232,229,227,249,242,233,236,236,233, 99,128, 4,165,232, + 239,239,235,227,249,242,233,236,236,233, 99,128, 4,200,243,240, + 225,227,101,128, 32, 2,111, 3, 80,206, 80,214, 80,223,231,239, + 238,229,107,128, 1, 25,235,239,242,229,225,110,128, 49, 83,240, + 229,110,130, 2, 91, 80,233, 80,242,227,236,239,243,229,100,128, + 2,154,242,229,246,229,242,243,229,100,130, 2, 92, 81, 1, 81, + 10,227,236,239,243,229,100,128, 2, 94,232,239,239,107,128, 2, + 93,112, 2, 81, 23, 81, 30,225,242,229,110,128, 36,160,243,233, + 236,239,110,129, 3,181, 81, 40,244,239,238,239,115,128, 3,173, + 241,117, 2, 81, 55, 81, 99,225,108,130, 0, 61, 81, 64, 81, 76, + 237,239,238,239,243,240,225,227,101,128,255, 29,115, 2, 81, 82, + 81, 89,237,225,236,108,128,254,102,245,240,229,242,233,239,114, + 128, 32,124,233,246,225,236,229,238,227,101,128, 34, 97,114, 3, + 81,118, 81,129, 81,140,226,239,240,239,237,239,230,111,128, 49, + 38,227,249,242,233,236,236,233, 99,128, 4, 64,229,246,229,242, + 243,229,100,129, 2, 88, 81,152,227,249,242,233,236,236,233, 99, + 128, 4, 77,115, 6, 81,177, 81,188, 81,208, 82, 33, 82, 78, 82, + 88,227,249,242,233,236,236,233, 99,128, 4, 65,228,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,171, + 104,132, 2,131, 81,220, 81,227, 82, 2, 82, 17,227,245,242,108, + 128, 2,134,239,242,116, 2, 81,235, 81,242,228,229,246, 97,128, + 9, 14,246,239,247,229,236,243,233,231,238,228,229,246, 97,128, + 9, 70,242,229,246,229,242,243,229,228,236,239,239,112,128, 1, + 170,243,241,245,225,244,242,229,246,229,242,243,229,100,128, 2, + 133,237,225,236,108, 2, 82, 42, 82, 53,232,233,242,225,231,225, + 238, 97,128, 48, 71,235,225,244,225,235,225,238, 97,129, 48,167, + 82, 66,232,225,236,230,247,233,228,244,104,128,255,106,244,233, + 237,225,244,229,100,128, 33, 46,245,240,229,242,233,239,114,128, + 246,236,116, 5, 82,110, 82,136, 82,140, 82,157, 82,223, 97,130, + 3,183, 82,118, 82,128,242,237,229,238,233,225,110,128, 5,104, + 244,239,238,239,115,128, 3,174,104,128, 0,240,233,236,228,101, + 129, 30,189, 82,149,226,229,236,239,119,128, 30, 27,238,225,232, + 244, 97, 3, 82,169, 82,201, 82,210,230,239,245,235,104, 2, 82, + 179, 82,188,232,229,226,242,229,119,128, 5,145,236,229,230,244, + 232,229,226,242,229,119,128, 5,145,232,229,226,242,229,119,128, + 5,145,236,229,230,244,232,229,226,242,229,119,128, 5,145,245, + 242,238,229,100,128, 1,221,117, 2, 82,237, 82,246,235,239,242, + 229,225,110,128, 49, 97,242,111,128, 32,172,246,239,247,229,236, + 243,233,231,110, 3, 83, 11, 83, 21, 83, 28,226,229,238,231,225, + 236,105,128, 9,199,228,229,246, 97,128, 9, 71,231,245,234,225, + 242,225,244,105,128, 10,199,120, 2, 83, 45, 83,118,227,236,225, + 109,132, 0, 33, 83, 60, 83, 71, 83, 98, 83,110,225,242,237,229, + 238,233,225,110,128, 5, 92,100, 2, 83, 77, 83, 82,226,108,128, + 32, 60,239,247,110,129, 0,161, 83, 90,243,237,225,236,108,128, + 247,161,237,239,238,239,243,240,225,227,101,128,255, 1,243,237, + 225,236,108,128,247, 33,233,243,244,229,238,244,233,225,108,128, + 34, 3,250,104,131, 2,146, 83,141, 83,160, 83,171, 99, 2, 83, + 147, 83,154,225,242,239,110,128, 1,239,245,242,108,128, 2,147, + 242,229,246,229,242,243,229,100,128, 1,185,244,225,233,108,128, + 1,186,102,140, 0,102, 83,206, 84, 32, 84, 43, 84, 52, 84, 64, + 84,167, 84,183, 86,191, 86,204, 86,230, 88,107, 88,115, 97, 4, + 83,216, 83,223, 83,234, 83,245,228,229,246, 97,128, 9, 94,231, + 245,242,237,245,235,232,105,128, 10, 94,232,242,229,238,232,229, + 233,116,128, 33, 9,244,232, 97, 3, 83,255, 84, 8, 84, 20,225, + 242,225,226,233, 99,128, 6, 78,236,239,247,225,242,225,226,233, + 99,128, 6, 78,244,225,238,225,242,225,226,233, 99,128, 6, 75, + 226,239,240,239,237,239,230,111,128, 49, 8,227,233,242,227,236, + 101,128, 36,213,228,239,244,225,227,227,229,238,116,128, 30, 31, + 101, 3, 84, 72, 84,150, 84,160,104, 4, 84, 82, 84,105, 84,119, + 84,135,225,114, 2, 84, 89, 84, 96,225,226,233, 99,128, 6, 65, + 237,229,238,233,225,110,128, 5,134,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,210,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,254,211,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,254,212,233,227,239,240,244,233, 99,128, 3,229, + 237,225,236,101,128, 38, 64,102,130,251, 0, 84,175, 84,179,105, + 128,251, 3,108,128,251, 4,105,136,251, 1, 84,203, 84,243, 84, + 254, 85, 20, 85,142, 85,159, 85,167, 85,180,230,244,229,229,110, + 2, 84,213, 84,222,227,233,242,227,236,101,128, 36,110,112, 2, + 84,228, 84,235,225,242,229,110,128, 36,130,229,242,233,239,100, + 128, 36,150,231,245,242,229,228,225,243,104,128, 32, 18,236,236, + 229,100, 2, 85, 7, 85, 13,226,239,120,128, 37,160,242,229,227, + 116,128, 37,172,238,225,108, 5, 85, 34, 85, 73, 85, 90, 85,107, + 85,123,235,225,102,130, 5,218, 85, 44, 85, 64,228,225,231,229, + 243,104,129,251, 58, 85, 55,232,229,226,242,229,119,128,251, 58, + 232,229,226,242,229,119,128, 5,218,237,229,109,129, 5,221, 85, + 81,232,229,226,242,229,119,128, 5,221,238,245,110,129, 5,223, + 85, 98,232,229,226,242,229,119,128, 5,223,240,101,129, 5,227, + 85,114,232,229,226,242,229,119,128, 5,227,244,243,225,228,105, + 129, 5,229, 85,133,232,229,226,242,229,119,128, 5,229,242,243, + 244,244,239,238,229,227,232,233,238,229,243,101,128, 2,201,243, + 232,229,249,101,128, 37,201,244,225,227,249,242,233,236,236,233, + 99,128, 4,115,246,101,142, 0, 53, 85,213, 85,222, 85,232, 86, + 6, 86, 13, 86, 23, 86, 48, 86, 75, 86,109, 86,121, 86,132, 86, + 165, 86,173, 86,184,225,242,225,226,233, 99,128, 6,101,226,229, + 238,231,225,236,105,128, 9,235,227,233,242,227,236,101,129, 36, + 100, 85,243,233,238,246,229,242,243,229,243,225,238,243,243,229, + 242,233,102,128, 39,142,228,229,246, 97,128, 9,107,229,233,231, + 232,244,232,115,128, 33, 93,231,117, 2, 86, 30, 86, 39,234,225, + 242,225,244,105,128, 10,235,242,237,245,235,232,105,128, 10,107, + 232, 97, 2, 86, 55, 86, 66,227,235,225,242,225,226,233, 99,128, + 6,101,238,231,250,232,239,117,128, 48, 37,105, 2, 86, 81, 86, + 99,228,229,239,231,242,225,240,232,233,227,240,225,242,229,110, + 128, 50, 36,238,230,229,242,233,239,114,128, 32,133,237,239,238, + 239,243,240,225,227,101,128,255, 21,239,236,228,243,244,249,236, + 101,128,247, 53,112, 2, 86,138, 86,145,225,242,229,110,128, 36, + 120,229,114, 2, 86,152, 86,158,233,239,100,128, 36,140,243,233, + 225,110,128, 6,245,242,239,237,225,110,128, 33,116,243,245,240, + 229,242,233,239,114,128, 32,117,244,232,225,105,128, 14, 85,108, + 129,251, 2, 86,197,239,242,233,110,128, 1,146,109, 2, 86,210, + 86,221,239,238,239,243,240,225,227,101,128,255, 70,243,241,245, + 225,242,101,128, 51,153,111, 4, 86,240, 87, 6, 87, 18, 87, 25, + 230, 97, 2, 86,247, 86,255,238,244,232,225,105,128, 14, 31,244, + 232,225,105,128, 14, 29,238,231,237,225,238,244,232,225,105,128, + 14, 79,242,225,236,108,128, 34, 0,245,114,142, 0, 52, 87, 58, + 87, 67, 87, 77, 87,107, 87,114, 87,139, 87,166, 87,200, 87,212, + 87,231, 87,242, 88, 19, 88, 27, 88, 38,225,242,225,226,233, 99, + 128, 6,100,226,229,238,231,225,236,105,128, 9,234,227,233,242, + 227,236,101,129, 36, 99, 87, 88,233,238,246,229,242,243,229,243, + 225,238,243,243,229,242,233,102,128, 39,141,228,229,246, 97,128, + 9,106,231,117, 2, 87,121, 87,130,234,225,242,225,244,105,128, + 10,234,242,237,245,235,232,105,128, 10,106,232, 97, 2, 87,146, + 87,157,227,235,225,242,225,226,233, 99,128, 6,100,238,231,250, + 232,239,117,128, 48, 36,105, 2, 87,172, 87,190,228,229,239,231, + 242,225,240,232,233,227,240,225,242,229,110,128, 50, 35,238,230, + 229,242,233,239,114,128, 32,132,237,239,238,239,243,240,225,227, + 101,128,255, 20,238,245,237,229,242,225,244,239,242,226,229,238, + 231,225,236,105,128, 9,247,239,236,228,243,244,249,236,101,128, + 247, 52,112, 2, 87,248, 87,255,225,242,229,110,128, 36,119,229, + 114, 2, 88, 6, 88, 12,233,239,100,128, 36,139,243,233,225,110, + 128, 6,244,242,239,237,225,110,128, 33,115,243,245,240,229,242, + 233,239,114,128, 32,116,116, 2, 88, 44, 88, 82,229,229,110, 2, + 88, 52, 88, 61,227,233,242,227,236,101,128, 36,109,112, 2, 88, + 67, 88, 74,225,242,229,110,128, 36,129,229,242,233,239,100,128, + 36,149,104, 2, 88, 88, 88, 93,225,105,128, 14, 84,244,239,238, + 229,227,232,233,238,229,243,101,128, 2,203,240,225,242,229,110, + 128, 36,161,242, 97, 2, 88,122, 88,130,227,244,233,239,110,128, + 32, 68,238, 99,128, 32,163,103,144, 0,103, 88,171, 89,117, 89, + 140, 89,201, 89,218, 90,139, 91,132, 91,217, 91,230, 92, 88, 92, + 113, 92,141, 92,163, 93,108, 93,130, 93,232, 97, 9, 88,191, 88, + 201, 88,208, 88,215, 89, 23, 89, 48, 89, 59, 89, 70, 89,104,226, + 229,238,231,225,236,105,128, 9,151,227,245,244,101,128, 1,245, + 228,229,246, 97,128, 9, 23,102, 4, 88,225, 88,234, 88,248, 89, + 8,225,242,225,226,233, 99,128, 6,175,230,233,238,225,236,225, + 242,225,226,233, 99,128,251,147,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,251,148,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,251,149,231,117, 2, 89, 30, 89, 39,234,225, + 242,225,244,105,128, 10,151,242,237,245,235,232,105,128, 10, 23, + 232,233,242,225,231,225,238, 97,128, 48, 76,235,225,244,225,235, + 225,238, 97,128, 48,172,237,237, 97,130, 3,179, 89, 80, 89, 93, + 236,225,244,233,238,243,237,225,236,108,128, 2, 99,243,245,240, + 229,242,233,239,114,128, 2,224,238,231,233,225,227,239,240,244, + 233, 99,128, 3,235, 98, 2, 89,123, 89,133,239,240,239,237,239, + 230,111,128, 49, 13,242,229,246,101,128, 1, 31, 99, 4, 89,150, + 89,157, 89,166, 89,188,225,242,239,110,128, 1,231,229,228,233, + 236,236, 97,128, 1, 35,233,242, 99, 2, 89,174, 89,179,236,101, + 128, 36,214,245,237,230,236,229,120,128, 1, 29,239,237,237,225, + 225,227,227,229,238,116,128, 1, 35,228,239,116,129, 1, 33, 89, + 209,225,227,227,229,238,116,128, 1, 33,101, 6, 89,232, 89,243, + 89,254, 90, 9, 90, 28, 90,130,227,249,242,233,236,236,233, 99, + 128, 4, 51,232,233,242,225,231,225,238, 97,128, 48, 82,235,225, + 244,225,235,225,238, 97,128, 48,178,239,237,229,244,242,233,227, + 225,236,236,249,229,241,245,225,108,128, 34, 81,114, 3, 90, 36, + 90, 85, 90, 95,229,243,104, 3, 90, 46, 90, 61, 90, 70,225,227, + 227,229,238,244,232,229,226,242,229,119,128, 5,156,232,229,226, + 242,229,119,128, 5,243,237,245,241,228,225,237,232,229,226,242, + 229,119,128, 5,157,237,225,238,228,226,236,115,128, 0,223,243, + 232,225,249,233,109, 2, 90,106, 90,121,225,227,227,229,238,244, + 232,229,226,242,229,119,128, 5,158,232,229,226,242,229,119,128, + 5,244,244,225,237,225,242,107,128, 48, 19,104, 5, 90,151, 91, + 28, 91, 91, 91,116, 91,122, 97, 4, 90,161, 90,171, 90,194, 90, + 219,226,229,238,231,225,236,105,128, 9,152,100, 2, 90,177, 90, + 188,225,242,237,229,238,233,225,110,128, 5,114,229,246, 97,128, + 9, 24,231,117, 2, 90,201, 90,210,234,225,242,225,244,105,128, + 10,152,242,237,245,235,232,105,128, 10, 24,233,110, 4, 90,230, + 90,239, 90,253, 91, 13,225,242,225,226,233, 99,128, 6, 58,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,206,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,207,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,254,208,101, 3, 91, 36, + 91, 57, 91, 74,237,233,228,228,236,229,232,239,239,235,227,249, + 242,233,236,236,233, 99,128, 4,149,243,244,242,239,235,229,227, + 249,242,233,236,236,233, 99,128, 4,147,245,240,244,245,242,238, + 227,249,242,233,236,236,233, 99,128, 4,145,232, 97, 2, 91, 98, + 91,105,228,229,246, 97,128, 9, 90,231,245,242,237,245,235,232, + 105,128, 10, 90,239,239,107,128, 2, 96,250,243,241,245,225,242, + 101,128, 51,147,105, 3, 91,140, 91,151, 91,162,232,233,242,225, + 231,225,238, 97,128, 48, 78,235,225,244,225,235,225,238, 97,128, + 48,174,109, 2, 91,168, 91,179,225,242,237,229,238,233,225,110, + 128, 5, 99,229,108,130, 5,210, 91,188, 91,208,228,225,231,229, + 243,104,129,251, 50, 91,199,232,229,226,242,229,119,128,251, 50, + 232,229,226,242,229,119,128, 5,210,234,229,227,249,242,233,236, + 236,233, 99,128, 4, 83,236,239,244,244,225,108, 2, 91,241, 92, + 2,233,238,246,229,242,244,229,228,243,244,242,239,235,101,128, + 1,190,243,244,239,112,132, 2,148, 92, 17, 92, 28, 92, 34, 92, + 66,233,238,246,229,242,244,229,100,128, 2,150,237,239,100,128, + 2,192,242,229,246,229,242,243,229,100,130, 2,149, 92, 49, 92, + 55,237,239,100,128, 2,193,243,245,240,229,242,233,239,114,128, + 2,228,243,244,242,239,235,101,129, 2,161, 92, 77,242,229,246, + 229,242,243,229,100,128, 2,162,109, 2, 92, 94, 92,102,225,227, + 242,239,110,128, 30, 33,239,238,239,243,240,225,227,101,128,255, + 71,111, 2, 92,119, 92,130,232,233,242,225,231,225,238, 97,128, + 48, 84,235,225,244,225,235,225,238, 97,128, 48,180,240, 97, 2, + 92,148, 92,154,242,229,110,128, 36,162,243,241,245,225,242,101, + 128, 51,172,114, 2, 92,169, 93, 10, 97, 2, 92,175, 92,183,228, + 233,229,238,116,128, 34, 7,246,101,134, 0, 96, 92,200, 92,211, + 92,228, 92,235, 92,244, 93, 0,226,229,236,239,247,227,237, 98, + 128, 3, 22, 99, 2, 92,217, 92,222,237, 98,128, 3, 0,239,237, + 98,128, 3, 0,228,229,246, 97,128, 9, 83,236,239,247,237,239, + 100,128, 2,206,237,239,238,239,243,240,225,227,101,128,255, 64, + 244,239,238,229,227,237, 98,128, 3, 64,229,225,244,229,114,132, + 0, 62, 93, 26, 93, 45, 93, 57, 93,100,229,241,245,225,108,129, + 34,101, 93, 36,239,242,236,229,243,115,128, 34,219,237,239,238, + 239,243,240,225,227,101,128,255, 30,111, 2, 93, 63, 93, 89,114, + 2, 93, 69, 93, 82,229,241,245,233,246,225,236,229,238,116,128, + 34,115,236,229,243,115,128, 34,119,246,229,242,229,241,245,225, + 108,128, 34,103,243,237,225,236,108,128,254,101,115, 2, 93,114, + 93,122,227,242,233,240,116,128, 2, 97,244,242,239,235,101,128, + 1,229,117, 4, 93,140, 93,151, 93,208, 93,219,232,233,242,225, + 231,225,238, 97,128, 48, 80,233,108, 2, 93,158, 93,183,236,229, + 237,239,116, 2, 93,168, 93,175,236,229,230,116,128, 0,171,242, + 233,231,232,116,128, 0,187,243,233,238,231,108, 2, 93,193, 93, + 200,236,229,230,116,128, 32, 57,242,233,231,232,116,128, 32, 58, + 235,225,244,225,235,225,238, 97,128, 48,176,242,225,237,245,243, + 241,245,225,242,101,128, 51, 24,249,243,241,245,225,242,101,128, + 51,201,104,144, 0,104, 94, 22, 96,164, 96,199, 96,236, 97, 20, + 98,164, 98,184, 99,149, 99,161, 99,173,100,241,100,249,101, 4, + 101, 13,101, 93,101, 97, 97, 13, 94, 50, 94, 89, 94, 99, 94,129, + 94,154, 94,232, 94,244, 95, 13, 95, 28, 95, 57, 95, 70, 95,128, + 95,137, 97, 2, 94, 56, 94, 75,226,235,232,225,243,233,225,238, + 227,249,242,233,236,236,233, 99,128, 4,169,236,244,239,238,229, + 225,242,225,226,233, 99,128, 6,193,226,229,238,231,225,236,105, + 128, 9,185,228,101, 2, 94,106, 94,124,243,227,229,238,228,229, + 242,227,249,242,233,236,236,233, 99,128, 4,179,246, 97,128, 9, + 57,231,117, 2, 94,136, 94,145,234,225,242,225,244,105,128, 10, + 185,242,237,245,235,232,105,128, 10, 57,104, 4, 94,164, 94,173, + 94,187, 94,217,225,242,225,226,233, 99,128, 6, 45,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,162,105, 2, 94,193, 94, + 208,238,233,244,233,225,236,225,242,225,226,233, 99,128,254,163, + 242,225,231,225,238, 97,128, 48,111,237,229,228,233,225,236,225, + 242,225,226,233, 99,128,254,164,233,244,245,243,241,245,225,242, + 101,128, 51, 42,235,225,244,225,235,225,238, 97,129, 48,207, 95, + 1,232,225,236,230,247,233,228,244,104,128,255,138,236,225,238, + 244,231,245,242,237,245,235,232,105,128, 10, 77,237,250, 97, 2, + 95, 36, 95, 45,225,242,225,226,233, 99,128, 6, 33,236,239,247, + 225,242,225,226,233, 99,128, 6, 33,238,231,245,236,230,233,236, + 236,229,114,128, 49,100,114, 2, 95, 76, 95, 92,228,243,233,231, + 238,227,249,242,233,236,236,233, 99,128, 4, 74,240,239,239,110, + 2, 95,101, 95,114,236,229,230,244,226,225,242,226,245,112,128, + 33,188,242,233,231,232,244,226,225,242,226,245,112,128, 33,192, + 243,241,245,225,242,101,128, 51,202,244,225,102, 3, 95,147, 95, + 239, 96, 74,240,225,244,225,104,134, 5,178, 95,167, 95,172, 95, + 186, 95,195, 95,210, 95,226,177, 54,128, 5,178, 50, 2, 95,178, + 95,182, 51,128, 5,178,102,128, 5,178,232,229,226,242,229,119, + 128, 5,178,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,178,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,178,247,233,228,229,232,229,226,242,229,119,128, 5,178,241, + 225,237,225,244,115,135, 5,179, 96, 6, 96, 11, 96, 16, 96, 21, + 96, 30, 96, 45, 96, 61,177, 98,128, 5,179,178, 56,128, 5,179, + 179, 52,128, 5,179,232,229,226,242,229,119,128, 5,179,238,225, + 242,242,239,247,232,229,226,242,229,119,128, 5,179,241,245,225, + 242,244,229,242,232,229,226,242,229,119,128, 5,179,247,233,228, + 229,232,229,226,242,229,119,128, 5,179,243,229,231,239,108,135, + 5,177, 96, 96, 96,101, 96,106, 96,111, 96,120, 96,135, 96,151, + 177, 55,128, 5,177,178, 52,128, 5,177,179, 48,128, 5,177,232, + 229,226,242,229,119,128, 5,177,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,177,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,177,247,233,228,229,232,229,226,242,229, + 119,128, 5,177, 98, 3, 96,172, 96,177, 96,187,225,114,128, 1, + 39,239,240,239,237,239,230,111,128, 49, 15,242,229,246,229,226, + 229,236,239,119,128, 30, 43, 99, 2, 96,205, 96,214,229,228,233, + 236,236, 97,128, 30, 41,233,242, 99, 2, 96,222, 96,227,236,101, + 128, 36,215,245,237,230,236,229,120,128, 1, 37,100, 2, 96,242, + 96,252,233,229,242,229,243,233,115,128, 30, 39,239,116, 2, 97, + 3, 97, 12,225,227,227,229,238,116,128, 30, 35,226,229,236,239, + 119,128, 30, 37,101,136, 5,212, 97, 40, 97, 73, 97, 93, 98, 66, + 98, 82, 98,127, 98,136, 98,149,225,242,116,129, 38,101, 97, 48, + 243,245,233,116, 2, 97, 57, 97, 65,226,236,225,227,107,128, 38, + 101,247,232,233,244,101,128, 38, 97,228,225,231,229,243,104,129, + 251, 52, 97, 84,232,229,226,242,229,119,128,251, 52,104, 6, 97, + 107, 97,135, 97,143, 97,193, 97,239, 98, 32, 97, 2, 97,113, 97, + 127,236,244,239,238,229,225,242,225,226,233, 99,128, 6,193,242, + 225,226,233, 99,128, 6, 71,229,226,242,229,119,128, 5,212,230, + 233,238,225,236, 97, 2, 97,154, 97,185,236,116, 2, 97,161, 97, + 173,239,238,229,225,242,225,226,233, 99,128,251,167,244,247,239, + 225,242,225,226,233, 99,128,254,234,242,225,226,233, 99,128,254, + 234,232,225,237,250,225,225,226,239,246,101, 2, 97,208, 97,222, + 230,233,238,225,236,225,242,225,226,233, 99,128,251,165,233,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,251,164,105, + 2, 97,245, 98, 23,238,233,244,233,225,236, 97, 2, 98, 1, 98, + 15,236,244,239,238,229,225,242,225,226,233, 99,128,251,168,242, + 225,226,233, 99,128,254,235,242,225,231,225,238, 97,128, 48,120, + 237,229,228,233,225,236, 97, 2, 98, 44, 98, 58,236,244,239,238, + 229,225,242,225,226,233, 99,128,251,169,242,225,226,233, 99,128, + 254,236,233,243,229,233,229,242,225,243,241,245,225,242,101,128, + 51,123,107, 2, 98, 88, 98,112,225,244,225,235,225,238, 97,129, + 48,216, 98,100,232,225,236,230,247,233,228,244,104,128,255,141, + 245,244,225,225,242,245,243,241,245,225,242,101,128, 51, 54,238, + 231,232,239,239,107,128, 2,103,242,245,244,245,243,241,245,225, + 242,101,128, 51, 57,116,129, 5,215, 98,155,232,229,226,242,229, + 119,128, 5,215,232,239,239,107,129, 2,102, 98,173,243,245,240, + 229,242,233,239,114,128, 2,177,105, 4, 98,194, 99, 23, 99, 34, + 99, 59,229,245,104, 4, 98,206, 98,241, 99, 0, 99, 9, 97, 2, + 98,212, 98,227,227,233,242,227,236,229,235,239,242,229,225,110, + 128, 50,123,240,225,242,229,238,235,239,242,229,225,110,128, 50, + 27,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,109, + 235,239,242,229,225,110,128, 49, 78,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 13,232,233,242,225,231,225,238, 97,128, + 48,114,235,225,244,225,235,225,238, 97,129, 48,210, 99, 47,232, + 225,236,230,247,233,228,244,104,128,255,139,242,233,113,134, 5, + 180, 99, 77, 99, 82, 99, 96, 99,105, 99,120, 99,136,177, 52,128, + 5,180, 50, 2, 99, 88, 99, 92, 49,128, 5,180,100,128, 5,180, + 232,229,226,242,229,119,128, 5,180,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,180,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,180,247,233,228,229,232,229,226,242, + 229,119,128, 5,180,236,233,238,229,226,229,236,239,119,128, 30, + 150,237,239,238,239,243,240,225,227,101,128,255, 72,111, 9, 99, + 193, 99,204, 99,228, 99,253,100, 85,100, 98,100,184,100,224,100, + 235,225,242,237,229,238,233,225,110,128, 5,112,232,105, 2, 99, + 211, 99,219,240,244,232,225,105,128, 14, 43,242,225,231,225,238, + 97,128, 48,123,235,225,244,225,235,225,238, 97,129, 48,219, 99, + 241,232,225,236,230,247,233,228,244,104,128,255,142,236,225,109, + 135, 5,185,100, 17,100, 22,100, 27,100, 32,100, 41,100, 56,100, + 72,177, 57,128, 5,185,178, 54,128, 5,185,179, 50,128, 5,185, + 232,229,226,242,229,119,128, 5,185,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,185,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,185,247,233,228,229,232,229,226,242, + 229,119,128, 5,185,238,239,235,232,245,235,244,232,225,105,128, + 14, 46,111, 2,100,104,100,174,107, 4,100,114,100,126,100,132, + 100,154,225,226,239,246,229,227,239,237, 98,128, 3, 9,227,237, + 98,128, 3, 9,240,225,236,225,244,225,236,233,250,229,228,226, + 229,236,239,247,227,237, 98,128, 3, 33,242,229,244,242,239,230, + 236,229,248,226,229,236,239,247,227,237, 98,128, 3, 34,238,243, + 241,245,225,242,101,128, 51, 66,114, 2,100,190,100,217,105, 2, + 100,196,100,205,227,239,240,244,233, 99,128, 3,233,250,239,238, + 244,225,236,226,225,114,128, 32, 21,238,227,237, 98,128, 3, 27, + 244,243,240,242,233,238,231,115,128, 38,104,245,243,101,128, 35, + 2,240,225,242,229,110,128, 36,163,243,245,240,229,242,233,239, + 114,128, 2,176,244,245,242,238,229,100,128, 2,101,117, 4,101, + 23,101, 34,101, 47,101, 72,232,233,242,225,231,225,238, 97,128, + 48,117,233,233,244,239,243,241,245,225,242,101,128, 51, 51,235, + 225,244,225,235,225,238, 97,129, 48,213,101, 60,232,225,236,230, + 247,233,228,244,104,128,255,140,238,231,225,242,245,237,236,225, + 245,116,129, 2,221,101, 87,227,237, 98,128, 3, 11,118,128, 1, + 149,249,240,232,229,110,132, 0, 45,101,113,101,124,101,136,101, + 159,233,238,230,229,242,233,239,114,128,246,229,237,239,238,239, + 243,240,225,227,101,128,255, 13,115, 2,101,142,101,149,237,225, + 236,108,128,254, 99,245,240,229,242,233,239,114,128,246,230,244, + 247,111,128, 32, 16,105,149, 0,105,101,211,101,234,102, 12,102, + 59,105,197,106, 61,106, 98,106,125,107, 31,107, 35,107, 73,107, + 95,107,179,108, 88,108,163,108,171,108,184,109, 15,109, 72,109, + 100,109,144,225, 99, 2,101,218,101,224,245,244,101,128, 0,237, + 249,242,233,236,236,233, 99,128, 4, 79, 98, 3,101,242,101,251, + 102, 5,229,238,231,225,236,105,128, 9,135,239,240,239,237,239, + 230,111,128, 49, 39,242,229,246,101,128, 1, 45, 99, 3,102, 20, + 102, 27,102, 49,225,242,239,110,128, 1,208,233,242, 99, 2,102, + 35,102, 40,236,101,128, 36,216,245,237,230,236,229,120,128, 0, + 238,249,242,233,236,236,233, 99,128, 4, 86,100, 4,102, 69,102, + 79,105,154,105,187,226,236,231,242,225,246,101,128, 2, 9,101, + 2,102, 85,105,149,239,231,242,225,240,104, 7,102,106,102,120, + 102,133,105, 62,105, 93,105,106,105,118,229,225,242,244,232,227, + 233,242,227,236,101,128, 50,143,230,233,242,229,227,233,242,227, + 236,101,128, 50,139,233, 99, 14,102,164,102,180,103, 23,103, 77, + 103,143,103,172,103,188,103,245,104, 38,104, 50,104, 77,104,144, + 105, 26,105, 55,225,236,236,233,225,238,227,229,240,225,242,229, + 110,128, 50, 63, 99, 4,102,190,102,201,102,215,102,222,225,236, + 236,240,225,242,229,110,128, 50, 58,229,238,244,242,229,227,233, + 242,227,236,101,128, 50,165,236,239,243,101,128, 48, 6,111, 3, + 102,230,102,245,103, 9,237,237, 97,129, 48, 1,102,238,236,229, + 230,116,128,255,100,238,231,242,225,244,245,236,225,244,233,239, + 238,240,225,242,229,110,128, 50, 55,242,242,229,227,244,227,233, + 242,227,236,101,128, 50,163,101, 3,103, 31,103, 43,103, 60,225, + 242,244,232,240,225,242,229,110,128, 50, 47,238,244,229,242,240, + 242,233,243,229,240,225,242,229,110,128, 50, 61,248,227,229,236, + 236,229,238,244,227,233,242,227,236,101,128, 50,157,102, 2,103, + 83,103, 98,229,243,244,233,246,225,236,240,225,242,229,110,128, + 50, 64,105, 2,103,104,103,133,238,225,238,227,233,225,108, 2, + 103,116,103,125,227,233,242,227,236,101,128, 50,150,240,225,242, + 229,110,128, 50, 54,242,229,240,225,242,229,110,128, 50, 43,104, + 2,103,149,103,160,225,246,229,240,225,242,229,110,128, 50, 50, + 233,231,232,227,233,242,227,236,101,128, 50,164,233,244,229,242, + 225,244,233,239,238,237,225,242,107,128, 48, 5,108, 3,103,196, + 103,222,103,234,225,226,239,114, 2,103,205,103,214,227,233,242, + 227,236,101,128, 50,152,240,225,242,229,110,128, 50, 56,229,230, + 244,227,233,242,227,236,101,128, 50,167,239,247,227,233,242,227, + 236,101,128, 50,166,109, 2,103,251,104, 27,101, 2,104, 1,104, + 16,228,233,227,233,238,229,227,233,242,227,236,101,128, 50,169, + 244,225,236,240,225,242,229,110,128, 50, 46,239,239,238,240,225, + 242,229,110,128, 50, 42,238,225,237,229,240,225,242,229,110,128, + 50, 52,112, 2,104, 56,104, 64,229,242,233,239,100,128, 48, 2, + 242,233,238,244,227,233,242,227,236,101,128, 50,158,114, 2,104, + 83,104,131,101, 3,104, 91,104,102,104,117,225,227,232,240,225, + 242,229,110,128, 50, 67,240,242,229,243,229,238,244,240,225,242, + 229,110,128, 50, 57,243,239,245,242,227,229,240,225,242,229,110, + 128, 50, 62,233,231,232,244,227,233,242,227,236,101,128, 50,168, + 115, 5,104,156,104,185,104,199,104,224,104,252,101, 2,104,162, + 104,175,227,242,229,244,227,233,242,227,236,101,128, 50,153,236, + 230,240,225,242,229,110,128, 50, 66,239,227,233,229,244,249,240, + 225,242,229,110,128, 50, 51,112, 2,104,205,104,211,225,227,101, + 128, 48, 0,229,227,233,225,236,240,225,242,229,110,128, 50, 53, + 116, 2,104,230,104,241,239,227,235,240,225,242,229,110,128, 50, + 49,245,228,249,240,225,242,229,110,128, 50, 59,117, 2,105, 2, + 105, 11,238,240,225,242,229,110,128, 50, 48,240,229,242,246,233, + 243,229,240,225,242,229,110,128, 50, 60,119, 2,105, 32,105, 44, + 225,244,229,242,240,225,242,229,110,128, 50, 44,239,239,228,240, + 225,242,229,110,128, 50, 45,250,229,242,111,128, 48, 7,109, 2, + 105, 68,105, 81,229,244,225,236,227,233,242,227,236,101,128, 50, + 142,239,239,238,227,233,242,227,236,101,128, 50,138,238,225,237, + 229,227,233,242,227,236,101,128, 50,148,243,245,238,227,233,242, + 227,236,101,128, 50,144,119, 2,105,124,105,137,225,244,229,242, + 227,233,242,227,236,101,128, 50,140,239,239,228,227,233,242,227, + 236,101,128, 50,141,246, 97,128, 9, 7,233,229,242,229,243,233, + 115,130, 0,239,105,168,105,176,225,227,245,244,101,128, 30, 47, + 227,249,242,233,236,236,233, 99,128, 4,229,239,244,226,229,236, + 239,119,128, 30,203,101, 3,105,205,105,221,105,232,226,242,229, + 246,229,227,249,242,233,236,236,233, 99,128, 4,215,227,249,242, + 233,236,236,233, 99,128, 4, 53,245,238,103, 4,105,244,106, 23, + 106, 38,106, 47, 97, 2,105,250,106, 9,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,117,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 21,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,103,235,239,242,229,225,110,128, 49, 71,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 7,103, 2,106, + 67,106, 74,242,225,246,101,128, 0,236,117, 2,106, 80,106, 89, + 234,225,242,225,244,105,128, 10,135,242,237,245,235,232,105,128, + 10, 7,104, 2,106,104,106,114,233,242,225,231,225,238, 97,128, + 48, 68,239,239,235,225,226,239,246,101,128, 30,201,105, 8,106, + 143,106,153,106,164,106,171,106,196,106,212,106,227,106,243,226, + 229,238,231,225,236,105,128, 9,136,227,249,242,233,236,236,233, + 99,128, 4, 56,228,229,246, 97,128, 9, 8,231,117, 2,106,178, + 106,187,234,225,242,225,244,105,128, 10,136,242,237,245,235,232, + 105,128, 10, 8,237,225,244,242,225,231,245,242,237,245,235,232, + 105,128, 10, 64,238,246,229,242,244,229,228,226,242,229,246,101, + 128, 2, 11,243,232,239,242,244,227,249,242,233,236,236,233, 99, + 128, 4, 57,246,239,247,229,236,243,233,231,110, 3,107, 3,107, + 13,107, 20,226,229,238,231,225,236,105,128, 9,192,228,229,246, + 97,128, 9, 64,231,245,234,225,242,225,244,105,128, 10,192,106, + 128, 1, 51,107, 2,107, 41,107, 65,225,244,225,235,225,238, 97, + 129, 48,164,107, 53,232,225,236,230,247,233,228,244,104,128,255, + 114,239,242,229,225,110,128, 49, 99,108, 2,107, 79,107, 84,228, + 101,128, 2,220,245,249,232,229,226,242,229,119,128, 5,172,109, + 2,107,101,107,168, 97, 3,107,109,107,129,107,154,227,242,239, + 110,129, 1, 43,107,118,227,249,242,233,236,236,233, 99,128, 4, + 227,231,229,239,242,225,240,240,242,239,248,233,237,225,244,229, + 236,249,229,241,245,225,108,128, 34, 83,244,242,225,231,245,242, + 237,245,235,232,105,128, 10, 63,239,238,239,243,240,225,227,101, + 128,255, 73,110, 5,107,191,107,201,107,210,107,222,108, 50,227, + 242,229,237,229,238,116,128, 34, 6,230,233,238,233,244,121,128, + 34, 30,233,225,242,237,229,238,233,225,110,128, 5,107,116, 2, + 107,228,108, 40,101, 2,107,234,108, 29,231,242,225,108,131, 34, + 43,107,247,108, 9,108, 14, 98, 2,107,253,108, 5,239,244,244, + 239,109,128, 35, 33,116,128, 35, 33,229,120,128,248,245,116, 2, + 108, 20,108, 25,239,112,128, 35, 32,112,128, 35, 32,242,243,229, + 227,244,233,239,110,128, 34, 41,233,243,241,245,225,242,101,128, + 51, 5,118, 3,108, 58,108, 67,108, 76,226,245,236,236,229,116, + 128, 37,216,227,233,242,227,236,101,128, 37,217,243,237,233,236, + 229,230,225,227,101,128, 38, 59,111, 3,108, 96,108,107,108,115, + 227,249,242,233,236,236,233, 99,128, 4, 81,231,239,238,229,107, + 128, 1, 47,244, 97,131, 3,185,108,126,108,147,108,155,228,233, + 229,242,229,243,233,115,129, 3,202,108,139,244,239,238,239,115, + 128, 3,144,236,225,244,233,110,128, 2,105,244,239,238,239,115, + 128, 3,175,240,225,242,229,110,128, 36,164,242,233,231,245,242, + 237,245,235,232,105,128, 10,114,115, 4,108,194,108,239,108,253, + 109, 5,237,225,236,108, 2,108,203,108,214,232,233,242,225,231, + 225,238, 97,128, 48, 67,235,225,244,225,235,225,238, 97,129, 48, + 163,108,227,232,225,236,230,247,233,228,244,104,128,255,104,243, + 232,225,242,226,229,238,231,225,236,105,128, 9,250,244,242,239, + 235,101,128, 2,104,245,240,229,242,233,239,114,128,246,237,116, + 2,109, 21,109, 55,229,242,225,244,233,239,110, 2,109, 33,109, + 44,232,233,242,225,231,225,238, 97,128, 48,157,235,225,244,225, + 235,225,238, 97,128, 48,253,233,236,228,101,129, 1, 41,109, 64, + 226,229,236,239,119,128, 30, 45,117, 2,109, 78,109, 89,226,239, + 240,239,237,239,230,111,128, 49, 41,227,249,242,233,236,236,233, + 99,128, 4, 78,246,239,247,229,236,243,233,231,110, 3,109,116, + 109,126,109,133,226,229,238,231,225,236,105,128, 9,191,228,229, + 246, 97,128, 9, 63,231,245,234,225,242,225,244,105,128, 10,191, + 250,232,233,244,243, 97, 2,109,155,109,166,227,249,242,233,236, + 236,233, 99,128, 4,117,228,226,236,231,242,225,246,229,227,249, + 242,233,236,236,233, 99,128, 4,119,106,138, 0,106,109,209,110, + 16,110, 27,110, 77,110, 93,110,206,111, 19,111, 24,111, 36,111, + 44, 97, 4,109,219,109,230,109,240,109,247,225,242,237,229,238, + 233,225,110,128, 5,113,226,229,238,231,225,236,105,128, 9,156, + 228,229,246, 97,128, 9, 28,231,117, 2,109,254,110, 7,234,225, + 242,225,244,105,128, 10,156,242,237,245,235,232,105,128, 10, 28, + 226,239,240,239,237,239,230,111,128, 49, 16, 99, 3,110, 35,110, + 42,110, 64,225,242,239,110,128, 1,240,233,242, 99, 2,110, 50, + 110, 55,236,101,128, 36,217,245,237,230,236,229,120,128, 1, 53, + 242,239,243,243,229,228,244,225,233,108,128, 2,157,228,239,244, + 236,229,243,243,243,244,242,239,235,101,128, 2, 95,101, 3,110, + 101,110,112,110,177,227,249,242,233,236,236,233, 99,128, 4, 88, + 229,109, 4,110,123,110,132,110,146,110,162,225,242,225,226,233, + 99,128, 6, 44,230,233,238,225,236,225,242,225,226,233, 99,128, + 254,158,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,159,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, + 160,104, 2,110,183,110,192,225,242,225,226,233, 99,128, 6,152, + 230,233,238,225,236,225,242,225,226,233, 99,128,251,139,104, 2, + 110,212,111, 6, 97, 3,110,220,110,230,110,237,226,229,238,231, + 225,236,105,128, 9,157,228,229,246, 97,128, 9, 29,231,117, 2, + 110,244,110,253,234,225,242,225,244,105,128, 10,157,242,237,245, + 235,232,105,128, 10, 29,229,232,225,242,237,229,238,233,225,110, + 128, 5,123,233,115,128, 48, 4,237,239,238,239,243,240,225,227, + 101,128,255, 74,240,225,242,229,110,128, 36,165,243,245,240,229, + 242,233,239,114,128, 2,178,107,146, 0,107,111, 95,113,184,113, + 195,114, 1,114, 12,114,102,114,116,115,224,116,164,116,177,116, + 203,116,252,117,134,117,156,117,169,117,192,117,234,117,244, 97, + 12,111,121,111,153,111,175,111,205,112, 63,112, 88,112,118,112, + 143,112,249,113, 7,113,130,113,159, 98, 2,111,127,111,144,225, + 243,232,235,233,242,227,249,242,233,236,236,233, 99,128, 4,161, + 229,238,231,225,236,105,128, 9,149, 99, 2,111,159,111,165,245, + 244,101,128, 30, 49,249,242,233,236,236,233, 99,128, 4, 58,228, + 101, 2,111,182,111,200,243,227,229,238,228,229,242,227,249,242, + 233,236,236,233, 99,128, 4,155,246, 97,128, 9, 21,102,135, 5, + 219,111,223,111,232,111,252,112, 10,112, 19,112, 35,112, 50,225, + 242,225,226,233, 99,128, 6, 67,228,225,231,229,243,104,129,251, + 59,111,243,232,229,226,242,229,119,128,251, 59,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,218,232,229,226,242,229,119, + 128, 5,219,233,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,219,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,220,242,225,230,229,232,229,226,242,229,119,128,251, 77,231, + 117, 2,112, 70,112, 79,234,225,242,225,244,105,128, 10,149,242, + 237,245,235,232,105,128, 10, 21,104, 2,112, 94,112,104,233,242, + 225,231,225,238, 97,128, 48, 75,239,239,235,227,249,242,233,236, + 236,233, 99,128, 4,196,235,225,244,225,235,225,238, 97,129, 48, + 171,112,131,232,225,236,230,247,233,228,244,104,128,255,118,112, + 2,112,149,112,170,240, 97,129, 3,186,112,156,243,249,237,226, + 239,236,231,242,229,229,107,128, 3,240,249,229,239,245,110, 3, + 112,182,112,196,112,230,237,233,229,245,237,235,239,242,229,225, + 110,128, 49,113,112, 2,112,202,112,217,232,233,229,245,240,232, + 235,239,242,229,225,110,128, 49,132,233,229,245,240,235,239,242, + 229,225,110,128, 49,120,243,243,225,238,231,240,233,229,245,240, + 235,239,242,229,225,110,128, 49,121,242,239,242,233,233,243,241, + 245,225,242,101,128, 51, 13,115, 5,113, 19,113, 63,113, 78,113, + 86,113,114,232,233,228,225,225,245,244,111, 2,113, 32,113, 41, + 225,242,225,226,233, 99,128, 6, 64,238,239,243,233,228,229,226, + 229,225,242,233,238,231,225,242,225,226,233, 99,128, 6, 64,237, + 225,236,236,235,225,244,225,235,225,238, 97,128, 48,245,241,245, + 225,242,101,128, 51,132,242, 97, 2,113, 93,113,102,225,242,225, + 226,233, 99,128, 6, 80,244,225,238,225,242,225,226,233, 99,128, + 6, 77,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, + 4,159,244,225,232,233,242,225,240,242,239,236,239,238,231,237, + 225,242,235,232,225,236,230,247,233,228,244,104,128,255,112,246, + 229,242,244,233,227,225,236,243,244,242,239,235,229,227,249,242, + 233,236,236,233, 99,128, 4,157,226,239,240,239,237,239,230,111, + 128, 49, 14, 99, 4,113,205,113,227,113,236,113,244, 97, 2,113, + 211,113,221,236,243,241,245,225,242,101,128, 51,137,242,239,110, + 128, 1,233,229,228,233,236,236, 97,128, 1, 55,233,242,227,236, + 101,128, 36,218,239,237,237,225,225,227,227,229,238,116,128, 1, + 55,228,239,244,226,229,236,239,119,128, 30, 51,101, 4,114, 22, + 114, 49,114, 74,114, 86,104, 2,114, 28,114, 39,225,242,237,229, + 238,233,225,110,128, 5,132,233,242,225,231,225,238, 97,128, 48, + 81,235,225,244,225,235,225,238, 97,129, 48,177,114, 62,232,225, + 236,230,247,233,228,244,104,128,255,121,238,225,242,237,229,238, + 233,225,110,128, 5,111,243,237,225,236,236,235,225,244,225,235, + 225,238, 97,128, 48,246,231,242,229,229,238,236,225,238,228,233, + 99,128, 1, 56,104, 6,114,130,115, 3,115, 14,115, 39,115,126, + 115,214, 97, 5,114,142,114,152,114,163,114,170,114,195,226,229, + 238,231,225,236,105,128, 9,150,227,249,242,233,236,236,233, 99, + 128, 4, 69,228,229,246, 97,128, 9, 22,231,117, 2,114,177,114, + 186,234,225,242,225,244,105,128, 10,150,242,237,245,235,232,105, + 128, 10, 22,104, 4,114,205,114,214,114,228,114,244,225,242,225, + 226,233, 99,128, 6, 46,230,233,238,225,236,225,242,225,226,233, + 99,128,254,166,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,167,237,229,228,233,225,236,225,242,225,226,233, 99, + 128,254,168,229,233,227,239,240,244,233, 99,128, 3,231,232, 97, + 2,115, 21,115, 28,228,229,246, 97,128, 9, 89,231,245,242,237, + 245,235,232,105,128, 10, 89,233,229,245,235,104, 4,115, 53,115, + 88,115,103,115,112, 97, 2,115, 59,115, 74,227,233,242,227,236, + 229,235,239,242,229,225,110,128, 50,120,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 24,227,233,242,227,236,229,235,239, + 242,229,225,110,128, 50,106,235,239,242,229,225,110,128, 49, 75, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 10,111, 4, + 115,136,115,185,115,195,115,200,235,104, 4,115,147,115,156,115, + 165,115,175,225,233,244,232,225,105,128, 14, 2,239,238,244,232, + 225,105,128, 14, 5,245,225,244,244,232,225,105,128, 14, 3,247, + 225,233,244,232,225,105,128, 14, 4,237,245,244,244,232,225,105, + 128, 14, 91,239,107,128, 1,153,242,225,235,232,225,238,231,244, + 232,225,105,128, 14, 6,250,243,241,245,225,242,101,128, 51,145, + 105, 4,115,234,115,245,116, 14,116, 63,232,233,242,225,231,225, + 238, 97,128, 48, 77,235,225,244,225,235,225,238, 97,129, 48,173, + 116, 2,232,225,236,230,247,233,228,244,104,128,255,119,242,111, + 3,116, 23,116, 38,116, 54,231,245,242,225,237,245,243,241,245, + 225,242,101,128, 51, 21,237,229,229,244,239,242,245,243,241,245, + 225,242,101,128, 51, 22,243,241,245,225,242,101,128, 51, 20,249, + 229,239,107, 5,116, 78,116,113,116,128,116,137,116,151, 97, 2, + 116, 84,116, 99,227,233,242,227,236,229,235,239,242,229,225,110, + 128, 50,110,240,225,242,229,238,235,239,242,229,225,110,128, 50, + 14,227,233,242,227,236,229,235,239,242,229,225,110,128, 50, 96, + 235,239,242,229,225,110,128, 49, 49,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 0,243,233,239,243,235,239,242,229,225, + 110,128, 49, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, + 92,108, 2,116,183,116,194,233,238,229,226,229,236,239,119,128, + 30, 53,243,241,245,225,242,101,128, 51,152,109, 3,116,211,116, + 225,116,236,227,245,226,229,228,243,241,245,225,242,101,128, 51, + 166,239,238,239,243,240,225,227,101,128,255, 75,243,241,245,225, + 242,229,228,243,241,245,225,242,101,128, 51,162,111, 5,117, 8, + 117, 34,117, 72,117, 84,117, 98,104, 2,117, 14,117, 24,233,242, + 225,231,225,238, 97,128, 48, 83,237,243,241,245,225,242,101,128, + 51,192,235, 97, 2,117, 41,117, 49,233,244,232,225,105,128, 14, + 1,244,225,235,225,238, 97,129, 48,179,117, 60,232,225,236,230, + 247,233,228,244,104,128,255,122,239,240,239,243,241,245,225,242, + 101,128, 51, 30,240,240,225,227,249,242,233,236,236,233, 99,128, + 4,129,114, 2,117,104,117,124,229,225,238,243,244,225,238,228, + 225,242,228,243,249,237,226,239,108,128, 50,127,239,238,233,243, + 227,237, 98,128, 3, 67,240, 97, 2,117,141,117,147,242,229,110, + 128, 36,166,243,241,245,225,242,101,128, 51,170,243,233,227,249, + 242,233,236,236,233, 99,128, 4,111,116, 2,117,175,117,184,243, + 241,245,225,242,101,128, 51,207,245,242,238,229,100,128, 2,158, + 117, 2,117,198,117,209,232,233,242,225,231,225,238, 97,128, 48, + 79,235,225,244,225,235,225,238, 97,129, 48,175,117,222,232,225, + 236,230,247,233,228,244,104,128,255,120,246,243,241,245,225,242, + 101,128, 51,184,247,243,241,245,225,242,101,128, 51,190,108,146, + 0,108,118, 38,120, 65,120, 94,120,160,120,198,121, 94,121,103, + 121,119,121,143,121,161,122, 23,122, 64,122,199,122,207,122,240, + 122,249,123, 1,123, 63, 97, 7,118, 54,118, 64,118, 71,118, 78, + 118,103,118,119,120, 53,226,229,238,231,225,236,105,128, 9,178, + 227,245,244,101,128, 1, 58,228,229,246, 97,128, 9, 50,231,117, + 2,118, 85,118, 94,234,225,242,225,244,105,128, 10,178,242,237, + 245,235,232,105,128, 10, 50,235,235,232,225,238,231,249,225,239, + 244,232,225,105,128, 14, 69,109, 10,118,141,119, 80,119, 97,119, + 135,119,149,119,168,119,184,119,204,119,224,119,247, 97, 2,118, + 147,119, 72,236,229,102, 4,118,159,118,173,119, 9,119, 26,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,252,232,225,237, + 250, 97, 2,118,183,118,224,225,226,239,246,101, 2,118,193,118, + 207,230,233,238,225,236,225,242,225,226,233, 99,128,254,248,233, + 243,239,236,225,244,229,228,225,242,225,226,233, 99,128,254,247, + 226,229,236,239,119, 2,118,234,118,248,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,250,233,243,239,236,225,244,229,228, + 225,242,225,226,233, 99,128,254,249,233,243,239,236,225,244,229, + 228,225,242,225,226,233, 99,128,254,251,237,225,228,228,225,225, + 226,239,246,101, 2,119, 41,119, 55,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,246,233,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,254,245,242,225,226,233, 99,128, 6, 68, + 226,228, 97,129, 3,187,119, 88,243,244,242,239,235,101,128, 1, + 155,229,100,130, 5,220,119,106,119,126,228,225,231,229,243,104, + 129,251, 60,119,117,232,229,226,242,229,119,128,251, 60,232,229, + 226,242,229,119,128, 5,220,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,222,232,225,232,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,202,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,223,234,229,229,237,233,238,233,244, + 233,225,236,225,242,225,226,233, 99,128,252,201,235,232,225,232, + 233,238,233,244,233,225,236,225,242,225,226,233, 99,128,252,203, + 236,225,237,232,229,232,233,243,239,236,225,244,229,228,225,242, + 225,226,233, 99,128,253,242,237,101, 2,119,254,120, 11,228,233, + 225,236,225,242,225,226,233, 99,128,254,224,229,109, 2,120, 18, + 120, 37,232,225,232,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,253,136,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,252,204,242,231,229,227,233,242,227,236,101,128, 37, + 239, 98, 3,120, 73,120, 78,120, 84,225,114,128, 1,154,229,236, + 116,128, 2,108,239,240,239,237,239,230,111,128, 49, 12, 99, 4, + 120,104,120,111,120,120,120,147,225,242,239,110,128, 1, 62,229, + 228,233,236,236, 97,128, 1, 60,233,242, 99, 2,120,128,120,133, + 236,101,128, 36,219,245,237,230,236,229,248,226,229,236,239,119, + 128, 30, 61,239,237,237,225,225,227,227,229,238,116,128, 1, 60, + 228,239,116,130, 1, 64,120,170,120,179,225,227,227,229,238,116, + 128, 1, 64,226,229,236,239,119,129, 30, 55,120,189,237,225,227, + 242,239,110,128, 30, 57,101, 3,120,206,120,244,121, 89,230,116, + 2,120,213,120,229,225,238,231,236,229,225,226,239,246,229,227, + 237, 98,128, 3, 26,244,225,227,235,226,229,236,239,247,227,237, + 98,128, 3, 24,243,115,132, 0, 60,121, 1,121, 23,121, 35,121, + 81,229,241,245,225,108,129, 34,100,121, 11,239,242,231,242,229, + 225,244,229,114,128, 34,218,237,239,238,239,243,240,225,227,101, + 128,255, 28,111, 2,121, 41,121, 70,114, 2,121, 47,121, 60,229, + 241,245,233,246,225,236,229,238,116,128, 34,114,231,242,229,225, + 244,229,114,128, 34,118,246,229,242,229,241,245,225,108,128, 34, + 102,243,237,225,236,108,128,254,100,250,104,128, 2,110,230,226, + 236,239,227,107,128, 37,140,232,239,239,235,242,229,244,242,239, + 230,236,229,120,128, 2,109,105, 2,121,125,121,130,242, 97,128, + 32,164,247,238,225,242,237,229,238,233,225,110,128, 5,108,106, + 129, 1,201,121,149,229,227,249,242,233,236,236,233, 99,128, 4, + 89,108,132,246,192,121,173,121,197,121,208,121,217, 97, 2,121, + 179,121,186,228,229,246, 97,128, 9, 51,231,245,234,225,242,225, + 244,105,128, 10,179,233,238,229,226,229,236,239,119,128, 30, 59, + 236,225,228,229,246, 97,128, 9, 52,246,239,227,225,236,233, 99, + 3,121,231,121,241,121,248,226,229,238,231,225,236,105,128, 9, + 225,228,229,246, 97,128, 9, 97,246,239,247,229,236,243,233,231, + 110, 2,122, 6,122, 16,226,229,238,231,225,236,105,128, 9,227, + 228,229,246, 97,128, 9, 99,109, 3,122, 31,122, 44,122, 55,233, + 228,228,236,229,244,233,236,228,101,128, 2,107,239,238,239,243, + 240,225,227,101,128,255, 76,243,241,245,225,242,101,128, 51,208, + 111, 6,122, 78,122, 90,122,132,122,143,122,149,122,191,227,232, + 245,236,225,244,232,225,105,128, 14, 44,231,233,227,225,108, 3, + 122,102,122,108,122,127,225,238,100,128, 34, 39,238,239,116,129, + 0,172,122,116,242,229,246,229,242,243,229,100,128, 35, 16,239, + 114,128, 34, 40,236,233,238,231,244,232,225,105,128, 14, 37,238, + 231,115,128, 1,127,247,236,233,238,101, 2,122,159,122,182, 99, + 2,122,165,122,177,229,238,244,229,242,236,233,238,101,128,254, + 78,237, 98,128, 3, 50,228,225,243,232,229,100,128,254, 77,250, + 229,238,231,101,128, 37,202,240,225,242,229,110,128, 36,167,115, + 3,122,215,122,222,122,230,236,225,243,104,128, 1, 66,241,245, + 225,242,101,128, 33, 19,245,240,229,242,233,239,114,128,246,238, + 244,243,232,225,228,101,128, 37,145,245,244,232,225,105,128, 14, + 38,246,239,227,225,236,233, 99, 3,123, 15,123, 25,123, 32,226, + 229,238,231,225,236,105,128, 9,140,228,229,246, 97,128, 9, 12, + 246,239,247,229,236,243,233,231,110, 2,123, 46,123, 56,226,229, + 238,231,225,236,105,128, 9,226,228,229,246, 97,128, 9, 98,248, + 243,241,245,225,242,101,128, 51,211,109,144, 0,109,123,109,125, + 218,125,243,126, 14,126, 39,127, 92,127,114,128,169,128,199,128, + 248,129, 99,129,121,129,146,129,155,130,182,130,210, 97, 12,123, + 135,123,145,123,209,123,216,123,241,124, 33,125,125,125,150,125, + 155,125,169,125,181,125,186,226,229,238,231,225,236,105,128, 9, + 174, 99, 2,123,151,123,203,242,239,110,132, 0,175,123,165,123, + 176,123,182,123,191,226,229,236,239,247,227,237, 98,128, 3, 49, + 227,237, 98,128, 3, 4,236,239,247,237,239,100,128, 2,205,237, + 239,238,239,243,240,225,227,101,128,255,227,245,244,101,128, 30, + 63,228,229,246, 97,128, 9, 46,231,117, 2,123,223,123,232,234, + 225,242,225,244,105,128, 10,174,242,237,245,235,232,105,128, 10, + 46,104, 2,123,247,124, 23,225,240,225,235,104, 2,124, 1,124, + 10,232,229,226,242,229,119,128, 5,164,236,229,230,244,232,229, + 226,242,229,119,128, 5,164,233,242,225,231,225,238, 97,128, 48, + 126,105, 5,124, 45,124,114,124,177,124,207,125,113,227,232,225, + 244,244,225,247, 97, 3,124, 60,124, 91,124, 98,236,239,119, 2, + 124, 68,124, 79,236,229,230,244,244,232,225,105,128,248,149,242, + 233,231,232,244,244,232,225,105,128,248,148,244,232,225,105,128, + 14, 75,245,240,240,229,242,236,229,230,244,244,232,225,105,128, + 248,147,229,107, 3,124,123,124,154,124,161,236,239,119, 2,124, + 131,124,142,236,229,230,244,244,232,225,105,128,248,140,242,233, + 231,232,244,244,232,225,105,128,248,139,244,232,225,105,128, 14, + 72,245,240,240,229,242,236,229,230,244,244,232,225,105,128,248, + 138,232,225,238,225,235,225,116, 2,124,189,124,200,236,229,230, + 244,244,232,225,105,128,248,132,244,232,225,105,128, 14, 49,116, + 3,124,215,124,243,125, 50,225,233,235,232,117, 2,124,225,124, + 236,236,229,230,244,244,232,225,105,128,248,137,244,232,225,105, + 128, 14, 71,232,111, 3,124,252,125, 27,125, 34,236,239,119, 2, + 125, 4,125, 15,236,229,230,244,244,232,225,105,128,248,143,242, + 233,231,232,244,244,232,225,105,128,248,142,244,232,225,105,128, + 14, 73,245,240,240,229,242,236,229,230,244,244,232,225,105,128, + 248,141,242,105, 3,125, 59,125, 90,125, 97,236,239,119, 2,125, + 67,125, 78,236,229,230,244,244,232,225,105,128,248,146,242,233, + 231,232,244,244,232,225,105,128,248,145,244,232,225,105,128, 14, + 74,245,240,240,229,242,236,229,230,244,244,232,225,105,128,248, + 144,249,225,237,239,235,244,232,225,105,128, 14, 70,235,225,244, + 225,235,225,238, 97,129, 48,222,125,138,232,225,236,230,247,233, + 228,244,104,128,255,143,236,101,128, 38, 66,238,243,249,239,238, + 243,241,245,225,242,101,128, 51, 71,241,225,230,232,229,226,242, + 229,119,128, 5,190,242,115,128, 38, 66,115, 2,125,192,125,210, + 239,242,225,227,233,242,227,236,229,232,229,226,242,229,119,128, + 5,175,241,245,225,242,101,128, 51,131, 98, 2,125,224,125,234, + 239,240,239,237,239,230,111,128, 49, 7,243,241,245,225,242,101, + 128, 51,212, 99, 2,125,249,126, 1,233,242,227,236,101,128, 36, + 220,245,226,229,228,243,241,245,225,242,101,128, 51,165,228,239, + 116, 2,126, 22,126, 31,225,227,227,229,238,116,128, 30, 65,226, + 229,236,239,119,128, 30, 67,101, 7,126, 55,126,182,126,193,126, + 208,126,233,127, 14,127, 26,101, 2,126, 61,126,169,109, 4,126, + 71,126, 80,126, 94,126,110,225,242,225,226,233, 99,128, 6, 69, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,226,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,227,237,101, + 2,126,117,126,130,228,233,225,236,225,242,225,226,233, 99,128, + 254,228,229,237,105, 2,126,138,126,153,238,233,244,233,225,236, + 225,242,225,226,233, 99,128,252,209,243,239,236,225,244,229,228, + 225,242,225,226,233, 99,128,252, 72,244,239,242,245,243,241,245, + 225,242,101,128, 51, 77,232,233,242,225,231,225,238, 97,128, 48, + 129,233,250,233,229,242,225,243,241,245,225,242,101,128, 51,126, + 235,225,244,225,235,225,238, 97,129, 48,225,126,221,232,225,236, + 230,247,233,228,244,104,128,255,146,109,130, 5,222,126,241,127, + 5,228,225,231,229,243,104,129,251, 62,126,252,232,229,226,242, + 229,119,128,251, 62,232,229,226,242,229,119,128, 5,222,238,225, + 242,237,229,238,233,225,110,128, 5,116,242,235,232, 97, 3,127, + 37,127, 46,127, 79,232,229,226,242,229,119,128, 5,165,235,229, + 230,245,236, 97, 2,127, 57,127, 66,232,229,226,242,229,119,128, + 5,166,236,229,230,244,232,229,226,242,229,119,128, 5,166,236, + 229,230,244,232,229,226,242,229,119,128, 5,165,104, 2,127, 98, + 127,104,239,239,107,128, 2,113,250,243,241,245,225,242,101,128, + 51,146,105, 6,127,128,127,165,128, 46,128, 57,128, 82,128,139, + 228,100, 2,127,135,127,160,236,229,228,239,244,235,225,244,225, + 235,225,238,225,232,225,236,230,247,233,228,244,104,128,255,101, + 239,116,128, 0,183,229,245,109, 5,127,179,127,214,127,229,127, + 238,128, 33, 97, 2,127,185,127,200,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50,114,240,225,242,229,238,235,239,242, + 229,225,110,128, 50, 18,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,100,235,239,242,229,225,110,128, 49, 65,112, 2, + 127,244,128, 20, 97, 2,127,250,128, 8,238,243,233,239,243,235, + 239,242,229,225,110,128, 49,112,242,229,238,235,239,242,229,225, + 110,128, 50, 4,233,229,245,240,235,239,242,229,225,110,128, 49, + 110,243,233,239,243,235,239,242,229,225,110,128, 49,111,232,233, + 242,225,231,225,238, 97,128, 48,127,235,225,244,225,235,225,238, + 97,129, 48,223,128, 70,232,225,236,230,247,233,228,244,104,128, + 255,144,238,117, 2,128, 89,128,134,115,132, 34, 18,128,101,128, + 112,128,121,128,127,226,229,236,239,247,227,237, 98,128, 3, 32, + 227,233,242,227,236,101,128, 34,150,237,239,100,128, 2,215,240, + 236,245,115,128, 34, 19,244,101,128, 32, 50,242,105, 2,128,146, + 128,160,226,225,225,242,245,243,241,245,225,242,101,128, 51, 74, + 243,241,245,225,242,101,128, 51, 73,108, 2,128,175,128,190,239, + 238,231,236,229,231,244,245,242,238,229,100,128, 2,112,243,241, + 245,225,242,101,128, 51,150,109, 3,128,207,128,221,128,232,227, + 245,226,229,228,243,241,245,225,242,101,128, 51,163,239,238,239, + 243,240,225,227,101,128,255, 77,243,241,245,225,242,229,228,243, + 241,245,225,242,101,128, 51,159,111, 5,129, 4,129, 30,129, 55, + 129, 65,129, 74,104, 2,129, 10,129, 20,233,242,225,231,225,238, + 97,128, 48,130,237,243,241,245,225,242,101,128, 51,193,235,225, + 244,225,235,225,238, 97,129, 48,226,129, 43,232,225,236,230,247, + 233,228,244,104,128,255,147,236,243,241,245,225,242,101,128, 51, + 214,237,225,244,232,225,105,128, 14, 33,246,229,242,243,243,241, + 245,225,242,101,129, 51,167,129, 89,228,243,241,245,225,242,101, + 128, 51,168,240, 97, 2,129,106,129,112,242,229,110,128, 36,168, + 243,241,245,225,242,101,128, 51,171,115, 2,129,127,129,136,243, + 241,245,225,242,101,128, 51,179,245,240,229,242,233,239,114,128, + 246,239,244,245,242,238,229,100,128, 2,111,117,141, 0,181,129, + 185,129,189,129,199,129,223,129,233,129,255,130, 10,130, 35,130, + 58,130, 68,130, 98,130,162,130,172, 49,128, 0,181,225,243,241, + 245,225,242,101,128, 51,130,227,104, 2,129,206,129,216,231,242, + 229,225,244,229,114,128, 34,107,236,229,243,115,128, 34,106,230, + 243,241,245,225,242,101,128, 51,140,103, 2,129,239,129,246,242, + 229,229,107,128, 3,188,243,241,245,225,242,101,128, 51,141,232, + 233,242,225,231,225,238, 97,128, 48,128,235,225,244,225,235,225, + 238, 97,129, 48,224,130, 23,232,225,236,230,247,233,228,244,104, + 128,255,145,108, 2,130, 41,130, 50,243,241,245,225,242,101,128, + 51,149,244,233,240,236,121,128, 0,215,237,243,241,245,225,242, + 101,128, 51,155,238,225,104, 2,130, 76,130, 85,232,229,226,242, + 229,119,128, 5,163,236,229,230,244,232,229,226,242,229,119,128, + 5,163,115, 2,130,104,130,153,233, 99, 3,130,113,130,130,130, + 141,225,236,238,239,244,101,129, 38,106,130,124,228,226,108,128, + 38,107,230,236,225,244,243,233,231,110,128, 38,109,243,232,225, + 242,240,243,233,231,110,128, 38,111,243,241,245,225,242,101,128, + 51,178,246,243,241,245,225,242,101,128, 51,182,247,243,241,245, + 225,242,101,128, 51,188,118, 2,130,188,130,201,237,229,231,225, + 243,241,245,225,242,101,128, 51,185,243,241,245,225,242,101,128, + 51,183,119, 2,130,216,130,229,237,229,231,225,243,241,245,225, + 242,101,128, 51,191,243,241,245,225,242,101,128, 51,189,110,150, + 0,110,131, 30,131,164,131,188,131,254,132, 23,132, 81,132, 91, + 132,158,132,201,134,235,134,253,135, 22,135, 53,135, 79,135,144, + 137,126,137,134,137,159,137,167,138,135,138,145,138,155, 97, 8, + 131, 48,131, 68,131, 75,131, 82,131,107,131,118,131,143,131,155, + 98, 2,131, 54,131, 63,229,238,231,225,236,105,128, 9,168,236, + 97,128, 34, 7,227,245,244,101,128, 1, 68,228,229,246, 97,128, + 9, 40,231,117, 2,131, 89,131, 98,234,225,242,225,244,105,128, + 10,168,242,237,245,235,232,105,128, 10, 40,232,233,242,225,231, + 225,238, 97,128, 48,106,235,225,244,225,235,225,238, 97,129, 48, + 202,131,131,232,225,236,230,247,233,228,244,104,128,255,133,240, + 239,243,244,242,239,240,232,101,128, 1, 73,243,241,245,225,242, + 101,128, 51,129, 98, 2,131,170,131,180,239,240,239,237,239,230, + 111,128, 49, 11,243,240,225,227,101,128, 0,160, 99, 4,131,198, + 131,205,131,214,131,241,225,242,239,110,128, 1, 72,229,228,233, + 236,236, 97,128, 1, 70,233,242, 99, 2,131,222,131,227,236,101, + 128, 36,221,245,237,230,236,229,248,226,229,236,239,119,128, 30, + 75,239,237,237,225,225,227,227,229,238,116,128, 1, 70,228,239, + 116, 2,132, 6,132, 15,225,227,227,229,238,116,128, 30, 69,226, + 229,236,239,119,128, 30, 71,101, 3,132, 31,132, 42,132, 67,232, + 233,242,225,231,225,238, 97,128, 48,109,235,225,244,225,235,225, + 238, 97,129, 48,205,132, 55,232,225,236,230,247,233,228,244,104, + 128,255,136,247,243,232,229,241,229,236,243,233,231,110,128, 32, + 170,230,243,241,245,225,242,101,128, 51,139,103, 2,132, 97,132, + 147, 97, 3,132,105,132,115,132,122,226,229,238,231,225,236,105, + 128, 9,153,228,229,246, 97,128, 9, 25,231,117, 2,132,129,132, + 138,234,225,242,225,244,105,128, 10,153,242,237,245,235,232,105, + 128, 10, 25,239,238,231,245,244,232,225,105,128, 14, 7,104, 2, + 132,164,132,174,233,242,225,231,225,238, 97,128, 48,147,239,239, + 107, 2,132,182,132,189,236,229,230,116,128, 2,114,242,229,244, + 242,239,230,236,229,120,128, 2,115,105, 4,132,211,133,124,133, + 135,133,193,229,245,110, 7,132,229,133, 8,133, 40,133, 54,133, + 63,133, 96,133,109, 97, 2,132,235,132,250,227,233,242,227,236, + 229,235,239,242,229,225,110,128, 50,111,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 15,227,105, 2,133, 15,133, 27,229, + 245,227,235,239,242,229,225,110,128, 49, 53,242,227,236,229,235, + 239,242,229,225,110,128, 50, 97,232,233,229,245,232,235,239,242, + 229,225,110,128, 49, 54,235,239,242,229,225,110,128, 49, 52,240, + 97, 2,133, 70,133, 84,238,243,233,239,243,235,239,242,229,225, + 110,128, 49,104,242,229,238,235,239,242,229,225,110,128, 50, 1, + 243,233,239,243,235,239,242,229,225,110,128, 49,103,244,233,235, + 229,245,244,235,239,242,229,225,110,128, 49,102,232,233,242,225, + 231,225,238, 97,128, 48,107,107, 2,133,141,133,165,225,244,225, + 235,225,238, 97,129, 48,203,133,153,232,225,236,230,247,233,228, + 244,104,128,255,134,232,225,232,233,116, 2,133,175,133,186,236, + 229,230,244,244,232,225,105,128,248,153,244,232,225,105,128, 14, + 77,238,101,141, 0, 57,133,224,133,233,133,243,134, 17,134, 24, + 134, 49,134, 76,134,110,134,122,134,133,134,166,134,174,134,185, + 225,242,225,226,233, 99,128, 6,105,226,229,238,231,225,236,105, + 128, 9,239,227,233,242,227,236,101,129, 36,104,133,254,233,238, + 246,229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39, + 146,228,229,246, 97,128, 9,111,231,117, 2,134, 31,134, 40,234, + 225,242,225,244,105,128, 10,239,242,237,245,235,232,105,128, 10, + 111,232, 97, 2,134, 56,134, 67,227,235,225,242,225,226,233, 99, + 128, 6,105,238,231,250,232,239,117,128, 48, 41,105, 2,134, 82, + 134,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 40,238,230,229,242,233,239,114,128, 32,137,237,239, + 238,239,243,240,225,227,101,128,255, 25,239,236,228,243,244,249, + 236,101,128,247, 57,112, 2,134,139,134,146,225,242,229,110,128, + 36,124,229,114, 2,134,153,134,159,233,239,100,128, 36,144,243, + 233,225,110,128, 6,249,242,239,237,225,110,128, 33,120,243,245, + 240,229,242,233,239,114,128, 32,121,116, 2,134,191,134,229,229, + 229,110, 2,134,199,134,208,227,233,242,227,236,101,128, 36,114, + 112, 2,134,214,134,221,225,242,229,110,128, 36,134,229,242,233, + 239,100,128, 36,154,232,225,105,128, 14, 89,106,129, 1,204,134, + 241,229,227,249,242,233,236,236,233, 99,128, 4, 90,235,225,244, + 225,235,225,238, 97,129, 48,243,135, 10,232,225,236,230,247,233, + 228,244,104,128,255,157,108, 2,135, 28,135, 42,229,231,242,233, + 231,232,244,236,239,238,103,128, 1,158,233,238,229,226,229,236, + 239,119,128, 30, 73,109, 2,135, 59,135, 70,239,238,239,243,240, + 225,227,101,128,255, 78,243,241,245,225,242,101,128, 51,154,110, + 2,135, 85,135,135, 97, 3,135, 93,135,103,135,110,226,229,238, + 231,225,236,105,128, 9,163,228,229,246, 97,128, 9, 35,231,117, + 2,135,117,135,126,234,225,242,225,244,105,128, 10,163,242,237, + 245,235,232,105,128, 10, 35,238,225,228,229,246, 97,128, 9, 41, + 111, 6,135,158,135,169,135,194,135,235,136,187,137,114,232,233, + 242,225,231,225,238, 97,128, 48,110,235,225,244,225,235,225,238, + 97,129, 48,206,135,182,232,225,236,230,247,233,228,244,104,128, + 255,137,110, 3,135,202,135,218,135,227,226,242,229,225,235,233, + 238,231,243,240,225,227,101,128, 0,160,229,238,244,232,225,105, + 128, 14, 19,245,244,232,225,105,128, 14, 25,239,110, 7,135,252, + 136, 5,136, 19,136, 53,136, 69,136,110,136,169,225,242,225,226, + 233, 99,128, 6, 70,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,230,231,232,245,238,238, 97, 2,136, 30,136, 39,225,242, + 225,226,233, 99,128, 6,186,230,233,238,225,236,225,242,225,226, + 233, 99,128,251,159,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,254,231,234,229,229,237,105, 2,136, 79,136, 94,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,210,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,252, 75,237,101, + 2,136,117,136,130,228,233,225,236,225,242,225,226,233, 99,128, + 254,232,229,237,105, 2,136,138,136,153,238,233,244,233,225,236, + 225,242,225,226,233, 99,128,252,213,243,239,236,225,244,229,228, + 225,242,225,226,233, 99,128,252, 78,238,239,239,238,230,233,238, + 225,236,225,242,225,226,233, 99,128,252,141,116, 7,136,203,136, + 214,136,243,137, 22,137, 34,137, 54,137, 80,227,239,238,244,225, + 233,238,115,128, 34, 12,101, 2,136,220,136,236,236,229,237,229, + 238,116,129, 34, 9,136,231,239,102,128, 34, 9,241,245,225,108, + 128, 34, 96,231,242,229,225,244,229,114,129, 34,111,136,255,238, + 239,114, 2,137, 7,137, 15,229,241,245,225,108,128, 34,113,236, + 229,243,115,128, 34,121,233,228,229,238,244,233,227,225,108,128, + 34, 98,236,229,243,115,129, 34,110,137, 43,238,239,242,229,241, + 245,225,108,128, 34,112,112, 2,137, 60,137, 70,225,242,225,236, + 236,229,108,128, 34, 38,242,229,227,229,228,229,115,128, 34,128, + 243,117, 3,137, 89,137, 96,137,105,226,243,229,116,128, 34,132, + 227,227,229,229,228,115,128, 34,129,240,229,242,243,229,116,128, + 34,133,247,225,242,237,229,238,233,225,110,128, 5,118,240,225, + 242,229,110,128, 36,169,115, 2,137,140,137,149,243,241,245,225, + 242,101,128, 51,177,245,240,229,242,233,239,114,128, 32,127,244, + 233,236,228,101,128, 0,241,117,132, 3,189,137,179,137,190,138, + 15,138, 98,232,233,242,225,231,225,238, 97,128, 48,108,107, 2, + 137,196,137,220,225,244,225,235,225,238, 97,129, 48,204,137,208, + 232,225,236,230,247,233,228,244,104,128,255,135,244, 97, 3,137, + 229,137,239,137,246,226,229,238,231,225,236,105,128, 9,188,228, + 229,246, 97,128, 9, 60,231,117, 2,137,253,138, 6,234,225,242, + 225,244,105,128, 10,188,242,237,245,235,232,105,128, 10, 60,109, + 2,138, 21,138, 55,226,229,242,243,233,231,110,130, 0, 35,138, + 35,138, 47,237,239,238,239,243,240,225,227,101,128,255, 3,243, + 237,225,236,108,128,254, 95,229,114, 2,138, 62,138, 94,225,236, + 243,233,231,110, 2,138, 73,138, 81,231,242,229,229,107,128, 3, + 116,236,239,247,229,242,231,242,229,229,107,128, 3,117,111,128, + 33, 22,110,130, 5,224,138,106,138,126,228,225,231,229,243,104, + 129,251, 64,138,117,232,229,226,242,229,119,128,251, 64,232,229, + 226,242,229,119,128, 5,224,246,243,241,245,225,242,101,128, 51, + 181,247,243,241,245,225,242,101,128, 51,187,249, 97, 3,138,164, + 138,174,138,181,226,229,238,231,225,236,105,128, 9,158,228,229, + 246, 97,128, 9, 30,231,117, 2,138,188,138,197,234,225,242,225, + 244,105,128, 10,158,242,237,245,235,232,105,128, 10, 30,111,147, + 0,111,138,248,139, 14,139, 92,140, 6,140, 78,140, 93,140,133, + 141, 0,141, 21,141, 59,141, 70,141,248,143, 82,143,146,143,179, + 143,225,144, 98,144,145,144,157, 97, 2,138,254,139, 5,227,245, + 244,101,128, 0,243,238,231,244,232,225,105,128, 14, 45, 98, 4, + 139, 24,139, 66,139, 75,139, 85,225,242,242,229,100,130, 2,117, + 139, 36,139, 47,227,249,242,233,236,236,233, 99,128, 4,233,228, + 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, + 4,235,229,238,231,225,236,105,128, 9,147,239,240,239,237,239, + 230,111,128, 49, 27,242,229,246,101,128, 1, 79, 99, 3,139,100, + 139,173,139,252, 97, 2,139,106,139,167,238,228,242, 97, 3,139, + 117,139,124,139,135,228,229,246, 97,128, 9, 17,231,245,234,225, + 242,225,244,105,128, 10,145,246,239,247,229,236,243,233,231,110, + 2,139,149,139,156,228,229,246, 97,128, 9, 73,231,245,234,225, + 242,225,244,105,128, 10,201,242,239,110,128, 1,210,233,242, 99, + 2,139,181,139,186,236,101,128, 36,222,245,237,230,236,229,120, + 133, 0,244,139,205,139,213,139,224,139,232,139,244,225,227,245, + 244,101,128, 30,209,228,239,244,226,229,236,239,119,128, 30,217, + 231,242,225,246,101,128, 30,211,232,239,239,235,225,226,239,246, + 101,128, 30,213,244,233,236,228,101,128, 30,215,249,242,233,236, + 236,233, 99,128, 4, 62,100, 4,140, 16,140, 39,140, 45,140, 68, + 226,108, 2,140, 23,140, 31,225,227,245,244,101,128, 1, 81,231, + 242,225,246,101,128, 2, 13,229,246, 97,128, 9, 19,233,229,242, + 229,243,233,115,129, 0,246,140, 57,227,249,242,233,236,236,233, + 99,128, 4,231,239,244,226,229,236,239,119,128, 30,205,101,129, + 1, 83,140, 84,235,239,242,229,225,110,128, 49, 90,103, 3,140, + 101,140,116,140,123,239,238,229,107,129, 2,219,140,110,227,237, + 98,128, 3, 40,242,225,246,101,128, 0,242,245,234,225,242,225, + 244,105,128, 10,147,104, 4,140,143,140,154,140,164,140,242,225, + 242,237,229,238,233,225,110,128, 5,133,233,242,225,231,225,238, + 97,128, 48, 74,111, 2,140,170,140,180,239,235,225,226,239,246, + 101,128, 30,207,242,110,133, 1,161,140,195,140,203,140,214,140, + 222,140,234,225,227,245,244,101,128, 30,219,228,239,244,226,229, + 236,239,119,128, 30,227,231,242,225,246,101,128, 30,221,232,239, + 239,235,225,226,239,246,101,128, 30,223,244,233,236,228,101,128, + 30,225,245,238,231,225,242,245,237,236,225,245,116,128, 1, 81, + 105,129, 1,163,141, 6,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 15,107, 2,141, 27,141, 51,225,244,225,235,225, + 238, 97,129, 48,170,141, 39,232,225,236,230,247,233,228,244,104, + 128,255,117,239,242,229,225,110,128, 49, 87,236,229,232,229,226, + 242,229,119,128, 5,171,109, 6,141, 84,141,112,141,119,141,208, + 141,219,141,237,225,227,242,239,110,130, 1, 77,141, 96,141,104, + 225,227,245,244,101,128, 30, 83,231,242,225,246,101,128, 30, 81, + 228,229,246, 97,128, 9, 80,229,231, 97,133, 3,201,141,135,141, + 139,141,150,141,164,141,180, 49,128, 3,214,227,249,242,233,236, + 236,233, 99,128, 4, 97,236,225,244,233,238,227,236,239,243,229, + 100,128, 2,119,242,239,245,238,228,227,249,242,233,236,236,233, + 99,128, 4,123,116, 2,141,186,141,201,233,244,236,239,227,249, + 242,233,236,236,233, 99,128, 4,125,239,238,239,115,128, 3,206, + 231,245,234,225,242,225,244,105,128, 10,208,233,227,242,239,110, + 129, 3,191,141,229,244,239,238,239,115,128, 3,204,239,238,239, + 243,240,225,227,101,128,255, 79,238,101,145, 0, 49,142, 31,142, + 40,142, 50,142, 80,142,105,142,114,142,123,142,148,142,182,142, + 216,142,228,142,247,143, 2,143, 35,143, 45,143, 53,143, 64,225, + 242,225,226,233, 99,128, 6, 97,226,229,238,231,225,236,105,128, + 9,231,227,233,242,227,236,101,129, 36, 96,142, 61,233,238,246, + 229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39,138, + 100, 2,142, 86,142, 92,229,246, 97,128, 9,103,239,244,229,238, + 236,229,225,228,229,114,128, 32, 36,229,233,231,232,244,104,128, + 33, 91,230,233,244,244,229,100,128,246,220,231,117, 2,142,130, + 142,139,234,225,242,225,244,105,128, 10,231,242,237,245,235,232, + 105,128, 10,103,232, 97, 3,142,157,142,168,142,173,227,235,225, + 242,225,226,233, 99,128, 6, 97,236,102,128, 0,189,238,231,250, + 232,239,117,128, 48, 33,105, 2,142,188,142,206,228,229,239,231, + 242,225,240,232,233,227,240,225,242,229,110,128, 50, 32,238,230, + 229,242,233,239,114,128, 32,129,237,239,238,239,243,240,225,227, + 101,128,255, 17,238,245,237,229,242,225,244,239,242,226,229,238, + 231,225,236,105,128, 9,244,239,236,228,243,244,249,236,101,128, + 247, 49,112, 2,143, 8,143, 15,225,242,229,110,128, 36,116,229, + 114, 2,143, 22,143, 28,233,239,100,128, 36,136,243,233,225,110, + 128, 6,241,241,245,225,242,244,229,114,128, 0,188,242,239,237, + 225,110,128, 33,112,243,245,240,229,242,233,239,114,128, 0,185, + 244,104, 2,143, 71,143, 76,225,105,128, 14, 81,233,242,100,128, + 33, 83,111, 3,143, 90,143,124,143,140,103, 2,143, 96,143,114, + 239,238,229,107,129, 1,235,143,105,237,225,227,242,239,110,128, + 1,237,245,242,237,245,235,232,105,128, 10, 19,237,225,244,242, + 225,231,245,242,237,245,235,232,105,128, 10, 75,240,229,110,128, + 2, 84,112, 3,143,154,143,161,143,172,225,242,229,110,128, 36, + 170,229,238,226,245,236,236,229,116,128, 37,230,244,233,239,110, + 128, 35, 37,114, 2,143,185,143,214,100, 2,143,191,143,202,230, + 229,237,233,238,233,238,101,128, 0,170,237,225,243,227,245,236, + 233,238,101,128, 0,186,244,232,239,231,239,238,225,108,128, 34, + 31,115, 5,143,237,144, 13,144, 30,144, 75,144, 88,232,239,242, + 116, 2,143,246,143,253,228,229,246, 97,128, 9, 18,246,239,247, + 229,236,243,233,231,238,228,229,246, 97,128, 9, 74,236,225,243, + 104,129, 0,248,144, 22,225,227,245,244,101,128, 1,255,237,225, + 236,108, 2,144, 39,144, 50,232,233,242,225,231,225,238, 97,128, + 48, 73,235,225,244,225,235,225,238, 97,129, 48,169,144, 63,232, + 225,236,230,247,233,228,244,104,128,255,107,244,242,239,235,229, + 225,227,245,244,101,128, 1,255,245,240,229,242,233,239,114,128, + 246,240,116, 2,144,104,144,115,227,249,242,233,236,236,233, 99, + 128, 4,127,233,236,228,101,130, 0,245,144,126,144,134,225,227, + 245,244,101,128, 30, 77,228,233,229,242,229,243,233,115,128, 30, + 79,245,226,239,240,239,237,239,230,111,128, 49, 33,118, 2,144, + 163,144,244,229,114, 2,144,170,144,236,236,233,238,101,131, 32, + 62,144,183,144,206,144,229, 99, 2,144,189,144,201,229,238,244, + 229,242,236,233,238,101,128,254, 74,237, 98,128, 3, 5,100, 2, + 144,212,144,220,225,243,232,229,100,128,254, 73,226,236,247,225, + 246,121,128,254, 76,247,225,246,121,128,254, 75,243,227,239,242, + 101,128, 0,175,239,247,229,236,243,233,231,110, 3,145, 3,145, + 13,145, 20,226,229,238,231,225,236,105,128, 9,203,228,229,246, + 97,128, 9, 75,231,245,234,225,242,225,244,105,128, 10,203,112, + 145, 0,112,145, 69,147,197,147,208,147,217,147,229,149,154,149, + 164,150,156,151,175,152, 9,152, 35,152,166,152,174,153, 76,153, + 134,153,162,153,172, 97, 14,145, 99,145,131,145,141,145,148,145, + 155,145,203,145,214,145,228,145,239,146, 30,146, 44,147, 56,147, + 95,147,185, 97, 2,145,105,145,117,237,240,243,243,241,245,225, + 242,101,128, 51,128,243,229,238,244,239,243,241,245,225,242,101, + 128, 51, 43,226,229,238,231,225,236,105,128, 9,170,227,245,244, + 101,128, 30, 85,228,229,246, 97,128, 9, 42,103, 2,145,161,145, + 179,101, 2,145,167,145,174,228,239,247,110,128, 33,223,245,112, + 128, 33,222,117, 2,145,185,145,194,234,225,242,225,244,105,128, + 10,170,242,237,245,235,232,105,128, 10, 42,232,233,242,225,231, + 225,238, 97,128, 48,113,233,249,225,238,238,239,233,244,232,225, + 105,128, 14, 47,235,225,244,225,235,225,238, 97,128, 48,209,108, + 2,145,245,146, 14,225,244,225,236,233,250,225,244,233,239,238, + 227,249,242,233,236,236,233,227,227,237, 98,128, 4,132,239,227, + 232,235,225,227,249,242,233,236,236,233, 99,128, 4,192,238,243, + 233,239,243,235,239,242,229,225,110,128, 49,127,114, 3,146, 52, + 146, 73,147, 45, 97, 2,146, 58,146, 66,231,242,225,240,104,128, + 0,182,236,236,229,108,128, 34, 37,229,110, 2,146, 80,146,190, + 236,229,230,116,136, 0, 40,146,103,146,118,146,123,146,128,146, + 139,146,151,146,174,146,179,225,236,244,239,238,229,225,242,225, + 226,233, 99,128,253, 62,226,116,128,248,237,229,120,128,248,236, + 233,238,230,229,242,233,239,114,128, 32,141,237,239,238,239,243, + 240,225,227,101,128,255, 8,115, 2,146,157,146,164,237,225,236, + 108,128,254, 89,245,240,229,242,233,239,114,128, 32,125,244,112, + 128,248,235,246,229,242,244,233,227,225,108,128,254, 53,242,233, + 231,232,116,136, 0, 41,146,214,146,229,146,234,146,239,146,250, + 147, 6,147, 29,147, 34,225,236,244,239,238,229,225,242,225,226, + 233, 99,128,253, 63,226,116,128,248,248,229,120,128,248,247,233, + 238,230,229,242,233,239,114,128, 32,142,237,239,238,239,243,240, + 225,227,101,128,255, 9,115, 2,147, 12,147, 19,237,225,236,108, + 128,254, 90,245,240,229,242,233,239,114,128, 32,126,244,112,128, + 248,246,246,229,242,244,233,227,225,108,128,254, 54,244,233,225, + 236,228,233,230,102,128, 34, 2,115, 3,147, 64,147, 75,147, 87, + 229,241,232,229,226,242,229,119,128, 5,192,232,244,225,232,229, + 226,242,229,119,128, 5,153,241,245,225,242,101,128, 51,169,244, + 225,104,134, 5,183,147,113,147,127,147,132,147,141,147,156,147, + 172, 49, 2,147,119,147,123, 49,128, 5,183,100,128, 5,183,178, + 97,128, 5,183,232,229,226,242,229,119,128, 5,183,238,225,242, + 242,239,247,232,229,226,242,229,119,128, 5,183,241,245,225,242, + 244,229,242,232,229,226,242,229,119,128, 5,183,247,233,228,229, + 232,229,226,242,229,119,128, 5,183,250,229,242,232,229,226,242, + 229,119,128, 5,161,226,239,240,239,237,239,230,111,128, 49, 6, + 227,233,242,227,236,101,128, 36,223,228,239,244,225,227,227,229, + 238,116,128, 30, 87,101,137, 5,228,147,251,148, 6,148, 26,148, + 38,148, 58,148,160,148,171,148,192,149,147,227,249,242,233,236, + 236,233, 99,128, 4, 63,228,225,231,229,243,104,129,251, 68,148, + 17,232,229,226,242,229,119,128,251, 68,229,250,233,243,241,245, + 225,242,101,128, 51, 59,230,233,238,225,236,228,225,231,229,243, + 232,232,229,226,242,229,119,128,251, 67,104, 5,148, 70,148, 93, + 148,101,148,115,148,145,225,114, 2,148, 77,148, 84,225,226,233, + 99,128, 6,126,237,229,238,233,225,110,128, 5,122,229,226,242, + 229,119,128, 5,228,230,233,238,225,236,225,242,225,226,233, 99, + 128,251, 87,105, 2,148,121,148,136,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,251, 88,242,225,231,225,238, 97,128, 48, + 122,237,229,228,233,225,236,225,242,225,226,233, 99,128,251, 89, + 235,225,244,225,235,225,238, 97,128, 48,218,237,233,228,228,236, + 229,232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,167, + 114, 5,148,204,148,216,149, 2,149,123,149,136,225,230,229,232, + 229,226,242,229,119,128,251, 78,227,229,238,116,131, 0, 37,148, + 229,148,238,148,250,225,242,225,226,233, 99,128, 6,106,237,239, + 238,239,243,240,225,227,101,128,255, 5,243,237,225,236,108,128, + 254,106,105, 2,149, 8,149,105,239,100,134, 0, 46,149, 25,149, + 36,149, 47,149, 59,149, 70,149, 82,225,242,237,229,238,233,225, + 110,128, 5,137,227,229,238,244,229,242,229,100,128, 0,183,232, + 225,236,230,247,233,228,244,104,128,255, 97,233,238,230,229,242, + 233,239,114,128,246,231,237,239,238,239,243,240,225,227,101,128, + 255, 14,115, 2,149, 88,149, 95,237,225,236,108,128,254, 82,245, + 240,229,242,233,239,114,128,246,232,243,240,239,237,229,238,233, + 231,242,229,229,235,227,237, 98,128, 3, 66,240,229,238,228,233, + 227,245,236,225,114,128, 34,165,244,232,239,245,243,225,238,100, + 128, 32, 48,243,229,244, 97,128, 32,167,230,243,241,245,225,242, + 101,128, 51,138,104, 3,149,172,149,222,150,103, 97, 3,149,180, + 149,190,149,197,226,229,238,231,225,236,105,128, 9,171,228,229, + 246, 97,128, 9, 43,231,117, 2,149,204,149,213,234,225,242,225, + 244,105,128, 10,171,242,237,245,235,232,105,128, 10, 43,105,133, + 3,198,149,236,149,240,150, 70,150, 78,150, 89, 49,128, 3,213, + 229,245,240,104, 4,149,253,150, 32,150, 47,150, 56, 97, 2,150, + 3,150, 18,227,233,242,227,236,229,235,239,242,229,225,110,128, + 50,122,240,225,242,229,238,235,239,242,229,225,110,128, 50, 26, + 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,108,235, + 239,242,229,225,110,128, 49, 77,240,225,242,229,238,235,239,242, + 229,225,110,128, 50, 12,236,225,244,233,110,128, 2,120,238,244, + 232,245,244,232,225,105,128, 14, 58,243,249,237,226,239,236,231, + 242,229,229,107,128, 3,213,111, 3,150,111,150,116,150,142,239, + 107,128, 1,165,240,104, 2,150,123,150,132,225,238,244,232,225, + 105,128, 14, 30,245,238,231,244,232,225,105,128, 14, 28,243,225, + 237,240,232,225,239,244,232,225,105,128, 14, 32,105,133, 3,192, + 150,170,151,126,151,137,151,148,151,162,229,245,112, 6,150,186, + 150,221,150,253,151, 25,151, 39,151, 91, 97, 2,150,192,150,207, + 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,115,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 19,227,105, 2, + 150,228,150,240,229,245,227,235,239,242,229,225,110,128, 49,118, + 242,227,236,229,235,239,242,229,225,110,128, 50,101,107, 2,151, + 3,151, 17,233,249,229,239,235,235,239,242,229,225,110,128, 49, + 114,239,242,229,225,110,128, 49, 66,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 5,243,233,239,115, 2,151, 48,151, 76, + 107, 2,151, 54,151, 68,233,249,229,239,235,235,239,242,229,225, + 110,128, 49,116,239,242,229,225,110,128, 49, 68,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49,117,116, 2,151, 97,151, + 112,232,233,229,245,244,232,235,239,242,229,225,110,128, 49,119, + 233,235,229,245,244,235,239,242,229,225,110,128, 49,115,232,233, + 242,225,231,225,238, 97,128, 48,116,235,225,244,225,235,225,238, + 97,128, 48,212,243,249,237,226,239,236,231,242,229,229,107,128, + 3,214,247,242,225,242,237,229,238,233,225,110,128, 5,131,236, + 245,115,132, 0, 43,151,189,151,200,151,209,151,242,226,229,236, + 239,247,227,237, 98,128, 3, 31,227,233,242,227,236,101,128, 34, + 149,109, 2,151,215,151,222,233,238,245,115,128, 0,177,111, 2, + 151,228,151,232,100,128, 2,214,238,239,243,240,225,227,101,128, + 255, 11,115, 2,151,248,151,255,237,225,236,108,128,254, 98,245, + 240,229,242,233,239,114,128, 32,122,109, 2,152, 15,152, 26,239, + 238,239,243,240,225,227,101,128,255, 80,243,241,245,225,242,101, + 128, 51,216,111, 5,152, 47,152, 58,152,125,152,136,152,146,232, + 233,242,225,231,225,238, 97,128, 48,125,233,238,244,233,238,231, + 233,238,228,229,120, 4,152, 78,152, 90,152,102,152,115,228,239, + 247,238,247,232,233,244,101,128, 38, 31,236,229,230,244,247,232, + 233,244,101,128, 38, 28,242,233,231,232,244,247,232,233,244,101, + 128, 38, 30,245,240,247,232,233,244,101,128, 38, 29,235,225,244, + 225,235,225,238, 97,128, 48,221,240,236,225,244,232,225,105,128, + 14, 27,243,244,225,236,237,225,242,107,129, 48, 18,152,159,230, + 225,227,101,128, 48, 32,240,225,242,229,110,128, 36,171,114, 3, + 152,182,152,208,152,233,101, 2,152,188,152,196,227,229,228,229, + 115,128, 34,122,243,227,242,233,240,244,233,239,110,128, 33, 30, + 233,237,101, 2,152,216,152,222,237,239,100,128, 2,185,242,229, + 246,229,242,243,229,100,128, 32, 53,111, 4,152,243,152,250,153, + 4,153, 17,228,245,227,116,128, 34, 15,234,229,227,244,233,246, + 101,128, 35, 5,236,239,238,231,229,228,235,225,238, 97,128, 48, + 252,112, 2,153, 23,153, 60,101, 2,153, 29,153, 36,236,236,239, + 114,128, 35, 24,242,243,117, 2,153, 44,153, 51,226,243,229,116, + 128, 34,130,240,229,242,243,229,116,128, 34,131,239,242,244,233, + 239,110,129, 34, 55,153, 71,225,108,128, 34, 29,115, 2,153, 82, + 153,125,105,130, 3,200,153, 90,153,101,227,249,242,233,236,236, + 233, 99,128, 4,113,236,233,240,238,229,245,237,225,244,225,227, + 249,242,233,236,236,233,227,227,237, 98,128, 4,134,243,241,245, + 225,242,101,128, 51,176,117, 2,153,140,153,151,232,233,242,225, + 231,225,238, 97,128, 48,119,235,225,244,225,235,225,238, 97,128, + 48,215,246,243,241,245,225,242,101,128, 51,180,247,243,241,245, + 225,242,101,128, 51,186,113,136, 0,113,153,202,154,251,155, 6, + 155, 15,155, 22,155, 34,155, 72,155, 80, 97, 4,153,212,153,235, + 154, 43,154,234,100, 2,153,218,153,224,229,246, 97,128, 9, 88, + 237,225,232,229,226,242,229,119,128, 5,168,102, 4,153,245,153, + 254,154, 12,154, 28,225,242,225,226,233, 99,128, 6, 66,230,233, + 238,225,236,225,242,225,226,233, 99,128,254,214,233,238,233,244, + 233,225,236,225,242,225,226,233, 99,128,254,215,237,229,228,233, + 225,236,225,242,225,226,233, 99,128,254,216,237,225,244,115,136, + 5,184,154, 66,154, 86,154,100,154,105,154,110,154,119,154,134, + 154,221, 49, 3,154, 74,154, 78,154, 82, 48,128, 5,184, 97,128, + 5,184, 99,128, 5,184, 50, 2,154, 92,154, 96, 55,128, 5,184, + 57,128, 5,184,179, 51,128, 5,184,228,101,128, 5,184,232,229, + 226,242,229,119,128, 5,184,238,225,242,242,239,247,232,229,226, + 242,229,119,128, 5,184,113, 2,154,140,154,206,225,244,225,110, + 4,154,153,154,162,154,177,154,193,232,229,226,242,229,119,128, + 5,184,238,225,242,242,239,247,232,229,226,242,229,119,128, 5, + 184,241,245,225,242,244,229,242,232,229,226,242,229,119,128, 5, + 184,247,233,228,229,232,229,226,242,229,119,128, 5,184,245,225, + 242,244,229,242,232,229,226,242,229,119,128, 5,184,247,233,228, + 229,232,229,226,242,229,119,128, 5,184,242,238,229,249,240,225, + 242,225,232,229,226,242,229,119,128, 5,159,226,239,240,239,237, + 239,230,111,128, 49, 17,227,233,242,227,236,101,128, 36,224,232, + 239,239,107,128, 2,160,237,239,238,239,243,240,225,227,101,128, + 255, 81,239,102,130, 5,231,155, 43,155, 63,228,225,231,229,243, + 104,129,251, 71,155, 54,232,229,226,242,229,119,128,251, 71,232, + 229,226,242,229,119,128, 5,231,240,225,242,229,110,128, 36,172, + 117, 4,155, 90,155,102,155,191,156, 22,225,242,244,229,242,238, + 239,244,101,128, 38,105,226,245,244,115,135, 5,187,155,123,155, + 128,155,133,155,138,155,147,155,162,155,178,177, 56,128, 5,187, + 178, 53,128, 5,187,179, 49,128, 5,187,232,229,226,242,229,119, + 128, 5,187,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,187,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,187,247,233,228,229,232,229,226,242,229,119,128, 5,187,229, + 243,244,233,239,110,133, 0, 63,155,210,155,233,155,250,156, 2, + 156, 14,225,114, 2,155,217,155,224,225,226,233, 99,128, 6, 31, + 237,229,238,233,225,110,128, 5, 94,228,239,247,110,129, 0,191, + 155,242,243,237,225,236,108,128,247,191,231,242,229,229,107,128, + 3,126,237,239,238,239,243,240,225,227,101,128,255, 31,243,237, + 225,236,108,128,247, 63,239,244,101, 4,156, 34,156,105,156,125, + 156,154,228,226,108,133, 0, 34,156, 50,156, 57,156, 64,156, 76, + 156, 97,226,225,243,101,128, 32, 30,236,229,230,116,128, 32, 28, + 237,239,238,239,243,240,225,227,101,128,255, 2,240,242,233,237, + 101,129, 48, 30,156, 86,242,229,246,229,242,243,229,100,128, 48, + 29,242,233,231,232,116,128, 32, 29,236,229,230,116,129, 32, 24, + 156,114,242,229,246,229,242,243,229,100,128, 32, 27,114, 2,156, + 131,156,141,229,246,229,242,243,229,100,128, 32, 27,233,231,232, + 116,129, 32, 25,156,150,110,128, 1, 73,243,233,238,231,108, 2, + 156,164,156,171,226,225,243,101,128, 32, 26,101,129, 0, 39,156, + 177,237,239,238,239,243,240,225,227,101,128,255, 7,114,145, 0, + 114,156,227,157,231,157,242,158, 33,158, 84,159,101,159,125,159, + 220,161,254,162, 35,162, 47,162,101,162,109,163, 15,163, 26,163, + 61,163,161, 97, 11,156,251,157, 6,157, 16,157, 23,157, 88,157, + 104,157,129,157,140,157,165,157,188,157,225,225,242,237,229,238, + 233,225,110,128, 5,124,226,229,238,231,225,236,105,128, 9,176, + 227,245,244,101,128, 1, 85,100, 4,157, 33,157, 39,157, 53,157, + 79,229,246, 97,128, 9, 48,233,227,225,108,129, 34, 26,157, 48, + 229,120,128,248,229,239,246,229,242,243,243,241,245,225,242,101, + 129, 51,174,157, 69,228,243,241,245,225,242,101,128, 51,175,243, + 241,245,225,242,101,128, 51,173,230,101,129, 5,191,157, 95,232, + 229,226,242,229,119,128, 5,191,231,117, 2,157,111,157,120,234, + 225,242,225,244,105,128, 10,176,242,237,245,235,232,105,128, 10, + 48,232,233,242,225,231,225,238, 97,128, 48,137,235,225,244,225, + 235,225,238, 97,129, 48,233,157,153,232,225,236,230,247,233,228, + 244,104,128,255,151,236,239,247,229,242,228,233,225,231,239,238, + 225,236,226,229,238,231,225,236,105,128, 9,241,109, 2,157,194, + 157,217,233,228,228,236,229,228,233,225,231,239,238,225,236,226, + 229,238,231,225,236,105,128, 9,240,243,232,239,242,110,128, 2, + 100,244,233,111,128, 34, 54,226,239,240,239,237,239,230,111,128, + 49, 22, 99, 4,157,252,158, 3,158, 12,158, 20,225,242,239,110, + 128, 1, 89,229,228,233,236,236, 97,128, 1, 87,233,242,227,236, + 101,128, 36,225,239,237,237,225,225,227,227,229,238,116,128, 1, + 87,100, 2,158, 39,158, 49,226,236,231,242,225,246,101,128, 2, + 17,239,116, 2,158, 56,158, 65,225,227,227,229,238,116,128, 30, + 89,226,229,236,239,119,129, 30, 91,158, 75,237,225,227,242,239, + 110,128, 30, 93,101, 6,158, 98,158,143,158,178,158,233,159, 2, + 159, 35,102, 2,158,104,158,117,229,242,229,238,227,229,237,225, + 242,107,128, 32, 59,236,229,248,243,117, 2,158,127,158,134,226, + 243,229,116,128, 34,134,240,229,242,243,229,116,128, 34,135,231, + 233,243,244,229,114, 2,158,154,158,159,229,100,128, 0,174,115, + 2,158,165,158,171,225,238,115,128,248,232,229,242,233,102,128, + 246,218,104, 3,158,186,158,209,158,223,225,114, 2,158,193,158, + 200,225,226,233, 99,128, 6, 49,237,229,238,233,225,110,128, 5, + 128,230,233,238,225,236,225,242,225,226,233, 99,128,254,174,233, + 242,225,231,225,238, 97,128, 48,140,235,225,244,225,235,225,238, + 97,129, 48,236,158,246,232,225,236,230,247,233,228,244,104,128, + 255,154,243,104,130, 5,232,159, 11,159, 26,228,225,231,229,243, + 232,232,229,226,242,229,119,128,251, 72,232,229,226,242,229,119, + 128, 5,232,118, 3,159, 43,159, 56,159, 88,229,242,243,229,228, + 244,233,236,228,101,128, 34, 61,233, 97, 2,159, 63,159, 72,232, + 229,226,242,229,119,128, 5,151,237,245,231,242,225,243,232,232, + 229,226,242,229,119,128, 5,151,236,239,231,233,227,225,236,238, + 239,116,128, 35, 16,230,233,243,232,232,239,239,107,129, 2,126, + 159,114,242,229,246,229,242,243,229,100,128, 2,127,104, 2,159, + 131,159,154, 97, 2,159,137,159,147,226,229,238,231,225,236,105, + 128, 9,221,228,229,246, 97,128, 9, 93,111,131, 3,193,159,164, + 159,193,159,207,239,107,129, 2,125,159,171,244,245,242,238,229, + 100,129, 2,123,159,182,243,245,240,229,242,233,239,114,128, 2, + 181,243,249,237,226,239,236,231,242,229,229,107,128, 3,241,244, + 233,227,232,239,239,235,237,239,100,128, 2,222,105, 6,159,234, + 161, 22,161, 68,161, 79,161,104,161,240,229,245,108, 9,160, 0, + 160, 35,160, 50,160, 64,160,110,160,124,160,210,160,223,161, 2, + 97, 2,160, 6,160, 21,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,113,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 17,227,233,242,227,236,229,235,239,242,229,225,110,128, + 50, 99,232,233,229,245,232,235,239,242,229,225,110,128, 49, 64, + 107, 2,160, 70,160,102,233,249,229,239,107, 2,160, 80,160, 89, + 235,239,242,229,225,110,128, 49, 58,243,233,239,243,235,239,242, + 229,225,110,128, 49,105,239,242,229,225,110,128, 49, 57,237,233, + 229,245,237,235,239,242,229,225,110,128, 49, 59,112, 3,160,132, + 160,164,160,179, 97, 2,160,138,160,152,238,243,233,239,243,235, + 239,242,229,225,110,128, 49,108,242,229,238,235,239,242,229,225, + 110,128, 50, 3,232,233,229,245,240,232,235,239,242,229,225,110, + 128, 49, 63,233,229,245,112, 2,160,188,160,197,235,239,242,229, + 225,110,128, 49, 60,243,233,239,243,235,239,242,229,225,110,128, + 49,107,243,233,239,243,235,239,242,229,225,110,128, 49, 61,116, + 2,160,229,160,244,232,233,229,245,244,232,235,239,242,229,225, + 110,128, 49, 62,233,235,229,245,244,235,239,242,229,225,110,128, + 49,106,249,229,239,242,233,238,232,233,229,245,232,235,239,242, + 229,225,110,128, 49,109,231,232,116, 2,161, 30,161, 38,225,238, + 231,236,101,128, 34, 31,116, 2,161, 44,161, 58,225,227,235,226, + 229,236,239,247,227,237, 98,128, 3, 25,242,233,225,238,231,236, + 101,128, 34,191,232,233,242,225,231,225,238, 97,128, 48,138,235, + 225,244,225,235,225,238, 97,129, 48,234,161, 92,232,225,236,230, + 247,233,228,244,104,128,255,152,110, 2,161,110,161,226,103,131, + 2,218,161,120,161,131,161,137,226,229,236,239,247,227,237, 98, + 128, 3, 37,227,237, 98,128, 3, 10,232,225,236,102, 2,161,146, + 161,192,236,229,230,116,131, 2,191,161,159,161,170,161,181,225, + 242,237,229,238,233,225,110,128, 5, 89,226,229,236,239,247,227, + 237, 98,128, 3, 28,227,229,238,244,229,242,229,100,128, 2,211, + 242,233,231,232,116,130, 2,190,161,204,161,215,226,229,236,239, + 247,227,237, 98,128, 3, 57,227,229,238,244,229,242,229,100,128, + 2,210,246,229,242,244,229,228,226,242,229,246,101,128, 2, 19, + 244,244,239,242,245,243,241,245,225,242,101,128, 51, 81,108, 2, + 162, 4,162, 15,233,238,229,226,229,236,239,119,128, 30, 95,239, + 238,231,236,229,103,129, 2,124,162, 26,244,245,242,238,229,100, + 128, 2,122,237,239,238,239,243,240,225,227,101,128,255, 82,111, + 3,162, 55,162, 66,162, 91,232,233,242,225,231,225,238, 97,128, + 48,141,235,225,244,225,235,225,238, 97,129, 48,237,162, 79,232, + 225,236,230,247,233,228,244,104,128,255,155,242,245,225,244,232, + 225,105,128, 14, 35,240,225,242,229,110,128, 36,173,114, 3,162, + 117,162,153,162,183, 97, 3,162,125,162,135,162,142,226,229,238, + 231,225,236,105,128, 9,220,228,229,246, 97,128, 9, 49,231,245, + 242,237,245,235,232,105,128, 10, 92,229,104, 2,162,160,162,169, + 225,242,225,226,233, 99,128, 6,145,230,233,238,225,236,225,242, + 225,226,233, 99,128,251,141,246,239,227,225,236,233, 99, 4,162, + 199,162,209,162,216,162,227,226,229,238,231,225,236,105,128, 9, + 224,228,229,246, 97,128, 9, 96,231,245,234,225,242,225,244,105, + 128, 10,224,246,239,247,229,236,243,233,231,110, 3,162,243,162, + 253,163, 4,226,229,238,231,225,236,105,128, 9,196,228,229,246, + 97,128, 9, 68,231,245,234,225,242,225,244,105,128, 10,196,243, + 245,240,229,242,233,239,114,128,246,241,116, 2,163, 32,163, 40, + 226,236,239,227,107,128, 37,144,245,242,238,229,100,129, 2,121, + 163, 50,243,245,240,229,242,233,239,114,128, 2,180,117, 4,163, + 71,163, 82,163,107,163,154,232,233,242,225,231,225,238, 97,128, + 48,139,235,225,244,225,235,225,238, 97,129, 48,235,163, 95,232, + 225,236,230,247,233,228,244,104,128,255,153,112, 2,163,113,163, + 148,229,101, 2,163,120,163,134,237,225,242,235,226,229,238,231, + 225,236,105,128, 9,242,243,233,231,238,226,229,238,231,225,236, + 105,128, 9,243,233,225,104,128,246,221,244,232,225,105,128, 14, + 36,246,239,227,225,236,233, 99, 4,163,177,163,187,163,194,163, + 205,226,229,238,231,225,236,105,128, 9,139,228,229,246, 97,128, + 9, 11,231,245,234,225,242,225,244,105,128, 10,139,246,239,247, + 229,236,243,233,231,110, 3,163,221,163,231,163,238,226,229,238, + 231,225,236,105,128, 9,195,228,229,246, 97,128, 9, 67,231,245, + 234,225,242,225,244,105,128, 10,195,115,147, 0,115,164, 35,166, + 5,166, 16,166,142,166,181,169,123,169,134,172, 21,174,159,174, + 205,174,232,175,167,175,234,177, 11,177, 21,177,207,178, 24,178, + 194,178,204, 97, 9,164, 55,164, 65,164, 86,164,158,164,183,164, + 194,164,219,164,251,165, 35,226,229,238,231,225,236,105,128, 9, + 184,227,245,244,101,129, 1, 91,164, 74,228,239,244,225,227,227, + 229,238,116,128, 30,101,100, 5,164, 98,164,107,164,113,164,127, + 164,143,225,242,225,226,233, 99,128, 6, 53,229,246, 97,128, 9, + 56,230,233,238,225,236,225,242,225,226,233, 99,128,254,186,233, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,254,187,237, + 229,228,233,225,236,225,242,225,226,233, 99,128,254,188,231,117, + 2,164,165,164,174,234,225,242,225,244,105,128, 10,184,242,237, + 245,235,232,105,128, 10, 56,232,233,242,225,231,225,238, 97,128, + 48, 85,235,225,244,225,235,225,238, 97,129, 48,181,164,207,232, + 225,236,230,247,233,228,244,104,128,255,123,236,236,225,236,236, + 225,232,239,245,225,236,225,249,232,229,247,225,243,225,236,236, + 225,237,225,242,225,226,233, 99,128,253,250,237,229,235,104,130, + 5,225,165, 6,165, 26,228,225,231,229,243,104,129,251, 65,165, + 17,232,229,226,242,229,119,128,251, 65,232,229,226,242,229,119, + 128, 5,225,242, 97, 5,165, 48,165,122,165,130,165,180,165,188, + 97, 5,165, 60,165, 68,165, 76,165,107,165,115,225,244,232,225, + 105,128, 14, 50,229,244,232,225,105,128, 14, 65,233,237,225,233, + 109, 2,165, 86,165, 97,225,236,225,233,244,232,225,105,128, 14, + 68,245,225,238,244,232,225,105,128, 14, 67,237,244,232,225,105, + 128, 14, 51,244,232,225,105,128, 14, 48,229,244,232,225,105,128, + 14, 64,105, 3,165,138,165,162,165,173,105, 2,165,144,165,155, + 236,229,230,244,244,232,225,105,128,248,134,244,232,225,105,128, + 14, 53,236,229,230,244,244,232,225,105,128,248,133,244,232,225, + 105,128, 14, 52,239,244,232,225,105,128, 14, 66,117, 3,165,196, + 165,246,165,253,101, 3,165,204,165,228,165,239,101, 2,165,210, + 165,221,236,229,230,244,244,232,225,105,128,248,136,244,232,225, + 105,128, 14, 55,236,229,230,244,244,232,225,105,128,248,135,244, + 232,225,105,128, 14, 54,244,232,225,105,128, 14, 56,245,244,232, + 225,105,128, 14, 57,226,239,240,239,237,239,230,111,128, 49, 25, + 99, 5,166, 28,166, 49,166, 58,166,107,166,129,225,242,239,110, + 129, 1, 97,166, 37,228,239,244,225,227,227,229,238,116,128, 30, + 103,229,228,233,236,236, 97,128, 1, 95,232,247, 97,131, 2, 89, + 166, 70,166, 81,166,100,227,249,242,233,236,236,233, 99,128, 4, + 217,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,219,232,239,239,107,128, 2, 90,233,242, 99, 2,166, + 115,166,120,236,101,128, 36,226,245,237,230,236,229,120,128, 1, + 93,239,237,237,225,225,227,227,229,238,116,128, 2, 25,228,239, + 116, 2,166,150,166,159,225,227,227,229,238,116,128, 30, 97,226, + 229,236,239,119,129, 30, 99,166,169,228,239,244,225,227,227,229, + 238,116,128, 30,105,101, 9,166,201,166,217,166,252,167, 61,167, + 164,167,191,167,216,168, 41,168, 68,225,231,245,236,236,226,229, + 236,239,247,227,237, 98,128, 3, 60, 99, 2,166,223,166,245,239, + 238,100,129, 32, 51,166,231,244,239,238,229,227,232,233,238,229, + 243,101,128, 2,202,244,233,239,110,128, 0,167,229,110, 4,167, + 7,167, 16,167, 30,167, 46,225,242,225,226,233, 99,128, 6, 51, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,178,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,179,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,254,180,231,239,108, + 135, 5,182,167, 81,167, 95,167,100,167,109,167,124,167,140,167, + 151, 49, 2,167, 87,167, 91, 51,128, 5,182,102,128, 5,182,178, + 99,128, 5,182,232,229,226,242,229,119,128, 5,182,238,225,242, + 242,239,247,232,229,226,242,229,119,128, 5,182,241,245,225,242, + 244,229,242,232,229,226,242,229,119,128, 5,182,244,225,232,229, + 226,242,229,119,128, 5,146,247,233,228,229,232,229,226,242,229, + 119,128, 5,182,104, 2,167,170,167,181,225,242,237,229,238,233, + 225,110,128, 5,125,233,242,225,231,225,238, 97,128, 48, 91,235, + 225,244,225,235,225,238, 97,129, 48,187,167,204,232,225,236,230, + 247,233,228,244,104,128,255,126,237,105, 2,167,223,168, 10,227, + 239,236,239,110,131, 0, 59,167,237,167,246,168, 2,225,242,225, + 226,233, 99,128, 6, 27,237,239,238,239,243,240,225,227,101,128, + 255, 27,243,237,225,236,108,128,254, 84,246,239,233,227,229,228, + 237,225,242,235,235,225,238, 97,129, 48,156,168, 29,232,225,236, + 230,247,233,228,244,104,128,255,159,238,116, 2,168, 48,168, 58, + 233,243,241,245,225,242,101,128, 51, 34,239,243,241,245,225,242, + 101,128, 51, 35,246,229,110,142, 0, 55,168,102,168,111,168,121, + 168,151,168,158,168,168,168,193,168,220,168,254,169, 10,169, 21, + 169, 54,169, 62,169, 73,225,242,225,226,233, 99,128, 6,103,226, + 229,238,231,225,236,105,128, 9,237,227,233,242,227,236,101,129, + 36,102,168,132,233,238,246,229,242,243,229,243,225,238,243,243, + 229,242,233,102,128, 39,144,228,229,246, 97,128, 9,109,229,233, + 231,232,244,232,115,128, 33, 94,231,117, 2,168,175,168,184,234, + 225,242,225,244,105,128, 10,237,242,237,245,235,232,105,128, 10, + 109,232, 97, 2,168,200,168,211,227,235,225,242,225,226,233, 99, + 128, 6,103,238,231,250,232,239,117,128, 48, 39,105, 2,168,226, + 168,244,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 38,238,230,229,242,233,239,114,128, 32,135,237,239, + 238,239,243,240,225,227,101,128,255, 23,239,236,228,243,244,249, + 236,101,128,247, 55,112, 2,169, 27,169, 34,225,242,229,110,128, + 36,122,229,114, 2,169, 41,169, 47,233,239,100,128, 36,142,243, + 233,225,110,128, 6,247,242,239,237,225,110,128, 33,118,243,245, + 240,229,242,233,239,114,128, 32,119,116, 2,169, 79,169,117,229, + 229,110, 2,169, 87,169, 96,227,233,242,227,236,101,128, 36,112, + 112, 2,169,102,169,109,225,242,229,110,128, 36,132,229,242,233, + 239,100,128, 36,152,232,225,105,128, 14, 87,230,244,232,249,240, + 232,229,110,128, 0,173,104, 7,169,150,170,124,170,135,170,149, + 171, 94,171,107,172, 15, 97, 6,169,164,169,175,169,185,169,196, + 170, 83,170,108,225,242,237,229,238,233,225,110,128, 5,119,226, + 229,238,231,225,236,105,128, 9,182,227,249,242,233,236,236,233, + 99,128, 4, 72,100, 2,169,202,170, 42,228, 97, 4,169,213,169, + 222,169,253,170, 11,225,242,225,226,233, 99,128, 6, 81,228,225, + 237,237, 97, 2,169,232,169,241,225,242,225,226,233, 99,128,252, + 97,244,225,238,225,242,225,226,233, 99,128,252, 94,230,225,244, + 232,225,225,242,225,226,233, 99,128,252, 96,235,225,243,242, 97, + 2,170, 21,170, 30,225,242,225,226,233, 99,128,252, 98,244,225, + 238,225,242,225,226,233, 99,128,252, 95,101,132, 37,146,170, 54, + 170, 61,170, 69,170, 78,228,225,242,107,128, 37,147,236,233,231, + 232,116,128, 37,145,237,229,228,233,245,109,128, 37,146,246, 97, + 128, 9, 54,231,117, 2,170, 90,170, 99,234,225,242,225,244,105, + 128, 10,182,242,237,245,235,232,105,128, 10, 54,236,243,232,229, + 236,229,244,232,229,226,242,229,119,128, 5,147,226,239,240,239, + 237,239,230,111,128, 49, 21,227,232,225,227,249,242,233,236,236, + 233, 99,128, 4, 73,101, 4,170,159,170,224,170,234,170,251,229, + 110, 4,170,170,170,179,170,193,170,209,225,242,225,226,233, 99, + 128, 6, 52,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 182,233,238,233,244,233,225,236,225,242,225,226,233, 99,128,254, + 183,237,229,228,233,225,236,225,242,225,226,233, 99,128,254,184, + 233,227,239,240,244,233, 99,128, 3,227,241,229,108,129, 32,170, + 170,242,232,229,226,242,229,119,128, 32,170,246, 97,134, 5,176, + 171, 12,171, 27,171, 41,171, 50,171, 65,171, 81, 49, 2,171, 18, + 171, 23,177, 53,128, 5,176, 53,128, 5,176, 50, 2,171, 33,171, + 37, 50,128, 5,176,101,128, 5,176,232,229,226,242,229,119,128, + 5,176,238,225,242,242,239,247,232,229,226,242,229,119,128, 5, + 176,241,245,225,242,244,229,242,232,229,226,242,229,119,128, 5, + 176,247,233,228,229,232,229,226,242,229,119,128, 5,176,232,225, + 227,249,242,233,236,236,233, 99,128, 4,187,105, 2,171,113,171, + 124,237,225,227,239,240,244,233, 99,128, 3,237,110,131, 5,233, + 171,134,171,217,171,226,100, 2,171,140,171,206,225,231,229,243, + 104,130,251, 73,171,152,171,161,232,229,226,242,229,119,128,251, + 73,115, 2,171,167,171,187,232,233,238,228,239,116,129,251, 44, + 171,178,232,229,226,242,229,119,128,251, 44,233,238,228,239,116, + 129,251, 45,171,197,232,229,226,242,229,119,128,251, 45,239,244, + 232,229,226,242,229,119,128, 5,193,232,229,226,242,229,119,128, + 5,233,115, 2,171,232,171,252,232,233,238,228,239,116,129,251, + 42,171,243,232,229,226,242,229,119,128,251, 42,233,238,228,239, + 116,129,251, 43,172, 6,232,229,226,242,229,119,128,251, 43,239, + 239,107,128, 2,130,105, 8,172, 39,172, 83,172, 94,172,119,172, + 149,172,157,172,170,173, 85,231,237, 97,131, 3,195,172, 51,172, + 55,172, 63, 49,128, 3,194,230,233,238,225,108,128, 3,194,236, + 245,238,225,244,229,243,249,237,226,239,236,231,242,229,229,107, + 128, 3,242,232,233,242,225,231,225,238, 97,128, 48, 87,235,225, + 244,225,235,225,238, 97,129, 48,183,172,107,232,225,236,230,247, + 233,228,244,104,128,255,124,236,245,113, 2,172,127,172,136,232, + 229,226,242,229,119,128, 5,189,236,229,230,244,232,229,226,242, + 229,119,128, 5,189,237,233,236,225,114,128, 34, 60,238,228,239, + 244,232,229,226,242,229,119,128, 5,194,239,115, 6,172,185,172, + 220,172,252,173, 24,173, 38,173, 70, 97, 2,172,191,172,206,227, + 233,242,227,236,229,235,239,242,229,225,110,128, 50,116,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 20,227,105, 2,172, + 227,172,239,229,245,227,235,239,242,229,225,110,128, 49,126,242, + 227,236,229,235,239,242,229,225,110,128, 50,102,107, 2,173, 2, + 173, 16,233,249,229,239,235,235,239,242,229,225,110,128, 49,122, + 239,242,229,225,110,128, 49, 69,238,233,229,245,238,235,239,242, + 229,225,110,128, 49,123,112, 2,173, 44,173, 57,225,242,229,238, + 235,239,242,229,225,110,128, 50, 6,233,229,245,240,235,239,242, + 229,225,110,128, 49,125,244,233,235,229,245,244,235,239,242,229, + 225,110,128, 49,124,120,141, 0, 54,173,115,173,124,173,134,173, + 164,173,171,173,196,173,223,174, 1,174, 13,174, 24,174, 57,174, + 65,174, 76,225,242,225,226,233, 99,128, 6,102,226,229,238,231, + 225,236,105,128, 9,236,227,233,242,227,236,101,129, 36,101,173, + 145,233,238,246,229,242,243,229,243,225,238,243,243,229,242,233, + 102,128, 39,143,228,229,246, 97,128, 9,108,231,117, 2,173,178, + 173,187,234,225,242,225,244,105,128, 10,236,242,237,245,235,232, + 105,128, 10,108,232, 97, 2,173,203,173,214,227,235,225,242,225, + 226,233, 99,128, 6,102,238,231,250,232,239,117,128, 48, 38,105, + 2,173,229,173,247,228,229,239,231,242,225,240,232,233,227,240, + 225,242,229,110,128, 50, 37,238,230,229,242,233,239,114,128, 32, + 134,237,239,238,239,243,240,225,227,101,128,255, 22,239,236,228, + 243,244,249,236,101,128,247, 54,112, 2,174, 30,174, 37,225,242, + 229,110,128, 36,121,229,114, 2,174, 44,174, 50,233,239,100,128, + 36,141,243,233,225,110,128, 6,246,242,239,237,225,110,128, 33, + 117,243,245,240,229,242,233,239,114,128, 32,118,116, 2,174, 82, + 174,153,229,229,110, 2,174, 90,174,132, 99, 2,174, 96,174,104, + 233,242,227,236,101,128, 36,111,245,242,242,229,238,227,249,228, + 229,238,239,237,233,238,225,244,239,242,226,229,238,231,225,236, + 105,128, 9,249,112, 2,174,138,174,145,225,242,229,110,128, 36, + 131,229,242,233,239,100,128, 36,151,232,225,105,128, 14, 86,108, + 2,174,165,174,185,225,243,104,129, 0, 47,174,173,237,239,238, + 239,243,240,225,227,101,128,255, 15,239,238,103,129, 1,127,174, + 193,228,239,244,225,227,227,229,238,116,128, 30,155,109, 2,174, + 211,174,221,233,236,229,230,225,227,101,128, 38, 58,239,238,239, + 243,240,225,227,101,128,255, 83,111, 6,174,246,175, 40,175, 51, + 175, 76,175,121,175,132,102, 2,174,252,175, 10,240,225,243,245, + 241,232,229,226,242,229,119,128, 5,195,116, 2,175, 16,175, 25, + 232,249,240,232,229,110,128, 0,173,243,233,231,238,227,249,242, + 233,236,236,233, 99,128, 4, 76,232,233,242,225,231,225,238, 97, + 128, 48, 93,235,225,244,225,235,225,238, 97,129, 48,189,175, 64, + 232,225,236,230,247,233,228,244,104,128,255,127,236,233,228,245, + 115, 2,175, 86,175,103,236,239,238,231,239,246,229,242,236,225, + 249,227,237, 98,128, 3, 56,243,232,239,242,244,239,246,229,242, + 236,225,249,227,237, 98,128, 3, 55,242,245,243,233,244,232,225, + 105,128, 14, 41,115, 3,175,140,175,150,175,158,225,236,225,244, + 232,225,105,128, 14, 40,239,244,232,225,105,128, 14, 11,245,225, + 244,232,225,105,128, 14, 42,240, 97, 3,175,176,175,196,175,228, + 227,101,129, 0, 32,175,183,232,225,227,235,225,242,225,226,233, + 99,128, 0, 32,228,101,129, 38, 96,175,203,243,245,233,116, 2, + 175,212,175,220,226,236,225,227,107,128, 38, 96,247,232,233,244, + 101,128, 38,100,242,229,110,128, 36,174,241,245,225,242,101, 11, + 176, 6,176, 17,176, 31,176, 56,176, 73,176, 99,176,114,176,147, + 176,174,176,230,176,245,226,229,236,239,247,227,237, 98,128, 3, + 59, 99, 2,176, 23,176, 27, 99,128, 51,196,109,128, 51,157,228, + 233,225,231,239,238,225,236,227,242,239,243,243,232,225,244,227, + 232,230,233,236,108,128, 37,169,232,239,242,233,250,239,238,244, + 225,236,230,233,236,108,128, 37,164,107, 2,176, 79,176, 83,103, + 128, 51,143,109,129, 51,158,176, 89,227,225,240,233,244,225,108, + 128, 51,206,108, 2,176,105,176,109,110,128, 51,209,239,103,128, + 51,210,109, 4,176,124,176,128,176,133,176,137,103,128, 51,142, + 233,108,128, 51,213,109,128, 51,156,243,241,245,225,242,229,100, + 128, 51,161,239,242,244,232,239,231,239,238,225,236,227,242,239, + 243,243,232,225,244,227,232,230,233,236,108,128, 37,166,245,240, + 240,229,114, 2,176,184,176,207,236,229,230,244,244,239,236,239, + 247,229,242,242,233,231,232,244,230,233,236,108,128, 37,167,242, + 233,231,232,244,244,239,236,239,247,229,242,236,229,230,244,230, + 233,236,108,128, 37,168,246,229,242,244,233,227,225,236,230,233, + 236,108,128, 37,165,247,232,233,244,229,247,233,244,232,243,237, + 225,236,236,226,236,225,227,107,128, 37,163,242,243,241,245,225, + 242,101,128, 51,219,115, 2,177, 27,177,197, 97, 4,177, 37,177, + 47,177, 54,177, 65,226,229,238,231,225,236,105,128, 9,183,228, + 229,246, 97,128, 9, 55,231,245,234,225,242,225,244,105,128, 10, + 183,238,103, 8,177, 84,177, 98,177,112,177,126,177,141,177,155, + 177,169,177,182,227,233,229,245,227,235,239,242,229,225,110,128, + 49, 73,232,233,229,245,232,235,239,242,229,225,110,128, 49,133, + 233,229,245,238,231,235,239,242,229,225,110,128, 49,128,235,233, + 249,229,239,235,235,239,242,229,225,110,128, 49, 50,238,233,229, + 245,238,235,239,242,229,225,110,128, 49,101,240,233,229,245,240, + 235,239,242,229,225,110,128, 49, 67,243,233,239,243,235,239,242, + 229,225,110,128, 49, 70,244,233,235,229,245,244,235,239,242,229, + 225,110,128, 49, 56,245,240,229,242,233,239,114,128,246,242,116, + 2,177,213,177,236,229,242,236,233,238,103,129, 0,163,177,224, + 237,239,238,239,243,240,225,227,101,128,255,225,242,239,235,101, + 2,177,245,178, 6,236,239,238,231,239,246,229,242,236,225,249, + 227,237, 98,128, 3, 54,243,232,239,242,244,239,246,229,242,236, + 225,249,227,237, 98,128, 3, 53,117, 7,178, 40,178, 72,178, 94, + 178,105,178,146,178,156,178,160,226,243,229,116,130, 34,130,178, + 51,178, 62,238,239,244,229,241,245,225,108,128, 34,138,239,242, + 229,241,245,225,108,128, 34,134, 99, 2,178, 78,178, 86,227,229, + 229,228,115,128, 34,123,232,244,232,225,116,128, 34, 11,232,233, + 242,225,231,225,238, 97,128, 48, 89,107, 2,178,111,178,135,225, + 244,225,235,225,238, 97,129, 48,185,178,123,232,225,236,230,247, + 233,228,244,104,128,255,125,245,238,225,242,225,226,233, 99,128, + 6, 82,237,237,225,244,233,239,110,128, 34, 17,110,128, 38, 60, + 240,229,242,243,229,116,130, 34,131,178,173,178,184,238,239,244, + 229,241,245,225,108,128, 34,139,239,242,229,241,245,225,108,128, + 34,135,246,243,241,245,225,242,101,128, 51,220,249,239,245,247, + 225,229,242,225,243,241,245,225,242,101,128, 51,124,116,144, 0, + 116,179, 1,180, 10,180, 31,180,174,180,214,183, 6,186,144,187, + 219,187,231,187,243,189, 20,189, 45,189,131,190, 55,190,239,191, + 73, 97, 10,179, 23,179, 33,179, 54,179, 61,179, 86,179,164,179, + 181,179,206,179,220,179,224,226,229,238,231,225,236,105,128, 9, + 164,227,107, 2,179, 40,179, 47,228,239,247,110,128, 34,164,236, + 229,230,116,128, 34,163,228,229,246, 97,128, 9, 36,231,117, 2, + 179, 68,179, 77,234,225,242,225,244,105,128, 10,164,242,237,245, + 235,232,105,128, 10, 36,104, 4,179, 96,179,105,179,119,179,149, + 225,242,225,226,233, 99,128, 6, 55,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,194,105, 2,179,125,179,140,238,233,244, + 233,225,236,225,242,225,226,233, 99,128,254,195,242,225,231,225, + 238, 97,128, 48, 95,237,229,228,233,225,236,225,242,225,226,233, + 99,128,254,196,233,243,249,239,245,229,242,225,243,241,245,225, + 242,101,128, 51,125,235,225,244,225,235,225,238, 97,129, 48,191, + 179,194,232,225,236,230,247,233,228,244,104,128,255,128,244,247, + 229,229,236,225,242,225,226,233, 99,128, 6, 64,117,128, 3,196, + 118,130, 5,234,179,232,180, 1,228,225,231,229,115,129,251, 74, + 179,242,104,129,251, 74,179,248,232,229,226,242,229,119,128,251, + 74,232,229,226,242,229,119,128, 5,234, 98, 2,180, 16,180, 21, + 225,114,128, 1,103,239,240,239,237,239,230,111,128, 49, 10, 99, + 6,180, 45,180, 52,180, 59,180, 68,180,134,180,161,225,242,239, + 110,128, 1,101,227,245,242,108,128, 2,168,229,228,233,236,236, + 97,128, 1, 99,232,229,104, 4,180, 80,180, 89,180,103,180,119, + 225,242,225,226,233, 99,128, 6,134,230,233,238,225,236,225,242, + 225,226,233, 99,128,251,123,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,251,124,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,251,125,233,242, 99, 2,180,142,180,147,236,101, + 128, 36,227,245,237,230,236,229,248,226,229,236,239,119,128, 30, + 113,239,237,237,225,225,227,227,229,238,116,128, 1, 99,100, 2, + 180,180,180,190,233,229,242,229,243,233,115,128, 30,151,239,116, + 2,180,197,180,206,225,227,227,229,238,116,128, 30,107,226,229, + 236,239,119,128, 30,109,101, 9,180,234,180,245,181, 9,182, 19, + 182, 44,182,108,182,175,182,180,182,232,227,249,242,233,236,236, + 233, 99,128, 4, 66,228,229,243,227,229,238,228,229,242,227,249, + 242,233,236,236,233, 99,128, 4,173,104, 7,181, 25,181, 34,181, + 48,181, 88,181,118,181,159,182, 1,225,242,225,226,233, 99,128, + 6, 42,230,233,238,225,236,225,242,225,226,233, 99,128,254,150, + 232,225,232,105, 2,181, 57,181, 72,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,162,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 12,105, 2,181, 94,181,109,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,151,242,225,231, + 225,238, 97,128, 48,102,234,229,229,237,105, 2,181,128,181,143, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,161,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 11,109, + 2,181,165,181,199,225,242,226,245,244, 97, 2,181,176,181,185, + 225,242,225,226,233, 99,128, 6, 41,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,148,101, 2,181,205,181,218,228,233,225, + 236,225,242,225,226,233, 99,128,254,152,229,237,105, 2,181,226, + 181,241,238,233,244,233,225,236,225,242,225,226,233, 99,128,252, + 164,243,239,236,225,244,229,228,225,242,225,226,233, 99,128,252, + 14,238,239,239,238,230,233,238,225,236,225,242,225,226,233, 99, + 128,252,115,235,225,244,225,235,225,238, 97,129, 48,198,182, 32, + 232,225,236,230,247,233,228,244,104,128,255,131,108, 2,182, 50, + 182, 69,229,240,232,239,238,101,129, 33, 33,182, 61,226,236,225, + 227,107,128, 38, 14,233,243,232, 97, 2,182, 78,182, 93,231,229, + 228,239,236,225,232,229,226,242,229,119,128, 5,160,241,229,244, + 225,238,225,232,229,226,242,229,119,128, 5,169,110, 4,182,118, + 182,127,182,146,182,167,227,233,242,227,236,101,128, 36,105,233, + 228,229,239,231,242,225,240,232,233,227,240,225,242,229,110,128, + 50, 41,112, 2,182,152,182,159,225,242,229,110,128, 36,125,229, + 242,233,239,100,128, 36,145,242,239,237,225,110,128, 33,121,243, + 104,128, 2,167,116,131, 5,216,182,190,182,210,182,219,228,225, + 231,229,243,104,129,251, 56,182,201,232,229,226,242,229,119,128, + 251, 56,232,229,226,242,229,119,128, 5,216,243,229,227,249,242, + 233,236,236,233, 99,128, 4,181,246,233,114, 2,182,240,182,249, + 232,229,226,242,229,119,128, 5,155,236,229,230,244,232,229,226, + 242,229,119,128, 5,155,104, 6,183, 20,183,172,184, 38,184,170, + 185, 77,186,134, 97, 5,183, 32,183, 42,183, 49,183, 74,183,103, + 226,229,238,231,225,236,105,128, 9,165,228,229,246, 97,128, 9, + 37,231,117, 2,183, 56,183, 65,234,225,242,225,244,105,128, 10, + 165,242,237,245,235,232,105,128, 10, 37,108, 2,183, 80,183, 89, + 225,242,225,226,233, 99,128, 6, 48,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,172,238,244,232,225,235,232,225,116, 3, + 183,118,183,149,183,156,236,239,119, 2,183,126,183,137,236,229, + 230,244,244,232,225,105,128,248,152,242,233,231,232,244,244,232, + 225,105,128,248,151,244,232,225,105,128, 14, 76,245,240,240,229, + 242,236,229,230,244,244,232,225,105,128,248,150,101, 3,183,180, + 183,244,184, 11,104, 4,183,190,183,199,183,213,183,229,225,242, + 225,226,233, 99,128, 6, 43,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,154,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,254,155,237,229,228,233,225,236,225,242,225,226,233, + 99,128,254,156,242,101, 2,183,251,184, 4,229,248,233,243,244, + 115,128, 34, 3,230,239,242,101,128, 34, 52,244, 97,130, 3,184, + 184, 20,184, 24, 49,128, 3,209,243,249,237,226,239,236,231,242, + 229,229,107,128, 3,209,105, 2,184, 44,184,130,229,245,244,104, + 4,184, 57,184, 92,184,107,184,116, 97, 2,184, 63,184, 78,227, + 233,242,227,236,229,235,239,242,229,225,110,128, 50,121,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 25,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,107,235,239,242,229,225, + 110,128, 49, 76,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 11,242,244,229,229,110, 2,184,140,184,149,227,233,242,227, + 236,101,128, 36,108,112, 2,184,155,184,162,225,242,229,110,128, + 36,128,229,242,233,239,100,128, 36,148,111, 6,184,184,184,201, + 184,206,184,220,184,225,185, 22,238,225,238,231,237,239,238,244, + 232,239,244,232,225,105,128, 14, 17,239,107,128, 1,173,240,232, + 245,244,232,225,239,244,232,225,105,128, 14, 18,242,110,128, 0, + 254,244,104, 3,184,234,185, 2,185, 12, 97, 2,184,240,184,250, + 232,225,238,244,232,225,105,128, 14, 23,238,244,232,225,105,128, + 14, 16,239,238,231,244,232,225,105,128, 14, 24,245,238,231,244, + 232,225,105,128, 14, 22,245,243,225,238,100, 2,185, 32,185, 43, + 227,249,242,233,236,236,233, 99,128, 4,130,243,243,229,240,225, + 242,225,244,239,114, 2,185, 58,185, 67,225,242,225,226,233, 99, + 128, 6,108,240,229,242,243,233,225,110,128, 6,108,242,229,101, + 144, 0, 51,185,115,185,124,185,134,185,164,185,171,185,181,185, + 206,185,233,186, 11,186, 23,186, 42,186, 53,186, 86,186,108,186, + 116,186,127,225,242,225,226,233, 99,128, 6, 99,226,229,238,231, + 225,236,105,128, 9,233,227,233,242,227,236,101,129, 36, 98,185, + 145,233,238,246,229,242,243,229,243,225,238,243,243,229,242,233, + 102,128, 39,140,228,229,246, 97,128, 9,105,229,233,231,232,244, + 232,115,128, 33, 92,231,117, 2,185,188,185,197,234,225,242,225, + 244,105,128, 10,233,242,237,245,235,232,105,128, 10,105,232, 97, + 2,185,213,185,224,227,235,225,242,225,226,233, 99,128, 6, 99, + 238,231,250,232,239,117,128, 48, 35,105, 2,185,239,186, 1,228, + 229,239,231,242,225,240,232,233,227,240,225,242,229,110,128, 50, + 34,238,230,229,242,233,239,114,128, 32,131,237,239,238,239,243, + 240,225,227,101,128,255, 19,238,245,237,229,242,225,244,239,242, + 226,229,238,231,225,236,105,128, 9,246,239,236,228,243,244,249, + 236,101,128,247, 51,112, 2,186, 59,186, 66,225,242,229,110,128, + 36,118,229,114, 2,186, 73,186, 79,233,239,100,128, 36,138,243, + 233,225,110,128, 6,243,241,245,225,242,244,229,242,115,129, 0, + 190,186, 99,229,237,228,225,243,104,128,246,222,242,239,237,225, + 110,128, 33,114,243,245,240,229,242,233,239,114,128, 0,179,244, + 232,225,105,128, 14, 83,250,243,241,245,225,242,101,128, 51,148, + 105, 7,186,160,186,171,187, 30,187,128,187,140,187,189,187,206, + 232,233,242,225,231,225,238, 97,128, 48, 97,107, 2,186,177,186, + 201,225,244,225,235,225,238, 97,129, 48,193,186,189,232,225,236, + 230,247,233,228,244,104,128,255,129,229,245,116, 4,186,213,186, + 248,187, 7,187, 16, 97, 2,186,219,186,234,227,233,242,227,236, + 229,235,239,242,229,225,110,128, 50,112,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 16,227,233,242,227,236,229,235,239, + 242,229,225,110,128, 50, 98,235,239,242,229,225,110,128, 49, 55, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 2,236,228, + 101,133, 2,220,187, 46,187, 57,187, 74,187, 86,187,114,226,229, + 236,239,247,227,237, 98,128, 3, 48, 99, 2,187, 63,187, 68,237, + 98,128, 3, 3,239,237, 98,128, 3, 3,228,239,245,226,236,229, + 227,237, 98,128, 3, 96,111, 2,187, 92,187,102,240,229,242,225, + 244,239,114,128, 34, 60,246,229,242,236,225,249,227,237, 98,128, + 3, 52,246,229,242,244,233,227,225,236,227,237, 98,128, 3, 62, + 237,229,243,227,233,242,227,236,101,128, 34,151,112, 2,187,146, + 187,176,229,232, 97, 2,187,154,187,163,232,229,226,242,229,119, + 128, 5,150,236,229,230,244,232,229,226,242,229,119,128, 5,150, + 240,233,231,245,242,237,245,235,232,105,128, 10,112,244,236,239, + 227,249,242,233,236,236,233,227,227,237, 98,128, 4,131,247,238, + 225,242,237,229,238,233,225,110,128, 5,127,236,233,238,229,226, + 229,236,239,119,128, 30,111,237,239,238,239,243,240,225,227,101, + 128,255, 84,111, 7,188, 3,188, 14,188, 25,188, 50,188,170,188, + 182,189, 10,225,242,237,229,238,233,225,110,128, 5,105,232,233, + 242,225,231,225,238, 97,128, 48,104,235,225,244,225,235,225,238, + 97,129, 48,200,188, 38,232,225,236,230,247,233,228,244,104,128, + 255,132,110, 3,188, 58,188,156,188,161,101, 4,188, 68,188,137, + 188,144,188,150,226,225,114, 4,188, 80,188,109,188,119,188,128, + 229,248,244,242, 97, 2,188, 90,188,100,232,233,231,232,237,239, + 100,128, 2,229,236,239,247,237,239,100,128, 2,233,232,233,231, + 232,237,239,100,128, 2,230,236,239,247,237,239,100,128, 2,232, + 237,233,228,237,239,100,128, 2,231,230,233,246,101,128, 1,189, + 243,233,120,128, 1,133,244,247,111,128, 1,168,239,115,128, 3, + 132,243,241,245,225,242,101,128, 51, 39,240,225,244,225,235,244, + 232,225,105,128, 14, 15,242,244,239,233,243,229,243,232,229,236, + 236,226,242,225,227,235,229,116, 2,188,205,188,235,236,229,230, + 116,130, 48, 20,188,216,188,224,243,237,225,236,108,128,254, 93, + 246,229,242,244,233,227,225,108,128,254, 57,242,233,231,232,116, + 130, 48, 21,188,247,188,255,243,237,225,236,108,128,254, 94,246, + 229,242,244,233,227,225,108,128,254, 58,244,225,239,244,232,225, + 105,128, 14, 21,240, 97, 2,189, 27,189, 39,236,225,244,225,236, + 232,239,239,107,128, 1,171,242,229,110,128, 36,175,114, 3,189, + 53,189, 84,189, 99,225,228,229,237,225,242,107,129, 33, 34,189, + 65,115, 2,189, 71,189, 77,225,238,115,128,248,234,229,242,233, + 102,128,246,219,229,244,242,239,230,236,229,248,232,239,239,107, + 128, 2,136,233,225,103, 4,189,111,189,116,189,121,189,126,228, + 110,128, 37,188,236,102,128, 37,196,242,116,128, 37,186,245,112, + 128, 37,178,115,132, 2,166,189,143,189,182,190, 32,190, 45,225, + 228,105,130, 5,230,189,153,189,173,228,225,231,229,243,104,129, + 251, 70,189,164,232,229,226,242,229,119,128,251, 70,232,229,226, + 242,229,119,128, 5,230,101, 2,189,188,189,199,227,249,242,233, + 236,236,233, 99,128, 4, 70,242,101,134, 5,181,189,216,189,230, + 189,235,189,244,190, 3,190, 19, 49, 2,189,222,189,226, 50,128, + 5,181,101,128, 5,181,178, 98,128, 5,181,232,229,226,242,229, + 119,128, 5,181,238,225,242,242,239,247,232,229,226,242,229,119, + 128, 5,181,241,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,181,247,233,228,229,232,229,226,242,229,119,128, 5,181, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 91,245,240,229, + 242,233,239,114,128,246,243,116, 4,190, 65,190,115,190,180,190, + 231, 97, 3,190, 73,190, 83,190, 90,226,229,238,231,225,236,105, + 128, 9,159,228,229,246, 97,128, 9, 31,231,117, 2,190, 97,190, + 106,234,225,242,225,244,105,128, 10,159,242,237,245,235,232,105, + 128, 10, 31,229,104, 4,190,126,190,135,190,149,190,165,225,242, + 225,226,233, 99,128, 6,121,230,233,238,225,236,225,242,225,226, + 233, 99,128,251,103,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,251,104,237,229,228,233,225,236,225,242,225,226,233, + 99,128,251,105,232, 97, 3,190,189,190,199,190,206,226,229,238, + 231,225,236,105,128, 9,160,228,229,246, 97,128, 9, 32,231,117, + 2,190,213,190,222,234,225,242,225,244,105,128, 10,160,242,237, + 245,235,232,105,128, 10, 32,245,242,238,229,100,128, 2,135,117, + 3,190,247,191, 2,191, 27,232,233,242,225,231,225,238, 97,128, + 48,100,235,225,244,225,235,225,238, 97,129, 48,196,191, 15,232, + 225,236,230,247,233,228,244,104,128,255,130,243,237,225,236,108, + 2,191, 37,191, 48,232,233,242,225,231,225,238, 97,128, 48, 99, + 235,225,244,225,235,225,238, 97,129, 48,195,191, 61,232,225,236, + 230,247,233,228,244,104,128,255,111,119, 2,191, 79,191,184,101, + 2,191, 85,191,133,236,246,101, 3,191, 95,191,104,191,125,227, + 233,242,227,236,101,128, 36,107,112, 2,191,110,191,117,225,242, + 229,110,128, 36,127,229,242,233,239,100,128, 36,147,242,239,237, + 225,110,128, 33,123,238,244,121, 3,191,143,191,152,191,163,227, + 233,242,227,236,101,128, 36,115,232,225,238,231,250,232,239,117, + 128, 83, 68,112, 2,191,169,191,176,225,242,229,110,128, 36,135, + 229,242,233,239,100,128, 36,155,111,142, 0, 50,191,216,191,225, + 191,235,192, 9,192, 61,192, 86,192,113,192,147,192,159,192,178, + 192,189,192,222,192,230,192,254,225,242,225,226,233, 99,128, 6, + 98,226,229,238,231,225,236,105,128, 9,232,227,233,242,227,236, + 101,129, 36, 97,191,246,233,238,246,229,242,243,229,243,225,238, + 243,243,229,242,233,102,128, 39,139,100, 2,192, 15,192, 21,229, + 246, 97,128, 9,104,239,116, 2,192, 28,192, 39,229,238,236,229, + 225,228,229,114,128, 32, 37,236,229,225,228,229,114,129, 32, 37, + 192, 50,246,229,242,244,233,227,225,108,128,254, 48,231,117, 2, + 192, 68,192, 77,234,225,242,225,244,105,128, 10,232,242,237,245, + 235,232,105,128, 10,104,232, 97, 2,192, 93,192,104,227,235,225, + 242,225,226,233, 99,128, 6, 98,238,231,250,232,239,117,128, 48, + 34,105, 2,192,119,192,137,228,229,239,231,242,225,240,232,233, + 227,240,225,242,229,110,128, 50, 33,238,230,229,242,233,239,114, + 128, 32,130,237,239,238,239,243,240,225,227,101,128,255, 18,238, + 245,237,229,242,225,244,239,242,226,229,238,231,225,236,105,128, + 9,245,239,236,228,243,244,249,236,101,128,247, 50,112, 2,192, + 195,192,202,225,242,229,110,128, 36,117,229,114, 2,192,209,192, + 215,233,239,100,128, 36,137,243,233,225,110,128, 6,242,242,239, + 237,225,110,128, 33,113,115, 2,192,236,192,244,244,242,239,235, + 101,128, 1,187,245,240,229,242,233,239,114,128, 0,178,244,104, + 2,193, 5,193, 10,225,105,128, 14, 82,233,242,228,115,128, 33, + 84,117,145, 0,117,193, 55,193, 63,193,104,193,161,194, 43,194, + 80,194,203,194,219,195, 14,195, 84,195,165,195,174,196, 37,196, + 61,196,169,196,197,197, 55,225,227,245,244,101,128, 0,250, 98, + 4,193, 73,193, 78,193, 87,193, 97,225,114,128, 2,137,229,238, + 231,225,236,105,128, 9,137,239,240,239,237,239,230,111,128, 49, + 40,242,229,246,101,128, 1,109, 99, 3,193,112,193,119,193,151, + 225,242,239,110,128, 1,212,233,242, 99, 2,193,127,193,132,236, + 101,128, 36,228,245,237,230,236,229,120,129, 0,251,193,143,226, + 229,236,239,119,128, 30,119,249,242,233,236,236,233, 99,128, 4, + 67,100, 5,193,173,193,184,193,207,193,213,194, 33,225,244,244, + 225,228,229,246, 97,128, 9, 81,226,108, 2,193,191,193,199,225, + 227,245,244,101,128, 1,113,231,242,225,246,101,128, 2, 21,229, + 246, 97,128, 9, 9,233,229,242,229,243,233,115,133, 0,252,193, + 233,193,241,193,249,194, 16,194, 24,225,227,245,244,101,128, 1, + 216,226,229,236,239,119,128, 30,115, 99, 2,193,255,194, 6,225, + 242,239,110,128, 1,218,249,242,233,236,236,233, 99,128, 4,241, + 231,242,225,246,101,128, 1,220,237,225,227,242,239,110,128, 1, + 214,239,244,226,229,236,239,119,128, 30,229,103, 2,194, 49,194, + 56,242,225,246,101,128, 0,249,117, 2,194, 62,194, 71,234,225, + 242,225,244,105,128, 10,137,242,237,245,235,232,105,128, 10, 9, + 104, 3,194, 88,194, 98,194,176,233,242,225,231,225,238, 97,128, + 48, 70,111, 2,194,104,194,114,239,235,225,226,239,246,101,128, + 30,231,242,110,133, 1,176,194,129,194,137,194,148,194,156,194, + 168,225,227,245,244,101,128, 30,233,228,239,244,226,229,236,239, + 119,128, 30,241,231,242,225,246,101,128, 30,235,232,239,239,235, + 225,226,239,246,101,128, 30,237,244,233,236,228,101,128, 30,239, + 245,238,231,225,242,245,237,236,225,245,116,129, 1,113,194,192, + 227,249,242,233,236,236,233, 99,128, 4,243,233,238,246,229,242, + 244,229,228,226,242,229,246,101,128, 2, 23,107, 3,194,227,194, + 251,195, 6,225,244,225,235,225,238, 97,129, 48,166,194,239,232, + 225,236,230,247,233,228,244,104,128,255,115,227,249,242,233,236, + 236,233, 99,128, 4,121,239,242,229,225,110,128, 49, 92,109, 2, + 195, 20,195, 73, 97, 2,195, 26,195, 59,227,242,239,110,130, 1, + 107,195, 37,195, 48,227,249,242,233,236,236,233, 99,128, 4,239, + 228,233,229,242,229,243,233,115,128, 30,123,244,242,225,231,245, + 242,237,245,235,232,105,128, 10, 65,239,238,239,243,240,225,227, + 101,128,255, 85,110, 2,195, 90,195,145,228,229,242,243,227,239, + 242,101,132, 0, 95,195,109,195,115,195,127,195,138,228,226,108, + 128, 32, 23,237,239,238,239,243,240,225,227,101,128,255, 63,246, + 229,242,244,233,227,225,108,128,254, 51,247,225,246,121,128,254, + 79,105, 2,195,151,195,156,239,110,128, 34, 42,246,229,242,243, + 225,108,128, 34, 0,239,231,239,238,229,107,128, 1,115,112, 5, + 195,186,195,193,195,201,195,216,196, 11,225,242,229,110,128, 36, + 176,226,236,239,227,107,128, 37,128,240,229,242,228,239,244,232, + 229,226,242,229,119,128, 5,196,243,233,236,239,110,131, 3,197, + 195,230,195,251,196, 3,228,233,229,242,229,243,233,115,129, 3, + 203,195,243,244,239,238,239,115,128, 3,176,236,225,244,233,110, + 128, 2,138,244,239,238,239,115,128, 3,205,244,225,227,107, 2, + 196, 20,196, 31,226,229,236,239,247,227,237, 98,128, 3, 29,237, + 239,100,128, 2,212,114, 2,196, 43,196, 55,225,231,245,242,237, + 245,235,232,105,128, 10,115,233,238,103,128, 1,111,115, 3,196, + 69,196, 84,196,129,232,239,242,244,227,249,242,233,236,236,233, + 99,128, 4, 94,237,225,236,108, 2,196, 93,196,104,232,233,242, + 225,231,225,238, 97,128, 48, 69,235,225,244,225,235,225,238, 97, + 129, 48,165,196,117,232,225,236,230,247,233,228,244,104,128,255, + 105,244,242,225,233,231,232,116, 2,196,141,196,152,227,249,242, + 233,236,236,233, 99,128, 4,175,243,244,242,239,235,229,227,249, + 242,233,236,236,233, 99,128, 4,177,244,233,236,228,101,130, 1, + 105,196,181,196,189,225,227,245,244,101,128, 30,121,226,229,236, + 239,119,128, 30,117,117, 5,196,209,196,219,196,226,196,251,197, + 11,226,229,238,231,225,236,105,128, 9,138,228,229,246, 97,128, + 9, 10,231,117, 2,196,233,196,242,234,225,242,225,244,105,128, + 10,138,242,237,245,235,232,105,128, 10, 10,237,225,244,242,225, + 231,245,242,237,245,235,232,105,128, 10, 66,246,239,247,229,236, + 243,233,231,110, 3,197, 27,197, 37,197, 44,226,229,238,231,225, + 236,105,128, 9,194,228,229,246, 97,128, 9, 66,231,245,234,225, + 242,225,244,105,128, 10,194,246,239,247,229,236,243,233,231,110, + 3,197, 71,197, 81,197, 88,226,229,238,231,225,236,105,128, 9, + 193,228,229,246, 97,128, 9, 65,231,245,234,225,242,225,244,105, + 128, 10,193,118,139, 0,118,197,125,198, 17,198, 26,198, 37,198, + 222,198,229,199, 71,199, 83,199,183,199,191,199,212, 97, 4,197, + 135,197,142,197,167,197,178,228,229,246, 97,128, 9, 53,231,117, + 2,197,149,197,158,234,225,242,225,244,105,128, 10,181,242,237, + 245,235,232,105,128, 10, 53,235,225,244,225,235,225,238, 97,128, + 48,247,118,132, 5,213,197,190,197,217,197,249,198, 5,228,225, + 231,229,243,104,130,251, 53,197,203,197,208,182, 53,128,251, 53, + 232,229,226,242,229,119,128,251, 53,104, 2,197,223,197,231,229, + 226,242,229,119,128, 5,213,239,236,225,109,129,251, 75,197,240, + 232,229,226,242,229,119,128,251, 75,246,225,246,232,229,226,242, + 229,119,128, 5,240,249,239,228,232,229,226,242,229,119,128, 5, + 241,227,233,242,227,236,101,128, 36,229,228,239,244,226,229,236, + 239,119,128, 30,127,101, 6,198, 51,198, 62,198,126,198,137,198, + 143,198,210,227,249,242,233,236,236,233, 99,128, 4, 50,104, 4, + 198, 72,198, 81,198, 95,198,111,225,242,225,226,233, 99,128, 6, + 164,230,233,238,225,236,225,242,225,226,233, 99,128,251,107,233, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,251,108,237, + 229,228,233,225,236,225,242,225,226,233, 99,128,251,109,235,225, + 244,225,235,225,238, 97,128, 48,249,238,245,115,128, 38, 64,242, + 244,233,227,225,108, 2,198,154,198,160,226,225,114,128, 0,124, + 236,233,238,101, 4,198,173,198,184,198,195,198,204,225,226,239, + 246,229,227,237, 98,128, 3, 13,226,229,236,239,247,227,237, 98, + 128, 3, 41,236,239,247,237,239,100,128, 2,204,237,239,100,128, + 2,200,247,225,242,237,229,238,233,225,110,128, 5,126,232,239, + 239,107,128, 2,139,105, 3,198,237,198,248,199, 31,235,225,244, + 225,235,225,238, 97,128, 48,248,242,225,237, 97, 3,199, 3,199, + 13,199, 20,226,229,238,231,225,236,105,128, 9,205,228,229,246, + 97,128, 9, 77,231,245,234,225,242,225,244,105,128, 10,205,243, + 225,242,231, 97, 3,199, 43,199, 53,199, 60,226,229,238,231,225, + 236,105,128, 9,131,228,229,246, 97,128, 9, 3,231,245,234,225, + 242,225,244,105,128, 10,131,237,239,238,239,243,240,225,227,101, + 128,255, 86,111, 3,199, 91,199,102,199,172,225,242,237,229,238, + 233,225,110,128, 5,120,233,227,229,100, 2,199,111,199,147,233, + 244,229,242,225,244,233,239,110, 2,199,125,199,136,232,233,242, + 225,231,225,238, 97,128, 48,158,235,225,244,225,235,225,238, 97, + 128, 48,254,237,225,242,235,235,225,238, 97,129, 48,155,199,160, + 232,225,236,230,247,233,228,244,104,128,255,158,235,225,244,225, + 235,225,238, 97,128, 48,250,240,225,242,229,110,128, 36,177,116, + 2,199,197,199,204,233,236,228,101,128, 30,125,245,242,238,229, + 100,128, 2,140,117, 2,199,218,199,229,232,233,242,225,231,225, + 238, 97,128, 48,148,235,225,244,225,235,225,238, 97,128, 48,244, + 119,143, 0,119,200, 18,200,251,201, 5,201, 28,201, 68,201,135, + 201,143,203,114,203,155,203,167,203,242,203,250,204, 1,204, 12, + 204, 21, 97, 8,200, 36,200, 43,200, 53,200, 64,200,102,200,134, + 200,146,200,182,227,245,244,101,128, 30,131,229,235,239,242,229, + 225,110,128, 49, 89,232,233,242,225,231,225,238, 97,128, 48,143, + 107, 2,200, 70,200, 94,225,244,225,235,225,238, 97,129, 48,239, + 200, 82,232,225,236,230,247,233,228,244,104,128,255,156,239,242, + 229,225,110,128, 49, 88,243,237,225,236,108, 2,200,112,200,123, + 232,233,242,225,231,225,238, 97,128, 48,142,235,225,244,225,235, + 225,238, 97,128, 48,238,244,244,239,243,241,245,225,242,101,128, + 51, 87,118, 2,200,152,200,160,229,228,225,243,104,128, 48, 28, + 249,245,238,228,229,242,243,227,239,242,229,246,229,242,244,233, + 227,225,108,128,254, 52,119, 3,200,190,200,199,200,213,225,242, + 225,226,233, 99,128, 6, 72,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,238,232,225,237,250,225,225,226,239,246,101, 2, + 200,228,200,237,225,242,225,226,233, 99,128, 6, 36,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,134,226,243,241,245,225, + 242,101,128, 51,221,227,233,242, 99, 2,201, 14,201, 19,236,101, + 128, 36,230,245,237,230,236,229,120,128, 1,117,100, 2,201, 34, + 201, 44,233,229,242,229,243,233,115,128, 30,133,239,116, 2,201, + 51,201, 60,225,227,227,229,238,116,128, 30,135,226,229,236,239, + 119,128, 30,137,101, 4,201, 78,201, 89,201,101,201,125,232,233, + 242,225,231,225,238, 97,128, 48,145,233,229,242,243,244,242,225, + 243,115,128, 33, 24,107, 2,201,107,201,117,225,244,225,235,225, + 238, 97,128, 48,241,239,242,229,225,110,128, 49, 94,239,235,239, + 242,229,225,110,128, 49, 93,231,242,225,246,101,128, 30,129,232, + 233,244,101, 8,201,164,201,173,202, 1,202, 91,202,175,202,220, + 203, 16,203, 72,226,245,236,236,229,116,128, 37,230, 99, 2,201, + 179,201,199,233,242,227,236,101,129, 37,203,201,189,233,238,246, + 229,242,243,101,128, 37,217,239,242,238,229,242,226,242,225,227, + 235,229,116, 2,201,216,201,236,236,229,230,116,129, 48, 14,201, + 225,246,229,242,244,233,227,225,108,128,254, 67,242,233,231,232, + 116,129, 48, 15,201,246,246,229,242,244,233,227,225,108,128,254, + 68,100, 2,202, 7,202, 48,233,225,237,239,238,100,129, 37,199, + 202, 18,227,239,238,244,225,233,238,233,238,231,226,236,225,227, + 235,243,237,225,236,236,228,233,225,237,239,238,100,128, 37,200, + 239,247,238,240,239,233,238,244,233,238,103, 2,202, 64,202, 80, + 243,237,225,236,236,244,242,233,225,238,231,236,101,128, 37,191, + 244,242,233,225,238,231,236,101,128, 37,189,236,101, 2,202, 98, + 202,140,230,244,240,239,233,238,244,233,238,103, 2,202,113,202, + 129,243,237,225,236,236,244,242,233,225,238,231,236,101,128, 37, + 195,244,242,233,225,238,231,236,101,128, 37,193,238,244,233,227, + 245,236,225,242,226,242,225,227,235,229,116, 2,202,160,202,167, + 236,229,230,116,128, 48, 22,242,233,231,232,116,128, 48, 23,242, + 233,231,232,244,240,239,233,238,244,233,238,103, 2,202,193,202, + 209,243,237,225,236,236,244,242,233,225,238,231,236,101,128, 37, + 185,244,242,233,225,238,231,236,101,128, 37,183,115, 3,202,228, + 203, 2,203, 10,109, 2,202,234,202,246,225,236,236,243,241,245, + 225,242,101,128, 37,171,233,236,233,238,231,230,225,227,101,128, + 38, 58,241,245,225,242,101,128, 37,161,244,225,114,128, 38, 6, + 116, 2,203, 22,203, 33,229,236,229,240,232,239,238,101,128, 38, + 15,239,242,244,239,233,243,229,243,232,229,236,236,226,242,225, + 227,235,229,116, 2,203, 57,203, 64,236,229,230,116,128, 48, 24, + 242,233,231,232,116,128, 48, 25,245,240,240,239,233,238,244,233, + 238,103, 2,203, 87,203,103,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,181,244,242,233,225,238,231,236,101,128, + 37,179,105, 2,203,120,203,131,232,233,242,225,231,225,238, 97, + 128, 48,144,107, 2,203,137,203,147,225,244,225,235,225,238, 97, + 128, 48,240,239,242,229,225,110,128, 49, 95,237,239,238,239,243, + 240,225,227,101,128,255, 87,111, 4,203,177,203,188,203,213,203, + 231,232,233,242,225,231,225,238, 97,128, 48,146,235,225,244,225, + 235,225,238, 97,129, 48,242,203,201,232,225,236,230,247,233,228, + 244,104,128,255,102,110,129, 32,169,203,219,237,239,238,239,243, + 240,225,227,101,128,255,230,247,225,229,238,244,232,225,105,128, + 14, 39,240,225,242,229,110,128, 36,178,242,233,238,103,128, 30, + 152,243,245,240,229,242,233,239,114,128, 2,183,244,245,242,238, + 229,100,128, 2,141,249,238,110,128, 1,191,120,137, 0,120,204, + 49,204, 60,204, 71,204, 80,204,107,204,120,204,124,204,136,204, + 144,225,226,239,246,229,227,237, 98,128, 3, 61,226,239,240,239, + 237,239,230,111,128, 49, 18,227,233,242,227,236,101,128, 36,231, + 100, 2,204, 86,204, 96,233,229,242,229,243,233,115,128, 30,141, + 239,244,225,227,227,229,238,116,128, 30,139,229,232,225,242,237, + 229,238,233,225,110,128, 5,109,105,128, 3,190,237,239,238,239, + 243,240,225,227,101,128,255, 88,240,225,242,229,110,128, 36,179, + 243,245,240,229,242,233,239,114,128, 2,227,121,143, 0,121,204, + 189,205,148,205,171,205,211,207,177,207,185,207,202,208, 10,208, + 22,209, 19,209, 59,209, 71,209, 82,209,103,210, 76, 97, 11,204, + 213,204,225,204,235,204,242,204,249,205, 3,205, 28,205, 39,205, + 77,205, 90,205,136,225,228,239,243,241,245,225,242,101,128, 51, + 78,226,229,238,231,225,236,105,128, 9,175,227,245,244,101,128, + 0,253,228,229,246, 97,128, 9, 47,229,235,239,242,229,225,110, + 128, 49, 82,231,117, 2,205, 10,205, 19,234,225,242,225,244,105, + 128, 10,175,242,237,245,235,232,105,128, 10, 47,232,233,242,225, + 231,225,238, 97,128, 48,132,107, 2,205, 45,205, 69,225,244,225, + 235,225,238, 97,129, 48,228,205, 57,232,225,236,230,247,233,228, + 244,104,128,255,148,239,242,229,225,110,128, 49, 81,237,225,235, + 235,225,238,244,232,225,105,128, 14, 78,243,237,225,236,108, 2, + 205,100,205,111,232,233,242,225,231,225,238, 97,128, 48,131,235, + 225,244,225,235,225,238, 97,129, 48,227,205,124,232,225,236,230, + 247,233,228,244,104,128,255,108,244,227,249,242,233,236,236,233, + 99,128, 4, 99,227,233,242, 99, 2,205,157,205,162,236,101,128, + 36,232,245,237,230,236,229,120,128, 1,119,100, 2,205,177,205, + 187,233,229,242,229,243,233,115,128, 0,255,239,116, 2,205,194, + 205,203,225,227,227,229,238,116,128, 30,143,226,229,236,239,119, + 128, 30,245,101, 7,205,227,206,235,206,244,207, 6,207, 38,207, + 114,207,165,104, 8,205,245,205,254,206, 32,206, 46,206,119,206, + 135,206,194,206,212,225,242,225,226,233, 99,128, 6, 74,226,225, + 242,242,229,101, 2,206, 9,206, 18,225,242,225,226,233, 99,128, + 6,210,230,233,238,225,236,225,242,225,226,233, 99,128,251,175, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,242,232,225, + 237,250,225,225,226,239,246,101, 4,206, 65,206, 74,206, 88,206, + 104,225,242,225,226,233, 99,128, 6, 38,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,138,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,139,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,140,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,254,243,237,101, 2,206,142,206,155,228,233, + 225,236,225,242,225,226,233, 99,128,254,244,229,237,105, 2,206, + 163,206,178,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 252,221,243,239,236,225,244,229,228,225,242,225,226,233, 99,128, + 252, 88,238,239,239,238,230,233,238,225,236,225,242,225,226,233, + 99,128,252,148,244,232,242,229,229,228,239,244,243,226,229,236, + 239,247,225,242,225,226,233, 99,128, 6,209,235,239,242,229,225, + 110,128, 49, 86,110,129, 0,165,206,250,237,239,238,239,243,240, + 225,227,101,128,255,229,111, 2,207, 12,207, 21,235,239,242,229, + 225,110,128, 49, 85,242,233,238,232,233,229,245,232,235,239,242, + 229,225,110,128, 49,134,114, 3,207, 46,207, 82,207, 94,225,232, + 226,229,238,249,239,237,111, 2,207, 60,207, 69,232,229,226,242, + 229,119,128, 5,170,236,229,230,244,232,229,226,242,229,119,128, + 5,170,233,227,249,242,233,236,236,233, 99,128, 4, 75,245,228, + 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, + 4,249,243,233,229,245,238,103, 3,207,127,207,136,207,152,235, + 239,242,229,225,110,128, 49,129,240,225,238,243,233,239,243,235, + 239,242,229,225,110,128, 49,131,243,233,239,243,235,239,242,229, + 225,110,128, 49,130,244,233,246,232,229,226,242,229,119,128, 5, + 154,231,242,225,246,101,128, 30,243,232,239,239,107,129, 1,180, + 207,194,225,226,239,246,101,128, 30,247,105, 5,207,214,207,225, + 207,236,207,245,207,253,225,242,237,229,238,233,225,110,128, 5, + 117,227,249,242,233,236,236,233, 99,128, 4, 87,235,239,242,229, + 225,110,128, 49, 98,238,249,225,238,103,128, 38, 47,247,238,225, + 242,237,229,238,233,225,110,128, 5,130,237,239,238,239,243,240, + 225,227,101,128,255, 89,111, 7,208, 38,208,108,208,119,208,129, + 208,167,208,213,208,222,100,131, 5,217,208, 48,208, 68,208, 77, + 228,225,231,229,243,104,129,251, 57,208, 59,232,229,226,242,229, + 119,128,251, 57,232,229,226,242,229,119,128, 5,217,249,239,100, + 2,208, 85,208, 94,232,229,226,242,229,119,128, 5,242,240,225, + 244,225,232,232,229,226,242,229,119,128,251, 31,232,233,242,225, + 231,225,238, 97,128, 48,136,233,235,239,242,229,225,110,128, 49, + 137,107, 2,208,135,208,159,225,244,225,235,225,238, 97,129, 48, + 232,208,147,232,225,236,230,247,233,228,244,104,128,255,150,239, + 242,229,225,110,128, 49, 91,243,237,225,236,108, 2,208,177,208, + 188,232,233,242,225,231,225,238, 97,128, 48,135,235,225,244,225, + 235,225,238, 97,129, 48,231,208,201,232,225,236,230,247,233,228, + 244,104,128,255,110,244,231,242,229,229,107,128, 3,243,121, 2, + 208,228,209, 9, 97, 2,208,234,208,244,229,235,239,242,229,225, + 110,128, 49,136,107, 2,208,250,209, 2,239,242,229,225,110,128, + 49,135,244,232,225,105,128, 14, 34,233,238,231,244,232,225,105, + 128, 14, 13,112, 2,209, 25,209, 32,225,242,229,110,128, 36,180, + 239,231,229,231,242,225,237,237,229,238,105,129, 3,122,209, 48, + 231,242,229,229,235,227,237, 98,128, 3, 69,114,129, 1,166,209, + 65,233,238,103,128, 30,153,243,245,240,229,242,233,239,114,128, + 2,184,116, 2,209, 88,209, 95,233,236,228,101,128, 30,249,245, + 242,238,229,100,128, 2,142,117, 5,209,115,209,126,209,136,209, + 174,210, 50,232,233,242,225,231,225,238, 97,128, 48,134,233,235, + 239,242,229,225,110,128, 49,140,107, 2,209,142,209,166,225,244, + 225,235,225,238, 97,129, 48,230,209,154,232,225,236,230,247,233, + 228,244,104,128,255,149,239,242,229,225,110,128, 49, 96,115, 3, + 209,182,209,220,210, 5,226,233,103, 2,209,190,209,201,227,249, + 242,233,236,236,233, 99,128, 4,107,233,239,244,233,230,233,229, + 228,227,249,242,233,236,236,233, 99,128, 4,109,236,233,244,244, + 236,101, 2,209,231,209,242,227,249,242,233,236,236,233, 99,128, + 4,103,233,239,244,233,230,233,229,228,227,249,242,233,236,236, + 233, 99,128, 4,105,237,225,236,108, 2,210, 14,210, 25,232,233, + 242,225,231,225,238, 97,128, 48,133,235,225,244,225,235,225,238, + 97,129, 48,229,210, 38,232,225,236,230,247,233,228,244,104,128, + 255,109,249,101, 2,210, 57,210, 66,235,239,242,229,225,110,128, + 49,139,239,235,239,242,229,225,110,128, 49,138,249, 97, 2,210, + 83,210, 93,226,229,238,231,225,236,105,128, 9,223,228,229,246, + 97,128, 9, 95,122,142, 0,122,210,132,211,140,211,151,211,194, + 211,221,213, 0,213,108,213,150,213,162,213,174,213,202,213,210, + 213,226,213,235, 97, 10,210,154,210,165,210,172,210,179,210,190, + 211, 12,211, 42,211, 53,211, 89,211,101,225,242,237,229,238,233, + 225,110,128, 5,102,227,245,244,101,128, 1,122,228,229,246, 97, + 128, 9, 91,231,245,242,237,245,235,232,105,128, 10, 91,104, 4, + 210,200,210,209,210,223,210,253,225,242,225,226,233, 99,128, 6, + 56,230,233,238,225,236,225,242,225,226,233, 99,128,254,198,105, + 2,210,229,210,244,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,199,242,225,231,225,238, 97,128, 48, 86,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,254,200,233,110, 2,211, + 19,211, 28,225,242,225,226,233, 99,128, 6, 50,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,176,235,225,244,225,235,225, + 238, 97,128, 48,182,241,229,102, 2,211, 61,211, 75,231,225,228, + 239,236,232,229,226,242,229,119,128, 5,149,241,225,244,225,238, + 232,229,226,242,229,119,128, 5,148,242,241,225,232,229,226,242, + 229,119,128, 5,152,249,233,110,130, 5,214,211,111,211,131,228, + 225,231,229,243,104,129,251, 54,211,122,232,229,226,242,229,119, + 128,251, 54,232,229,226,242,229,119,128, 5,214,226,239,240,239, + 237,239,230,111,128, 49, 23, 99, 3,211,159,211,166,211,188,225, + 242,239,110,128, 1,126,233,242, 99, 2,211,174,211,179,236,101, + 128, 36,233,245,237,230,236,229,120,128, 30,145,245,242,108,128, + 2,145,228,239,116,130, 1,124,211,204,211,213,225,227,227,229, + 238,116,128, 1,124,226,229,236,239,119,128, 30,147,101, 6,211, + 235,211,246,212, 33,212, 44,212, 55,212,251,227,249,242,233,236, + 236,233, 99,128, 4, 55,100, 2,211,252,212, 15,229,243,227,229, + 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,153,233, + 229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, 4, + 223,232,233,242,225,231,225,238, 97,128, 48, 92,235,225,244,225, + 235,225,238, 97,128, 48,188,242,111,140, 0, 48,212, 84,212, 93, + 212,103,212,110,212,135,212,148,212,159,212,171,212,182,212,192, + 212,203,212,210,225,242,225,226,233, 99,128, 6, 96,226,229,238, + 231,225,236,105,128, 9,230,228,229,246, 97,128, 9,102,231,117, + 2,212,117,212,126,234,225,242,225,244,105,128, 10,230,242,237, + 245,235,232,105,128, 10,102,232,225,227,235,225,242,225,226,233, + 99,128, 6, 96,233,238,230,229,242,233,239,114,128, 32,128,237, + 239,238,239,243,240,225,227,101,128,255, 16,239,236,228,243,244, + 249,236,101,128,247, 48,240,229,242,243,233,225,110,128, 6,240, + 243,245,240,229,242,233,239,114,128, 32,112,244,232,225,105,128, + 14, 80,247,233,228,244,104, 3,212,222,212,231,212,243,234,239, + 233,238,229,114,128,254,255,238,239,238,234,239,233,238,229,114, + 128, 32, 12,243,240,225,227,101,128, 32, 11,244, 97,128, 3,182, + 104, 2,213, 6,213, 17,226,239,240,239,237,239,230,111,128, 49, + 19,101, 4,213, 27,213, 38,213, 54,213, 65,225,242,237,229,238, + 233,225,110,128, 5,106,226,242,229,246,229,227,249,242,233,236, + 236,233, 99,128, 4,194,227,249,242,233,236,236,233, 99,128, 4, + 54,100, 2,213, 71,213, 90,229,243,227,229,238,228,229,242,227, + 249,242,233,236,236,233, 99,128, 4,151,233,229,242,229,243,233, + 243,227,249,242,233,236,236,233, 99,128, 4,221,105, 3,213,116, + 213,127,213,138,232,233,242,225,231,225,238, 97,128, 48, 88,235, + 225,244,225,235,225,238, 97,128, 48,184,238,239,242,232,229,226, + 242,229,119,128, 5,174,236,233,238,229,226,229,236,239,119,128, + 30,149,237,239,238,239,243,240,225,227,101,128,255, 90,111, 2, + 213,180,213,191,232,233,242,225,231,225,238, 97,128, 48, 94,235, + 225,244,225,235,225,238, 97,128, 48,190,240,225,242,229,110,128, + 36,181,242,229,244,242,239,230,236,229,248,232,239,239,107,128, + 2,144,243,244,242,239,235,101,128, 1,182,117, 2,213,241,213, + 252,232,233,242,225,231,225,238, 97,128, 48, 90,235,225,244,225, + 235,225,238, 97,128, 48,186 + }; + + + /* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + + + if ( name == 0 || name >= limit ) + goto NotFound; + + c = *name++; + count = p[1]; + p += 2; + + min = 0; + max = count; + + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + + + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + + Found: + for (;;) + { + /* assert (*p & 127) == c */ + + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + + continue; + } + + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + + p++; + + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + + NextIter: + ; + } + + NotFound: + return 0; + } + + +/* END */ diff --git a/src/freetype2/raster/ftmisc.h b/src/freetype2/raster/ftmisc.h new file mode 100644 index 0000000..c5dbd50 --- /dev/null +++ b/src/freetype2/raster/ftmisc.h @@ -0,0 +1,83 @@ +/***************************************************************************/ +/* */ +/* ftmisc.h */ +/* */ +/* Miscellaneous macros for stand-alone rasterizer (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 *not* portable! You have to adapt */ + /* its definitions to your platform. */ + /* */ + /***************************************************/ + +#ifndef __FTMISC_H__ +#define __FTMISC_H__ + +#include <string.h> /* memset */ + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#define FT_LOCAL_DEF( x ) static x + + /* from include/freetype2/fttypes.h */ + + typedef unsigned char FT_Byte; + typedef signed int FT_Int; + typedef unsigned int FT_UInt; + typedef signed long FT_Long; + typedef unsigned long FT_ULong; + typedef signed long FT_F26Dot6; + typedef int FT_Error; + +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /* from src/ftcalc.c */ + +#include <inttypes.h> + + typedef int64_t FT_Int64; + + static 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; + } + +#endif /* __FTMISC_H__ */ + + +/* END */ diff --git a/src/freetype2/raster/ftraster.c b/src/freetype2/raster/ftraster.c new file mode 100644 index 0000000..4cfca4e --- /dev/null +++ b/src/freetype2/raster/ftraster.c @@ -0,0 +1,3369 @@ +/***************************************************************************/ +/* */ +/* ftraster.c */ +/* */ +/* The FreeType glyph rasterizer (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file can be compiled without the rest of the FreeType engine, by */ + /* defining the _STANDALONE_ macro when compiling it. You also need to */ + /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir) */ + /* directory. Typically, you should do something like */ + /* */ + /* - copy `src/raster/ftraster.c' (this file) to your current directory */ + /* */ + /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */ + /* to your current directory */ + /* */ + /* - compile `ftraster' with the _STANDALONE_ macro defined, as in */ + /* */ + /* cc -c -D_STANDALONE_ ftraster.c */ + /* */ + /* The renderer can be initialized with a call to */ + /* `ft_standard_raster.raster_new'; a bitmap can be generated */ + /* with a call to `ft_standard_raster.raster_render'. */ + /* */ + /* See the comments and documentation in the file `ftimage.h' for more */ + /* details on how the raster works. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This is a rewrite of the FreeType 1.x scan-line converter */ + /* */ + /*************************************************************************/ + +#ifdef _STANDALONE_ + +#include "ftmisc.h" +#include "ftimage.h" + +#else /* !_STANDALONE_ */ + +#include <ft2build.h> +#include "ftraster.h" +#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */ + +#endif /* !_STANDALONE_ */ + + + /*************************************************************************/ + /* */ + /* A simple technical note on how the raster works */ + /* ----------------------------------------------- */ + /* */ + /* Converting an outline into a bitmap is achieved in several steps: */ + /* */ + /* 1 - Decomposing the outline into successive `profiles'. Each */ + /* profile is simply an array of scanline intersections on a given */ + /* dimension. A profile's main attributes are */ + /* */ + /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */ + /* */ + /* o an array of intersection coordinates for each scanline */ + /* between `Ymin' and `Ymax'. */ + /* */ + /* o a direction, indicating whether it was built going `up' or */ + /* `down', as this is very important for filling rules. */ + /* */ + /* 2 - Sweeping the target map's scanlines in order to compute segment */ + /* `spans' which are then filled. Additionally, this pass */ + /* performs drop-out control. */ + /* */ + /* The outline data is parsed during step 1 only. The profiles are */ + /* built from the bottom of the render pool, used as a stack. The */ + /* following graphics shows the profile list under construction: */ + /* */ + /* ____________________________________________________________ _ _ */ + /* | | | | | */ + /* | profile | coordinates for | profile | coordinates for |--> */ + /* | 1 | profile 1 | 2 | profile 2 |--> */ + /* |_________|___________________|_________|_________________|__ _ _ */ + /* */ + /* ^ ^ */ + /* | | */ + /* start of render pool top */ + /* */ + /* The top of the profile stack is kept in the `top' variable. */ + /* */ + /* As you can see, a profile record is pushed on top of the render */ + /* pool, which is then followed by its coordinates/intersections. If */ + /* a change of direction is detected in the outline, a new profile is */ + /* generated until the end of the outline. */ + /* */ + /* Note that when all profiles have been generated, the function */ + /* Finalize_Profile_Table() is used to record, for each profile, its */ + /* bottom-most scanline as well as the scanline above its upmost */ + /* boundary. These positions are called `y-turns' because they (sort */ + /* of) correspond to local extrema. They are stored in a sorted list */ + /* built from the top of the render pool as a downwards stack: */ + /* */ + /* _ _ _______________________________________ */ + /* | | */ + /* <--| sorted list of | */ + /* <--| extrema scanlines | */ + /* _ _ __________________|____________________| */ + /* */ + /* ^ ^ */ + /* | | */ + /* maxBuff sizeBuff = end of pool */ + /* */ + /* This list is later used during the sweep phase in order to */ + /* optimize performance (see technical note on the sweep below). */ + /* */ + /* Of course, the raster detects whether the two stacks collide and */ + /* handles the situation properly. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** CONFIGURATION MACROS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /* define DEBUG_RASTER if you want to compile a debugging version */ +#define xxxDEBUG_RASTER + + /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */ + /* 5-levels anti-aliasing */ +#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS +#define FT_RASTER_OPTION_ANTI_ALIASING +#endif + + /* The size of the two-lines intermediate bitmap used */ + /* for anti-aliasing, in bytes. */ +#define RASTER_GRAY_LINES 2048 + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OTHER MACROS (do not change) **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* 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_raster + + +#ifdef _STANDALONE_ + + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these two macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ +#define FT_TRACE1( x ) do ; while ( 0 ) /* nothing */ +#define FT_TRACE6( x ) do ; while ( 0 ) /* nothing */ +#endif + +#define Raster_Err_None 0 +#define Raster_Err_Not_Ini -1 +#define Raster_Err_Overflow -2 +#define Raster_Err_Neg_Height -3 +#define Raster_Err_Invalid -4 +#define Raster_Err_Unsupported -5 + +#define ft_memset memset + +#else /* _STANDALONE_ */ + + +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */ + +#include "rasterrs.h" + +#define Raster_Err_None Raster_Err_Ok +#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized +#define Raster_Err_Overflow Raster_Err_Raster_Overflow +#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height +#define Raster_Err_Invalid Raster_Err_Invalid_Outline +#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph + + +#endif /* _STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + + /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ + /* typically a small value and the result of a*b is known to fit into */ + /* 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) + + /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ + /* for clipping computations. It simply uses the FT_MulDiv() function */ + /* defined in `ftcalc.h'. */ +#define SMulDiv FT_MulDiv + + /* The rasterizer is a very general purpose component; please leave */ + /* the following redefinitions there (you never know your target */ + /* environment). */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE 1 +#endif + + +#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ + /* Setting this constant to more than 32 is a */ + /* pure waste of space. */ + +#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SIMPLE TYPE DECLARATIONS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + typedef int Int; + typedef unsigned int UInt; + typedef short Short; + typedef unsigned short UShort, *PUShort; + typedef long Long, *PLong; + typedef unsigned long ULong; + + typedef unsigned char Byte, *PByte; + typedef char Bool; + + + typedef union Alignment_ + { + long l; + void* p; + void (*f)(void); + + } Alignment, *PAlignment; + + + typedef struct TPoint_ + { + Long x; + Long y; + + } TPoint; + + + typedef enum TFlow_ + { + Flow_None = 0, + Flow_Up = 1, + Flow_Down = -1 + + } TFlow; + + + /* States of each line, arc, and profile */ + typedef enum TStates_ + { + Unknown_State, + Ascending_State, + Descending_State, + Flat_State + + } TStates; + + + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + + struct TProfile_ + { + FT_F26Dot6 X; /* current coordinate during sweep */ + PProfile link; /* link to next profile - various purpose */ + PLong offset; /* start of profile's data in render pool */ + int flow; /* Profile orientation: Asc/Descending */ + long height; /* profile's height in scanlines */ + long start; /* profile's starting scanline */ + + unsigned countL; /* number of lines to step before this */ + /* profile becomes drawable */ + + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + }; + + typedef PProfile TProfileList; + typedef PProfile* PProfileList; + + + /* Simple record used to implement a stack of bands, required */ + /* by the sub-banding mechanism */ + typedef struct TBand_ + { + Short y_min; /* band's minimum */ + Short y_max; /* band's maximum */ + + } TBand; + + +#define AlignProfileSize \ + ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) ) + + +#ifdef FT_STATIC_RASTER + + +#define RAS_ARGS /* void */ +#define RAS_ARG /* void */ + +#define RAS_VARS /* void */ +#define RAS_VAR /* void */ + +#define FT_UNUSED_RASTER do ; while ( 0 ) + + +#else /* FT_STATIC_RASTER */ + + +#define RAS_ARGS PWorker worker, +#define RAS_ARG PWorker worker + +#define RAS_VARS worker, +#define RAS_VAR worker + +#define FT_UNUSED_RASTER FT_UNUSED( worker ) + + +#endif /* FT_STATIC_RASTER */ + + + typedef struct TWorker_ TWorker, *PWorker; + + + /* prototypes used for sweep function dispatch */ + typedef void + Function_Sweep_Init( RAS_ARGS Short* min, + Short* max ); + + typedef void + Function_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ); + + typedef void + Function_Sweep_Step( RAS_ARG ); + + + /* NOTE: These operations are only valid on 2's complement processors */ + +#define FLOOR( x ) ( (x) & -ras.precision ) +#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) +#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) +#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) +#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) + + /* Note that I have moved the location of some fields in the */ + /* structure to ensure that the most used variables are used */ + /* at the top. Thus, their offset can be coded with less */ + /* opcodes, and it results in a smaller executable. */ + + struct TWorker_ + { + Int precision_bits; /* precision related variables */ + Int precision; + Int precision_half; + Long precision_mask; + Int precision_shift; + Int precision_step; + Int precision_jitter; + + Int scale_shift; /* == precision_shift for bitmaps */ + /* == precision_shift+1 for pixmaps */ + + PLong buff; /* The profiles buffer */ + PLong sizeBuff; /* Render pool size */ + PLong maxBuff; /* Profiles buffer size */ + PLong top; /* Current cursor in buffer */ + + FT_Error error; + + Int numTurns; /* number of Y-turns in outline */ + + TPoint* arc; /* current Bezier arc pointer */ + + UShort bWidth; /* target bitmap width */ + PByte bTarget; /* target bitmap buffer */ + PByte gTarget; /* target pixmap buffer */ + + Long lastX, lastY, minY, maxY; + + UShort num_Profs; /* current number of profiles */ + + Bool fresh; /* signals a fresh new profile which */ + /* 'start' field must be completed */ + Bool joint; /* signals that the last arc ended */ + /* exactly on a scanline. Allows */ + /* removal of doublets */ + PProfile cProfile; /* current profile */ + PProfile fProfile; /* head of linked list of profiles */ + PProfile gProfile; /* contour's first profile in case */ + /* of impact */ + + TStates state; /* rendering state */ + + FT_Bitmap target; /* description of target bit/pixmap */ + FT_Outline outline; + + Long traceOfs; /* current offset in target bitmap */ + Long traceG; /* current offset in target pixmap */ + + Short traceIncr; /* sweep's increment in target bitmap */ + + Short gray_min_x; /* current min x during gray rendering */ + Short gray_max_x; /* current max x during gray rendering */ + + /* dispatch variables */ + + Function_Sweep_Init* Proc_Sweep_Init; + Function_Sweep_Span* Proc_Sweep_Span; + Function_Sweep_Span* Proc_Sweep_Drop; + Function_Sweep_Step* Proc_Sweep_Step; + + Byte dropOutControl; /* current drop_out control method */ + + Bool second_pass; /* indicates whether a horizontal pass */ + /* should be performed to control */ + /* drop-out accurately when calling */ + /* Render_Glyph. Note that there is */ + /* no horizontal pass during gray */ + /* rendering. */ + + TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ + + TBand band_stack[16]; /* band stack used for sub-banding */ + Int band_top; /* band stack top */ + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + Byte* grays; + + Byte gray_lines[RASTER_GRAY_LINES]; + /* Intermediate table used to render the */ + /* graylevels pixmaps. */ + /* gray_lines is a buffer holding two */ + /* monochrome scanlines */ + + Short gray_width; /* width in bytes of one monochrome */ + /* intermediate scanline of gray_lines. */ + /* Each gray pixel takes 2 bits long there */ + + /* The gray_lines must hold 2 lines, thus with size */ + /* in bytes of at least `gray_width*2'. */ + +#endif /* FT_RASTER_ANTI_ALIASING */ + + }; + + + typedef struct TRaster_ + { + char* buffer; + long buffer_size; + void* memory; + PWorker worker; + Byte grays[5]; + Short gray_width; + + } TRaster, *PRaster; + +#ifdef FT_STATIC_RASTER + + static TWorker cur_ras; +#define ras cur_ras + +#else + +#define ras (*worker) + +#endif /* FT_STATIC_RASTER */ + + +static const char count_table[256] = +{ + 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4, + 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5, + 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7, + 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7, + 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6, + 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7, + 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7, + 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8 }; + + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** PROFILES COMPUTATION **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Set_High_Precision */ + /* */ + /* <Description> */ + /* Sets precision variables according to param flag. */ + /* */ + /* <Input> */ + /* High :: Set to True for high precision (typically for ppem < 18), */ + /* false otherwise. */ + /* */ + static void + Set_High_Precision( RAS_ARGS Int High ) + { + if ( High ) + { + ras.precision_bits = 10; + ras.precision_step = 128; + ras.precision_jitter = 24; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + ras.precision_jitter = 2; + } + + FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); + + ras.precision = 1 << ras.precision_bits; + ras.precision_half = ras.precision / 2; + ras.precision_shift = ras.precision_bits - Pixel_Bits; + ras.precision_mask = -ras.precision; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* New_Profile */ + /* */ + /* <Description> */ + /* Creates a new profile in the render pool. */ + /* */ + /* <Input> */ + /* aState :: The state/orientation of the new profile. */ + /* */ + /* <Return> */ + /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ + /* profile. */ + /* */ + static Bool + New_Profile( RAS_ARGS TStates aState ) + { + if ( !ras.fProfile ) + { + ras.cProfile = (PProfile)ras.top; + ras.fProfile = ras.cProfile; + ras.top += AlignProfileSize; + } + + if ( ras.top >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flow = Flow_Up; + FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile )); + break; + + case Descending_State: + ras.cProfile->flow = Flow_Down; + FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile )); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction!\n" )); + ras.error = Raster_Err_Invalid; + return FAILURE; + } + + ras.cProfile->start = 0; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + ras.cProfile->link = (PProfile)0; + ras.cProfile->next = (PProfile)0; + + if ( !ras.gProfile ) + ras.gProfile = ras.cProfile; + + ras.state = aState; + ras.fresh = TRUE; + ras.joint = FALSE; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* End_Profile */ + /* */ + /* <Description> */ + /* Finalizes the current profile. */ + /* */ + /* <Return> */ + /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ + /* */ + static Bool + End_Profile( RAS_ARG ) + { + Long h; + PProfile oldProfile; + + + h = (Long)( ras.top - ras.cProfile->offset ); + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered!\n" )); + ras.error = Raster_Err_Neg_Height; + return FAILURE; + } + + if ( h > 0 ) + { + FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n", + (long)ras.cProfile, ras.cProfile->start, h )); + + oldProfile = ras.cProfile; + ras.cProfile->height = h; + ras.cProfile = (PProfile)ras.top; + + ras.top += AlignProfileSize; + + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + oldProfile->next = ras.cProfile; + ras.num_Profs++; + } + + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in End_Profile\n" )); + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + ras.joint = FALSE; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Insert_Y_Turn */ + /* */ + /* <Description> */ + /* Inserts a salient into the sorted list placed on top of the render */ + /* pool. */ + /* */ + /* <Input> */ + /* New y scanline position. */ + /* */ + /* <Return> */ + /* SUCCESS on success. FAILURE in case of overflow. */ + /* */ + static Bool + Insert_Y_Turn( RAS_ARGS Int y ) + { + PLong y_turns; + Int y2, n; + + + n = ras.numTurns - 1; + y_turns = ras.sizeBuff - ras.numTurns; + + /* look for first y value that is <= */ + while ( n >= 0 && y < y_turns[n] ) + n--; + + /* if it is <, simply insert it, ignore if == */ + if ( n >= 0 && y > y_turns[n] ) + while ( n >= 0 ) + { + y2 = (Int)y_turns[n]; + y_turns[n] = y; + y = y2; + n--; + } + + if ( n < 0 ) + { + ras.maxBuff--; + if ( ras.maxBuff <= ras.top ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + ras.numTurns++; + ras.sizeBuff[-ras.numTurns] = y; + } + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Finalize_Profile_Table */ + /* */ + /* <Description> */ + /* Adjusts all links in the profiles list. */ + /* */ + /* <Return> */ + /* SUCCESS on success. FAILURE in case of overflow. */ + /* */ + static Bool + Finalize_Profile_Table( RAS_ARG ) + { + Int bottom, top; + UShort n; + PProfile p; + + + n = ras.num_Profs; + + if ( n > 1 ) + { + p = ras.fProfile; + while ( n > 0 ) + { + if ( n > 1 ) + p->link = (PProfile)( p->offset + p->height ); + else + p->link = NULL; + + switch ( p->flow ) + { + case Flow_Down: + bottom = (Int)( p->start - p->height + 1 ); + top = (Int)p->start; + p->start = bottom; + p->offset += p->height - 1; + break; + + case Flow_Up: + default: + bottom = (Int)p->start; + top = (Int)( p->start + p->height - 1 ); + } + + if ( Insert_Y_Turn( RAS_VARS bottom ) || + Insert_Y_Turn( RAS_VARS top + 1 ) ) + return FAILURE; + + p = p->link; + n--; + } + } + else + ras.fProfile = NULL; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Split_Conic */ + /* */ + /* <Description> */ + /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */ + /* stack. */ + /* */ + /* <Input> */ + /* None (subdivided Bezier is taken from the top of the stack). */ + /* */ + /* <Note> */ + /* This routine is the `beef' of this component. It is _the_ inner */ + /* loop that should be optimized to hell to get the best performance. */ + /* */ + static void + Split_Conic( TPoint* base ) + { + Long a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + + /* hand optimized. gcc doesn't seem to be too good at common */ + /* expression substitution and instruction scheduling ;-) */ + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Split_Cubic */ + /* */ + /* <Description> */ + /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ + /* Bezier stack. */ + /* */ + /* <Note> */ + /* This routine is the `beef' of the component. It is one of _the_ */ + /* inner loops that should be optimized like hell to get the best */ + /* performance. */ + /* */ + static void + Split_Cubic( TPoint* base ) + { + Long a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c + 1 ) >> 1; + base[5].x = b = ( base[3].x + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].x = a = ( a + c + 1 ) >> 1; + base[4].x = b = ( b + c + 1 ) >> 1; + base[3].x = ( a + b + 1 ) >> 1; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c + 1 ) >> 1; + base[5].y = b = ( base[3].y + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].y = a = ( a + c + 1 ) >> 1; + base[4].y = b = ( b + c + 1 ) >> 1; + base[3].y = ( a + b + 1 ) >> 1; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Line_Up */ + /* */ + /* <Description> */ + /* Computes the x-coordinates of an ascending line segment and stores */ + /* them in the render pool. */ + /* */ + /* <Input> */ + /* x1 :: The x-coordinate of the segment's start point. */ + /* */ + /* y1 :: The y-coordinate of the segment's start point. */ + /* */ + /* x2 :: The x-coordinate of the segment's end point. */ + /* */ + /* y2 :: The y-coordinate of the segment's end point. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static Bool + Line_Up( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Long Dx, Dy; + Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ + Long Ix, Rx, Ax; + + PLong top; + + + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dy <= 0 || y2 < miny || y1 > maxy ) + return SUCCESS; + + if ( y1 < miny ) + { + /* Take care: miny-y1 can be a very large value; we use */ + /* a slow MulDiv function to avoid clipping bugs */ + x1 += SMulDiv( Dx, miny - y1, Dy ); + e1 = (Int)TRUNC( miny ); + f1 = 0; + } + else + { + e1 = (Int)TRUNC( y1 ); + f1 = (Int)FRAC( y1 ); + } + + if ( y2 > maxy ) + { + /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ + e2 = (Int)TRUNC( maxy ); + f2 = 0; + } + else + { + e2 = (Int)TRUNC( y2 ); + f2 = (Int)FRAC( y2 ); + } + + if ( f1 > 0 ) + { + if ( e1 == e2 ) + return SUCCESS; + else + { + x1 += FMulDiv( Dx, ras.precision - f1, Dy ); + e1 += 1; + } + } + else + if ( ras.joint ) + { + ras.top--; + ras.joint = FALSE; + } + + ras.joint = (char)( f2 == 0 ); + + if ( ras.fresh ) + { + ras.cProfile->start = e1; + ras.fresh = FALSE; + } + + size = e2 - e1 + 1; + if ( ras.top + size >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + if ( Dx > 0 ) + { + Ix = ( ras.precision * Dx ) / Dy; + Rx = ( ras.precision * Dx ) % Dy; + Dx = 1; + } + else + { + Ix = -( ( ras.precision * -Dx ) / Dy ); + Rx = ( ras.precision * -Dx ) % Dy; + Dx = -1; + } + + Ax = -Dy; + top = ras.top; + + while ( size > 0 ) + { + *top++ = x1; + + x1 += Ix; + Ax += Rx; + if ( Ax >= 0 ) + { + Ax -= Dy; + x1 += Dx; + } + size--; + } + + ras.top = top; + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Line_Down */ + /* */ + /* <Description> */ + /* Computes the x-coordinates of an descending line segment and */ + /* stores them in the render pool. */ + /* */ + /* <Input> */ + /* x1 :: The x-coordinate of the segment's start point. */ + /* */ + /* y1 :: The y-coordinate of the segment's start point. */ + /* */ + /* x2 :: The x-coordinate of the segment's end point. */ + /* */ + /* y2 :: The y-coordinate of the segment's end point. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static Bool + Line_Down( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Bool result, fresh; + + + fresh = ras.fresh; + + result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + return result; + } + + + /* A function type describing the functions used to split Bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Bezier_Up */ + /* */ + /* <Description> */ + /* Computes the x-coordinates of an ascending Bezier arc and stores */ + /* them in the render pool. */ + /* */ + /* <Input> */ + /* degree :: The degree of the Bezier arc (either 2 or 3). */ + /* */ + /* splitter :: The function to split Bezier arcs. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static Bool + Bezier_Up( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, e0; + Short f1; + + TPoint* arc; + TPoint* start_arc; + + PLong top; + + + arc = ras.arc; + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.top; + + if ( y2 < miny || y1 > maxy ) + goto Fin; + + e2 = FLOOR( y2 ); + + if ( e2 > maxy ) + e2 = maxy; + + e0 = miny; + + if ( y1 < miny ) + e = miny; + else + { + e = CEILING( y1 ); + f1 = (Short)( FRAC( y1 ) ); + e0 = e; + + if ( f1 == 0 ) + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + + *top++ = arc[degree].x; + + e += ras.precision; + } + } + + if ( ras.fresh ) + { + ras.cProfile->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + + if ( e2 < e ) + goto Fin; + + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.top = top; + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + start_arc = arc; + + while ( arc >= start_arc && e <= e2 ) + { + ras.joint = FALSE; + + y2 = arc[0].y; + + if ( y2 > e ) + { + y1 = arc[degree].y; + if ( y2 - y1 >= ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x, + e - y1, y2 - y1 ); + arc -= degree; + e += ras.precision; + } + } + else + { + if ( y2 == e ) + { + ras.joint = TRUE; + *top++ = arc[0].x; + + e += ras.precision; + } + arc -= degree; + } + } + + Fin: + ras.top = top; + ras.arc -= degree; + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Bezier_Down */ + /* */ + /* <Description> */ + /* Computes the x-coordinates of an descending Bezier arc and stores */ + /* them in the render pool. */ + /* */ + /* <Input> */ + /* degree :: The degree of the Bezier arc (either 2 or 3). */ + /* */ + /* splitter :: The function to split Bezier arcs. */ + /* */ + /* miny :: A lower vertical clipping bound value. */ + /* */ + /* maxy :: An upper vertical clipping bound value. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow. */ + /* */ + static Bool + Bezier_Down( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + TPoint* arc = ras.arc; + Bool result, fresh; + + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if ( degree > 2 ) + arc[3].y = -arc[3].y; + + fresh = ras.fresh; + + result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + arc[0].y = -arc[0].y; + return result; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Line_To */ + /* */ + /* <Description> */ + /* Injects a new line segment and adjusts Profiles list. */ + /* */ + /* <Input> */ + /* x :: The x-coordinate of the segment's end point (its start point */ + /* is stored in `lastX'). */ + /* */ + /* y :: The y-coordinate of the segment's end point (its start point */ + /* is stored in `lastY'). */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static Bool + Line_To( RAS_ARGS Long x, + Long y ) + { + /* First, detect a change of direction */ + + switch ( ras.state ) + { + case Unknown_State: + if ( y > ras.lastY ) + { + if ( New_Profile( RAS_VARS Ascending_State ) ) + return FAILURE; + } + else + { + if ( y < ras.lastY ) + if ( New_Profile( RAS_VARS Descending_State ) ) + return FAILURE; + } + break; + + case Ascending_State: + if ( y < ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Descending_State ) ) + return FAILURE; + } + break; + + case Descending_State: + if ( y > ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Ascending_State ) ) + return FAILURE; + } + break; + + default: + ; + } + + /* Then compute the lines */ + + switch ( ras.state ) + { + case Ascending_State: + if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + case Descending_State: + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + default: + ; + } + + ras.lastX = x; + ras.lastY = y; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Conic_To */ + /* */ + /* <Description> */ + /* Injects a new conic arc and adjusts the profile list. */ + /* */ + /* <Input> */ + /* cx :: The x-coordinate of the arc's new control point. */ + /* */ + /* cy :: The y-coordinate of the arc's new control point. */ + /* */ + /* x :: The x-coordinate of the arc's end point (its start point is */ + /* stored in `lastX'). */ + /* */ + /* y :: The y-coordinate of the arc's end point (its start point is */ + /* stored in `lastY'). */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static Bool + Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) + { + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; + + + ras.arc = ras.arcs; + ras.arc[2].x = ras.lastX; + ras.arc[2].y = ras.lastY; + ras.arc[1].x = cx; ras.arc[1].y = cy; + ras.arc[0].x = x; ras.arc[0].y = y; + + do + { + y1 = ras.arc[2].y; + y2 = ras.arc[1].y; + y3 = ras.arc[0].y; + x3 = ras.arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y3 ) + { + ymin = y1; + ymax = y3; + } + else + { + ymin = y3; + ymax = y1; + } + + if ( y2 < ymin || y2 > ymax ) + { + /* this arc has no given direction, split it! */ + Split_Conic( ras.arc ); + ras.arc += 2; + } + else if ( y1 == y3 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 2; + } + else + { + /* the arc is y-monotonous, either ascending or descending */ + /* detect a change of direction */ + state_bez = y1 < y3 ? Ascending_State : Descending_State; + if ( ras.state != state_bez ) + { + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; + + /* create a new profile */ + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* now call the appropriate routine */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + + } while ( ras.arc >= ras.arcs ); + + ras.lastX = x3; + ras.lastY = y3; + + return SUCCESS; + + Fail: + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Cubic_To */ + /* */ + /* <Description> */ + /* Injects a new cubic arc and adjusts the profile list. */ + /* */ + /* <Input> */ + /* cx1 :: The x-coordinate of the arc's first new control point. */ + /* */ + /* cy1 :: The y-coordinate of the arc's first new control point. */ + /* */ + /* cx2 :: The x-coordinate of the arc's second new control point. */ + /* */ + /* cy2 :: The y-coordinate of the arc's second new control point. */ + /* */ + /* x :: The x-coordinate of the arc's end point (its start point is */ + /* stored in `lastX'). */ + /* */ + /* y :: The y-coordinate of the arc's end point (its start point is */ + /* stored in `lastY'). */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ + /* profile. */ + /* */ + static Bool + Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) + { + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; + + + ras.arc = ras.arcs; + ras.arc[3].x = ras.lastX; + ras.arc[3].y = ras.lastY; + ras.arc[2].x = cx1; ras.arc[2].y = cy1; + ras.arc[1].x = cx2; ras.arc[1].y = cy2; + ras.arc[0].x = x; ras.arc[0].y = y; + + do + { + y1 = ras.arc[3].y; + y2 = ras.arc[2].y; + y3 = ras.arc[1].y; + y4 = ras.arc[0].y; + x4 = ras.arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y4 ) + { + ymin1 = y1; + ymax1 = y4; + } + else + { + ymin1 = y4; + ymax1 = y1; + } + + if ( y2 <= y3 ) + { + ymin2 = y2; + ymax2 = y3; + } + else + { + ymin2 = y3; + ymax2 = y2; + } + + if ( ymin2 < ymin1 || ymax2 > ymax1 ) + { + /* this arc has no given direction, split it! */ + Split_Cubic( ras.arc ); + ras.arc += 3; + } + else if ( y1 == y4 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 3; + } + else + { + state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; + + /* detect a change of direction */ + if ( ras.state != state_bez ) + { + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; + + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* compute intersections */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + + } while ( ras.arc >= ras.arcs ); + + ras.lastX = x4; + ras.lastY = y4; + + return SUCCESS; + + Fail: + return FAILURE; + } + + +#undef SWAP_ +#define SWAP_( x, y ) do \ + { \ + Long swap = x; \ + \ + \ + x = y; \ + y = swap; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Decompose_Curve */ + /* */ + /* <Description> */ + /* Scans the outline arrays in order to emit individual segments and */ + /* Beziers by calling Line_To() and Bezier_To(). It handles all */ + /* weird cases, like when the first point is off the curve, or when */ + /* there are simply no `on' points in the contour! */ + /* */ + /* <Input> */ + /* first :: The index of the first point in the contour. */ + /* */ + /* last :: The index of the last point in the contour. */ + /* */ + /* flipped :: If set, flip the direction of the curve. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE on error. */ + /* */ + static Bool + Decompose_Curve( RAS_ARGS UShort first, + UShort last, + int flipped ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + char* tags; + + unsigned tag; /* current point's state */ + + + points = ras.outline.points; + limit = points + last; + + v_start.x = SCALED( points[first].x ); + v_start.y = SCALED( points[first].y ); + v_last.x = SCALED( points[last].x ); + v_last.y = SCALED( points[last].y ); + + if ( flipped ) + { + SWAP_( v_start.x, v_start.y ); + SWAP_( v_last.x, v_last.y ); + } + + v_control = v_start; + + point = points + first; + tags = ras.outline.tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + ras.lastX = v_start.x; + ras.lastY = v_start.y; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + Long x, y; + + + x = SCALED( point->x ); + y = SCALED( point->y ); + if ( flipped ) + SWAP_( x, y ); + + if ( Line_To( RAS_VARS x, y ) ) + goto Fail; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point[0].x ); + v_control.y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( v_control.x, v_control.y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector v_middle; + Long x, y; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + x = SCALED( point[0].x ); + y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x, y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) + goto Fail; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + x ) / 2; + v_middle.y = ( v_control.y + y ) / 2; + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y ) ) + goto Fail; + + v_control.x = x; + v_control.y = y; + + goto Do_Conic; + } + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y ) ) + goto Fail; + + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + Long x1, y1, x2, y2, x3, y3; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + x1 = SCALED( point[-2].x ); + y1 = SCALED( point[-2].y ); + x2 = SCALED( point[-1].x ); + y2 = SCALED( point[-1].y ); + x3 = SCALED( point[ 0].x ); + y3 = SCALED( point[ 0].y ); + + if ( flipped ) + { + SWAP_( x1, y1 ); + SWAP_( x2, y2 ); + SWAP_( x3, y3 ); + } + + if ( point <= limit ) + { + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) + goto Fail; + continue; + } + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) + goto Fail; + goto Close; + } + } + } + + /* close the contour with a line segment */ + if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) + goto Fail; + + Close: + return SUCCESS; + + Invalid_Outline: + ras.error = Raster_Err_Invalid; + + Fail: + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Convert_Glyph */ + /* */ + /* <Description> */ + /* Converts a glyph into a series of segments and arcs and makes a */ + /* profiles list with them. */ + /* */ + /* <Input> */ + /* flipped :: If set, flip the direction of curve. */ + /* */ + /* <Return> */ + /* SUCCESS on success, FAILURE if any error was encountered during */ + /* rendering. */ + /* */ + static Bool + Convert_Glyph( RAS_ARGS int flipped ) + { + int i; + unsigned start; + + PProfile lastProfile; + + + ras.fProfile = NULL; + ras.joint = FALSE; + ras.fresh = FALSE; + + ras.maxBuff = ras.sizeBuff - AlignProfileSize; + + ras.numTurns = 0; + + ras.cProfile = (PProfile)ras.top; + ras.cProfile->offset = ras.top; + ras.num_Profs = 0; + + start = 0; + + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + ras.state = Unknown_State; + ras.gProfile = NULL; + + if ( Decompose_Curve( RAS_VARS (unsigned short)start, + ras.outline.contours[i], + flipped ) ) + return FAILURE; + + start = ras.outline.contours[i] + 1; + + /* We must now see whether the extreme arcs join or not */ + if ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) + if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow ) + ras.top--; + /* Note that ras.gProfile can be nil if the contour was too small */ + /* to be drawn. */ + + lastProfile = ras.cProfile; + if ( End_Profile( RAS_VAR ) ) + return FAILURE; + + /* close the `next profile in contour' linked list */ + if ( ras.gProfile ) + lastProfile->next = ras.gProfile; + } + + if ( Finalize_Profile_Table( RAS_VAR ) ) + return FAILURE; + + return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SCAN-LINE SWEEPS AND DRAWING **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Init_Linked */ + /* */ + /* Initializes an empty linked list. */ + /* */ + static void + Init_Linked( TProfileList* l ) + { + *l = NULL; + } + + + /*************************************************************************/ + /* */ + /* InsNew */ + /* */ + /* Inserts a new profile in a linked list. */ + /* */ + static void + InsNew( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + Long x; + + + old = list; + current = *old; + x = profile->X; + + while ( current ) + { + if ( x < current->X ) + break; + old = ¤t->link; + current = *old; + } + + profile->link = current; + *old = profile; + } + + + /*************************************************************************/ + /* */ + /* DelOld */ + /* */ + /* Removes an old profile from a linked list. */ + /* */ + static void + DelOld( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + + + old = list; + current = *old; + + while ( current ) + { + if ( current == profile ) + { + *old = current->link; + return; + } + + old = ¤t->link; + current = *old; + } + + /* we should never get there, unless the profile was not part of */ + /* the list. */ + } + + + /*************************************************************************/ + /* */ + /* Sort */ + /* */ + /* Sorts a trace list. In 95%, the list is already sorted. We need */ + /* an algorithm which is fast in this case. Bubble sort is enough */ + /* and simple. */ + /* */ + static void + Sort( PProfileList list ) + { + PProfile *old, current, next; + + + /* First, set the new X coordinate of each profile */ + current = *list; + while ( current ) + { + current->X = *current->offset; + current->offset += current->flow; + current->height--; + current = current->link; + } + + /* Then sort them */ + old = list; + current = *old; + + if ( !current ) + return; + + next = current->link; + + while ( next ) + { + if ( current->X <= next->X ) + { + old = ¤t->link; + current = *old; + + if ( !current ) + return; + } + else + { + *old = next; + current->link = next->link; + next->link = current; + + old = list; + current = *old; + } + + next = current->link; + } + } + + + /*************************************************************************/ + /* */ + /* Vertical Sweep Procedure Set */ + /* */ + /* These four routines are used during the vertical black/white sweep */ + /* phase by the generic Draw_Sweep() function. */ + /* */ + /*************************************************************************/ + + static void + Vertical_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch = ras.target.pitch; + + FT_UNUSED( max ); + + + ras.traceIncr = (Short)-pitch; + ras.traceOfs = -*min * pitch; + if ( pitch > 0 ) + ras.traceOfs += ( ras.target.rows - 1 ) * pitch; + + ras.gray_min_x = 0; + ras.gray_max_x = 0; + } + + + static void + Vertical_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + int c1, c2; + Byte f1, f2; + Byte* target; + + FT_UNUSED( y ); + FT_UNUSED( left ); + FT_UNUSED( right ); + + + /* Drop-out control */ + + e1 = TRUNC( CEILING( x1 ) ); + + if ( x2 - x1 - ras.precision <= ras.precision_jitter ) + e2 = e1; + else + e2 = TRUNC( FLOOR( x2 ) ); + + if ( e2 >= 0 && e1 < ras.bWidth ) + { + if ( e1 < 0 ) + e1 = 0; + if ( e2 >= ras.bWidth ) + e2 = ras.bWidth - 1; + + c1 = (Short)( e1 >> 3 ); + c2 = (Short)( e2 >> 3 ); + + f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); + f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); + + if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1; + if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2; + + target = ras.bTarget + ras.traceOfs + c1; + c2 -= c1; + + if ( c2 > 0 ) + { + target[0] |= f1; + + /* memset() is slower than the following code on many platforms. */ + /* This is due to the fact that, in the vast majority of cases, */ + /* the span length in bytes is relatively small. */ + c2--; + while ( c2 > 0 ) + { + *(++target) = 0xFF; + c2--; + } + target[1] |= f2; + } + else + *target |= ( f1 & f2 ); + } + } + + + static void + Vertical_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + Short c1, f1; + + + /* Drop-out control */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( (x1 + x2 + 1) / 2 ); + break; + + case 2: + case 5: + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + /* Here, we only get rid of stubs recognized if: */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + + /* FIXXXME: uncommenting this line solves the disappearing */ + /* bit problem in the `7' of verdana 10pts, but */ + /* makes a new one in the `C' of arial 14pts */ + +#if 0 + if ( x2 - x1 < ras.precision_half ) +#endif + { + /* upper stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* lower stub test */ + if ( right->next == left && left->start == y ) + return; + } + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.bWidth ) + { + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + + if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; + if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; + + ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); + } + } + + + static void + Vertical_Sweep_Step( RAS_ARG ) + { + ras.traceOfs += ras.traceIncr; + } + + + /***********************************************************************/ + /* */ + /* Horizontal Sweep Procedure Set */ + /* */ + /* These four routines are used during the horizontal black/white */ + /* sweep phase by the generic Draw_Sweep() function. */ + /* */ + /***********************************************************************/ + + static void + Horizontal_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + /* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( min ); + FT_UNUSED( max ); + } + + + static void + Horizontal_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte bits; + Byte f1; + + FT_UNUSED( left ); + FT_UNUSED( right ); + + + if ( x2 - x1 < ras.precision ) + { + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 == e2 ) + { + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.target.rows ) + { + PByte p; + + + p = bits - e1*ras.target.pitch; + if ( ras.target.pitch > 0 ) + p += ( ras.target.rows - 1 ) * ras.target.pitch; + + p[0] |= f1; + } + } + } + } + + + static void + Horizontal_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte bits; + Byte f1; + + + /* During the horizontal sweep, we only take care of drop-outs */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + + /* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* leftmost stub test */ + if ( right->next == left && left->start == y ) + return; + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + + if ( e1 >= 0 && + e1 < ras.target.rows && + *bits & f1 ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.target.rows ) + { + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + + bits[0] |= f1; + } + } + + + static void + Horizontal_Sweep_Step( RAS_ARG ) + { + /* Nothing, really */ + FT_UNUSED_RASTER; + } + + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + + /*************************************************************************/ + /* */ + /* Vertical Gray Sweep Procedure Set */ + /* */ + /* These two routines are used during the vertical gray-levels sweep */ + /* phase by the generic Draw_Sweep() function. */ + /* */ + /* NOTES */ + /* */ + /* - The target pixmap's width *must* be a multiple of 4. */ + /* */ + /* - You have to use the function Vertical_Sweep_Span() for the gray */ + /* span call. */ + /* */ + /*************************************************************************/ + + static void + Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch, byte_len; + + + *min = *min & -2; + *max = ( *max + 3 ) & -2; + + ras.traceOfs = 0; + pitch = ras.target.pitch; + byte_len = -pitch; + ras.traceIncr = (Short)byte_len; + ras.traceG = ( *min / 2 ) * byte_len; + + if ( pitch > 0 ) + { + ras.traceG += ( ras.target.rows - 1 ) * pitch; + byte_len = -byte_len; + } + + ras.gray_min_x = (Short)byte_len; + ras.gray_max_x = -(Short)byte_len; + } + + + static void + Vertical_Gray_Sweep_Step( RAS_ARG ) + { + Int c1, c2; + PByte pix, bit, bit2; + char* count = (char*)count_table; + Byte* grays; + + + ras.traceOfs += ras.gray_width; + + if ( ras.traceOfs > ras.gray_width ) + { + pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; + grays = ras.grays; + + if ( ras.gray_max_x >= 0 ) + { + Long last_pixel = ras.target.width - 1; + Int last_cell = last_pixel >> 2; + Int last_bit = last_pixel & 3; + Bool over = 0; + + + if ( ras.gray_max_x >= last_cell && last_bit != 3 ) + { + ras.gray_max_x = last_cell - 1; + over = 1; + } + + if ( ras.gray_min_x < 0 ) + ras.gray_min_x = 0; + + bit = ras.bTarget + ras.gray_min_x; + bit2 = bit + ras.gray_width; + + c1 = ras.gray_max_x - ras.gray_min_x; + + while ( c1 >= 0 ) + { + c2 = count[*bit] + count[*bit2]; + + if ( c2 ) + { + pix[0] = grays[(c2 >> 12) & 0x000F]; + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + pix[3] = grays[ c2 & 0x000F]; + + *bit = 0; + *bit2 = 0; + } + + bit++; + bit2++; + pix += 4; + c1--; + } + + if ( over ) + { + c2 = count[*bit] + count[*bit2]; + if ( c2 ) + { + switch ( last_bit ) + { + case 2: + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + case 1: + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + default: + pix[0] = grays[(c2 >> 12) & 0x000F]; + } + + *bit = 0; + *bit2 = 0; + } + } + } + + ras.traceOfs = 0; + ras.traceG += ras.traceIncr; + + ras.gray_min_x = 32000; + ras.gray_max_x = -32000; + } + } + + + static void + Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + /* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( y ); + FT_UNUSED( x1 ); + FT_UNUSED( x2 ); + FT_UNUSED( left ); + FT_UNUSED( right ); + } + + + static void + Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte pixel; + Byte color; + + + /* During the horizontal sweep, we only take care of drop-outs */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of `stubs'. */ + /* */ + + /* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) + return; + + /* leftmost stub test */ + if ( right->next == left && left->start == y ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + if ( e1 >= 0 ) + { + if ( x2 - x1 >= ras.precision_half ) + color = ras.grays[2]; + else + color = ras.grays[1]; + + e1 = TRUNC( e1 ) / 2; + if ( e1 < ras.target.rows ) + { + pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; + if ( ras.target.pitch > 0 ) + pixel += ( ras.target.rows - 1 ) * ras.target.pitch; + + if ( pixel[0] == ras.grays[0] ) + pixel[0] = color; + } + } + } + + +#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ + + + /*************************************************************************/ + /* */ + /* Generic Sweep Drawing routine */ + /* */ + /*************************************************************************/ + + static Bool + Draw_Sweep( RAS_ARG ) + { + Short y, y_change, y_height; + + PProfile P, Q, P_Left, P_Right; + + Short min_Y, max_Y, top, bottom, dropouts; + + Long x1, x2, xs, e1, e2; + + TProfileList waiting; + TProfileList draw_left, draw_right; + + + /* Init empty linked lists */ + + Init_Linked( &waiting ); + + Init_Linked( &draw_left ); + Init_Linked( &draw_right ); + + /* first, compute min and max Y */ + + P = ras.fProfile; + max_Y = (Short)TRUNC( ras.minY ); + min_Y = (Short)TRUNC( ras.maxY ); + + while ( P ) + { + Q = P->link; + + bottom = (Short)P->start; + top = (Short)( P->start + P->height - 1 ); + + if ( min_Y > bottom ) min_Y = bottom; + if ( max_Y < top ) max_Y = top; + + P->X = 0; + InsNew( &waiting, P ); + + P = Q; + } + + /* Check the Y-turns */ + if ( ras.numTurns == 0 ) + { + ras.error = Raster_Err_Invalid; + return FAILURE; + } + + /* Now inits the sweep */ + + ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); + + /* Then compute the distance of each profile from min_Y */ + + P = waiting; + + while ( P ) + { + P->countL = (UShort)( P->start - min_Y ); + P = P->link; + } + + /* Let's go */ + + y = min_Y; + y_height = 0; + + if ( ras.numTurns > 0 && + ras.sizeBuff[-ras.numTurns] == min_Y ) + ras.numTurns--; + + while ( ras.numTurns > 0 ) + { + /* look in the waiting list for new activations */ + + P = waiting; + + while ( P ) + { + Q = P->link; + P->countL -= y_height; + if ( P->countL == 0 ) + { + DelOld( &waiting, P ); + + switch ( P->flow ) + { + case Flow_Up: + InsNew( &draw_left, P ); + break; + + case Flow_Down: + InsNew( &draw_right, P ); + break; + } + } + + P = Q; + } + + /* Sort the drawing lists */ + + Sort( &draw_left ); + Sort( &draw_right ); + + y_change = (Short)ras.sizeBuff[-ras.numTurns--]; + y_height = (Short)( y_change - y ); + + while ( y < y_change ) + { + /* Let's trace */ + + dropouts = 0; + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left ) + { + x1 = P_Left ->X; + x2 = P_Right->X; + + if ( x1 > x2 ) + { + xs = x1; + x1 = x2; + x2 = xs; + } + + if ( x2 - x1 <= ras.precision ) + { + e1 = FLOOR( x1 ); + e2 = CEILING( x2 ); + + if ( ras.dropOutControl != 0 && + ( e1 > e2 || e2 == e1 + ras.precision ) ) + { + /* a drop out was detected */ + + P_Left ->X = x1; + P_Right->X = x2; + + /* mark profile for drop-out processing */ + P_Left->countL = 1; + dropouts++; + + goto Skip_To_Next; + } + } + + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + + Skip_To_Next: + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + /* now perform the dropouts _after_ the span drawing -- */ + /* drop-outs processing has been moved out of the loop */ + /* for performance tuning */ + if ( dropouts > 0 ) + goto Scan_DropOuts; + + Next_Line: + + ras.Proc_Sweep_Step( RAS_VAR ); + + y++; + + if ( y < y_change ) + { + Sort( &draw_left ); + Sort( &draw_right ); + } + } + + /* Now finalize the profiles that needs it */ + + P = draw_left; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_left, P ); + P = Q; + } + + P = draw_right; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_right, P ); + P = Q; + } + } + + /* for gray-scaling, flushes the bitmap scanline cache */ + while ( y <= max_Y ) + { + ras.Proc_Sweep_Step( RAS_VAR ); + y++; + } + + return SUCCESS; + + Scan_DropOuts: + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left ) + { + if ( P_Left->countL ) + { + P_Left->countL = 0; +#if 0 + dropouts--; /* -- this is useful when debugging only */ +#endif + ras.Proc_Sweep_Drop( RAS_VARS y, + P_Left->X, + P_Right->X, + P_Left, + P_Right ); + } + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + goto Next_Line; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Render_Single_Pass */ + /* */ + /* <Description> */ + /* Performs one sweep with sub-banding. */ + /* */ + /* <Input> */ + /* flipped :: If set, flip the direction of the outline. */ + /* */ + /* <Return> */ + /* Renderer error code. */ + /* */ + static int + Render_Single_Pass( RAS_ARGS Bool flipped ) + { + Short i, j, k; + + + while ( ras.band_top >= 0 ) + { + ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; + ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; + + ras.top = ras.buff; + + ras.error = Raster_Err_None; + + if ( Convert_Glyph( RAS_VARS flipped ) ) + { + if ( ras.error != Raster_Err_Overflow ) + return FAILURE; + + ras.error = Raster_Err_None; + + /* sub-banding */ + +#ifdef DEBUG_RASTER + ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); +#endif + + i = ras.band_stack[ras.band_top].y_min; + j = ras.band_stack[ras.band_top].y_max; + + k = (Short)( ( i + j ) / 2 ); + + if ( ras.band_top >= 7 || k < i ) + { + ras.band_top = 0; + ras.error = Raster_Err_Invalid; + + return ras.error; + } + + ras.band_stack[ras.band_top + 1].y_min = k; + ras.band_stack[ras.band_top + 1].y_max = j; + + ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); + + ras.band_top++; + } + else + { + if ( ras.fProfile ) + if ( Draw_Sweep( RAS_VAR ) ) + return ras.error; + ras.band_top--; + } + } + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Render_Glyph */ + /* */ + /* <Description> */ + /* Renders a glyph in a bitmap. Sub-banding if needed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + Render_Glyph( RAS_ARG ) + { + FT_Error error; + + + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + ras.scale_shift = ras.precision_shift; + /* Drop-out mode 2 is hard-coded since this is the only mode used */ + /* on Windows platforms. Using other modes, as specified by the */ + /* font, results in misplaced pixels. */ + ras.dropOutControl = 2; + ras.second_pass = (FT_Byte)( !( ras.outline.flags & + FT_OUTLINE_SINGLE_PASS ) ); + + /* Vertical Sweep */ + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = (short)( ras.target.rows - 1 ); + + ras.bWidth = (unsigned short)ras.target.width; + ras.bTarget = (Byte*)ras.target.buffer; + + if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) + return error; + + /* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 0 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = (short)( ras.target.width - 1 ); + + if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) + return error; + } + + return Raster_Err_None; + } + + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Render_Gray_Glyph */ + /* */ + /* <Description> */ + /* Renders a glyph with grayscaling. Sub-banding if needed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + Render_Gray_Glyph( RAS_ARG ) + { + Long pixel_width; + FT_Error error; + + + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + ras.scale_shift = ras.precision_shift + 1; + /* Drop-out mode 2 is hard-coded since this is the only mode used */ + /* on Windows platforms. Using other modes, as specified by the */ + /* font, results in misplaced pixels. */ + ras.dropOutControl = 2; + ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ); + + /* Vertical Sweep */ + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = 2 * ras.target.rows - 1; + + ras.bWidth = ras.gray_width; + pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); + + if ( ras.bWidth > pixel_width ) + ras.bWidth = pixel_width; + + ras.bWidth = ras.bWidth * 8; + ras.bTarget = (Byte*)ras.gray_lines; + ras.gTarget = (Byte*)ras.target.buffer; + + ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 0 ); + if ( error ) + return error; + + /* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 0 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.width * 2 - 1; + + error = Render_Single_Pass( RAS_VARS 1 ); + if ( error ) + return error; + } + + return Raster_Err_None; + } + +#else /* !FT_RASTER_OPTION_ANTI_ALIASING */ + + FT_LOCAL_DEF( FT_Error ) + Render_Gray_Glyph( RAS_ARG ) + { + FT_UNUSED_RASTER; + + return Raster_Err_Unsupported; + } + +#endif /* !FT_RASTER_OPTION_ANTI_ALIASING */ + + + static void + ft_black_init( PRaster raster ) + { + FT_UNUSED( raster ); + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + FT_UInt n; + + + /* set default 5-levels gray palette */ + for ( n = 0; n < 5; n++ ) + raster->grays[n] = n * 255 / 4; + + raster->gray_width = RASTER_GRAY_LINES / 2; + +#endif + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + + +#ifdef _STANDALONE_ + + + static int + ft_black_new( void* memory, + FT_Raster *araster ) + { + static TRaster the_raster; + + + *araster = (FT_Raster)&the_raster; + FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); + ft_black_init( &the_raster ); + + return 0; + } + + + static void + ft_black_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + + +#else /* _STANDALONE_ */ + + + static int + ft_black_new( FT_Memory memory, + PRaster *araster ) + { + FT_Error error; + PRaster raster; + + + *araster = 0; + if ( !FT_NEW( raster ) ) + { + raster->memory = memory; + ft_black_init( raster ); + + *araster = raster; + } + + return error; + } + + + static void + ft_black_done( PRaster raster ) + { + FT_Memory memory = (FT_Memory)raster->memory; + FT_FREE( raster ); + } + + +#endif /* _STANDALONE_ */ + + + static void + ft_black_reset( PRaster raster, + char* pool_base, + long pool_size ) + { + if ( raster ) + { + if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 ) + { + PWorker worker = (PWorker)pool_base; + + + raster->buffer = pool_base + ( (sizeof ( *worker ) + 7 ) & ~7 ); + raster->buffer_size = ( ( pool_base + pool_size ) - + (char*)raster->buffer ) / sizeof ( Long ); + raster->worker = worker; + } + else + { + raster->buffer = NULL; + raster->buffer_size = 0; + raster->worker = NULL; + } + } + } + + + static void + ft_black_set_mode( PRaster raster, + unsigned long mode, + const char* palette ) + { +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) + { + /* set 5-levels gray palette */ + raster->grays[0] = palette[0]; + raster->grays[1] = palette[1]; + raster->grays[2] = palette[2]; + raster->grays[3] = palette[3]; + raster->grays[4] = palette[4]; + } + +#else + + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( palette ); + +#endif + } + + + static int + ft_black_render( PRaster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + PWorker worker; + + + if ( !raster || !raster->buffer || !raster->buffer_size ) + return Raster_Err_Not_Ini; + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return Raster_Err_None; + + if ( !outline || !outline->contours || !outline->points ) + return Raster_Err_Invalid; + + if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) + return Raster_Err_Invalid; + + worker = raster->worker; + + /* this version of the raster does not support direct rendering, sorry */ + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + return Raster_Err_Unsupported; + + if ( !target_map || !target_map->buffer ) + return Raster_Err_Invalid; + + ras.outline = *outline; + ras.target = *target_map; + + worker->buff = (PLong) raster->buffer; + worker->sizeBuff = worker->buff + + raster->buffer_size / sizeof ( Long ); +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + worker->grays = raster->grays; + worker->gray_width = raster->gray_width; +#endif + + return ( ( params->flags & FT_RASTER_FLAG_AA ) + ? Render_Gray_Glyph( RAS_VAR ) + : Render_Glyph( RAS_VAR ) ); + } + + + const FT_Raster_Funcs ft_standard_raster = + { + FT_GLYPH_FORMAT_OUTLINE, + (FT_Raster_New_Func) ft_black_new, + (FT_Raster_Reset_Func) ft_black_reset, + (FT_Raster_Set_Mode_Func)ft_black_set_mode, + (FT_Raster_Render_Func) ft_black_render, + (FT_Raster_Done_Func) ft_black_done + }; + + +/* END */ diff --git a/src/freetype2/raster/ftraster.h b/src/freetype2/raster/ftraster.h new file mode 100644 index 0000000..80fe46d --- /dev/null +++ b/src/freetype2/raster/ftraster.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* ftraster.h */ +/* */ +/* The FreeType glyph rasterizer (specification). */ +/* */ +/* Copyright 1996-2001 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 __FTRASTER_H__ +#define __FTRASTER_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_IMAGE_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* Uncomment the following line if you are using ftraster.c as a */ + /* standalone module, fully independent of FreeType. */ + /* */ +/* #define _STANDALONE_ */ + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster; + + +FT_END_HEADER + +#endif /* __FTRASTER_H__ */ + + +/* END */ diff --git a/src/freetype2/raster/ftrend1.c b/src/freetype2/raster/ftrend1.c new file mode 100644 index 0000000..3cc8d07 --- /dev/null +++ b/src/freetype2/raster/ftrend1.c @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* ftrend1.c */ +/* */ +/* The FreeType glyph rasterizer interface (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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_OBJECTS_H +#include FT_OUTLINE_H +#include "ftrend1.h" +#include "ftraster.h" + +#include "rasterrs.h" + + + /* initialize renderer -- init its raster */ + static FT_Error + ft_raster1_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + + + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + + return Raster_Err_Ok; + } + + + /* set render-specific mode */ + static FT_Error + ft_raster1_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + /* transform a given glyph image */ + static FT_Error + ft_raster1_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = Raster_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = Raster_Err_Invalid_Argument; + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_raster1_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_raster1_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + FT_Outline* outline; + FT_BBox cbox; + FT_UInt width, height, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = Raster_Err_Invalid_Argument; + goto Exit; + } + + /* check rendering mode */ + if ( mode != FT_RENDER_MODE_MONO ) + { + /* raster1 is only capable of producing monochrome bitmaps */ + if ( render->clazz == &ft_raster1_renderer_class ) + return Raster_Err_Cannot_Render_Glyph; + } + else + { + /* raster5 is only capable of producing 5-gray-levels bitmaps */ + if ( render->clazz == &ft_raster5_renderer_class ) + return Raster_Err_Cannot_Render_Glyph; + } + + outline = &slot->outline; + + /* translate the outline to the new origin if needed */ + if ( origin ) + FT_Outline_Translate( outline, origin->x, origin->y ); + + /* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); + + cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); + cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); + cbox.xMax = FT_PIX_CEIL( cbox.xMax ); + cbox.yMax = FT_PIX_CEIL( cbox.yMax ); + + width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); + height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); + bitmap = &slot->bitmap; + memory = render->root.memory; + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* allocate new one, depends on pixel format */ + if ( !( mode & FT_RENDER_MODE_MONO ) ) + { + /* we pad to 32 bits, only for backwards compatibility with FT 1.x */ + pitch = FT_PAD_CEIL( width, 4 ); + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + } + else + { + pitch = ( ( width + 15 ) >> 4 ) << 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + } + + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; + + if ( FT_ALLOC_MULT( bitmap->buffer, pitch, height ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + /* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = 0; + + if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ) + params.flags |= FT_RASTER_FLAG_AA; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + FT_Outline_Translate( outline, cbox.xMin, cbox.yMin ); + + if ( error ) + goto Exit; + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 ); + slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 ); + + Exit: + return error; + } + + + FT_CALLBACK_TABLE_DEF + const FT_Renderer_Class ft_raster1_renderer_class = + { + { + FT_MODULE_RENDERER, + sizeof( FT_RendererRec ), + + "raster1", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_raster1_render, + (FT_Renderer_TransformFunc)ft_raster1_transform, + (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, + (FT_Renderer_SetModeFunc) ft_raster1_set_mode, + + (FT_Raster_Funcs*) &ft_standard_raster + }; + + + /* This renderer is _NOT_ part of the default modules; you will need */ + /* to register it by hand in your application. It should only be */ + /* used for backwards-compatibility with FT 1.x anyway. */ + /* */ + FT_CALLBACK_TABLE_DEF + const FT_Renderer_Class ft_raster5_renderer_class = + { + { + FT_MODULE_RENDERER, + sizeof( FT_RendererRec ), + + "raster5", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_raster1_render, + (FT_Renderer_TransformFunc)ft_raster1_transform, + (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, + (FT_Renderer_SetModeFunc) ft_raster1_set_mode, + + (FT_Raster_Funcs*) &ft_standard_raster + }; + + +/* END */ diff --git a/src/freetype2/raster/ftrend1.h b/src/freetype2/raster/ftrend1.h new file mode 100644 index 0000000..76e9a5f --- /dev/null +++ b/src/freetype2/raster/ftrend1.h @@ -0,0 +1,44 @@ +/***************************************************************************/ +/* */ +/* ftrend1.h */ +/* */ +/* The FreeType glyph rasterizer interface (specification). */ +/* */ +/* Copyright 1996-2001 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 __FTREND1_H__ +#define __FTREND1_H__ + + +#include <ft2build.h> +#include FT_RENDER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster1_renderer_class; + + /* this renderer is _NOT_ part of the default modules, you'll need */ + /* to register it by hand in your application. It should only be */ + /* used for backwards-compatibility with FT 1.x anyway. */ + /* */ + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster5_renderer_class; + + +FT_END_HEADER + +#endif /* __FTREND1_H__ */ + + +/* END */ diff --git a/src/freetype2/raster/raster.c b/src/freetype2/raster/raster.c new file mode 100644 index 0000000..f13a67a --- /dev/null +++ b/src/freetype2/raster/raster.c @@ -0,0 +1,26 @@ +/***************************************************************************/ +/* */ +/* raster.c */ +/* */ +/* FreeType monochrome rasterer module component (body only). */ +/* */ +/* Copyright 1996-2001 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 "ftraster.c" +#include "ftrend1.c" + + +/* END */ diff --git a/src/freetype2/raster/rasterrs.h b/src/freetype2/raster/rasterrs.h new file mode 100644 index 0000000..5df9a7a --- /dev/null +++ b/src/freetype2/raster/rasterrs.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* rasterrs.h */ +/* */ +/* monochrome renderer error codes (specification only). */ +/* */ +/* Copyright 2001 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 monochrome renderer error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __RASTERRS_H__ +#define __RASTERRS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX Raster_Err_ +#define FT_ERR_BASE FT_Mod_Err_Raster + +#include FT_ERRORS_H + +#endif /* __RASTERRS_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/sfdriver.c b/src/freetype2/sfnt/sfdriver.c new file mode 100644 index 0000000..5ba22a6 --- /dev/null +++ b/src/freetype2/sfnt/sfdriver.c @@ -0,0 +1,618 @@ +/***************************************************************************/ +/* */ +/* sfdriver.c */ +/* */ +/* High-level SFNT driver interface (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_SFNT_H +#include FT_INTERNAL_OBJECTS_H + +#include "sfdriver.h" +#include "ttload.h" +#include "sfobjs.h" + +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include "ttsbit.h" +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include "ttpost.h" +#endif + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#include FT_SERVICE_BDF_H +#endif + +#include "ttcmap.h" +#include "ttkern.h" +#include "ttmtx.h" + +#include FT_SERVICE_GLYPH_DICT_H +#include FT_SERVICE_POSTSCRIPT_NAME_H +#include FT_SERVICE_SFNT_H +#include FT_SERVICE_TT_CMAP_H + + + /* + * SFNT TABLE SERVICE + * + */ + + static void* + get_sfnt_table( TT_Face face, + FT_Sfnt_Tag tag ) + { + void* table; + + + switch ( tag ) + { + case ft_sfnt_head: + table = &face->header; + break; + + case ft_sfnt_hhea: + table = &face->horizontal; + break; + + case ft_sfnt_vhea: + table = face->vertical_info ? &face->vertical : 0; + break; + + case ft_sfnt_os2: + table = face->os2.version == 0xFFFFU ? 0 : &face->os2; + break; + + case ft_sfnt_post: + table = &face->postscript; + break; + + case ft_sfnt_maxp: + table = &face->max_profile; + break; + + case ft_sfnt_pclt: + table = face->pclt.Version ? &face->pclt : 0; + break; + + default: + table = 0; + } + + return table; + } + + + static FT_Error + sfnt_table_info( TT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *length ) + { + if ( !tag || !length ) + return SFNT_Err_Invalid_Argument; + + if ( idx >= face->num_tables ) + return SFNT_Err_Table_Missing; + + *tag = face->dir_tables[idx].Tag; + *length = face->dir_tables[idx].Length; + + return SFNT_Err_Ok; + } + + + static const FT_Service_SFNT_TableRec sfnt_service_sfnt_table = + { + (FT_SFNT_TableLoadFunc)tt_face_load_any, + (FT_SFNT_TableGetFunc) get_sfnt_table, + (FT_SFNT_TableInfoFunc)sfnt_table_info + }; + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + /* + * GLYPH DICT SERVICE + * + */ + + static FT_Error + sfnt_get_glyph_name( TT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + FT_Error error; + + + error = tt_face_get_ps_name( face, glyph_index, &gname ); + if ( !error ) + FT_STRCPYN( buffer, gname, buffer_max ); + + return error; + } + + + static const FT_Service_GlyphDictRec sfnt_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)NULL + }; + +#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + sfnt_get_ps_name( TT_Face face ) + { + FT_Int n, found_win, found_apple; + const char* result = NULL; + + + /* shouldn't happen, but just in case to avoid memory leaks */ + if ( face->postscript_name ) + return face->postscript_name; + + /* scan the name table to see whether we have a Postscript name here, */ + /* either in Macintosh or Windows platform encodings */ + found_win = -1; + found_apple = -1; + + for ( n = 0; n < face->num_names; n++ ) + { + TT_NameEntryRec* name = face->name_table.names + n; + + + if ( name->nameID == 6 && name->stringLength > 0 ) + { + if ( name->platformID == 3 && + name->encodingID == 1 && + name->languageID == 0x409 ) + found_win = n; + + if ( name->platformID == 1 && + name->encodingID == 0 && + name->languageID == 0 ) + found_apple = n; + } + } + + if ( found_win != -1 ) + { + FT_Memory memory = face->root.memory; + TT_NameEntryRec* name = face->name_table.names + found_win; + FT_UInt len = name->stringLength / 2; + FT_Error error = SFNT_Err_Ok; + + FT_UNUSED( error ); + + + if ( !FT_ALLOC( result, name->stringLength + 1 ) ) + { + FT_Stream stream = face->name_table.stream; + FT_String* r = (FT_String*)result; + FT_Byte* p = (FT_Byte*)name->string; + + + if ( FT_STREAM_SEEK( name->stringOffset ) || + FT_FRAME_ENTER( name->stringLength ) ) + { + FT_FREE( result ); + name->stringLength = 0; + name->stringOffset = 0; + FT_FREE( name->string ); + + goto Exit; + } + + p = (FT_Byte*)stream->cursor; + + for ( ; len > 0; len--, p += 2 ) + { + if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 ) + *r++ = p[1]; + } + *r = '\0'; + + FT_FRAME_EXIT(); + } + goto Exit; + } + + if ( found_apple != -1 ) + { + FT_Memory memory = face->root.memory; + TT_NameEntryRec* name = face->name_table.names + found_apple; + FT_UInt len = name->stringLength; + FT_Error error = SFNT_Err_Ok; + + FT_UNUSED( error ); + + + if ( !FT_ALLOC( result, len + 1 ) ) + { + FT_Stream stream = face->name_table.stream; + + + if ( FT_STREAM_SEEK( name->stringOffset ) || + FT_STREAM_READ( result, len ) ) + { + name->stringOffset = 0; + name->stringLength = 0; + FT_FREE( name->string ); + FT_FREE( result ); + goto Exit; + } + ((char*)result)[len] = '\0'; + } + } + + Exit: + face->postscript_name = result; + return result; + } + + static const FT_Service_PsFontNameRec sfnt_service_ps_name = + { + (FT_PsName_GetFunc)sfnt_get_ps_name + }; + + + /* + * TT CMAP INFO + */ + static const FT_Service_TTCMapsRec tt_service_get_cmap_info = + { + (TT_CMap_Info_GetFunc)tt_get_cmap_info + }; + + +#ifdef TT_CONFIG_OPTION_BDF + + static FT_Error + sfnt_get_charset_id( TT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_PropertyRec encoding, registry; + FT_Error error; + + + /* XXX: I don't know whether this is correct, since + * tt_face_find_bdf_prop only returns something correct if we have + * previously selected a size that is listed in the BDF table. + * Should we change the BDF table format to include single offsets + * for `CHARSET_REGISTRY' and `CHARSET_ENCODING'? + */ + error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry ); + if ( !error ) + { + error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding ); + if ( !error ) + { + if ( registry.type == BDF_PROPERTY_TYPE_ATOM && + encoding.type == BDF_PROPERTY_TYPE_ATOM ) + { + *acharset_encoding = encoding.u.atom; + *acharset_registry = registry.u.atom; + } + else + error = FT_Err_Invalid_Argument; + } + } + + return error; + } + + + static const FT_Service_BDFRec sfnt_service_bdf = + { + (FT_BDF_GetCharsetIdFunc) sfnt_get_charset_id, + (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop, + }; + +#endif /* TT_CONFIG_OPTION_BDF */ + + + /* + * SERVICE LIST + */ + + static const FT_ServiceDescRec sfnt_services[] = + { + { FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name }, +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + { FT_SERVICE_ID_GLYPH_DICT, &sfnt_service_glyph_dict }, +#endif +#ifdef TT_CONFIG_OPTION_BDF + { FT_SERVICE_ID_BDF, &sfnt_service_bdf }, +#endif + { FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info }, + + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + sfnt_get_interface( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sfnt_services, module_interface ); + } + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_CALLBACK_DEF( FT_Error ) + tt_face_load_sfnt_header_stub( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header header ) + { + FT_UNUSED( face ); + FT_UNUSED( stream ); + FT_UNUSED( face_index ); + FT_UNUSED( header ); + + return FT_Err_Unimplemented_Feature; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_load_directory_stub( TT_Face face, + FT_Stream stream, + SFNT_Header header ) + { + FT_UNUSED( face ); + FT_UNUSED( stream ); + FT_UNUSED( header ); + + return FT_Err_Unimplemented_Feature; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_load_hdmx_stub( TT_Face face, + FT_Stream stream ) + { + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Unimplemented_Feature; + } + + + FT_CALLBACK_DEF( void ) + tt_face_free_hdmx_stub( TT_Face face ) + { + FT_UNUSED( face ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_set_sbit_strike_stub( TT_Face face, + FT_UInt x_ppem, + FT_UInt y_ppem, + FT_ULong* astrike_index ) + { + /* + * We simply forge a FT_Size_Request and call the real function + * that does all the work. + * + * This stub might be called by libXfont in the X.Org Xserver, + * compiled against version 2.1.8 or newer. + */ + + FT_Size_RequestRec req; + + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = (FT_F26Dot6)x_ppem; + req.height = (FT_F26Dot6)y_ppem; + req.horiResolution = 0; + req.vertResolution = 0; + + *astrike_index = 0x7FFFFFFFUL; + + return tt_face_set_sbit_strike( face, &req, astrike_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_load_sbit_stub( TT_Face face, + FT_Stream stream ) + { + FT_UNUSED( face ); + FT_UNUSED( stream ); + + /* + * This function was originally implemented to load the sbit table. + * However, it has been replaced by `tt_face_load_eblc', and this stub + * is only there for some rogue clients which would want to call it + * directly (which doesn't make much sense). + */ + return FT_Err_Unimplemented_Feature; + } + + + FT_CALLBACK_DEF( void ) + tt_face_free_sbit_stub( TT_Face face ) + { + /* nothing to do in this stub */ + FT_UNUSED( face ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_load_charmap_stub( TT_Face face, + void* cmap, + FT_Stream input ) + { + FT_UNUSED( face ); + FT_UNUSED( cmap ); + FT_UNUSED( input ); + + return FT_Err_Unimplemented_Feature; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_face_free_charmap_stub( TT_Face face, + void* cmap ) + { + FT_UNUSED( face ); + FT_UNUSED( cmap ); + + return 0; + } + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + static + const SFNT_Interface sfnt_interface = + { + tt_face_goto_table, + + sfnt_init_face, + sfnt_load_face, + sfnt_done_face, + sfnt_get_interface, + + tt_face_load_any, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + tt_face_load_sfnt_header_stub, + tt_face_load_directory_stub, +#endif + + tt_face_load_head, + tt_face_load_hhea, + tt_face_load_cmap, + tt_face_load_maxp, + tt_face_load_os2, + tt_face_load_post, + + tt_face_load_name, + tt_face_free_name, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + tt_face_load_hdmx_stub, + tt_face_free_hdmx_stub, +#endif + + tt_face_load_kern, + tt_face_load_gasp, + tt_face_load_pclt, + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /* see `ttload.h' */ + tt_face_load_bhed, +#else + 0, +#endif + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + tt_face_set_sbit_strike_stub, + tt_face_load_sbit_stub, + + tt_find_sbit_image, + tt_load_sbit_metrics, +#endif + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + tt_face_load_sbit_image, +#else + 0, +#endif + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + tt_face_free_sbit_stub, +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + /* see `ttpost.h' */ + tt_face_get_ps_name, + tt_face_free_ps_names, +#else + 0, + 0, +#endif + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + tt_face_load_charmap_stub, + tt_face_free_charmap_stub, +#endif + + /* since version 2.1.8 */ + + tt_face_get_kerning, + + /* since version 2.2 */ + + tt_face_load_font_dir, + tt_face_load_hmtx, + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /* see `ttsbit.h' and `sfnt.h' */ + tt_face_load_eblc, + tt_face_free_eblc, + + tt_face_set_sbit_strike, + tt_face_load_strike_metrics, +#else + 0, + 0, + 0, + 0, +#endif + + tt_face_get_metrics + }; + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class sfnt_module_class = + { + 0, /* not a font driver or renderer */ + sizeof( FT_ModuleRec ), + + "sfnt", /* driver name */ + 0x10000L, /* driver version 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or higher */ + + (const void*)&sfnt_interface, /* module specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) sfnt_get_interface + }; + + +/* END */ diff --git a/src/freetype2/sfnt/sfdriver.h b/src/freetype2/sfnt/sfdriver.h new file mode 100644 index 0000000..92db796 --- /dev/null +++ b/src/freetype2/sfnt/sfdriver.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* sfdriver.h */ +/* */ +/* High-level SFNT driver interface (specification). */ +/* */ +/* Copyright 1996-2001 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 __SFDRIVER_H__ +#define __SFDRIVER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) sfnt_module_class; + + +FT_END_HEADER + +#endif /* __SFDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/sferrors.h b/src/freetype2/sfnt/sferrors.h new file mode 100644 index 0000000..27f90de --- /dev/null +++ b/src/freetype2/sfnt/sferrors.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* sferrors.h */ +/* */ +/* SFNT error codes (specification only). */ +/* */ +/* Copyright 2001, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the SFNT error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __SFERRORS_H__ +#define __SFERRORS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX SFNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_SFNT + +#define FT_KEEP_ERR_PREFIX + +#include FT_ERRORS_H + +#endif /* __SFERRORS_H__ */ + +/* END */ diff --git a/src/freetype2/sfnt/sfnt.c b/src/freetype2/sfnt/sfnt.c new file mode 100644 index 0000000..45a820b --- /dev/null +++ b/src/freetype2/sfnt/sfnt.c @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* sfnt.c */ +/* */ +/* Single object library component. */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> +#include "ttload.c" +#include "ttmtx.c" +#include "ttcmap.c" +#include "ttkern.c" +#include "sfobjs.c" +#include "sfdriver.c" + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include "ttsbit.c" +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include "ttpost.c" +#endif + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.c" +#endif + +/* END */ diff --git a/src/freetype2/sfnt/sfobjs.c b/src/freetype2/sfnt/sfobjs.c new file mode 100644 index 0000000..cc90110 --- /dev/null +++ b/src/freetype2/sfnt/sfobjs.c @@ -0,0 +1,1070 @@ +/***************************************************************************/ +/* */ +/* sfobjs.c */ +/* */ +/* SFNT object management (base). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include "sfobjs.h" +#include "ttload.h" +#include "ttcmap.h" +#include "ttkern.h" +#include FT_INTERNAL_SFNT_H +#include FT_INTERNAL_DEBUG_H +#include FT_TRUETYPE_IDS_H +#include FT_TRUETYPE_TAGS_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#endif + + + /*************************************************************************/ + /* */ + /* 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_sfobjs + + + + /* convert a UTF-16 name entry to ASCII */ + static FT_String* + tt_name_entry_ascii_from_utf16( TT_NameEntry entry, + FT_Memory memory ) + { + FT_String* string; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength / 2; + + if ( FT_NEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = FT_NEXT_USHORT( read ); + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[len] = 0; + + return string; + } + + + /* convert an Apple Roman or symbol name entry to ASCII */ + static FT_String* + tt_name_entry_ascii_from_other( TT_NameEntry entry, + FT_Memory memory ) + { + FT_String* string; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength; + + if ( FT_NEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = *read++; + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[len] = 0; + + return string; + } + + + typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry, + FT_Memory memory ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_get_name */ + /* */ + /* <Description> */ + /* Returns a given ENGLISH name record in ASCII. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* nameid :: The name id of the name record to return. */ + /* */ + /* <Return> */ + /* Character string. NULL if no name is present. */ + /* */ + static FT_String* + tt_face_get_name( TT_Face face, + FT_UShort nameid ) + { + FT_Memory memory = face->root.memory; + FT_String* result = NULL; + FT_UShort n; + TT_NameEntryRec* rec; + FT_Int found_apple = -1; + FT_Int found_apple_roman = -1; + FT_Int found_apple_english = -1; + FT_Int found_win = -1; + FT_Int found_unicode = -1; + + FT_Bool is_english = 0; + + TT_NameEntry_ConvertFunc convert; + + + rec = face->name_table.names; + for ( n = 0; n < face->num_names; n++, rec++ ) + { + /* According to the OpenType 1.3 specification, only Microsoft or */ + /* Apple platform IDs might be used in the `name' table. The */ + /* `Unicode' platform is reserved for the `cmap' table, and the */ + /* `Iso' one is deprecated. */ + /* */ + /* However, the Apple TrueType specification doesn't say the same */ + /* thing and goes to suggest that all Unicode `name' table entries */ + /* should be coded in UTF-16 (in big-endian format I suppose). */ + /* */ + if ( rec->nameID == nameid && rec->stringLength > 0 ) + { + switch ( rec->platformID ) + { + case TT_PLATFORM_APPLE_UNICODE: + case TT_PLATFORM_ISO: + /* there is `languageID' to check there. We should use this */ + /* field only as a last solution when nothing else is */ + /* available. */ + /* */ + found_unicode = n; + break; + + case TT_PLATFORM_MACINTOSH: + /* This is a bit special because some fonts will use either */ + /* an English language id, or a Roman encoding id, to indicate */ + /* the English version of its font name. */ + /* */ + if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) + found_apple_english = n; + else if ( rec->encodingID == TT_MAC_ID_ROMAN ) + found_apple_roman = n; + break; + + case TT_PLATFORM_MICROSOFT: + /* we only take a non-English name when there is nothing */ + /* else available in the font */ + /* */ + if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) + { + switch ( rec->encodingID ) + { + case TT_MS_ID_SYMBOL_CS: + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_UCS_4: + is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); + found_win = n; + break; + + default: + ; + } + } + break; + + default: + ; + } + } + } + + found_apple = found_apple_roman; + if ( found_apple_english >= 0 ) + found_apple = found_apple_english; + + /* some fonts contain invalid Unicode or Macintosh formatted entries; */ + /* we will thus favor names encoded in Windows formats if available */ + /* (provided it is an English name) */ + /* */ + convert = NULL; + if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) + { + rec = face->name_table.names + found_win; + switch ( rec->encodingID ) + { + /* all Unicode strings are encoded using UTF-16BE */ + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_SYMBOL_CS: + convert = tt_name_entry_ascii_from_utf16; + break; + + case TT_MS_ID_UCS_4: + /* Apparently, if this value is found in a name table entry, it is */ + /* documented as `full Unicode repertoire'. Experience with the */ + /* MsGothic font shipped with Windows Vista shows that this really */ + /* means UTF-16 encoded names (UCS-4 values are only used within */ + /* charmaps). */ + convert = tt_name_entry_ascii_from_utf16; + break; + + default: + ; + } + } + else if ( found_apple >= 0 ) + { + rec = face->name_table.names + found_apple; + convert = tt_name_entry_ascii_from_other; + } + else if ( found_unicode >= 0 ) + { + rec = face->name_table.names + found_unicode; + convert = tt_name_entry_ascii_from_utf16; + } + + if ( rec && convert ) + { + if ( rec->string == NULL ) + { + FT_Error error = SFNT_Err_Ok; + FT_Stream stream = face->name_table.stream; + + FT_UNUSED( error ); + + + if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || + FT_STREAM_SEEK( rec->stringOffset ) || + FT_STREAM_READ( rec->string, rec->stringLength ) ) + { + FT_FREE( rec->string ); + rec->stringLength = 0; + result = NULL; + goto Exit; + } + } + + result = convert( rec, memory ); + } + + Exit: + return result; + } + + + static FT_Encoding + sfnt_find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + + } TEncoding; + + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, + + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_GB2312 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } + }; + + const TEncoding *cur, *limit; + + + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + + return FT_ENCODING_NONE; + } + + + /* Fill in face->ttc_header. If the font is not a TTC, it is */ + /* synthesized into a TTC with one offset table. */ + static FT_Error + sfnt_open_font( FT_Stream stream, + TT_Face face ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_ULong tag, offset; + + static const FT_Frame_Field ttc_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TTC_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_LONG( version ), + FT_FRAME_LONG( count ), + FT_FRAME_END + }; + + + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + + offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( tag ) ) + return error; + + if ( tag != 0x00010000UL && + tag != TTAG_ttcf && + tag != FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) && + tag != TTAG_true && + tag != 0x00020000UL ) + return SFNT_Err_Unknown_File_Format; + + face->ttc_header.tag = TTAG_ttcf; + + if ( tag == TTAG_ttcf ) + { + FT_Int n; + + + FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); + + if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) + return error; + + /* now read the offsets of each font in the file */ + if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + return error; + + if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) + return error; + + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + } + else + { + FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); + + face->ttc_header.version = 1 << 16; + face->ttc_header.count = 1; + + if ( FT_NEW( face->ttc_header.offsets) ) + return error; + + face->ttc_header.offsets[0] = offset; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Service sfnt; + + + /* for now, parameters are unused */ + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + sfnt = (SFNT_Service)face->sfnt; + if ( !sfnt ) + { + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + return SFNT_Err_Invalid_File_Format; + + face->sfnt = sfnt; + face->goto_table = sfnt->goto_table; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); + + error = sfnt_open_font( stream, face ); + if ( error ) + return error; + + FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index )); + + if ( face_index < 0 ) + face_index = 0; + + if ( face_index >= face->ttc_header.count ) + return SFNT_Err_Bad_Argument; + + if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) + return error; + + /* check that we have a valid TrueType file */ + error = sfnt->load_font_dir( face, stream ); + if ( error ) + return error; + + face->root.num_faces = face->ttc_header.count; + + return error; + } + + +#define LOAD_( x ) \ + do { \ + FT_TRACE2(( "`" #x "' " )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_##x( face, stream ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : ( error == SFNT_Err_Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + +#define LOADM_( x, vertical ) \ + do { \ + FT_TRACE2(( "`%s" #x "' ", \ + vertical ? "vertical " : "" )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_##x( face, stream, vertical ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : ( error == SFNT_Err_Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + + + FT_LOCAL_DEF( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error, psnames_error; + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_UNUSED( face_index ); + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* Load tables */ + + /* We now support two SFNT-based bitmapped font formats. They */ + /* are recognized easily as they do not include a `glyf' */ + /* table. */ + /* */ + /* The first format comes from Apple, and uses a table named */ + /* `bhed' instead of `head' to store the font header (using */ + /* the same format). It also doesn't include horizontal and */ + /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ + /* missing). */ + /* */ + /* The other format comes from Microsoft, and is used with */ + /* WinCE/PocketPC. It looks like a standard TTF, except that */ + /* it doesn't contain outlines. */ + /* */ + + FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); + + /* do we have outlines in there? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || + tt_face_lookup_table( face, TTAG_glyf ) != 0 || + tt_face_lookup_table( face, TTAG_CFF ) != 0 ); +#else + has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || + tt_face_lookup_table( face, TTAG_CFF ) != 0 ); +#endif + + is_apple_sbit = 0; + + /* if this font doesn't contain outlines, we try to load */ + /* a `bhed' table */ + if ( !has_outline && sfnt->load_bhed ) + { + LOAD_( bhed ); + is_apple_sbit = FT_BOOL( !error ); + } + + /* load the font header (`head' table) if this isn't an Apple */ + /* sbit font file */ + if ( !is_apple_sbit ) + { + LOAD_( head ); + if ( error ) + goto Exit; + } + + if ( face->header.Units_Per_EM == 0 ) + { + error = SFNT_Err_Invalid_Table; + + goto Exit; + } + + /* the following tables are often not present in embedded TrueType */ + /* fonts within PDF documents, so don't check for them. */ + LOAD_( maxp ); + LOAD_( cmap ); + + /* the following tables are optional in PCL fonts -- */ + /* don't check for errors */ + LOAD_( name ); + LOAD_( post ); + psnames_error = error; + + /* do not load the metrics headers and tables if this is an Apple */ + /* sbit font file */ + if ( !is_apple_sbit ) + { + /* load the `hhea' and `hmtx' tables */ + LOADM_( hhea, 0 ); + if ( !error ) + { + LOADM_( hmtx, 0 ); + if ( error == SFNT_Err_Table_Missing ) + { + error = SFNT_Err_Hmtx_Table_Missing; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hmtx' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = SFNT_Err_Ok; + } +#endif + } + } + else if ( error == SFNT_Err_Table_Missing ) + { + /* No `hhea' table necessary for SFNT Mac fonts. */ + if ( face->format_tag == TTAG_true ) + { + FT_TRACE2(( "This is an SFNT Mac font.\n" )); + has_outline = 0; + error = SFNT_Err_Ok; + } + else + { + error = SFNT_Err_Horiz_Header_Missing; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hhea' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = SFNT_Err_Ok; + } +#endif + + } + } + + if ( error ) + goto Exit; + + /* try to load the `vhea' and `vmtx' tables */ + LOADM_( hhea, 1 ); + if ( !error ) + { + LOADM_( hmtx, 1 ); + if ( !error ) + face->vertical_info = 1; + } + + if ( error && error != SFNT_Err_Table_Missing ) + goto Exit; + + LOAD_( os2 ); + if ( error ) + { + if ( error != SFNT_Err_Table_Missing ) + goto Exit; + + face->os2.version = 0xFFFFU; + } + + } + + /* the optional tables */ + + /* embedded bitmap support. */ + if ( sfnt->load_eblc ) + { + LOAD_( eblc ); + if ( error ) + { + /* return an error if this font file has no outlines */ + if ( error == SFNT_Err_Table_Missing && has_outline ) + error = SFNT_Err_Ok; + else + goto Exit; + } + } + + LOAD_( pclt ); + if ( error ) + { + if ( error != SFNT_Err_Table_Missing ) + goto Exit; + + face->pclt.Version = 0; + } + + /* consider the kerning and gasp tables as optional */ + LOAD_( gasp ); + LOAD_( kern ); + + error = SFNT_Err_Ok; + + face->root.num_glyphs = face->max_profile.numGlyphs; + + face->root.family_name = tt_face_get_name( face, + TT_NAME_ID_PREFERRED_FAMILY ); + if ( !face->root.family_name ) + face->root.family_name = tt_face_get_name( face, + TT_NAME_ID_FONT_FAMILY ); + + face->root.style_name = tt_face_get_name( face, + TT_NAME_ID_PREFERRED_SUBFAMILY ); + if ( !face->root.style_name ) + face->root.style_name = tt_face_get_name( face, + TT_NAME_ID_FONT_SUBFAMILY ); + + /* now set up root fields */ + { + FT_Face root = &face->root; + FT_Int32 flags = root->face_flags; + + + /*********************************************************************/ + /* */ + /* Compute face flags. */ + /* */ + if ( has_outline == TRUE ) + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + + /* The sfnt driver only supports bitmap fonts natively, thus we */ + /* don't set FT_FACE_FLAG_HINTER. */ + flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ + FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + if ( psnames_error == SFNT_Err_Ok && + face->postscript.FormatType != 0x00030000L ) + flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + + /* fixed width font? */ + if ( face->postscript.isFixedPitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* vertical information? */ + if ( face->vertical_info ) + flags |= FT_FACE_FLAG_VERTICAL; + + /* kerning available ? */ + if ( TT_FACE_HAS_KERNING( face ) ) + flags |= FT_FACE_FLAG_KERNING; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Don't bother to load the tables unless somebody asks for them. */ + /* No need to do work which will (probably) not be used. */ + if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && + tt_face_lookup_table( face, TTAG_fvar ) != 0 && + tt_face_lookup_table( face, TTAG_gvar ) != 0 ) + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; +#endif + + root->face_flags = flags; + + /*********************************************************************/ + /* */ + /* Compute style flags. */ + /* */ + flags = 0; + if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) + { + /* we have an OS/2 table; use the `fsSelection' field */ + if ( face->os2.fsSelection & 1 ) + flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->os2.fsSelection & 32 ) + flags |= FT_STYLE_FLAG_BOLD; + } + else + { + /* this is an old Mac font, use the header field */ + if ( face->header.Mac_Style & 1 ) + flags |= FT_STYLE_FLAG_BOLD; + + if ( face->header.Mac_Style & 2 ) + flags |= FT_STYLE_FLAG_ITALIC; + } + + root->style_flags = flags; + + /*********************************************************************/ + /* */ + /* Polish the charmaps. */ + /* */ + /* Try to set the charmap encoding according to the platform & */ + /* encoding ID of each charmap. */ + /* */ + + tt_face_build_cmaps( face ); /* ignore errors */ + + + /* set the encoding fields */ + { + FT_Int m; + + + for ( m = 0; m < root->num_charmaps; m++ ) + { + FT_CharMap charmap = root->charmaps[m]; + + + charmap->encoding = sfnt_find_encoding( charmap->platform_id, + charmap->encoding_id ); + +#if 0 + if ( root->charmap == NULL && + charmap->encoding == FT_ENCODING_UNICODE ) + { + /* set 'root->charmap' to the first Unicode encoding we find */ + root->charmap = charmap; + } +#endif + } + } + + + /*********************************************************************/ + /* */ + /* Set up metrics. */ + /* */ + if ( has_outline == TRUE ) + { + /* XXX What about if outline header is missing */ + /* (e.g. sfnt wrapped bitmap)? */ + root->bbox.xMin = face->header.xMin; + root->bbox.yMin = face->header.yMin; + root->bbox.xMax = face->header.xMax; + root->bbox.yMax = face->header.yMax; + root->units_per_EM = face->header.Units_Per_EM; + + + /* XXX: Computing the ascender/descender/height is very different */ + /* from what the specification tells you. Apparently, we */ + /* must be careful because */ + /* */ + /* - not all fonts have an OS/2 table; in this case, we take */ + /* the values in the horizontal header. However, these */ + /* values very often are not reliable. */ + /* */ + /* - otherwise, the correct typographic values are in the */ + /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ + /* */ + /* However, certain fonts have these fields set to 0. */ + /* Rather, they have usWinAscent & usWinDescent correctly */ + /* set (but with different values). */ + /* */ + /* As an example, Arial Narrow is implemented through four */ + /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ + /* */ + /* Strangely, all fonts have the same values in their */ + /* sTypoXXX fields, except ARIALNB which sets them to 0. */ + /* */ + /* On the other hand, they all have different */ + /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ + /* table cannot be used to compute the text height reliably! */ + /* */ + + /* The ascender/descender/height are computed from the OS/2 table */ + /* when found. Otherwise, they're taken from the horizontal */ + /* header. */ + /* */ + + root->ascender = face->horizontal.Ascender; + root->descender = face->horizontal.Descender; + + root->height = (FT_Short)( root->ascender - root->descender + + face->horizontal.Line_Gap ); + +#if 0 + /* if the line_gap is 0, we add an extra 15% to the text height -- */ + /* this computation is based on various versions of Times New Roman */ + if ( face->horizontal.Line_Gap == 0 ) + root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 ); +#endif + +#if 0 + + /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */ + /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */ + if ( face->os2.version != 0xFFFFU && root->ascender ) + { + FT_Int height; + + + root->ascender = face->os2.sTypoAscender; + root->descender = -face->os2.sTypoDescender; + + height = root->ascender + root->descender + face->os2.sTypoLineGap; + if ( height > root->height ) + root->height = height; + } + +#endif /* 0 */ + + root->max_advance_width = face->horizontal.advance_Width_Max; + + root->max_advance_height = (FT_Short)( face->vertical_info + ? face->vertical.advance_Height_Max + : root->height ); + + root->underline_position = face->postscript.underlinePosition; + root->underline_thickness = face->postscript.underlineThickness; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* + * Now allocate the root array of FT_Bitmap_Size records and + * populate them. Unfortunately, it isn't possible to indicate bit + * depths in the FT_Bitmap_Size record. This is a design error. + */ + { + FT_UInt i, count; + + +#if !defined FT_CONFIG_OPTION_OLD_INTERNALS + count = face->sbit_num_strikes; +#else + count = (FT_UInt)face->num_sbit_strikes; +#endif + + if ( count > 0 ) + { + FT_Memory memory = face->root.stream->memory; + FT_UShort em_size = face->header.Units_Per_EM; + FT_Short avgwidth = face->os2.xAvgCharWidth; + FT_Size_Metrics metrics; + + + if ( em_size == 0 || face->os2.version == 0xFFFFU ) + { + avgwidth = 0; + em_size = 1; + } + + if ( FT_NEW_ARRAY( root->available_sizes, count ) ) + goto Exit; + + for ( i = 0; i < count; i++ ) + { + FT_Bitmap_Size* bsize = root->available_sizes + i; + + + error = sfnt->load_strike_metrics( face, i, &metrics ); + if ( error ) + goto Exit; + + bsize->height = (FT_Short)( metrics.height >> 6 ); + bsize->width = (FT_Short)( + ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); + + bsize->x_ppem = metrics.x_ppem << 6; + bsize->y_ppem = metrics.y_ppem << 6; + + /* assume 72dpi */ + bsize->size = metrics.y_ppem << 6; + } + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + root->num_fixed_sizes = (FT_Int)count; + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + } + + Exit: + FT_TRACE2(( "sfnt_load_face: done\n" )); + + return error; + } + + +#undef LOAD_ +#undef LOADM_ + + + FT_LOCAL_DEF( void ) + sfnt_done_face( TT_Face face ) + { + FT_Memory memory = face->root.memory; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + if ( sfnt ) + { + /* destroy the postscript names table if it is loaded */ + if ( sfnt->free_psnames ) + sfnt->free_psnames( face ); + + /* destroy the embedded bitmaps table if it is loaded */ + if ( sfnt->free_eblc ) + sfnt->free_eblc( face ); + } + +#ifdef TT_CONFIG_OPTION_BDF + /* freeing the embedded BDF properties */ + tt_face_free_bdf_props( face ); +#endif + + /* freeing the kerning table */ + tt_face_done_kern( face ); + + /* freeing the collection table */ + FT_FREE( face->ttc_header.offsets ); + face->ttc_header.count = 0; + + /* freeing table directory */ + FT_FREE( face->dir_tables ); + face->num_tables = 0; + + { + FT_Stream stream = FT_FACE_STREAM( face ); + + + /* simply release the 'cmap' table frame */ + FT_FRAME_RELEASE( face->cmap_table ); + face->cmap_size = 0; + } + + /* freeing the horizontal metrics */ +#if !defined FT_CONFIG_OPTION_OLD_INTERNALS + { + FT_Stream stream = FT_FACE_STREAM( face ); + + + FT_FRAME_RELEASE( face->horz_metrics ); + FT_FRAME_RELEASE( face->vert_metrics ); + face->horz_metrics_size = 0; + face->vert_metrics_size = 0; + } +#else + FT_FREE( face->horizontal.long_metrics ); + FT_FREE( face->horizontal.short_metrics ); +#endif + + /* freeing the vertical ones, if any */ + if ( face->vertical_info ) + { + FT_FREE( face->vertical.long_metrics ); + FT_FREE( face->vertical.short_metrics ); + face->vertical_info = 0; + } + + /* freeing the gasp table */ + FT_FREE( face->gasp.gaspRanges ); + face->gasp.numRanges = 0; + + /* freeing the name table */ + sfnt->free_name( face ); + + /* freeing family and style name */ + FT_FREE( face->root.family_name ); + FT_FREE( face->root.style_name ); + + /* freeing sbit size table */ + FT_FREE( face->root.available_sizes ); + face->root.num_fixed_sizes = 0; + + FT_FREE( face->postscript_name ); + + face->sfnt = 0; + } + + +/* END */ diff --git a/src/freetype2/sfnt/sfobjs.h b/src/freetype2/sfnt/sfobjs.h new file mode 100644 index 0000000..6241c93 --- /dev/null +++ b/src/freetype2/sfnt/sfobjs.h @@ -0,0 +1,54 @@ +/***************************************************************************/ +/* */ +/* sfobjs.h */ +/* */ +/* SFNT object management (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __SFOBJS_H__ +#define __SFOBJS_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_SFNT_H +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + sfnt_done_face( TT_Face face ); + + +FT_END_HEADER + +#endif /* __SFDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttbdf.c b/src/freetype2/sfnt/ttbdf.c new file mode 100644 index 0000000..6c95387 --- /dev/null +++ b/src/freetype2/sfnt/ttbdf.c @@ -0,0 +1,250 @@ +/***************************************************************************/ +/* */ +/* ttbdf.c */ +/* */ +/* TrueType and OpenType embedded BDF properties (body). */ +/* */ +/* Copyright 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_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttbdf.h" + +#include "sferrors.h" + + +#ifdef TT_CONFIG_OPTION_BDF + + /*************************************************************************/ + /* */ + /* 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_ttbdf + + + FT_LOCAL_DEF( void ) + tt_face_free_bdf_props( TT_Face face ) + { + TT_BDF bdf = &face->bdf; + + + if ( bdf->loaded ) + { + FT_Stream stream = FT_FACE(face)->stream; + + + if ( bdf->table != NULL ) + FT_FRAME_RELEASE( bdf->table ); + + bdf->table_end = NULL; + bdf->strings = NULL; + bdf->strings_size = 0; + } + } + + + static FT_Error + tt_face_load_bdf_props( TT_Face face, + FT_Stream stream ) + { + TT_BDF bdf = &face->bdf; + FT_ULong length; + FT_Error error; + + + FT_ZERO( bdf ); + + error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); + if ( error || + length < 8 || + FT_FRAME_EXTRACT( length, bdf->table ) ) + { + error = FT_Err_Invalid_Table; + goto Exit; + } + + bdf->table_end = bdf->table + length; + + { + FT_Byte* p = bdf->table; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt num_strikes = FT_NEXT_USHORT( p ); + FT_UInt32 strings = FT_NEXT_ULONG ( p ); + FT_UInt count; + FT_Byte* strike; + + + if ( version != 0x0001 || + strings < 8 || + ( strings - 8 ) / 4 < num_strikes || + strings + 1 > length ) + { + goto BadTable; + } + + bdf->num_strikes = num_strikes; + bdf->strings = bdf->table + strings; + bdf->strings_size = length - strings; + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + count * 4; + + + for ( ; count > 0; count-- ) + { + FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); + + /* + * We don't need to check the value sets themselves, since this + * is done later. + */ + strike += 10 * num_items; + + p += 4; + } + + if ( strike > bdf->strings ) + goto BadTable; + } + + bdf->loaded = 1; + + Exit: + return error; + + BadTable: + FT_FRAME_RELEASE( bdf->table ); + FT_ZERO( bdf ); + error = FT_Err_Invalid_Table; + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_find_bdf_prop( TT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ) + { + TT_BDF bdf = &face->bdf; + FT_Size size = FT_FACE(face)->size; + FT_Error error = 0; + FT_Byte* p; + FT_UInt count; + FT_Byte* strike; + FT_UInt property_len; + + + aprop->type = BDF_PROPERTY_TYPE_NONE; + + if ( bdf->loaded == 0 ) + { + error = tt_face_load_bdf_props( face, FT_FACE( face )->stream ); + if ( error ) + goto Exit; + } + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + 4 * count; + + error = FT_Err_Invalid_Argument; + + if ( size == NULL || property_name == NULL ) + goto Exit; + + property_len = ft_strlen( property_name ); + if ( property_len == 0 ) + goto Exit; + + for ( ; count > 0; count-- ) + { + FT_UInt _ppem = FT_NEXT_USHORT( p ); + FT_UInt _count = FT_NEXT_USHORT( p ); + + if ( _ppem == size->metrics.y_ppem ) + { + count = _count; + goto FoundStrike; + } + + strike += 10 * _count; + } + goto Exit; + + FoundStrike: + p = strike; + for ( ; count > 0; count-- ) + { + FT_UInt type = FT_PEEK_USHORT( p + 4 ); + + if ( ( type & 0x10 ) != 0 ) + { + FT_UInt32 name_offset = FT_PEEK_ULONG( p ); + FT_UInt32 value = FT_PEEK_ULONG( p + 6 ); + + /* be a bit paranoid for invalid entries here */ + if ( name_offset < bdf->strings_size && + property_len < bdf->strings_size - name_offset && + ft_strncmp( property_name, + (const char*)bdf->strings + name_offset, + bdf->strings_size - name_offset ) == 0 ) + { + switch ( type & 0x0F ) + { + case 0x00: /* string */ + case 0x01: /* atoms */ + /* check that the content is really 0-terminated */ + if ( value < bdf->strings_size && + ft_memchr( bdf->strings + value, 0, bdf->strings_size ) ) + { + aprop->type = BDF_PROPERTY_TYPE_ATOM; + aprop->u.atom = (const char*)bdf->strings + value; + error = 0; + goto Exit; + } + break; + + case 0x02: + aprop->type = BDF_PROPERTY_TYPE_INTEGER; + aprop->u.integer = (FT_Int32)value; + error = 0; + goto Exit; + + case 0x03: + aprop->type = BDF_PROPERTY_TYPE_CARDINAL; + aprop->u.cardinal = value; + error = 0; + goto Exit; + + default: + ; + } + } + } + p += 10; + } + + Exit: + return error; + } + +#endif /* TT_CONFIG_OPTION_BDF */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttbdf.h b/src/freetype2/sfnt/ttbdf.h new file mode 100644 index 0000000..48a10d6 --- /dev/null +++ b/src/freetype2/sfnt/ttbdf.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* ttbdf.h */ +/* */ +/* TrueType and OpenType embedded BDF properties (specification). */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTBDF_H__ +#define __TTBDF_H__ + + +#include <ft2build.h> +#include "ttload.h" +#include FT_BDF_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + tt_face_free_bdf_props( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_find_bdf_prop( TT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ); + + +FT_END_HEADER + +#endif /* __TTBDF_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttcmap.c b/src/freetype2/sfnt/ttcmap.c new file mode 100644 index 0000000..854d567 --- /dev/null +++ b/src/freetype2/sfnt/ttcmap.c @@ -0,0 +1,2356 @@ +/***************************************************************************/ +/* */ +/* ttcmap.c */ +/* */ +/* TrueType character mapping table (cmap) support (body). */ +/* */ +/* Copyright 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H + +#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */ + +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_STREAM_H +#include "ttload.h" +#include "ttcmap.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_ttcmap + + +#define TT_PEEK_SHORT FT_PEEK_SHORT +#define TT_PEEK_USHORT FT_PEEK_USHORT +#define TT_PEEK_LONG FT_PEEK_LONG +#define TT_PEEK_ULONG FT_PEEK_ULONG + +#define TT_NEXT_SHORT FT_NEXT_SHORT +#define TT_NEXT_USHORT FT_NEXT_USHORT +#define TT_NEXT_LONG FT_NEXT_LONG +#define TT_NEXT_ULONG FT_NEXT_ULONG + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_init( TT_CMap cmap, + FT_Byte* table ) + { + cmap->data = table; + return SFNT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 0 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 0 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* glyph_ids 6 BYTE[256] array of glyph indices */ + /* 262 */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; + FT_UInt length = TT_NEXT_USHORT( p ); + + + if ( table + length > valid->limit || length < 262 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices whenever necessary */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt n, idx; + + + p = table + 6; + for ( n = 0; n < 256; n++ ) + { + idx = *p++; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + + + return char_code < 256 ? table[6 + char_code] : 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 charcode = *pchar_code; + FT_UInt32 result = 0; + FT_UInt gindex = 0; + + + table += 6; /* go to glyph ids */ + while ( ++charcode < 256 ) + { + gindex = table[charcode]; + if ( gindex != 0 ) + { + result = charcode; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->format = 0; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap0_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap0_char_index, + (FT_CMap_CharNextFunc) tt_cmap0_char_next + }, + 0, + (TT_CMap_ValidateFunc) tt_cmap0_validate, + (TT_CMap_Info_GetFunc) tt_cmap0_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 2 *****/ + /***** *****/ + /***** This is used for certain CJK encodings that encode text in a *****/ + /***** mixed 8/16 bits encoding along the following lines: *****/ + /***** *****/ + /***** * Certain byte values correspond to an 8-bit character code *****/ + /***** (typically in the range 0..127 for ASCII compatibility). *****/ + /***** *****/ + /***** * Certain byte values signal the first byte of a 2-byte *****/ + /***** character code (but these values are also valid as the *****/ + /***** second byte of a 2-byte character). *****/ + /***** *****/ + /***** The following charmap lookup and iteration functions all *****/ + /***** assume that the value "charcode" correspond to following: *****/ + /***** *****/ + /***** - For one byte characters, "charcode" is simply the *****/ + /***** character code. *****/ + /***** *****/ + /***** - For two byte characters, "charcode" is the 2-byte *****/ + /***** character code in big endian format. More exactly: *****/ + /***** *****/ + /***** (charcode >> 8) is the first byte value *****/ + /***** (charcode & 0xFF) is the second byte value *****/ + /***** *****/ + /***** Note that not all values of "charcode" are valid according *****/ + /***** to these rules, and the function moderately check the *****/ + /***** arguments. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 2 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* keys 6 USHORT[256] sub-header keys */ + /* subs 518 SUBHEAD[NSUBS] sub-headers array */ + /* glyph_ids 518+NSUB*8 USHORT[] glyph id array */ + /* */ + /* The `keys' table is used to map charcode high-bytes to sub-headers. */ + /* The value of `NSUBS' is the number of sub-headers defined in the */ + /* table and is computed by finding the maximum of the `keys' table. */ + /* */ + /* Note that for any n, `keys[n]' is a byte offset within the `subs' */ + /* table, i.e., it is the corresponding sub-header index multiplied */ + /* by 8. */ + /* */ + /* Each sub-header has the following format: */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* first 0 USHORT first valid low-byte */ + /* count 2 USHORT number of valid low-bytes */ + /* delta 4 SHORT see below */ + /* offset 6 USHORT see below */ + /* */ + /* A sub-header defines, for each high-byte, the range of valid */ + /* low-bytes within the charmap. Note that the range defined by `first' */ + /* and `count' must be completely included in the interval [0..255] */ + /* according to the specification. */ + /* */ + /* If a character code is contained within a given sub-header, then */ + /* mapping it to a glyph index is done as follows: */ + /* */ + /* * The value of `offset' is read. This is a _byte_ distance from the */ + /* location of the `offset' field itself into a slice of the */ + /* `glyph_ids' table. Let's call it `slice' (it's a USHORT[] too). */ + /* */ + /* * The value `slice[char.lo - first]' is read. If it is 0, there is */ + /* no glyph for the charcode. Otherwise, the value of `delta' is */ + /* added to it (modulo 65536) to form a new glyph index. */ + /* */ + /* It is up to the validation routine to check that all offsets fall */ + /* within the glyph ids table (and not within the `subs' table itself or */ + /* outside of the CMap). */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; /* skip format */ + FT_UInt length = TT_PEEK_USHORT( p ); + FT_UInt n, max_subs; + FT_Byte* keys; /* keys table */ + FT_Byte* subs; /* sub-headers */ + FT_Byte* glyph_ids; /* glyph id array */ + + + if ( table + length > valid->limit || length < 6 + 512 ) + FT_INVALID_TOO_SHORT; + + keys = table + 6; + + /* parse keys to compute sub-headers count */ + p = keys; + max_subs = 0; + for ( n = 0; n < 256; n++ ) + { + FT_UInt idx = TT_NEXT_USHORT( p ); + + + /* value must be multiple of 8 */ + if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) + FT_INVALID_DATA; + + idx >>= 3; + + if ( idx > max_subs ) + max_subs = idx; + } + + FT_ASSERT( p == table + 518 ); + + subs = p; + glyph_ids = subs + (max_subs + 1) * 8; + if ( glyph_ids > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* parse sub-headers */ + for ( n = 0; n <= max_subs; n++ ) + { + FT_UInt first_code, code_count, offset; + FT_Int delta; + FT_Byte* ids; + + + first_code = TT_NEXT_USHORT( p ); + code_count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT( p ); + offset = TT_NEXT_USHORT( p ); + + /* check range within 0..255 */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + if ( first_code >= 256 || first_code + code_count > 256 ) + FT_INVALID_DATA; + } + + /* check offset */ + if ( offset != 0 ) + { + ids = p - 2 + offset; + if ( ids < glyph_ids || ids + code_count*2 > table + length ) + FT_INVALID_OFFSET; + + /* check glyph ids */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_Byte* limit = p + code_count * 2; + FT_UInt idx; + + + for ( ; p < limit; ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = ( idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + } + + return SFNT_Err_Ok; + } + + + /* return sub header corresponding to a given character code */ + /* NULL on invalid charcode */ + static FT_Byte* + tt_cmap2_get_subheader( FT_Byte* table, + FT_UInt32 char_code ) + { + FT_Byte* result = NULL; + + + if ( char_code < 0x10000UL ) + { + FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); + FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); + FT_Byte* p = table + 6; /* keys table */ + FT_Byte* subs = table + 518; /* subheaders table */ + FT_Byte* sub; + + + if ( char_hi == 0 ) + { + /* an 8-bit character code -- we use subHeader 0 in this case */ + /* to test whether the character code is in the charmap */ + /* */ + sub = subs; /* jump to first sub-header */ + + /* check that the sub-header for this byte is 0, which */ + /* indicates that it's really a valid one-byte value */ + /* Otherwise, return 0 */ + /* */ + p += char_lo * 2; + if ( TT_PEEK_USHORT( p ) != 0 ) + goto Exit; + } + else + { + /* a 16-bit character code */ + + /* jump to key entry */ + p += char_hi * 2; + /* jump to sub-header */ + sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); + + /* check that the high byte isn't a valid one-byte value */ + if ( sub == subs ) + goto Exit; + } + result = sub; + } + Exit: + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* subheader; + + + subheader = tt_cmap2_get_subheader( table, char_code ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt idx = (FT_UInt)(char_code & 0xFF); + FT_UInt start, count; + FT_Int delta; + FT_UInt offset; + + + start = TT_NEXT_USHORT( p ); + count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT ( p ); + offset = TT_PEEK_USHORT( p ); + + idx -= start; + if ( idx < count && offset != 0 ) + { + p += offset + 2 * idx; + idx = TT_PEEK_USHORT( p ); + + if ( idx != 0 ) + result = (FT_UInt)( idx + delta ) & 0xFFFFU; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( TT_CMap cmap, + FT_UInt32 *pcharcode ) + { + FT_Byte* table = cmap->data; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 charcode = *pcharcode + 1; + FT_Byte* subheader; + + + while ( charcode < 0x10000UL ) + { + subheader = tt_cmap2_get_subheader( table, charcode ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_Int delta = TT_NEXT_SHORT ( p ); + FT_UInt offset = TT_PEEK_USHORT( p ); + FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); + FT_UInt pos, idx; + + + if ( offset == 0 ) + goto Next_SubHeader; + + if ( char_lo < start ) + { + char_lo = start; + pos = 0; + } + else + pos = (FT_UInt)( char_lo - start ); + + p += offset + pos * 2; + charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; + + for ( ; pos < count; pos++, charcode++ ) + { + idx = TT_NEXT_USHORT( p ); + + if ( idx != 0 ) + { + gindex = ( idx + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = charcode; + goto Exit; + } + } + } + } + + /* jump to next sub-header, i.e. higher byte value */ + Next_SubHeader: + charcode = FT_PAD_FLOOR( charcode, 256 ) + 256; + } + + Exit: + *pcharcode = result; + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->format = 2; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap2_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap2_char_index, + (FT_CMap_CharNextFunc) tt_cmap2_char_next + }, + 2, + (TT_CMap_ValidateFunc) tt_cmap2_validate, + (TT_CMap_Info_GetFunc) tt_cmap2_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_2 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 4 */ + /* length 2 USHORT table length */ + /* in bytes */ + /* language 4 USHORT Mac language code */ + /* */ + /* segCountX2 6 USHORT 2*NUM_SEGS */ + /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */ + /* entrySelector 10 USHORT LOG_SEGS */ + /* rangeShift 12 USHORT segCountX2 - */ + /* searchRange */ + /* */ + /* endCount 14 USHORT[NUM_SEGS] end charcode for */ + /* each segment; last */ + /* is 0xFFFF */ + /* */ + /* pad 14+NUM_SEGS*2 USHORT padding */ + /* */ + /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */ + /* each segment */ + /* */ + /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */ + /* segment */ + /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */ + /* each segment; can be */ + /* zero */ + /* */ + /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph id */ + /* ranges */ + /* */ + /* Character codes are modelled by a series of ordered (increasing) */ + /* intervals called segments. Each segment has start and end codes, */ + /* provided by the `startCount' and `endCount' arrays. Segments must */ + /* not be overlapping and the last segment should always contain the */ + /* `0xFFFF' endCount. */ + /* */ + /* The fields `searchRange', `entrySelector' and `rangeShift' are better */ + /* ignored (they are traces of over-engineering in the TrueType */ + /* specification). */ + /* */ + /* Each segment also has a signed `delta', as well as an optional offset */ + /* within the `glyphIds' table. */ + /* */ + /* If a segment's idOffset is 0, the glyph index corresponding to any */ + /* charcode within the segment is obtained by adding the value of */ + /* `idDelta' directly to the charcode, modulo 65536. */ + /* */ + /* Otherwise, a glyph index is taken from the glyph ids sub-array for */ + /* the segment, and the value of `idDelta' is added to it. */ + /* */ + /* */ + /* Finally, note that certain fonts contain invalid charmaps that */ + /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the */ + /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */ + /* we need special code to deal with them correctly... */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + + typedef struct TT_CMap4Rec_ + { + TT_CMapRec cmap; + FT_UInt32 cur_charcode; /* current charcode */ + FT_UInt cur_gindex; /* current glyph index */ + + FT_UInt num_ranges; + FT_UInt cur_range; + FT_UInt cur_start; + FT_UInt cur_end; + FT_Int cur_delta; + FT_Byte* cur_values; + + } TT_CMap4Rec, *TT_CMap4; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_init( TT_CMap4 cmap, + FT_Byte* table ) + { + FT_Byte* p; + + + cmap->cmap.data = table; + + p = table + 6; + cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + cmap->cur_charcode = 0xFFFFFFFFUL; + cmap->cur_gindex = 0; + + return SFNT_Err_Ok; + } + + + static FT_Int + tt_cmap4_set_range( TT_CMap4 cmap, + FT_UInt range_index ) + { + FT_Byte* table = cmap->cmap.data; + FT_Byte* p; + FT_UInt num_ranges = cmap->num_ranges; + + + while ( range_index < num_ranges ) + { + FT_UInt offset; + + + p = table + 14 + range_index * 2; + cmap->cur_end = FT_PEEK_USHORT( p ); + + p += 2 + num_ranges * 2; + cmap->cur_start = FT_PEEK_USHORT( p ); + + p += num_ranges * 2; + cmap->cur_delta = FT_PEEK_SHORT( p ); + + p += num_ranges * 2; + offset = FT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + { + cmap->cur_values = offset ? p + offset : NULL; + cmap->cur_range = range_index; + return 0; + } + + /* we skip empty segments */ + range_index++; + } + + return -1; + } + + + /* search the index of the charcode next to cmap->cur_charcode; */ + /* caller should call tt_cmap4_set_range with proper range */ + /* before calling this function */ + /* */ + static void + tt_cmap4_next( TT_CMap4 cmap ) + { + FT_UInt charcode; + + + if ( cmap->cur_charcode >= 0xFFFFUL ) + goto Fail; + + charcode = cmap->cur_charcode + 1; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + + for ( ;; ) + { + FT_Byte* values = cmap->cur_values; + FT_UInt end = cmap->cur_end; + FT_Int delta = cmap->cur_delta; + + + if ( charcode <= end ) + { + if ( values ) + { + FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); + + + do + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex != 0 ) + { + gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU ); + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } + } while ( ++charcode <= end ); + } + else + { + do + { + FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU ); + + + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } while ( ++charcode <= end ); + } + } + + /* we need to find another range */ + if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) + break; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + } + + Fail: + cmap->cur_charcode = 0xFFFFFFFFUL; + cmap->cur_gindex = 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; /* skip format */ + FT_UInt length = TT_NEXT_USHORT( p ); + FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; + FT_UInt num_segs; + FT_Error error = SFNT_Err_Ok; + + + if ( length < 16 ) + FT_INVALID_TOO_SHORT; + + /* in certain fonts, the `length' field is invalid and goes */ + /* out of bound. We try to correct this here... */ + if ( table + length > valid->limit ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_TOO_SHORT; + + length = (FT_UInt)( valid->limit - table ); + } + + p = table + 6; + num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ + + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check that we have an even value here */ + if ( num_segs & 1 ) + FT_INVALID_DATA; + } + + num_segs /= 2; + + if ( length < 16 + num_segs * 2 * 4 ) + FT_INVALID_TOO_SHORT; + + /* check the search parameters - even though we never use them */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */ + FT_UInt search_range = TT_NEXT_USHORT( p ); + FT_UInt entry_selector = TT_NEXT_USHORT( p ); + FT_UInt range_shift = TT_NEXT_USHORT( p ); + + + if ( ( search_range | range_shift ) & 1 ) /* must be even values */ + FT_INVALID_DATA; + + search_range /= 2; + range_shift /= 2; + + /* `search range' is the greatest power of 2 that is <= num_segs */ + + if ( search_range > num_segs || + search_range * 2 < num_segs || + search_range + range_shift != num_segs || + search_range != ( 1U << entry_selector ) ) + FT_INVALID_DATA; + } + + ends = table + 14; + starts = table + 16 + num_segs * 2; + deltas = starts + num_segs * 2; + offsets = deltas + num_segs * 2; + glyph_ids = offsets + num_segs * 2; + + /* check last segment, its end count must be FFFF */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + p = ends + ( num_segs - 1 ) * 2; + if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) + FT_INVALID_DATA; + } + + { + FT_UInt start, end, offset, n; + FT_UInt last_start = 0, last_end = 0; + FT_Int delta; + FT_Byte* p_start = starts; + FT_Byte* p_end = ends; + FT_Byte* p_delta = deltas; + FT_Byte* p_offset = offsets; + + + for ( n = 0; n < num_segs; n++ ) + { + p = p_offset; + start = TT_NEXT_USHORT( p_start ); + end = TT_NEXT_USHORT( p_end ); + delta = TT_NEXT_SHORT( p_delta ); + offset = TT_NEXT_USHORT( p_offset ); + + if ( start > end ) + FT_INVALID_DATA; + + /* this test should be performed at default validation level; */ + /* unfortunately, some popular Asian fonts present overlapping */ + /* ranges in their charmaps */ + /* */ + if ( start <= last_end && n > 0 ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + else + { + /* allow overlapping segments, provided their start points */ + /* and end points, respectively, are in ascending order. */ + /* */ + if ( last_start > start || last_end > end ) + error |= TT_CMAP_FLAG_UNSORTED; + else + error |= TT_CMAP_FLAG_OVERLAPPING; + } + } + + if ( offset && offset != 0xFFFFU ) + { + p += offset; /* start of glyph id array */ + + /* check that we point within the glyph ids table only */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > table + length ) + FT_INVALID_DATA; + } + else + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > valid->limit ) + FT_INVALID_DATA; + } + + /* check glyph indices within the segment range */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt i, idx; + + + for ( i = start; i < end; i++ ) + { + idx = FT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( idx + delta ) & 0xFFFFU; + + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + else if ( offset == 0xFFFFU ) + { + /* Some fonts (erroneously?) use a range offset of 0xFFFF */ + /* to mean missing glyph in cmap table */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID || + n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) ) + FT_INVALID_DATA; + } + + last_start = start; + last_end = end; + } + } + + return error; + } + + + static FT_UInt + tt_cmap4_char_map_linear( TT_CMap cmap, + FT_UInt* pcharcode, + FT_Bool next ) + { + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt i, num_segs; + FT_UInt32 charcode = *pcharcode; + FT_UInt gindex = 0; + FT_Byte* p; + + + p = cmap->data + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + + num_segs = num_segs2 >> 1; + + if ( !num_segs ) + return 0; + + if ( next ) + charcode++; + + /* linear search */ + for ( ; charcode <= 0xFFFFU; charcode++ ) + { + FT_Byte* q; + + + p = cmap->data + 14; /* ends table */ + q = cmap->data + 16 + num_segs2; /* starts table */ + + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); + + if ( charcode >= start && charcode <= end ) + { + p = q - 2 + num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset == 0xFFFFU ) + continue; + + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + gindex = TT_PEEK_USHORT( p ); + if ( gindex != 0 ) + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + } + else + gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; + + break; + } + } + + if ( !next || gindex ) + break; + } + + if ( next && gindex ) + *pcharcode = charcode; + + return gindex; + } + + + static FT_UInt + tt_cmap4_char_map_binary( TT_CMap cmap, + FT_UInt* pcharcode, + FT_Bool next ) + { + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt max, min, mid, num_segs; + FT_UInt charcode = *pcharcode; + FT_UInt gindex = 0; + FT_Byte* p; + + + p = cmap->data + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + + if ( !num_segs2 ) + return 0; + + num_segs = num_segs2 >> 1; + + /* make compiler happy */ + mid = num_segs; + end = 0xFFFFU; + + if ( next ) + charcode++; + + min = 0; + max = num_segs; + + /* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + + if ( charcode < start ) + max = mid; + else if ( charcode > end ) + min = mid + 1; + else + { + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + /* search the first segment containing `charcode' */ + if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING ) + { + FT_UInt i; + + + /* call the current segment `max' */ + max = mid; + + if ( offset == 0xFFFFU ) + mid = max + 1; + + /* search in segments before the current segment */ + for ( i = max ; i > 0; i-- ) + { + FT_UInt prev_end; + FT_Byte* old_p; + + + old_p = p; + p = cmap->data + 14 + ( i - 1 ) * 2; + prev_end = TT_PEEK_USHORT( p ); + + if ( charcode > prev_end ) + { + p = old_p; + break; + } + + end = prev_end; + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i - 1; + } + + /* no luck */ + if ( mid == max + 1 ) + { + if ( i != max ) + { + p = cmap->data + 14 + max * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + + mid = max; + + /* search in segments after the current segment */ + for ( i = max + 1; i < num_segs; i++ ) + { + FT_UInt next_end, next_start; + + + p = cmap->data + 14 + i * 2; + next_end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + next_start = TT_PEEK_USHORT( p ); + + if ( charcode < next_start ) + break; + + end = next_end; + start = next_start; + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i; + } + i--; + + /* still no luck */ + if ( mid == max ) + { + mid = i; + + break; + } + } + + /* end, start, delta, and offset are for the i'th segment */ + if ( mid != i ) + { + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + } + else + { + if ( offset == 0xFFFFU ) + break; + } + + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + gindex = TT_PEEK_USHORT( p ); + if ( gindex != 0 ) + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + } + else + gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; + + break; + } + } + + if ( next ) + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* if `charcode' is not in any segment, then `mid' is */ + /* the segment nearest to `charcode' */ + /* */ + + if ( charcode > end ) + { + mid++; + if ( mid == num_segs ) + return 0; + } + + if ( tt_cmap4_set_range( cmap4, mid ) ) + { + if ( gindex ) + *pcharcode = charcode; + } + else + { + cmap4->cur_charcode = charcode; + + if ( gindex ) + cmap4->cur_gindex = gindex; + else + { + cmap4->cur_charcode = charcode; + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + } + + if ( gindex ) + *pcharcode = cmap4->cur_charcode; + } + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + if ( char_code >= 0x10000UL ) + return 0; + + if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( cmap, &char_code, 0 ); + else + return tt_cmap4_char_map_binary( cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFU ) + return 0; + + if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 ); + else + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* no need to search */ + if ( *pchar_code == cmap4->cur_charcode ) + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + if ( gindex ) + *pchar_code = cmap4->cur_charcode; + } + else + gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 ); + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->format = 4; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap4_class_rec = + { + { + sizeof ( TT_CMap4Rec ), + (FT_CMap_InitFunc) tt_cmap4_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap4_char_index, + (FT_CMap_CharNextFunc) tt_cmap4_char_next + }, + 4, + (TT_CMap_ValidateFunc) tt_cmap4_validate, + (TT_CMap_Info_GetFunc) tt_cmap4_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_4 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 4 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* */ + /* first 6 USHORT first segment code */ + /* count 8 USHORT segment size in chars */ + /* glyphIds 10 USHORT[count] glyph ids */ + /* */ + /* A very simplified segment mapping. */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length, count; + + + if ( table + 10 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_USHORT( p ); + + p = table + 8; /* skip language and start index */ + count = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 10 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx = (FT_UInt)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx; + + + if ( char_code >= 0x10000UL ) + goto Exit; + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + result = char_code; + break; + } + char_code++; + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->format = 6; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap6_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap6_char_index, + (FT_CMap_CharNextFunc) tt_cmap6_char_next + }, + 6, + (TT_CMap_ValidateFunc) tt_cmap6_validate, + (TT_CMap_Info_GetFunc) tt_cmap6_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_6 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 8 *****/ + /***** *****/ + /***** It's hard to completely understand what the OpenType spec *****/ + /***** says about this format, but here is my conclusion. *****/ + /***** *****/ + /***** The purpose of this format is to easily map UTF-16 text to *****/ + /***** glyph indices. Basically, the `char_code' must be in one of *****/ + /***** the following formats: *****/ + /***** *****/ + /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ + /***** Area (i.e. U+D800-U+DFFF). *****/ + /***** *****/ + /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ + /***** `char_code = (char_hi << 16) | char_lo', then both *****/ + /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ + /***** Area. *****/ + /***** *****/ + /***** The 'is32' table embedded in the charmap indicates whether a *****/ + /***** given 16-bit value is in the surrogates area or not. *****/ + /***** *****/ + /***** So, for any given `char_code', we can assert the following: *****/ + /***** *****/ + /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ + /***** *****/ + /***** If `char_hi != 0' then we must have both *****/ + /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 8 */ + /* reserved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* is32 12 BYTE[8192] 32-bitness bitmap */ + /* count 8204 ULONG number of groups */ + /* */ + /* This header is followed by 'count' groups of the following format: */ + /* */ + /* start 0 ULONG first charcode */ + /* end 4 ULONG last charcode */ + /* startId 8 ULONG start glyph id for the group */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_Byte* is32; + FT_UInt32 length; + FT_UInt32 num_groups; + + + if ( table + 16 + 8192 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + if ( table + length > valid->limit || length < 8208 ) + FT_INVALID_TOO_SHORT; + + is32 = table + 12; + p = is32 + 8192; /* skip `is32' array */ + num_groups = TT_NEXT_ULONG( p ); + + if ( p + num_groups * 12 > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_UInt32 n, start, end, start_id, count, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + FT_UInt hi, lo; + + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + + count = (FT_UInt32)( end - start + 1 ); + + if ( start & ~0xFFFFU ) + { + /* start_hi != 0; check that is32[i] is 1 for each i in */ + /* the `hi' and `lo' of the range [start..end] */ + for ( ; count > 0; count--, start++ ) + { + hi = (FT_UInt)( start >> 16 ); + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + } + } + else + { + /* start_hi == 0; check that is32[i] is 0 for each i in */ + /* the range [start..end] */ + + /* end_hi cannot be != 0! */ + if ( end & ~0xFFFFU ) + FT_INVALID_DATA; + + for ( ; count > 0; count--, start++ ) + { + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) + FT_INVALID_DATA; + } + } + } + + last = end; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + break; + + if ( char_code <= end ) + { + result = (FT_UInt)( start_id + char_code - start ); + break; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* table = cmap->data; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + p = table + 8208; + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + if ( char_code <= end ) + { + gindex = (FT_UInt)( char_code - start + start_id ); + if ( gindex != 0 ) + { + result = char_code; + goto Exit; + } + } + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->format = 8; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap8_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap8_char_index, + (FT_CMap_CharNextFunc) tt_cmap8_char_next + }, + 8, + (TT_CMap_ValidateFunc) tt_cmap8_validate, + (TT_CMap_Info_GetFunc) tt_cmap8_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_8 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 10 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 10 */ + /* reserved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* */ + /* start 12 ULONG first char in range */ + /* count 16 ULONG number of chars in range */ + /* glyphIds 20 USHORT[count] glyph indices covered */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_ULong length, count; + + + if ( table + 20 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + p = table + 16; + count = TT_NEXT_ULONG( p ); + + if ( table + length > valid->limit || length < 20 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx = (FT_ULong)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt32)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + break; + char_code++; + } + + *pchar_code = char_code; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->format = 10; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap10_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap10_char_index, + (FT_CMap_CharNextFunc) tt_cmap10_char_next + }, + 10, + (TT_CMap_ValidateFunc) tt_cmap10_validate, + (TT_CMap_Info_GetFunc) tt_cmap10_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_10 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 12 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 12 */ + /* reserved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* count 12 ULONG number of groups */ + /* 16 */ + /* */ + /* This header is followed by `count' groups of the following format: */ + /* */ + /* start 0 ULONG first charcode */ + /* end 4 ULONG last charcode */ + /* startId 8 ULONG start glyph id for the group */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + + typedef struct TT_CMap12Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + + } TT_CMap12Rec, *TT_CMap12; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_init( TT_CMap12 cmap, + FT_Byte* table ) + { + cmap->cmap.data = table; + + table += 12; + cmap->num_groups = FT_PEEK_ULONG( table ); + + cmap->valid = 0; + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( table + length > valid->limit || length < 16 + 12 * num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, start_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return SFNT_Err_Ok; + } + + + /* search the index of the charcode next to cmap->cur_charcode */ + /* cmap->cur_group should be set up properly by caller */ + /* */ + static void + tt_cmap12_next( TT_CMap12 cmap ) + { + FT_Byte* p; + FT_ULong start, end, start_id, char_code; + FT_ULong n; + FT_UInt gindex; + + + if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) + goto Fail; + + char_code = cmap->cur_charcode + 1; + + n = cmap->cur_group; + + for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + { + p = cmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_PEEK_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + for ( ; char_code <= end; char_code++ ) + { + gindex = (FT_UInt)( start_id + char_code - start ); + + if ( gindex ) + { + cmap->cur_charcode = char_code;; + cmap->cur_gindex = gindex; + cmap->cur_group = n; + + return; + } + } + } + + Fail: + cmap->valid = 0; + } + + + static FT_UInt + tt_cmap12_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code; + FT_UInt32 start, end, start_id; + FT_UInt32 max, min, mid; + + + if ( !num_groups ) + return 0; + + /* make compiler happy */ + mid = num_groups; + end = 0xFFFFFFFFUL; + + if ( next ) + char_code++; + + min = 0; + max = num_groups; + + /* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + start_id = TT_PEEK_ULONG( p ); + gindex = (FT_UInt)( start_id + char_code - start ); + + break; + } + } + + if ( next ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; + + + /* if `char_code' is not in any group, then `mid' is */ + /* the group nearest to `char_code' */ + /* */ + + if ( char_code > end ) + { + mid++; + if ( mid == num_groups ) + return 0; + } + + cmap12->valid = 1; + cmap12->cur_charcode = char_code; + cmap12->cur_group = mid; + + if ( !gindex ) + { + tt_cmap12_next( cmap12 ); + + if ( cmap12->valid ) + gindex = cmap12->cur_gindex; + } + else + cmap12->cur_gindex = gindex; + + if ( gindex ) + *pchar_code = cmap12->cur_charcode; + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + return tt_cmap12_char_map_binary( cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; + FT_ULong gindex; + + + if ( cmap12->cur_charcode >= 0xFFFFFFFFUL ) + return 0; + + /* no need to search */ + if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) + { + tt_cmap12_next( cmap12 ); + if ( cmap12->valid ) + { + gindex = cmap12->cur_gindex; + if ( gindex ) + *pchar_code = cmap12->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->format = 12; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap12_class_rec = + { + { + sizeof ( TT_CMap12Rec ), + + (FT_CMap_InitFunc) tt_cmap12_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap12_char_index, + (FT_CMap_CharNextFunc) tt_cmap12_char_next + }, + 12, + (TT_CMap_ValidateFunc) tt_cmap12_validate, + (TT_CMap_Info_GetFunc) tt_cmap12_get_info + }; + + +#endif /* TT_CONFIG_CMAP_FORMAT_12 */ + + + static const TT_CMap_Class tt_cmap_classes[] = + { +#ifdef TT_CONFIG_CMAP_FORMAT_0 + &tt_cmap0_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + &tt_cmap2_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + &tt_cmap4_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + &tt_cmap6_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + &tt_cmap8_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + &tt_cmap10_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + &tt_cmap12_class_rec, +#endif + + NULL, + }; + + + /* parse the `cmap' table and build the corresponding TT_CMap objects */ + /* in the current face */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Byte* table = face->cmap_table; + FT_Byte* limit = table + face->cmap_size; + FT_UInt volatile num_cmaps; + FT_Byte* volatile p = table; + + + if ( p + 4 > limit ) + return SFNT_Err_Invalid_Table; + + /* only recognize format 0 */ + if ( TT_NEXT_USHORT( p ) != 0 ) + { + p -= 2; + FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n", + TT_PEEK_USHORT( p ) )); + return SFNT_Err_Invalid_Table; + } + + num_cmaps = TT_NEXT_USHORT( p ); + + for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) + { + FT_CharMapRec charmap; + FT_UInt32 offset; + + + charmap.platform_id = TT_NEXT_USHORT( p ); + charmap.encoding_id = TT_NEXT_USHORT( p ); + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ + offset = TT_NEXT_ULONG( p ); + + if ( offset && offset <= face->cmap_size - 2 ) + { + FT_Byte* volatile cmap = table + offset; + volatile FT_UInt format = TT_PEEK_USHORT( cmap ); + const TT_CMap_Class* volatile pclazz = tt_cmap_classes; + TT_CMap_Class volatile clazz; + + + for ( ; *pclazz; pclazz++ ) + { + clazz = *pclazz; + if ( clazz->format == format ) + { + volatile TT_ValidatorRec valid; + volatile FT_Error error = SFNT_Err_Ok; + + + ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, + FT_VALIDATE_DEFAULT ); + + valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; + + if ( ft_setjmp( + *((ft_jmp_buf*)&FT_VALIDATOR( &valid )->jump_buffer) ) == 0 ) + { + /* validate this cmap sub-table */ + error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); + } + + if ( valid.validator.error == 0 ) + { + FT_CMap ttcmap; + + + if ( !FT_CMap_New( (FT_CMap_Class)clazz, + cmap, &charmap, &ttcmap ) ) + { + /* it is simpler to directly set `flags' than adding */ + /* a parameter to FT_CMap_New */ + ((TT_CMap)ttcmap)->flags = (FT_Int)error; + } + } + else + { + FT_ERROR(( "tt_face_build_cmaps:" )); + FT_ERROR(( " broken cmap sub-table ignored!\n" )); + } + break; + } + } + } + } + + return SFNT_Err_Ok; + } + + + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = (FT_CMap)charmap; + TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + + + return clazz->get_cmap_info( charmap, cmap_info ); + } + + +/* END */ diff --git a/src/freetype2/sfnt/ttcmap.h b/src/freetype2/sfnt/ttcmap.h new file mode 100644 index 0000000..a10a3e2 --- /dev/null +++ b/src/freetype2/sfnt/ttcmap.h @@ -0,0 +1,85 @@ +/***************************************************************************/ +/* */ +/* ttcmap.h */ +/* */ +/* TrueType character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 2002, 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 __TTCMAP_H__ +#define __TTCMAP_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_INTERNAL_VALIDATE_H +#include FT_SERVICE_TT_CMAP_H + +FT_BEGIN_HEADER + + +#define TT_CMAP_FLAG_UNSORTED 1 +#define TT_CMAP_FLAG_OVERLAPPING 2 + + typedef struct TT_CMapRec_ + { + FT_CMapRec cmap; + FT_Byte* data; /* pointer to in-memory cmap table */ + FT_Int flags; /* for format 4 only */ + + } TT_CMapRec, *TT_CMap; + + typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; + + + typedef FT_Error + (*TT_CMap_ValidateFunc)( FT_Byte* data, + FT_Validator valid ); + + typedef struct TT_CMap_ClassRec_ + { + FT_CMap_ClassRec clazz; + FT_UInt format; + TT_CMap_ValidateFunc validate; + TT_CMap_Info_GetFunc get_cmap_info; + + } TT_CMap_ClassRec; + + + typedef struct TT_ValidatorRec_ + { + FT_ValidatorRec validator; + FT_UInt num_glyphs; + + } TT_ValidatorRec, *TT_Validator; + + +#define TT_VALIDATOR( x ) ((TT_Validator)( x )) +#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs + + + FT_LOCAL( FT_Error ) + tt_face_build_cmaps( TT_Face face ); + + /* used in tt-cmaps service */ + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + +FT_END_HEADER + +#endif /* __TTCMAP_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttkern.c b/src/freetype2/sfnt/ttkern.c new file mode 100644 index 0000000..28e52c3 --- /dev/null +++ b/src/freetype2/sfnt/ttkern.c @@ -0,0 +1,292 @@ +/***************************************************************************/ +/* */ +/* ttkern.c */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttkern.h" +#include "ttload.h" + +#include "sferrors.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_ttkern + + +#undef TT_KERN_INDEX +#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, num_tables; + FT_UInt32 avail = 0, ordered = 0; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 4 ) /* the case of a malformed table */ + { + FT_ERROR(( "kerning table is too small - ignored\n" )); + error = SFNT_Err_Table_Missing; + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) + { + FT_ERROR(( "could not extract kerning table\n" )); + goto Exit; + } + + face->kern_table_size = table_size; + + p = face->kern_table; + p_limit = p + table_size; + + p += 2; /* skip version */ + num_tables = FT_NEXT_USHORT( p ); + + if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ + num_tables = 32; + + for ( nn = 0; nn < num_tables; nn++ ) + { + FT_UInt num_pairs, length, coverage; + FT_Byte* p_next; + FT_UInt32 mask = 1UL << nn; + + + if ( p + 6 > p_limit ) + break; + + p_next = p; + + p += 2; /* skip version */ + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + + if ( length <= 6 ) + break; + + p_next += length; + + /* only use horizontal kerning tables */ + if ( ( coverage & ~8 ) != 0x0001 || + p + 8 > p_limit ) + goto NextTable; + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( p + 6 * num_pairs > p_limit ) + goto NextTable; + + avail |= mask; + + /* + * Now check whether the pairs in this table are ordered. + * We then can use binary search. + */ + if ( num_pairs > 0 ) + { + FT_UInt count; + FT_UInt old_pair; + + + old_pair = FT_NEXT_ULONG( p ); + p += 2; + + for ( count = num_pairs - 1; count > 0; count-- ) + { + FT_UInt32 cur_pair; + + + cur_pair = FT_NEXT_ULONG( p ); + if ( cur_pair <= old_pair ) + break; + + p += 2; + old_pair = cur_pair; + } + + if ( count == 0 ) + ordered |= mask; + } + + NextTable: + p = p_next; + } + + face->num_kern_tables = nn; + face->kern_avail_bits = avail; + face->kern_order_bits = ordered; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->kern_table ); + face->kern_table_size = 0; + face->num_kern_tables = 0; + face->kern_avail_bits = 0; + face->kern_order_bits = 0; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + FT_UInt count, mask = 1; + FT_Byte* p = face->kern_table; + + + p += 4; + mask = 0x0001; + + for ( count = face->num_kern_tables; count > 0; count--, mask <<= 1 ) + { + FT_Byte* base = p; + FT_Byte* next = base; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt length = FT_NEXT_USHORT( p ); + FT_UInt coverage = FT_NEXT_USHORT( p ); + FT_Int value = 0; + + FT_UNUSED( version ); + + + next = base + length; + + if ( ( face->kern_avail_bits & mask ) == 0 ) + goto NextTable; + + if ( p + 8 > next ) + goto NextTable; + + switch ( coverage >> 8 ) + { + case 0: + { + FT_UInt num_pairs = FT_NEXT_USHORT( p ); + FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); + + + p += 6; + + if ( face->kern_order_bits & mask ) /* binary search */ + { + FT_UInt min = 0; + FT_UInt max = num_pairs; + + + while ( min < max ) + { + FT_UInt mid = ( min + max ) >> 1; + FT_Byte* q = p + 6 * mid; + FT_ULong key; + + + key = FT_NEXT_ULONG( q ); + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( q ); + goto Found; + } + if ( key < key0 ) + min = mid + 1; + else + max = mid; + } + } + else /* linear search */ + { + FT_UInt count2; + + + for ( count2 = num_pairs; count2 > 0; count2-- ) + { + FT_ULong key = FT_NEXT_ULONG( p ); + + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( p ); + goto Found; + } + p += 2; + } + } + } + break; + + /* + * We don't support format 2 because we haven't seen a single font + * using it in real life... + */ + + default: + ; + } + + goto NextTable; + + Found: + if ( coverage & 8 ) /* override or add */ + result = value; + else + result += value; + + NextTable: + p = next; + } + + return result; + } + +#undef TT_KERN_INDEX + +/* END */ diff --git a/src/freetype2/sfnt/ttkern.h b/src/freetype2/sfnt/ttkern.h new file mode 100644 index 0000000..df1da9b --- /dev/null +++ b/src/freetype2/sfnt/ttkern.h @@ -0,0 +1,52 @@ +/***************************************************************************/ +/* */ +/* ttkern.h */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTKERN_H__ +#define __TTKERN_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_kern( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + +#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) + + +FT_END_HEADER + +#endif /* __TTKERN_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttload.c b/src/freetype2/sfnt/ttload.c new file mode 100644 index 0000000..abe0278 --- /dev/null +++ b/src/freetype2/sfnt/ttload.c @@ -0,0 +1,1176 @@ +/***************************************************************************/ +/* */ +/* ttload.c */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttload.h" + +#include "sferrors.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_ttload + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_lookup_table */ + /* */ + /* <Description> */ + /* Looks for a TrueType table by name. */ + /* */ + /* <Input> */ + /* face :: A face object handle. */ + /* */ + /* tag :: The searched tag. */ + /* */ + /* <Return> */ + /* A pointer to the table directory entry. 0 if not found. */ + /* */ + FT_LOCAL_DEF( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ) + { + TT_Table entry; + TT_Table limit; + + + FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", + face, + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { + /* For compatibility with Windows, we consider 0-length */ + /* tables the same as missing tables. */ + if ( entry->Tag == tag && entry->Length != 0 ) + { + FT_TRACE4(( "found table.\n" )); + return entry; + } + } + + FT_TRACE4(( "could not find table!\n" )); + return 0; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_goto_table */ + /* */ + /* <Description> */ + /* Looks for a TrueType table by name, then seek a stream to it. */ + /* */ + /* <Input> */ + /* face :: A face object handle. */ + /* */ + /* tag :: The searched tag. */ + /* */ + /* stream :: The stream to seek when the table is found. */ + /* */ + /* <Output> */ + /* length :: The length of the table if found, undefined otherwise. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ) + { + TT_Table table; + FT_Error error; + + + table = tt_face_lookup_table( face, tag ); + if ( table ) + { + if ( length ) + *length = table->Length; + + if ( FT_STREAM_SEEK( table->Offset ) ) + goto Exit; + } + else + error = SFNT_Err_Table_Missing; + + Exit: + return error; + } + + + /* Here, we */ + /* */ + /* - check that `num_tables' is valid */ + /* - look for a `head' table, check its size, and parse it to check */ + /* whether its `magic' field is correctly set */ + /* */ + /* When checking directory entries, ignore the tables `glyx' and `locx' */ + /* which are hacked-out versions of `glyf' and `loca' in some PostScript */ + /* Type 42 fonts, and which are generally invalid. */ + /* */ + static FT_Error + check_table_dir( SFNT_Header sfnt, + FT_Stream stream ) + { + FT_Error error; + FT_UInt nn; + FT_UInt has_head = 0, has_sing = 0, has_meta = 0; + FT_ULong offset = sfnt->offset + 12; + + const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); + const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); + + static const FT_Frame_Field table_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG( Tag ), + FT_FRAME_ULONG( CheckSum ), + FT_FRAME_ULONG( Offset ), + FT_FRAME_ULONG( Length ), + FT_FRAME_END + }; + + + if ( sfnt->num_tables == 0 || + offset + sfnt->num_tables * 16 > stream->size ) + return SFNT_Err_Unknown_File_Format; + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + for ( nn = 0; nn < sfnt->num_tables; nn++ ) + { + TT_TableRec table; + + + if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) + return error; + + if ( table.Offset + table.Length > stream->size && + table.Tag != glyx_tag && + table.Tag != locx_tag ) + return SFNT_Err_Unknown_File_Format; + + if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) + { + FT_UInt32 magic; + + +#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + if ( table.Tag == TTAG_head ) +#endif + has_head = 1; + + /* + * The table length should be 0x36, but certain font tools make it + * 0x38, so we will just check that it is greater. + * + * Note that according to the specification, the table must be + * padded to 32-bit lengths, but this doesn't apply to the value of + * its `Length' field! + * + */ + if ( table.Length < 0x36 ) + return SFNT_Err_Unknown_File_Format; + + if ( FT_STREAM_SEEK( table.Offset + 12 ) || + FT_READ_ULONG( magic ) ) + return error; + + if ( magic != 0x5F0F3CF5UL ) + return SFNT_Err_Unknown_File_Format; + + if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) + return error; + } + else if ( table.Tag == TTAG_SING ) + has_sing = 1; + else if ( table.Tag == TTAG_META ) + has_meta = 1; + } + + /* if `sing' and `meta' tables are present, there is no `head' table */ + if ( has_head || ( has_sing && has_meta ) ) + return SFNT_Err_Ok; + else + return SFNT_Err_Unknown_File_Format; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_font_dir */ + /* */ + /* <Description> */ + /* Loads the header of a SFNT font file. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Output> */ + /* sfnt :: The SFNT header. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the beginning of the font directory. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ) + { + SFNT_HeaderRec sfnt; + FT_Error error; + FT_Memory memory = stream->memory; + TT_TableRec* entry; + TT_TableRec* limit; + + static const FT_Frame_Field offset_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE SFNT_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( search_range ), + FT_FRAME_USHORT( entry_selector ), + FT_FRAME_USHORT( range_shift ), + FT_FRAME_END + }; + + + FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); + + /* read the offset table */ + + sfnt.offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( sfnt.format_tag ) || + FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) + return error; + + /* many fonts don't have these fields set correctly */ +#if 0 + if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || + sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) + return SFNT_Err_Unknown_File_Format; +#endif + + /* load the table directory */ + + FT_TRACE2(( "-- Tables count: %12u\n", sfnt.num_tables )); + FT_TRACE2(( "-- Format version: %08lx\n", sfnt.format_tag )); + + /* check first */ + error = check_table_dir( &sfnt, stream ); + if ( error ) + { + FT_TRACE2(( "tt_face_load_font_dir: invalid table directory!\n" )); + + return error; + } + + face->num_tables = sfnt.num_tables; + face->format_tag = sfnt.format_tag; + + if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) + return error; + + if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || + FT_FRAME_ENTER( face->num_tables * 16L ) ) + return error; + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { + entry->Tag = FT_GET_TAG4(); + entry->CheckSum = FT_GET_ULONG(); + entry->Offset = FT_GET_LONG(); + entry->Length = FT_GET_LONG(); + + FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", + (FT_Char)( entry->Tag >> 24 ), + (FT_Char)( entry->Tag >> 16 ), + (FT_Char)( entry->Tag >> 8 ), + (FT_Char)( entry->Tag ), + entry->Offset, + entry->Length )); + } + + FT_FRAME_EXIT(); + + FT_TRACE2(( "table directory loaded\n\n" )); + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_any */ + /* */ + /* <Description> */ + /* Loads any font table into client memory. */ + /* */ + /* <Input> */ + /* face :: The face object to look for. */ + /* */ + /* tag :: The tag of table to load. Use the value 0 if you want */ + /* to access the whole font file, else set this parameter */ + /* to a valid TrueType table tag that you can forge with */ + /* the MAKE_TT_TAG macro. */ + /* */ + /* offset :: The starting offset in the table (or the file if */ + /* tag == 0). */ + /* */ + /* length :: The address of the decision variable: */ + /* */ + /* If length == NULL: */ + /* Loads the whole table. Returns an error if */ + /* `offset' == 0! */ + /* */ + /* If *length == 0: */ + /* Exits immediately; returning the length of the given */ + /* table or of the font file, depending on the value of */ + /* `tag'. */ + /* */ + /* If *length != 0: */ + /* Loads the next `length' bytes of table or font, */ + /* starting at offset `offset' (in table or font too). */ + /* */ + /* <Output> */ + /* buffer :: The address of target buffer. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Error error; + FT_Stream stream; + TT_Table table; + FT_ULong size; + + + if ( tag != 0 ) + { + /* look for tag in font directory */ + table = tt_face_lookup_table( face, tag ); + if ( !table ) + { + error = SFNT_Err_Table_Missing; + goto Exit; + } + + offset += table->Offset; + size = table->Length; + } + else + /* tag == 0 -- the user wants to access the font file directly */ + size = face->root.stream->size; + + if ( length && *length == 0 ) + { + *length = size; + + return SFNT_Err_Ok; + } + + if ( length ) + size = *length; + + stream = face->root.stream; + /* the `if' is syntactic sugar for picky compilers */ + if ( FT_STREAM_READ_AT( offset, buffer, size ) ) + goto Exit; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_generic_header */ + /* */ + /* <Description> */ + /* Loads the TrueType table `head' or `bhed'. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + tt_face_load_generic_header( TT_Face face, + FT_Stream stream, + FT_ULong tag ) + { + FT_Error error; + TT_Header* header; + + static const FT_Frame_Field header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Header + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Table_Version ), + FT_FRAME_ULONG ( Font_Revision ), + FT_FRAME_LONG ( CheckSum_Adjust ), + FT_FRAME_LONG ( Magic_Number ), + FT_FRAME_USHORT( Flags ), + FT_FRAME_USHORT( Units_Per_EM ), + FT_FRAME_LONG ( Created[0] ), + FT_FRAME_LONG ( Created[1] ), + FT_FRAME_LONG ( Modified[0] ), + FT_FRAME_LONG ( Modified[1] ), + FT_FRAME_SHORT ( xMin ), + FT_FRAME_SHORT ( yMin ), + FT_FRAME_SHORT ( xMax ), + FT_FRAME_SHORT ( yMax ), + FT_FRAME_USHORT( Mac_Style ), + FT_FRAME_USHORT( Lowest_Rec_PPEM ), + FT_FRAME_SHORT ( Font_Direction ), + FT_FRAME_SHORT ( Index_To_Loc_Format ), + FT_FRAME_SHORT ( Glyph_Data_Format ), + FT_FRAME_END + }; + + + error = face->goto_table( face, tag, stream, 0 ); + if ( error ) + goto Exit; + + header = &face->header; + + if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) + goto Exit; + + FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_head ); + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_bhed ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_max_profile */ + /* */ + /* <Description> */ + /* Loads the maximum profile into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_MaxProfile* maxProfile = &face->max_profile; + + const FT_Frame_Field maxp_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_MaxProfile + + FT_FRAME_START( 6 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( numGlyphs ), + FT_FRAME_END + }; + + const FT_Frame_Field maxp_fields_extra[] = + { + FT_FRAME_START( 26 ), + FT_FRAME_USHORT( maxPoints ), + FT_FRAME_USHORT( maxContours ), + FT_FRAME_USHORT( maxCompositePoints ), + FT_FRAME_USHORT( maxCompositeContours ), + FT_FRAME_USHORT( maxZones ), + FT_FRAME_USHORT( maxTwilightPoints ), + FT_FRAME_USHORT( maxStorage ), + FT_FRAME_USHORT( maxFunctionDefs ), + FT_FRAME_USHORT( maxInstructionDefs ), + FT_FRAME_USHORT( maxStackElements ), + FT_FRAME_USHORT( maxSizeOfInstructions ), + FT_FRAME_USHORT( maxComponentElements ), + FT_FRAME_USHORT( maxComponentDepth ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) + goto Exit; + + maxProfile->maxPoints = 0; + maxProfile->maxContours = 0; + maxProfile->maxCompositePoints = 0; + maxProfile->maxCompositeContours = 0; + maxProfile->maxZones = 0; + maxProfile->maxTwilightPoints = 0; + maxProfile->maxStorage = 0; + maxProfile->maxFunctionDefs = 0; + maxProfile->maxInstructionDefs = 0; + maxProfile->maxStackElements = 0; + maxProfile->maxSizeOfInstructions = 0; + maxProfile->maxComponentElements = 0; + maxProfile->maxComponentDepth = 0; + + if ( maxProfile->version >= 0x10000L ) + { + if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) + goto Exit; + + /* XXX: an adjustment that is necessary to load certain */ + /* broken fonts like `Keystrokes MT' :-( */ + /* */ + /* We allocate 64 function entries by default when */ + /* the maxFunctionDefs field is null. */ + + if ( maxProfile->maxFunctionDefs == 0 ) + maxProfile->maxFunctionDefs = 64; + } + + FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_names */ + /* */ + /* <Description> */ + /* Loads the name records. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_pos, table_len; + FT_ULong storage_start, storage_limit; + FT_UInt count; + TT_NameTable table; + + static const FT_Frame_Field name_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameTableRec + + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( format ), + FT_FRAME_USHORT( numNameRecords ), + FT_FRAME_USHORT( storageOffset ), + FT_FRAME_END + }; + + static const FT_Frame_Field name_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameEntryRec + + /* no FT_FRAME_START */ + FT_FRAME_USHORT( platformID ), + FT_FRAME_USHORT( encodingID ), + FT_FRAME_USHORT( languageID ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + + + table = &face->name_table; + table->stream = stream; + + error = face->goto_table( face, TTAG_name, stream, &table_len ); + if ( error ) + goto Exit; + + table_pos = FT_STREAM_POS(); + + + if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) + goto Exit; + + /* Some popular Asian fonts have an invalid `storageOffset' value */ + /* (it should be at least "6 + 12*num_names"). However, the string */ + /* offsets, computed as "storageOffset + entry->stringOffset", are */ + /* valid pointers within the name table... */ + /* */ + /* We thus can't check `storageOffset' right now. */ + /* */ + storage_start = table_pos + 6 + 12*table->numNameRecords; + storage_limit = table_pos + table_len; + + if ( storage_start > storage_limit ) + { + FT_ERROR(( "invalid `name' table\n" )); + error = SFNT_Err_Name_Table_Missing; + goto Exit; + } + + /* Allocate the array of name records. */ + count = table->numNameRecords; + table->numNameRecords = 0; + + if ( FT_NEW_ARRAY( table->names, count ) || + FT_FRAME_ENTER( count * 12 ) ) + goto Exit; + + /* Load the name records and determine how much storage is needed */ + /* to hold the strings themselves. */ + { + TT_NameEntryRec* entry = table->names; + + + for ( ; count > 0; count-- ) + { + if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) + continue; + + /* check that the name is not empty */ + if ( entry->stringLength == 0 ) + continue; + + /* check that the name string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { + /* invalid entry - ignore it */ + entry->stringOffset = 0; + entry->stringLength = 0; + continue; + } + + entry++; + } + + table->numNameRecords = (FT_UInt)( entry - table->names ); + } + + FT_FRAME_EXIT(); + + /* everything went well, update face->num_names */ + face->num_names = (FT_UShort) table->numNameRecords; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_free_names */ + /* */ + /* <Description> */ + /* Frees the name records. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + FT_LOCAL_DEF( void ) + tt_face_free_name( TT_Face face ) + { + FT_Memory memory = face->root.driver->root.memory; + TT_NameTable table = &face->name_table; + TT_NameEntry entry = table->names; + FT_UInt count = table->numNameRecords; + + + if ( table->names ) + { + for ( ; count > 0; count--, entry++ ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + + /* free strings table */ + FT_FREE( table->names ); + } + + table->numNameRecords = 0; + table->format = 0; + table->storageOffset = 0; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_cmap */ + /* */ + /* <Description> */ + /* Loads the cmap directory in a face object. The cmaps themselves */ + /* are loaded on demand in the `ttcmap.c' module. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + + + error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); + if ( error ) + goto Exit; + + if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) + face->cmap_size = 0; + + Exit: + return error; + } + + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_os2 */ + /* */ + /* <Description> */ + /* Loads the OS2 table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_OS2* os2; + + const FT_Frame_Field os2_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_OS2 + + FT_FRAME_START( 78 ), + FT_FRAME_USHORT( version ), + FT_FRAME_SHORT ( xAvgCharWidth ), + FT_FRAME_USHORT( usWeightClass ), + FT_FRAME_USHORT( usWidthClass ), + FT_FRAME_SHORT ( fsType ), + FT_FRAME_SHORT ( ySubscriptXSize ), + FT_FRAME_SHORT ( ySubscriptYSize ), + FT_FRAME_SHORT ( ySubscriptXOffset ), + FT_FRAME_SHORT ( ySubscriptYOffset ), + FT_FRAME_SHORT ( ySuperscriptXSize ), + FT_FRAME_SHORT ( ySuperscriptYSize ), + FT_FRAME_SHORT ( ySuperscriptXOffset ), + FT_FRAME_SHORT ( ySuperscriptYOffset ), + FT_FRAME_SHORT ( yStrikeoutSize ), + FT_FRAME_SHORT ( yStrikeoutPosition ), + FT_FRAME_SHORT ( sFamilyClass ), + FT_FRAME_BYTE ( panose[0] ), + FT_FRAME_BYTE ( panose[1] ), + FT_FRAME_BYTE ( panose[2] ), + FT_FRAME_BYTE ( panose[3] ), + FT_FRAME_BYTE ( panose[4] ), + FT_FRAME_BYTE ( panose[5] ), + FT_FRAME_BYTE ( panose[6] ), + FT_FRAME_BYTE ( panose[7] ), + FT_FRAME_BYTE ( panose[8] ), + FT_FRAME_BYTE ( panose[9] ), + FT_FRAME_ULONG ( ulUnicodeRange1 ), + FT_FRAME_ULONG ( ulUnicodeRange2 ), + FT_FRAME_ULONG ( ulUnicodeRange3 ), + FT_FRAME_ULONG ( ulUnicodeRange4 ), + FT_FRAME_BYTE ( achVendID[0] ), + FT_FRAME_BYTE ( achVendID[1] ), + FT_FRAME_BYTE ( achVendID[2] ), + FT_FRAME_BYTE ( achVendID[3] ), + + FT_FRAME_USHORT( fsSelection ), + FT_FRAME_USHORT( usFirstCharIndex ), + FT_FRAME_USHORT( usLastCharIndex ), + FT_FRAME_SHORT ( sTypoAscender ), + FT_FRAME_SHORT ( sTypoDescender ), + FT_FRAME_SHORT ( sTypoLineGap ), + FT_FRAME_USHORT( usWinAscent ), + FT_FRAME_USHORT( usWinDescent ), + FT_FRAME_END + }; + + const FT_Frame_Field os2_fields_extra[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_ULONG( ulCodePageRange1 ), + FT_FRAME_ULONG( ulCodePageRange2 ), + FT_FRAME_END + }; + + const FT_Frame_Field os2_fields_extra2[] = + { + FT_FRAME_START( 10 ), + FT_FRAME_SHORT ( sxHeight ), + FT_FRAME_SHORT ( sCapHeight ), + FT_FRAME_USHORT( usDefaultChar ), + FT_FRAME_USHORT( usBreakChar ), + FT_FRAME_USHORT( usMaxContext ), + FT_FRAME_END + }; + + + /* We now support old Mac fonts where the OS/2 table doesn't */ + /* exist. Simply put, we set the `version' field to 0xFFFF */ + /* and test this value each time we need to access the table. */ + error = face->goto_table( face, TTAG_OS2, stream, 0 ); + if ( error ) + goto Exit; + + os2 = &face->os2; + + if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) + goto Exit; + + os2->ulCodePageRange1 = 0; + os2->ulCodePageRange2 = 0; + os2->sxHeight = 0; + os2->sCapHeight = 0; + os2->usDefaultChar = 0; + os2->usBreakChar = 0; + os2->usMaxContext = 0; + + if ( os2->version >= 0x0001 ) + { + /* only version 1 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0002 ) + { + /* only version 2 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) + goto Exit; + } + } + + FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_postscript */ + /* */ + /* <Description> */ + /* Loads the Postscript table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Postscript* post = &face->postscript; + + static const FT_Frame_Field post_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Postscript + + FT_FRAME_START( 32 ), + FT_FRAME_ULONG( FormatType ), + FT_FRAME_ULONG( italicAngle ), + FT_FRAME_SHORT( underlinePosition ), + FT_FRAME_SHORT( underlineThickness ), + FT_FRAME_ULONG( isFixedPitch ), + FT_FRAME_ULONG( minMemType42 ), + FT_FRAME_ULONG( maxMemType42 ), + FT_FRAME_ULONG( minMemType1 ), + FT_FRAME_ULONG( maxMemType1 ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + return error; + + if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) + return error; + + /* we don't load the glyph names, we do that in another */ + /* module (ttpost). */ + + FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); + FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch + ? " yes" : " no" )); + + return SFNT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_pclt */ + /* */ + /* <Description> */ + /* Loads the PCL 5 Table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ) + { + static const FT_Frame_Field pclt_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_PCLT + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_ULONG ( FontNumber ), + FT_FRAME_USHORT( Pitch ), + FT_FRAME_USHORT( xHeight ), + FT_FRAME_USHORT( Style ), + FT_FRAME_USHORT( TypeFamily ), + FT_FRAME_USHORT( CapHeight ), + FT_FRAME_BYTES ( TypeFace, 16 ), + FT_FRAME_BYTES ( CharacterComplement, 8 ), + FT_FRAME_BYTES ( FileName, 6 ), + FT_FRAME_CHAR ( StrokeWeight ), + FT_FRAME_CHAR ( WidthType ), + FT_FRAME_BYTE ( SerifStyle ), + FT_FRAME_BYTE ( Reserved ), + FT_FRAME_END + }; + + FT_Error error; + TT_PCLT* pclt = &face->pclt; + + + /* optional table */ + error = face->goto_table( face, TTAG_PCLT, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) + goto Exit; + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_gasp */ + /* */ + /* <Description> */ + /* Loads the `gasp' table into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UInt j,num_ranges; + TT_GaspRange gaspranges; + + + /* the gasp table is optional */ + error = face->goto_table( face, TTAG_gasp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_FRAME_ENTER( 4L ) ) + goto Exit; + + face->gasp.version = FT_GET_USHORT(); + face->gasp.numRanges = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + /* only support versions 0 and 1 of the table */ + if ( face->gasp.version >= 2 ) + { + face->gasp.numRanges = 0; + error = SFNT_Err_Invalid_Table; + goto Exit; + } + + num_ranges = face->gasp.numRanges; + FT_TRACE3(( "numRanges: %u\n", num_ranges )); + + if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) + goto Exit; + + face->gasp.gaspRanges = gaspranges; + + for ( j = 0; j < num_ranges; j++ ) + { + gaspranges[j].maxPPEM = FT_GET_USHORT(); + gaspranges[j].gaspFlag = FT_GET_USHORT(); + + FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", + j, + gaspranges[j].maxPPEM, + gaspranges[j].gaspFlag )); + } + + FT_FRAME_EXIT(); + + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype2/sfnt/ttload.h b/src/freetype2/sfnt/ttload.h new file mode 100644 index 0000000..49a1aee --- /dev/null +++ b/src/freetype2/sfnt/ttload.h @@ -0,0 +1,112 @@ +/***************************************************************************/ +/* */ +/* ttload.h */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTLOAD_H__ +#define __TTLOAD_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ); + + FT_LOCAL( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_name( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ); + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + +FT_END_HEADER + +#endif /* __TTLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttmtx.c b/src/freetype2/sfnt/ttmtx.c new file mode 100644 index 0000000..286bd0c --- /dev/null +++ b/src/freetype2/sfnt/ttmtx.c @@ -0,0 +1,465 @@ +/***************************************************************************/ +/* */ +/* ttmtx.c */ +/* */ +/* Load the metrics tables common to TTF and OTF fonts (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 <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttmtx.h" + +#include "sferrors.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_ttmtx + + + /* + * Unfortunately, we can't enable our memory optimizations if + * FT_CONFIG_OPTION_OLD_INTERNALS is defined. This is because at least + * one rogue client (libXfont in the X.Org XServer) is directly accessing + * the metrics. + */ + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_hmtx */ + /* */ + /* <Description> */ + /* Load the `hmtx' or `vmtx' table into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load `vmtx'. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ +#if !defined FT_CONFIG_OPTION_OLD_INTERNALS + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_ULong tag, table_size; + FT_ULong* ptable_offset; + FT_ULong* ptable_size; + + + if ( vertical ) + { + tag = TTAG_vmtx; + ptable_offset = &face->vert_metrics_offset; + ptable_size = &face->vert_metrics_size; + } + else + { + tag = TTAG_hmtx; + ptable_offset = &face->horz_metrics_offset; + ptable_size = &face->horz_metrics_size; + } + + error = face->goto_table( face, tag, stream, &table_size ); + if ( error ) + goto Fail; + + *ptable_size = table_size; + *ptable_offset = FT_STREAM_POS(); + + Fail: + return error; + } + +#else /* !OPTIMIZE_MEMORY || OLD_INTERNALS */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_ULong table_len; + FT_Long num_shorts, num_longs, num_shorts_checked; + + TT_LongMetrics* longs; + TT_ShortMetrics** shorts; + FT_Byte* p; + + + if ( vertical ) + { + void* lm = &face->vertical.long_metrics; + void** sm = &face->vertical.short_metrics; + + + error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); + if ( error ) + goto Fail; + + num_longs = face->vertical.number_Of_VMetrics; + if ( (FT_ULong)num_longs > table_len / 4 ) + num_longs = (FT_Long)( table_len / 4 ); + + face->vertical.number_Of_VMetrics = 0; + + longs = (TT_LongMetrics*)lm; + shorts = (TT_ShortMetrics**)sm; + } + else + { + void* lm = &face->horizontal.long_metrics; + void** sm = &face->horizontal.short_metrics; + + + error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); + if ( error ) + goto Fail; + + num_longs = face->horizontal.number_Of_HMetrics; + if ( (FT_ULong)num_longs > table_len / 4 ) + num_longs = (FT_Long)( table_len / 4 ); + + face->horizontal.number_Of_HMetrics = 0; + + longs = (TT_LongMetrics*)lm; + shorts = (TT_ShortMetrics**)sm; + } + + /* never trust derived values */ + + num_shorts = face->max_profile.numGlyphs - num_longs; + num_shorts_checked = ( table_len - num_longs * 4L ) / 2; + + if ( num_shorts < 0 ) + { + FT_ERROR(( "%cmtx has more metrics than glyphs.\n" )); + + /* Adobe simply ignores this problem. So we shall do the same. */ +#if 0 + error = vertical ? SFNT_Err_Invalid_Vert_Metrics + : SFNT_Err_Invalid_Horiz_Metrics; + goto Exit; +#else + num_shorts = 0; +#endif + } + + if ( FT_QNEW_ARRAY( *longs, num_longs ) || + FT_QNEW_ARRAY( *shorts, num_shorts ) ) + goto Fail; + + if ( FT_FRAME_ENTER( table_len ) ) + goto Fail; + + p = stream->cursor; + + { + TT_LongMetrics cur = *longs; + TT_LongMetrics limit = cur + num_longs; + + + for ( ; cur < limit; cur++ ) + { + cur->advance = FT_NEXT_USHORT( p ); + cur->bearing = FT_NEXT_SHORT( p ); + } + } + + /* do we have an inconsistent number of metric values? */ + { + TT_ShortMetrics* cur = *shorts; + TT_ShortMetrics* limit = cur + + FT_MIN( num_shorts, num_shorts_checked ); + + + for ( ; cur < limit; cur++ ) + *cur = FT_NEXT_SHORT( p ); + + /* We fill up the missing left side bearings with the */ + /* last valid value. Since this will occur for buggy CJK */ + /* fonts usually only, nothing serious will happen. */ + if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) + { + FT_Short val = (*shorts)[num_shorts_checked - 1]; + + + limit = *shorts + num_shorts; + for ( ; cur < limit; cur++ ) + *cur = val; + } + } + + FT_FRAME_EXIT(); + + if ( vertical ) + face->vertical.number_Of_VMetrics = (FT_UShort)num_longs; + else + face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs; + + Fail: + return error; + } + +#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_hhea */ + /* */ + /* <Description> */ + /* Load the `hhea' or 'vhea' table into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load `vhea'. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + TT_HoriHeader* header; + + const FT_Frame_Field metrics_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_HoriHeader + + FT_FRAME_START( 36 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_SHORT ( Ascender ), + FT_FRAME_SHORT ( Descender ), + FT_FRAME_SHORT ( Line_Gap ), + FT_FRAME_USHORT( advance_Width_Max ), + FT_FRAME_SHORT ( min_Left_Side_Bearing ), + FT_FRAME_SHORT ( min_Right_Side_Bearing ), + FT_FRAME_SHORT ( xMax_Extent ), + FT_FRAME_SHORT ( caret_Slope_Rise ), + FT_FRAME_SHORT ( caret_Slope_Run ), + FT_FRAME_SHORT ( caret_Offset ), + FT_FRAME_SHORT ( Reserved[0] ), + FT_FRAME_SHORT ( Reserved[1] ), + FT_FRAME_SHORT ( Reserved[2] ), + FT_FRAME_SHORT ( Reserved[3] ), + FT_FRAME_SHORT ( metric_Data_Format ), + FT_FRAME_USHORT( number_Of_HMetrics ), + FT_FRAME_END + }; + + + if ( vertical ) + { + void *v = &face->vertical; + + + error = face->goto_table( face, TTAG_vhea, stream, 0 ); + if ( error ) + goto Fail; + + header = (TT_HoriHeader*)v; + } + else + { + error = face->goto_table( face, TTAG_hhea, stream, 0 ); + if ( error ) + goto Fail; + + header = &face->horizontal; + } + + if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) + goto Fail; + + FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); + FT_TRACE3(( "Descender: %5d\n", header->Descender )); + FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); + + header->long_metrics = NULL; + header->short_metrics = NULL; + + Fail: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_get_metrics */ + /* */ + /* <Description> */ + /* Returns the horizontal or vertical metrics in font units for a */ + /* given glyph. The metrics are the left side bearing (resp. top */ + /* side bearing) and advance width (resp. advance height). */ + /* */ + /* <Input> */ + /* header :: A pointer to either the horizontal or vertical metrics */ + /* structure. */ + /* */ + /* idx :: The glyph index. */ + /* */ + /* <Output> */ + /* bearing :: The bearing, either left side or top side. */ + /* */ + /* advance :: The advance width resp. advance height. */ + /* */ +#if !defined FT_CONFIG_OPTION_OLD_INTERNALS + + FT_LOCAL_DEF( FT_Error ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short *abearing, + FT_UShort *aadvance ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + TT_HoriHeader* header; + FT_ULong table_pos, table_size, table_end; + FT_UShort k; + + + if ( vertical ) + { + void* v = &face->vertical; + + + header = (TT_HoriHeader*)v; + table_pos = face->vert_metrics_offset; + table_size = face->vert_metrics_size; + } + else + { + header = &face->horizontal; + table_pos = face->horz_metrics_offset; + table_size = face->horz_metrics_size; + } + + table_end = table_pos + table_size; + + k = header->number_Of_HMetrics; + + if ( k > 0 ) + { + if ( gindex < (FT_UInt)k ) + { + table_pos += 4 * gindex; + if ( table_pos + 4 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) || + FT_READ_SHORT( *abearing ) ) + goto NoData; + } + else + { + table_pos += 4 * ( k - 1 ); + if ( table_pos + 4 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) ) + goto NoData; + + table_pos += 4 + 2 * ( gindex - k ); + if ( table_pos + 2 > table_end ) + *abearing = 0; + else + { + if ( !FT_STREAM_SEEK( table_pos ) ) + (void)FT_READ_SHORT( *abearing ); + } + } + } + else + { + NoData: + *abearing = 0; + *aadvance = 0; + } + + return SFNT_Err_Ok; + } + +#else /* OLD_INTERNALS */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ) + { + void* v = &face->vertical; + void* h = &face->horizontal; + TT_HoriHeader* header = vertical ? (TT_HoriHeader*)v : h; + TT_LongMetrics longs_m; + FT_UShort k = header->number_Of_HMetrics; + + + if ( k == 0 || + !header->long_metrics || + gindex >= (FT_UInt)face->max_profile.numGlyphs ) + { + *abearing = *aadvance = 0; + return SFNT_Err_Ok; + } + + if ( gindex < (FT_UInt)k ) + { + longs_m = (TT_LongMetrics)header->long_metrics + gindex; + *abearing = longs_m->bearing; + *aadvance = longs_m->advance; + } + else + { + *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k]; + *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance; + } + + return SFNT_Err_Ok; + } + +#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttmtx.h b/src/freetype2/sfnt/ttmtx.h new file mode 100644 index 0000000..8b91a11 --- /dev/null +++ b/src/freetype2/sfnt/ttmtx.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* ttmtx.h */ +/* */ +/* Load the metrics tables common to TTF and OTF fonts (specification). */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTMTX_H__ +#define __TTMTX_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( FT_Error ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + +FT_END_HEADER + +#endif /* __TTMTX_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttpost.c b/src/freetype2/sfnt/ttpost.c new file mode 100644 index 0000000..1e61636 --- /dev/null +++ b/src/freetype2/sfnt/ttpost.c @@ -0,0 +1,521 @@ +/***************************************************************************/ +/* */ +/* ttpost.c */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* The post table is not completely loaded by the core engine. This */ + /* file loads the missing PS glyph names and implements an API to access */ + /* them. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttpost.h" +#include "ttload.h" + +#include "sferrors.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_ttpost + + + /* If this configuration macro is defined, we rely on the `PSNames' */ + /* module to grab the glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + +#define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) ) + + +#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* Otherwise, we ignore the `PSNames' module, and provide our own */ + /* table of Mac names. Thus, it is possible to build a version of */ + /* FreeType without the Type 1 driver & PSNames module. */ + +#define MAC_NAME( x ) tt_post_default_names[x] + + /* the 258 default Mac PS glyph names */ + + static const FT_String* tt_post_default_names[258] = + { + /* 0 */ + ".notdef", ".null", "CR", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + /* 10 */ + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + /* 20 */ + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + /* 30 */ + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + /* 40 */ + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + /* 50 */ + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + /* 60 */ + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + /* 70 */ + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + /* 80 */ + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + /* 90 */ + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + /* 100 */ + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + /* 110 */ + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + /* 120 */ + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + /* 130 */ + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + /* 140 */ + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + /* 150 */ + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + /* 160 */ + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + /* 170 */ + "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + /* 180 */ + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + /* 190 */ + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + /* 200 */ + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + /* 210 */ + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + /* 220 */ + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + /* 230 */ + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + /* 240 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + /* 250 */ + "Idot", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dmacron", + }; + + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static FT_Error + load_format_20( TT_Face face, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_Int num_glyphs; + FT_UShort num_names; + + FT_UShort* glyph_indices = 0; + FT_Char** name_strings = 0; + + + if ( FT_READ_USHORT( num_glyphs ) ) + goto Exit; + + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + + /* There already exist fonts which have more than 32768 glyph names */ + /* in this table, so the test for this threshold has been dropped. */ + + if ( num_glyphs > face->max_profile.numGlyphs ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + /* load the indices */ + { + FT_Int n; + + + if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2L ) ) + goto Fail; + + for ( n = 0; n < num_glyphs; n++ ) + glyph_indices[n] = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + } + + /* compute number of names stored in table */ + { + FT_Int n; + + + num_names = 0; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int idx; + + + idx = glyph_indices[n]; + if ( idx >= 258 ) + { + idx -= 257; + if ( idx > num_names ) + num_names = (FT_UShort)idx; + } + } + } + + /* now load the name strings */ + { + FT_UShort n; + + + if ( FT_NEW_ARRAY( name_strings, num_names ) ) + goto Fail; + + for ( n = 0; n < num_names; n++ ) + { + FT_UInt len; + + + if ( FT_READ_BYTE ( len ) || + FT_NEW_ARRAY( name_strings[n], len + 1 ) || + FT_STREAM_READ ( name_strings[n], len ) ) + goto Fail1; + + name_strings[n][len] = '\0'; + } + } + + /* all right, set table fields and exit successfully */ + { + TT_Post_20 table = &face->postscript_names.names.format_20; + + + table->num_glyphs = (FT_UShort)num_glyphs; + table->num_names = (FT_UShort)num_names; + table->glyph_indices = glyph_indices; + table->glyph_names = name_strings; + } + return SFNT_Err_Ok; + + Fail1: + { + FT_UShort n; + + + for ( n = 0; n < num_names; n++ ) + FT_FREE( name_strings[n] ); + } + + Fail: + FT_FREE( name_strings ); + FT_FREE( glyph_indices ); + + Exit: + return error; + } + + + static FT_Error + load_format_25( TT_Face face, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_Int num_glyphs; + FT_Char* offset_table = 0; + + + /* UNDOCUMENTED! This value appears only in the Apple TT specs. */ + if ( FT_READ_USHORT( num_glyphs ) ) + goto Exit; + + /* check the number of glyphs */ + if ( num_glyphs > face->max_profile.numGlyphs || num_glyphs > 258 ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || + FT_STREAM_READ( offset_table, num_glyphs ) ) + goto Fail; + + /* now check the offset table */ + { + FT_Int n; + + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Long idx = (FT_Long)n + offset_table[n]; + + + if ( idx < 0 || idx > num_glyphs ) + { + error = SFNT_Err_Invalid_File_Format; + goto Fail; + } + } + } + + /* OK, set table fields and exit successfully */ + { + TT_Post_25 table = &face->postscript_names.names.format_25; + + + table->num_glyphs = (FT_UShort)num_glyphs; + table->offsets = offset_table; + } + + return SFNT_Err_Ok; + + Fail: + FT_FREE( offset_table ); + + Exit: + return error; + } + + + static FT_Error + load_post_names( TT_Face face ) + { + FT_Stream stream; + FT_Error error; + FT_Fixed format; + + + /* get a stream for the face's resource */ + stream = face->root.stream; + + /* seek to the beginning of the PS names table */ + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + goto Exit; + + format = face->postscript.FormatType; + + /* go to beginning of subtable */ + if ( FT_STREAM_SKIP( 32 ) ) + goto Exit; + + /* now read postscript table */ + if ( format == 0x00020000L ) + error = load_format_20( face, stream ); + else if ( format == 0x00028000L ) + error = load_format_25( face, stream ); + else + error = SFNT_Err_Invalid_File_Format; + + face->postscript_names.loaded = 1; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_ps_names( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_Post_Names names = &face->postscript_names; + FT_Fixed format; + + + if ( names->loaded ) + { + format = face->postscript.FormatType; + + if ( format == 0x00020000L ) + { + TT_Post_20 table = &names->names.format_20; + FT_UShort n; + + + FT_FREE( table->glyph_indices ); + table->num_glyphs = 0; + + for ( n = 0; n < table->num_names; n++ ) + FT_FREE( table->glyph_names[n] ); + + FT_FREE( table->glyph_names ); + table->num_names = 0; + } + else if ( format == 0x00028000L ) + { + TT_Post_25 table = &names->names.format_25; + + + FT_FREE( table->offsets ); + table->num_glyphs = 0; + } + } + names->loaded = 0; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_get_ps_name */ + /* */ + /* <Description> */ + /* Gets the PostScript glyph name of a glyph. */ + /* */ + /* <Input> */ + /* face :: A handle to the parent face. */ + /* */ + /* idx :: The glyph index. */ + /* */ + /* PSname :: The address of a string pointer. Will be NULL in case */ + /* of error, otherwise it is a pointer to the glyph name. */ + /* */ + /* You must not modify the returned string! */ + /* */ + /* <Output> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ) + { + FT_Error error; + TT_Post_Names names; + FT_Fixed format; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Service_PsCMaps psnames; +#endif + + + if ( !face ) + return SFNT_Err_Invalid_Face_Handle; + + if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) + return SFNT_Err_Invalid_Glyph_Index; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames = (FT_Service_PsCMaps)face->psnames; + if ( !psnames ) + return SFNT_Err_Unimplemented_Feature; +#endif + + names = &face->postscript_names; + + /* `.notdef' by default */ + *PSname = MAC_NAME( 0 ); + + format = face->postscript.FormatType; + + if ( format == 0x00010000L ) + { + if ( idx < 258 ) /* paranoid checking */ + *PSname = MAC_NAME( idx ); + } + else if ( format == 0x00020000L ) + { + TT_Post_20 table = &names->names.format_20; + + + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } + + if ( idx < (FT_UInt)table->num_glyphs ) + { + FT_UShort name_index = table->glyph_indices[idx]; + + + if ( name_index < 258 ) + *PSname = MAC_NAME( name_index ); + else + *PSname = (FT_String*)table->glyph_names[name_index - 258]; + } + } + else if ( format == 0x00028000L ) + { + TT_Post_25 table = &names->names.format_25; + + + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } + + if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */ + { + idx += table->offsets[idx]; + *PSname = MAC_NAME( idx ); + } + } + + /* nothing to do for format == 0x00030000L */ + + End: + return SFNT_Err_Ok; + } + + +/* END */ diff --git a/src/freetype2/sfnt/ttpost.h b/src/freetype2/sfnt/ttpost.h new file mode 100644 index 0000000..6f06d75 --- /dev/null +++ b/src/freetype2/sfnt/ttpost.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* ttpost.h */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTPOST_H__ +#define __TTPOST_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + FT_LOCAL( void ) + tt_face_free_ps_names( TT_Face face ); + + +FT_END_HEADER + +#endif /* __TTPOST_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttsbit.c b/src/freetype2/sfnt/ttsbit.c new file mode 100644 index 0000000..eff49da --- /dev/null +++ b/src/freetype2/sfnt/ttsbit.c @@ -0,0 +1,1501 @@ +/***************************************************************************/ +/* */ +/* ttsbit.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H + + /* + * Alas, the memory-optimized sbit loader can't be used when implementing + * the `old internals' hack + */ +#if !defined FT_CONFIG_OPTION_OLD_INTERNALS + +#include "ttsbit0.c" + +#else /* !FT_CONFIG_OPTION_OLD_INTERNALS */ + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttsbit.h" + +#include "sferrors.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_ttsbit + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* blit_sbit */ + /* */ + /* <Description> */ + /* Blits a bitmap from an input stream into a given target. Supports */ + /* x and y offsets as well as byte padded lines. */ + /* */ + /* <Input> */ + /* target :: The target bitmap/pixmap. */ + /* */ + /* source :: The input packed bitmap data. */ + /* */ + /* line_bits :: The number of bits per line. */ + /* */ + /* byte_padded :: A flag which is true if lines are byte-padded. */ + /* */ + /* x_offset :: The horizontal offset. */ + /* */ + /* y_offset :: The vertical offset. */ + /* */ + /* <Note> */ + /* IMPORTANT: The x and y offsets are relative to the top corner of */ + /* the target bitmap (unlike the normal TrueType */ + /* convention). A positive y offset indicates a downwards */ + /* direction! */ + /* */ + static void + blit_sbit( FT_Bitmap* target, + FT_Byte* source, + FT_Int line_bits, + FT_Bool byte_padded, + FT_Int x_offset, + FT_Int y_offset ) + { + FT_Byte* line_buff; + FT_Int line_incr; + FT_Int height; + + FT_UShort acc; + FT_UInt loaded; + + + /* first of all, compute starting write position */ + line_incr = target->pitch; + line_buff = target->buffer; + + if ( line_incr < 0 ) + line_buff -= line_incr * ( target->rows - 1 ); + + line_buff += ( x_offset >> 3 ) + y_offset * line_incr; + + /***********************************************************************/ + /* */ + /* We use the extra-classic `accumulator' trick to extract the bits */ + /* from the source byte stream. */ + /* */ + /* Namely, the variable `acc' is a 16-bit accumulator containing the */ + /* last `loaded' bits from the input stream. The bits are shifted to */ + /* the upmost position in `acc'. */ + /* */ + /***********************************************************************/ + + acc = 0; /* clear accumulator */ + loaded = 0; /* no bits were loaded */ + + for ( height = target->rows; height > 0; height-- ) + { + FT_Byte* cur = line_buff; /* current write cursor */ + FT_Int count = line_bits; /* # of bits to extract per line */ + FT_Byte shift = (FT_Byte)( x_offset & 7 ); /* current write shift */ + FT_Byte space = (FT_Byte)( 8 - shift ); + + + /* first of all, read individual source bytes */ + if ( count >= 8 ) + { + count -= 8; + { + do + { + FT_Byte val; + + + /* ensure that there are at least 8 bits in the accumulator */ + if ( loaded < 8 ) + { + acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded )); + loaded += 8; + } + + /* now write one byte */ + val = (FT_Byte)( acc >> 8 ); + if ( shift ) + { + cur[0] |= (FT_Byte)( val >> shift ); + cur[1] |= (FT_Byte)( val << space ); + } + else + cur[0] |= val; + + cur++; + acc <<= 8; /* remove bits from accumulator */ + loaded -= 8; + count -= 8; + + } while ( count >= 0 ); + } + + /* restore `count' to correct value */ + count += 8; + } + + /* now write remaining bits (count < 8) */ + if ( count > 0 ) + { + FT_Byte val; + + + /* ensure that there are at least `count' bits in the accumulator */ + if ( (FT_Int)loaded < count ) + { + acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded )); + loaded += 8; + } + + /* now write remaining bits */ + val = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) ); + cur[0] |= (FT_Byte)( val >> shift ); + + if ( count > space ) + cur[1] |= (FT_Byte)( val << space ); + + acc <<= count; + loaded -= count; + } + + /* now, skip to next line */ + if ( byte_padded ) + { + acc = 0; + loaded = 0; /* clear accumulator on byte-padded lines */ + } + + line_buff += line_incr; + } + } + + + static const FT_Frame_Field sbit_metrics_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_MetricsRec + + FT_FRAME_START( 8 ), + FT_FRAME_BYTE( height ), + FT_FRAME_BYTE( width ), + + FT_FRAME_CHAR( horiBearingX ), + FT_FRAME_CHAR( horiBearingY ), + FT_FRAME_BYTE( horiAdvance ), + + FT_FRAME_CHAR( vertBearingX ), + FT_FRAME_CHAR( vertBearingY ), + FT_FRAME_BYTE( vertAdvance ), + FT_FRAME_END + }; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Load_SBit_Const_Metrics */ + /* */ + /* <Description> */ + /* Loads the metrics for `EBLC' index tables format 2 and 5. */ + /* */ + /* <Input> */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Load_SBit_Const_Metrics( TT_SBit_Range range, + FT_Stream stream ) + { + FT_Error error; + + + if ( FT_READ_ULONG( range->image_size ) ) + return error; + + return FT_STREAM_READ_FIELDS( sbit_metrics_fields, &range->metrics ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Load_SBit_Range_Codes */ + /* */ + /* <Description> */ + /* Loads the range codes for `EBLC' index tables format 4 and 5. */ + /* */ + /* <Input> */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* load_offsets :: A flag whether to load the glyph offset table. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Load_SBit_Range_Codes( TT_SBit_Range range, + FT_Stream stream, + FT_Bool load_offsets ) + { + FT_Error error; + FT_ULong count, n, size; + FT_Memory memory = stream->memory; + + + if ( FT_READ_ULONG( count ) ) + goto Exit; + + range->num_glyphs = count; + + /* Allocate glyph offsets table if needed */ + if ( load_offsets ) + { + if ( FT_NEW_ARRAY( range->glyph_offsets, count ) ) + goto Exit; + + size = count * 4L; + } + else + size = count * 2L; + + /* Allocate glyph codes table and access frame */ + if ( FT_NEW_ARRAY ( range->glyph_codes, count ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + for ( n = 0; n < count; n++ ) + { + range->glyph_codes[n] = FT_GET_USHORT(); + + if ( load_offsets ) + range->glyph_offsets[n] = (FT_ULong)range->image_offset + + FT_GET_USHORT(); + } + + FT_FRAME_EXIT(); + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Load_SBit_Range */ + /* */ + /* <Description> */ + /* Loads a given `EBLC' index/range table. */ + /* */ + /* <Input> */ + /* range :: The target range. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Load_SBit_Range( TT_SBit_Range range, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + + switch( range->index_format ) + { + case 1: /* variable metrics with 4-byte offsets */ + case 3: /* variable metrics with 2-byte offsets */ + { + FT_ULong num_glyphs, n; + FT_Int size_elem; + FT_Bool large = FT_BOOL( range->index_format == 1 ); + + + + if ( range->last_glyph < range->first_glyph ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + num_glyphs = range->last_glyph - range->first_glyph + 1L; + range->num_glyphs = num_glyphs; + num_glyphs++; /* XXX: BEWARE - see spec */ + + size_elem = large ? 4 : 2; + + if ( FT_NEW_ARRAY( range->glyph_offsets, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * size_elem ) ) + goto Exit; + + for ( n = 0; n < num_glyphs; n++ ) + range->glyph_offsets[n] = (FT_ULong)( range->image_offset + + ( large ? FT_GET_ULONG() + : FT_GET_USHORT() ) ); + FT_FRAME_EXIT(); + } + break; + + case 2: /* all glyphs have identical metrics */ + error = Load_SBit_Const_Metrics( range, stream ); + break; + + case 4: + error = Load_SBit_Range_Codes( range, stream, 1 ); + break; + + case 5: + error = Load_SBit_Const_Metrics( range, stream ) || + Load_SBit_Range_Codes( range, stream, 0 ); + break; + + default: + error = SFNT_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_eblc */ + /* */ + /* <Description> */ + /* Loads the table of embedded bitmap sizes for this face. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_eblc( TT_Face face, + FT_Stream stream ) + { + FT_Error error = 0; + FT_Memory memory = stream->memory; + FT_Fixed version; + FT_ULong num_strikes; + FT_ULong table_base; + + static const FT_Frame_Field sbit_line_metrics_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_LineMetricsRec + + /* no FT_FRAME_START */ + FT_FRAME_CHAR( ascender ), + FT_FRAME_CHAR( descender ), + FT_FRAME_BYTE( max_width ), + + FT_FRAME_CHAR( caret_slope_numerator ), + FT_FRAME_CHAR( caret_slope_denominator ), + FT_FRAME_CHAR( caret_offset ), + + FT_FRAME_CHAR( min_origin_SB ), + FT_FRAME_CHAR( min_advance_SB ), + FT_FRAME_CHAR( max_before_BL ), + FT_FRAME_CHAR( min_after_BL ), + FT_FRAME_CHAR( pads[0] ), + FT_FRAME_CHAR( pads[1] ), + FT_FRAME_END + }; + + static const FT_Frame_Field strike_start_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_StrikeRec + + /* no FT_FRAME_START */ + FT_FRAME_ULONG( ranges_offset ), + FT_FRAME_SKIP_LONG, + FT_FRAME_ULONG( num_ranges ), + FT_FRAME_ULONG( color_ref ), + FT_FRAME_END + }; + + static const FT_Frame_Field strike_end_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_USHORT( start_glyph ), + FT_FRAME_USHORT( end_glyph ), + FT_FRAME_BYTE ( x_ppem ), + FT_FRAME_BYTE ( y_ppem ), + FT_FRAME_BYTE ( bit_depth ), + FT_FRAME_CHAR ( flags ), + FT_FRAME_END + }; + + + face->num_sbit_strikes = 0; + + /* this table is optional */ + error = face->goto_table( face, TTAG_EBLC, stream, 0 ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, 0 ); + if ( error ) + goto Exit; + + table_base = FT_STREAM_POS(); + if ( FT_FRAME_ENTER( 8L ) ) + goto Exit; + + version = FT_GET_LONG(); + num_strikes = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + /* check version number and strike count */ + if ( version != 0x00020000L || + num_strikes >= 0x10000L ) + { + FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version!\n" )); + error = SFNT_Err_Invalid_File_Format; + + goto Exit; + } + + /* allocate the strikes table */ + if ( FT_NEW_ARRAY( face->sbit_strikes, num_strikes ) ) + goto Exit; + + face->num_sbit_strikes = num_strikes; + + /* now read each strike table separately */ + { + TT_SBit_Strike strike = face->sbit_strikes; + FT_ULong count = num_strikes; + + + if ( FT_FRAME_ENTER( 48L * num_strikes ) ) + goto Exit; + + while ( count > 0 ) + { + if ( FT_STREAM_READ_FIELDS( strike_start_fields, strike ) || + FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->hori ) || + FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->vert ) || + FT_STREAM_READ_FIELDS( strike_end_fields, strike ) ) + break; + + count--; + strike++; + } + + FT_FRAME_EXIT(); + } + + /* allocate the index ranges for each strike table */ + { + TT_SBit_Strike strike = face->sbit_strikes; + FT_ULong count = num_strikes; + + + while ( count > 0 ) + { + TT_SBit_Range range; + FT_ULong count2 = strike->num_ranges; + + + /* read each range */ + if ( FT_STREAM_SEEK( table_base + strike->ranges_offset ) || + FT_FRAME_ENTER( strike->num_ranges * 8L ) ) + goto Exit; + + if ( FT_NEW_ARRAY( strike->sbit_ranges, strike->num_ranges ) ) + goto Exit; + + range = strike->sbit_ranges; + while ( count2 > 0 ) + { + range->first_glyph = FT_GET_USHORT(); + range->last_glyph = FT_GET_USHORT(); + range->table_offset = table_base + strike->ranges_offset + + FT_GET_ULONG(); + count2--; + range++; + } + + FT_FRAME_EXIT(); + + /* Now, read each index table */ + count2 = strike->num_ranges; + range = strike->sbit_ranges; + while ( count2 > 0 ) + { + /* Read the header */ + if ( FT_STREAM_SEEK( range->table_offset ) || + FT_FRAME_ENTER( 8L ) ) + goto Exit; + + range->index_format = FT_GET_USHORT(); + range->image_format = FT_GET_USHORT(); + range->image_offset = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + error = Load_SBit_Range( range, stream ); + if ( error ) + goto Exit; + + count2--; + range++; + } + + count--; + strike++; + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_free_eblc */ + /* */ + /* <Description> */ + /* Releases the embedded bitmap tables. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + FT_LOCAL_DEF( void ) + tt_face_free_eblc( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_SBit_Strike strike = face->sbit_strikes; + TT_SBit_Strike strike_limit = strike + face->num_sbit_strikes; + + + if ( strike ) + { + for ( ; strike < strike_limit; strike++ ) + { + TT_SBit_Range range = strike->sbit_ranges; + TT_SBit_Range range_limit = range + strike->num_ranges; + + + if ( range ) + { + for ( ; range < range_limit; range++ ) + { + /* release the glyph offsets and codes tables */ + /* where appropriate */ + FT_FREE( range->glyph_offsets ); + FT_FREE( range->glyph_codes ); + } + } + FT_FREE( strike->sbit_ranges ); + strike->num_ranges = 0; + } + FT_FREE( face->sbit_strikes ); + } + face->num_sbit_strikes = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ) + { + return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ) + { + TT_SBit_Strike strike; + + + if ( strike_index >= face->num_sbit_strikes ) + return SFNT_Err_Invalid_Argument; + + strike = face->sbit_strikes + strike_index; + + metrics->x_ppem = strike->x_ppem; + metrics->y_ppem = strike->y_ppem; + + metrics->ascender = strike->hori.ascender << 6; + metrics->descender = strike->hori.descender << 6; + + /* XXX: Is this correct? */ + metrics->max_advance = ( strike->hori.min_origin_SB + + strike->hori.max_width + + strike->hori.min_advance_SB ) << 6; + + metrics->height = metrics->ascender - metrics->descender; + + return SFNT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* find_sbit_range */ + /* */ + /* <Description> */ + /* Scans a given strike's ranges and return, for a given glyph */ + /* index, the corresponding sbit range, and `EBDT' offset. */ + /* */ + /* <Input> */ + /* glyph_index :: The glyph index. */ + /* */ + /* strike :: The source/current sbit strike. */ + /* */ + /* <Output> */ + /* arange :: The sbit range containing the glyph index. */ + /* */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means the glyph index was found. */ + /* */ + static FT_Error + find_sbit_range( FT_UInt glyph_index, + TT_SBit_Strike strike, + TT_SBit_Range *arange, + FT_ULong *aglyph_offset ) + { + TT_SBit_RangeRec *range, *range_limit; + + + /* check whether the glyph index is within this strike's */ + /* glyph range */ + if ( glyph_index < (FT_UInt)strike->start_glyph || + glyph_index > (FT_UInt)strike->end_glyph ) + goto Fail; + + /* scan all ranges in strike */ + range = strike->sbit_ranges; + range_limit = range + strike->num_ranges; + if ( !range ) + goto Fail; + + for ( ; range < range_limit; range++ ) + { + if ( glyph_index >= (FT_UInt)range->first_glyph && + glyph_index <= (FT_UInt)range->last_glyph ) + { + FT_UShort delta = (FT_UShort)( glyph_index - range->first_glyph ); + + + switch ( range->index_format ) + { + case 1: + case 3: + *aglyph_offset = range->glyph_offsets[delta]; + break; + + case 2: + *aglyph_offset = range->image_offset + + range->image_size * delta; + break; + + case 4: + case 5: + { + FT_ULong n; + + + for ( n = 0; n < range->num_glyphs; n++ ) + { + if ( (FT_UInt)range->glyph_codes[n] == glyph_index ) + { + if ( range->index_format == 4 ) + *aglyph_offset = range->glyph_offsets[n]; + else + *aglyph_offset = range->image_offset + + n * range->image_size; + goto Found; + } + } + } + + /* fall-through */ + default: + goto Fail; + } + + Found: + /* return successfully! */ + *arange = range; + return 0; + } + } + + Fail: + *arange = 0; + *aglyph_offset = 0; + + return SFNT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_find_sbit_image */ + /* */ + /* <Description> */ + /* Checks whether an embedded bitmap (an `sbit') exists for a given */ + /* glyph, at a given strike. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* strike_index :: The current strike index. */ + /* */ + /* <Output> */ + /* arange :: The SBit range containing the glyph index. */ + /* */ + /* astrike :: The SBit strike containing the glyph index. */ + /* */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns */ + /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */ + /* glyph. */ + /* */ + FT_LOCAL( FT_Error ) + tt_find_sbit_image( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ) + { + FT_Error error; + TT_SBit_Strike strike; + + + if ( !face->sbit_strikes || + ( face->num_sbit_strikes <= strike_index ) ) + goto Fail; + + strike = &face->sbit_strikes[strike_index]; + + error = find_sbit_range( glyph_index, strike, + arange, aglyph_offset ); + if ( error ) + goto Fail; + + *astrike = strike; + + return SFNT_Err_Ok; + + Fail: + /* no embedded bitmap for this glyph in face */ + *arange = 0; + *astrike = 0; + *aglyph_offset = 0; + + return SFNT_Err_Invalid_Argument; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_load_sbit_metrics */ + /* */ + /* <Description> */ + /* Gets the big metrics for a given SBit. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* range :: The SBit range containing the glyph. */ + /* */ + /* <Output> */ + /* big_metrics :: A big SBit metrics structure for the glyph. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be positioned at the glyph's offset within */ + /* the `EBDT' table before the call. */ + /* */ + /* If the image format uses variable metrics, the stream cursor is */ + /* positioned just after the metrics header in the `EBDT' table on */ + /* function exit. */ + /* */ + FT_LOCAL( FT_Error ) + tt_load_sbit_metrics( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ) + { + FT_Error error = SFNT_Err_Ok; + + + switch ( range->image_format ) + { + case 1: + case 2: + case 8: + /* variable small metrics */ + { + TT_SBit_SmallMetricsRec smetrics; + + static const FT_Frame_Field sbit_small_metrics_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_SmallMetricsRec + + FT_FRAME_START( 5 ), + FT_FRAME_BYTE( height ), + FT_FRAME_BYTE( width ), + FT_FRAME_CHAR( bearingX ), + FT_FRAME_CHAR( bearingY ), + FT_FRAME_BYTE( advance ), + FT_FRAME_END + }; + + + /* read small metrics */ + if ( FT_STREAM_READ_FIELDS( sbit_small_metrics_fields, &smetrics ) ) + goto Exit; + + /* convert it to a big metrics */ + metrics->height = smetrics.height; + metrics->width = smetrics.width; + metrics->horiBearingX = smetrics.bearingX; + metrics->horiBearingY = smetrics.bearingY; + metrics->horiAdvance = smetrics.advance; + + /* these metrics are made up at a higher level when */ + /* needed. */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + } + break; + + case 6: + case 7: + case 9: + /* variable big metrics */ + if ( FT_STREAM_READ_FIELDS( sbit_metrics_fields, metrics ) ) + goto Exit; + break; + + case 5: + default: /* constant metrics */ + if ( range->index_format == 2 || range->index_format == 5 ) + *metrics = range->metrics; + else + return SFNT_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* crop_bitmap */ + /* */ + /* <Description> */ + /* Crops a bitmap to its tightest bounding box, and adjusts its */ + /* metrics. */ + /* */ + /* <InOut> */ + /* map :: The bitmap. */ + /* */ + /* metrics :: The corresponding metrics structure. */ + /* */ + static void + crop_bitmap( FT_Bitmap* map, + TT_SBit_Metrics metrics ) + { + /***********************************************************************/ + /* */ + /* In this situation, some bounding boxes of embedded bitmaps are too */ + /* large. We need to crop it to a reasonable size. */ + /* */ + /* --------- */ + /* | | ----- */ + /* | *** | |***| */ + /* | * | | * | */ + /* | * | ------> | * | */ + /* | * | | * | */ + /* | * | | * | */ + /* | *** | |***| */ + /* --------- ----- */ + /* */ + /***********************************************************************/ + + FT_Int rows, count; + FT_Long line_len; + FT_Byte* line; + + + /***********************************************************************/ + /* */ + /* first of all, check the top-most lines of the bitmap, and remove */ + /* them if they're empty. */ + /* */ + { + line = (FT_Byte*)map->buffer; + rows = map->rows; + line_len = map->pitch; + + + for ( count = 0; count < rows; count++ ) + { + FT_Byte* cur = line; + FT_Byte* limit = line + line_len; + + + for ( ; cur < limit; cur++ ) + if ( cur[0] ) + goto Found_Top; + + /* the current line was empty - skip to next one */ + line = limit; + } + + Found_Top: + /* check that we have at least one filled line */ + if ( count >= rows ) + goto Empty_Bitmap; + + /* now, crop the empty upper lines */ + if ( count > 0 ) + { + line = (FT_Byte*)map->buffer; + + FT_MEM_MOVE( line, line + count * line_len, + ( rows - count ) * line_len ); + + metrics->height = (FT_Byte)( metrics->height - count ); + metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count ); + metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count ); + + map->rows -= count; + rows -= count; + } + } + + /***********************************************************************/ + /* */ + /* second, crop the lower lines */ + /* */ + { + line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len; + + for ( count = 0; count < rows; count++ ) + { + FT_Byte* cur = line; + FT_Byte* limit = line + line_len; + + + for ( ; cur < limit; cur++ ) + if ( cur[0] ) + goto Found_Bottom; + + /* the current line was empty - skip to previous one */ + line -= line_len; + } + + Found_Bottom: + if ( count > 0 ) + { + metrics->height = (FT_Byte)( metrics->height - count ); + rows -= count; + map->rows -= count; + } + } + + /***********************************************************************/ + /* */ + /* third, get rid of the space on the left side of the glyph */ + /* */ + do + { + FT_Byte* limit; + + + line = (FT_Byte*)map->buffer; + limit = line + rows * line_len; + + for ( ; line < limit; line += line_len ) + if ( line[0] & 0x80 ) + goto Found_Left; + + /* shift the whole glyph one pixel to the left */ + line = (FT_Byte*)map->buffer; + limit = line + rows * line_len; + + for ( ; line < limit; line += line_len ) + { + FT_Int n, width = map->width; + FT_Byte old; + FT_Byte* cur = line; + + + old = (FT_Byte)(cur[0] << 1); + for ( n = 8; n < width; n += 8 ) + { + FT_Byte val; + + + val = cur[1]; + cur[0] = (FT_Byte)( old | ( val >> 7 ) ); + old = (FT_Byte)( val << 1 ); + cur++; + } + cur[0] = old; + } + + map->width--; + metrics->horiBearingX++; + metrics->vertBearingX++; + metrics->width--; + + } while ( map->width > 0 ); + + Found_Left: + + /***********************************************************************/ + /* */ + /* finally, crop the bitmap width to get rid of the space on the right */ + /* side of the glyph. */ + /* */ + do + { + FT_Int right = map->width - 1; + FT_Byte* limit; + FT_Byte mask; + + + line = (FT_Byte*)map->buffer + ( right >> 3 ); + limit = line + rows * line_len; + mask = (FT_Byte)( 0x80 >> ( right & 7 ) ); + + for ( ; line < limit; line += line_len ) + if ( line[0] & mask ) + goto Found_Right; + + /* crop the whole glyph to the right */ + map->width--; + metrics->width--; + + } while ( map->width > 0 ); + + Found_Right: + /* all right, the bitmap was cropped */ + return; + + Empty_Bitmap: + map->width = 0; + map->rows = 0; + map->pitch = 0; + map->pixel_mode = FT_PIXEL_MODE_MONO; + } + + + static FT_Error + Load_SBit_Single( FT_Bitmap* map, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + FT_UShort image_format, + TT_SBit_Metrics metrics, + FT_Stream stream ) + { + FT_Error error; + + + /* check that the source bitmap fits into the target pixmap */ + if ( x_offset < 0 || x_offset + metrics->width > map->width || + y_offset < 0 || y_offset + metrics->height > map->rows ) + { + error = SFNT_Err_Invalid_Argument; + + goto Exit; + } + + { + FT_Int glyph_width = metrics->width; + FT_Int glyph_height = metrics->height; + FT_Int glyph_size; + FT_Int line_bits = pix_bits * glyph_width; + FT_Bool pad_bytes = 0; + + + /* compute size of glyph image */ + switch ( image_format ) + { + case 1: /* byte-padded formats */ + case 6: + { + FT_Int line_length; + + + switch ( pix_bits ) + { + case 1: + line_length = ( glyph_width + 7 ) >> 3; + break; + case 2: + line_length = ( glyph_width + 3 ) >> 2; + break; + case 4: + line_length = ( glyph_width + 1 ) >> 1; + break; + default: + line_length = glyph_width; + } + + glyph_size = glyph_height * line_length; + pad_bytes = 1; + } + break; + + case 2: + case 5: + case 7: + line_bits = glyph_width * pix_bits; + glyph_size = ( glyph_height * line_bits + 7 ) >> 3; + break; + + default: /* invalid format */ + return SFNT_Err_Invalid_File_Format; + } + + /* Now read data and draw glyph into target pixmap */ + if ( FT_FRAME_ENTER( glyph_size ) ) + goto Exit; + + /* don't forget to multiply `x_offset' by `map->pix_bits' as */ + /* the sbit blitter doesn't make a difference between pixmap */ + /* depths. */ + blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes, + x_offset * pix_bits, y_offset ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + static FT_Error + Load_SBit_Image( TT_SBit_Strike strike, + TT_SBit_Range range, + FT_ULong ebdt_pos, + FT_ULong glyph_offset, + FT_GlyphSlot slot, + FT_Int x_offset, + FT_Int y_offset, + FT_Stream stream, + TT_SBit_Metrics metrics, + FT_Int depth ) + { + FT_Memory memory = stream->memory; + FT_Bitmap* map = &slot->bitmap; + FT_Error error; + + + /* place stream at beginning of glyph data and read metrics */ + if ( FT_STREAM_SEEK( ebdt_pos + glyph_offset ) ) + goto Exit; + + error = tt_load_sbit_metrics( stream, range, metrics ); + if ( error ) + goto Exit; + + /* This function is recursive. At the top-level call, we */ + /* compute the dimensions of the higher-level glyph to */ + /* allocate the final pixmap buffer. */ + if ( depth == 0 ) + { + FT_Long size; + + + map->width = metrics->width; + map->rows = metrics->height; + + switch ( strike->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = ( map->width + 7 ) >> 3; + break; + + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = ( map->width + 3 ) >> 2; + break; + + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = ( map->width + 1 ) >> 1; + break; + + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = map->width; + break; + + default: + return SFNT_Err_Invalid_File_Format; + } + + size = map->rows * map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + error = ft_glyphslot_alloc_bitmap( slot, size ); + if (error) + goto Exit; + } + + switch ( range->image_format ) + { + case 1: /* single sbit image - load it */ + case 2: + case 5: + case 6: + case 7: + return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth, + range->image_format, metrics, stream ); + + case 8: /* compound format */ + FT_Stream_Skip( stream, 1L ); + /* fallthrough */ + + case 9: + break; + + default: /* invalid image format */ + return SFNT_Err_Invalid_File_Format; + } + + /* All right, we have a compound format. First of all, read */ + /* the array of elements. */ + { + TT_SBit_Component components; + TT_SBit_Component comp; + FT_UShort num_components, count; + + + if ( FT_READ_USHORT( num_components ) || + FT_NEW_ARRAY( components, num_components ) ) + goto Exit; + + count = num_components; + + if ( FT_FRAME_ENTER( 4L * num_components ) ) + goto Fail_Memory; + + for ( comp = components; count > 0; count--, comp++ ) + { + comp->glyph_code = FT_GET_USHORT(); + comp->x_offset = FT_GET_CHAR(); + comp->y_offset = FT_GET_CHAR(); + } + + FT_FRAME_EXIT(); + + /* Now recursively load each element glyph */ + count = num_components; + comp = components; + for ( ; count > 0; count--, comp++ ) + { + TT_SBit_Range elem_range; + TT_SBit_MetricsRec elem_metrics; + FT_ULong elem_offset; + + + /* find the range for this element */ + error = find_sbit_range( comp->glyph_code, + strike, + &elem_range, + &elem_offset ); + if ( error ) + goto Fail_Memory; + + /* now load the element, recursively */ + error = Load_SBit_Image( strike, + elem_range, + ebdt_pos, + elem_offset, + slot, + x_offset + comp->x_offset, + y_offset + comp->y_offset, + stream, + &elem_metrics, + depth + 1 ); + if ( error ) + goto Fail_Memory; + } + + Fail_Memory: + FT_FREE( components ); + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_sbit_image */ + /* */ + /* <Description> */ + /* Loads a given glyph sbit image from the font resource. This also */ + /* returns its metrics. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* strike_index :: The current strike index. */ + /* */ + /* glyph_index :: The current glyph index. */ + /* */ + /* load_flags :: The glyph load flags (the code checks for the flag */ + /* FT_LOAD_CROP_BITMAP). */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Output> */ + /* map :: The target pixmap. */ + /* */ + /* metrics :: A big sbit metrics structure for the glyph image. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* glyph sbit exists for the index. */ + /* */ + /* <Note> */ + /* The `map.buffer' field is always freed before the glyph is loaded. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + FT_Error error; + FT_ULong ebdt_pos, glyph_offset; + + TT_SBit_Strike strike; + TT_SBit_Range range; + + + /* Check whether there is a glyph sbit for the current index */ + error = tt_find_sbit_image( face, glyph_index, strike_index, + &range, &strike, &glyph_offset ); + if ( error ) + goto Exit; + + /* now, find the location of the `EBDT' table in */ + /* the font file */ + error = face->goto_table( face, TTAG_EBDT, stream, 0 ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, 0 ); + if ( error ) + goto Exit; + + ebdt_pos = FT_STREAM_POS(); + + error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset, + face->root.glyph, 0, 0, stream, metrics, 0 ); + if ( error ) + goto Exit; + + /* setup vertical metrics if needed */ + if ( strike->flags & 1 ) + { + /* in case of a horizontal strike only */ + FT_Int advance; + + + advance = strike->hori.ascender - strike->hori.descender; + + /* some heuristic values */ + + metrics->vertBearingX = (FT_Char)(-metrics->width / 2 ); + metrics->vertBearingY = (FT_Char)( ( advance - metrics->height ) / 2 ); + metrics->vertAdvance = (FT_Char)( advance * 12 / 10 ); + } + + /* Crop the bitmap now, unless specified otherwise */ + if ( load_flags & FT_LOAD_CROP_BITMAP ) + crop_bitmap( map, metrics ); + + Exit: + return error; + } + +#endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttsbit.h b/src/freetype2/sfnt/ttsbit.h new file mode 100644 index 0000000..c6067c0 --- /dev/null +++ b/src/freetype2/sfnt/ttsbit.h @@ -0,0 +1,79 @@ +/***************************************************************************/ +/* */ +/* ttsbit.h */ +/* */ +/* TrueType and OpenType embedded bitmap support (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTSBIT_H__ +#define __TTSBIT_H__ + + +#include <ft2build.h> +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_eblc( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_eblc( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + FT_LOCAL( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + +#if defined FT_CONFIG_OPTION_OLD_INTERNALS + FT_LOCAL( FT_Error ) + tt_find_sbit_image( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); + + FT_LOCAL( FT_Error ) + tt_load_sbit_metrics( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ); + + +FT_END_HEADER + +#endif /* __TTSBIT_H__ */ + + +/* END */ diff --git a/src/freetype2/sfnt/ttsbit0.c b/src/freetype2/sfnt/ttsbit0.c new file mode 100644 index 0000000..f8adc64 --- /dev/null +++ b/src/freetype2/sfnt/ttsbit0.c @@ -0,0 +1,996 @@ +/***************************************************************************/ +/* */ +/* ttsbit0.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* This is a heap-optimized version. */ +/* */ +/* Copyright 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. */ +/* */ +/***************************************************************************/ + + +/* This file is included by ttsbit.c */ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttsbit.h" + +#include "sferrors.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_ttsbit + + + static const FT_Frame_Field tt_sbit_line_metrics_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_LineMetricsRec + + /* no FT_FRAME_START */ + FT_FRAME_CHAR( ascender ), + FT_FRAME_CHAR( descender ), + FT_FRAME_BYTE( max_width ), + + FT_FRAME_CHAR( caret_slope_numerator ), + FT_FRAME_CHAR( caret_slope_denominator ), + FT_FRAME_CHAR( caret_offset ), + + FT_FRAME_CHAR( min_origin_SB ), + FT_FRAME_CHAR( min_advance_SB ), + FT_FRAME_CHAR( max_before_BL ), + FT_FRAME_CHAR( min_after_BL ), + FT_FRAME_CHAR( pads[0] ), + FT_FRAME_CHAR( pads[1] ), + FT_FRAME_END + }; + + static const FT_Frame_Field tt_strike_start_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_StrikeRec + + /* no FT_FRAME_START */ + FT_FRAME_ULONG( ranges_offset ), + FT_FRAME_SKIP_LONG, + FT_FRAME_ULONG( num_ranges ), + FT_FRAME_ULONG( color_ref ), + FT_FRAME_END + }; + + static const FT_Frame_Field tt_strike_end_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_USHORT( start_glyph ), + FT_FRAME_USHORT( end_glyph ), + FT_FRAME_BYTE ( x_ppem ), + FT_FRAME_BYTE ( y_ppem ), + FT_FRAME_BYTE ( bit_depth ), + FT_FRAME_CHAR ( flags ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_eblc( TT_Face face, + FT_Stream stream ) + { + FT_Error error = SFNT_Err_Ok; + FT_Fixed version; + FT_ULong num_strikes, table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt count; + + + face->sbit_num_strikes = 0; + + /* this table is optional */ + error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 8 ) + { + FT_ERROR(( "%s: table too short!\n", "tt_face_load_sbit_strikes" )); + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_table_size = table_size; + + p = face->sbit_table; + p_limit = p + table_size; + + version = FT_NEXT_ULONG( p ); + num_strikes = FT_NEXT_ULONG( p ); + + if ( version != 0x00020000UL || num_strikes >= 0x10000UL ) + { + FT_ERROR(( "%s: invalid table version!\n", + "tt_face_load_sbit_strikes" )); + error = SFNT_Err_Invalid_File_Format; + goto Fail; + } + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 48UL * count > table_size ) + count = (FT_UInt)( ( p_limit - p ) / 48 ); + + face->sbit_num_strikes = count; + + FT_TRACE3(( "sbit_num_strikes: %u\n", count )); + Exit: + return error; + + Fail: + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_eblc( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_num_strikes = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ) + { + return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ) + { + FT_Byte* strike; + + + if ( strike_index >= (FT_ULong)face->sbit_num_strikes ) + return SFNT_Err_Invalid_Argument; + + strike = face->sbit_table + 8 + strike_index * 48; + + metrics->x_ppem = (FT_UShort)strike[44]; + metrics->y_ppem = (FT_UShort)strike[45]; + + metrics->ascender = (FT_Char)strike[16] << 6; /* hori.ascender */ + metrics->descender = (FT_Char)strike[17] << 6; /* hori.descender */ + metrics->height = metrics->ascender - metrics->descender; + + /* XXX: Is this correct? */ + metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */ + strike[18] + /* max_width */ + (FT_Char)strike[23] /* min_advance_SB */ + ) << 6; + + return SFNT_Err_Ok; + } + + + typedef struct + { + TT_Face face; + FT_Stream stream; + FT_Bitmap* bitmap; + TT_SBit_Metrics metrics; + FT_Bool metrics_loaded; + FT_Bool bitmap_allocated; + FT_Byte bit_depth; + + FT_ULong ebdt_start; + FT_ULong ebdt_size; + + FT_ULong strike_index_array; + FT_ULong strike_index_count; + FT_Byte* eblc_base; + FT_Byte* eblc_limit; + + } TT_SBitDecoderRec, *TT_SBitDecoder; + + + static FT_Error + tt_sbit_decoder_init( TT_SBitDecoder decoder, + TT_Face face, + FT_ULong strike_index, + TT_SBit_MetricsRec* metrics ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + FT_ULong ebdt_size; + + + error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); + if ( error ) + goto Exit; + + decoder->face = face; + decoder->stream = stream; + decoder->bitmap = &face->root.glyph->bitmap; + decoder->metrics = metrics; + + decoder->metrics_loaded = 0; + decoder->bitmap_allocated = 0; + + decoder->ebdt_start = FT_STREAM_POS(); + decoder->ebdt_size = ebdt_size; + + decoder->eblc_base = face->sbit_table; + decoder->eblc_limit = face->sbit_table + face->sbit_table_size; + + /* now find the strike corresponding to the index */ + { + FT_Byte* p; + + + if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + p = decoder->eblc_base + 8 + 48 * strike_index; + + decoder->strike_index_array = FT_NEXT_ULONG( p ); + p += 4; + decoder->strike_index_count = FT_NEXT_ULONG( p ); + p += 34; + decoder->bit_depth = *p; + + if ( decoder->strike_index_array > face->sbit_table_size || + decoder->strike_index_array + 8 * decoder->strike_index_count > + face->sbit_table_size ) + error = SFNT_Err_Invalid_File_Format; + } + + Exit: + return error; + } + + + static void + tt_sbit_decoder_done( TT_SBitDecoder decoder ) + { + FT_UNUSED( decoder ); + } + + + static FT_Error + tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt width, height; + FT_Bitmap* map = decoder->bitmap; + FT_Long size; + + + if ( !decoder->metrics_loaded ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + + width = decoder->metrics->width; + height = decoder->metrics->height; + + map->width = (int)width; + map->rows = (int)height; + + switch ( decoder->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = ( map->width + 7 ) >> 3; + break; + + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = ( map->width + 3 ) >> 2; + break; + + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = ( map->width + 1 ) >> 1; + break; + + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = map->width; + break; + + default: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + size = map->rows * map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); + if ( error ) + goto Exit; + + decoder->bitmap_allocated = 1; + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, + FT_Byte* *pp, + FT_Byte* limit, + FT_Bool big ) + { + FT_Byte* p = *pp; + TT_SBit_Metrics metrics = decoder->metrics; + + + if ( p + 5 > limit ) + goto Fail; + + if ( !decoder->metrics_loaded ) + { + metrics->height = p[0]; + metrics->width = p[1]; + metrics->horiBearingX = (FT_Char)p[2]; + metrics->horiBearingY = (FT_Char)p[3]; + metrics->horiAdvance = p[4]; + } + + p += 5; + if ( big ) + { + if ( p + 3 > limit ) + goto Fail; + + if ( !decoder->metrics_loaded ) + { + metrics->vertBearingX = (FT_Char)p[0]; + metrics->vertBearingY = (FT_Char)p[1]; + metrics->vertAdvance = p[2]; + } + + p += 3; + } + + decoder->metrics_loaded = 1; + *pp = p; + return 0; + + Fail: + return SFNT_Err_Invalid_Argument; + } + + + /* forward declaration */ + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ); + + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos ); + + + static FT_Error + tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h; + FT_Bitmap* bitmap; + + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + if ( x_pos == 0 ) /* the easy one */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + + + for ( w = width; w >= 8; w -= 8 ) + { + write[0] = (FT_Byte)( write[0] | *p++ ); + write += 1; + } + + if ( w > 0 ) + write[0] = (FT_Byte)( write[0] | ( *p++ & ( 0xFF00U >> w ) ) ); + } + } + else /* x_pos > 0 */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + FT_UInt wval = 0; + + + for ( w = width; w >= 8; w -= 8 ) + { + wval = (FT_UInt)( wval | *p++ ); + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + write += 1; + wval <<= 8; + } + + if ( w > 0 ) + wval = (FT_UInt)( wval | ( *p++ & ( 0xFF00U >> w ) ) ); + + /* all bits read and there are ( x_pos + w ) bits to be written */ + + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + + if ( x_pos + w > 8 ) + { + write++; + wval <<= 8; + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + } + } + } + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h, nbits; + FT_Bitmap* bitmap; + FT_UShort rval; + + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( p + ( ( width * height + 7 ) >> 3 ) > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + /* the higher byte of `rval' is used as a buffer */ + rval = 0; + nbits = 0; + + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w = width; + + + if ( x_pos ) + { + w = ( width < 8 - x_pos ) ? width : 8 - x_pos; + + if ( nbits < w ) + { + rval |= *p++; + nbits += 8 - w; + } + else + { + rval >>= 8; + nbits -= w; + } + + *write++ |= ( ( rval >> nbits ) & 0xFF ) & ~( 0xFF << w ); + rval <<= 8; + + w = width - w; + } + + for ( ; w >= 8; w -= 8 ) + { + rval |= *p++; + *write++ |= ( rval >> nbits ) & 0xFF; + + rval <<= 8; + } + + if ( w > 0 ) + { + if ( nbits < w ) + { + rval |= *p++; + *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits += 8 - w; + + rval <<= 8; + } + else + { + *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits -= w; + } + } + } + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt num_components, nn; + + + if ( p + 2 > limit ) + goto Fail; + + num_components = FT_NEXT_USHORT( p ); + if ( p + 4 * num_components > limit ) + goto Fail; + + for ( nn = 0; nn < num_components; nn++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + FT_Byte dx = FT_NEXT_BYTE( p ); + FT_Byte dy = FT_NEXT_BYTE( p ); + + + /* NB: a recursive call */ + error = tt_sbit_decoder_load_image( decoder, gindex, + x_pos + dx, y_pos + dy ); + if ( error ) + break; + } + + Exit: + return error; + + Fail: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + + static FT_Error + tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, + FT_UInt glyph_format, + FT_ULong glyph_start, + FT_ULong glyph_size, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error; + FT_Stream stream = decoder->stream; + FT_Byte* p; + FT_Byte* p_limit; + FT_Byte* data; + + + /* seek into the EBDT table now */ + if ( glyph_start + glyph_size > decoder->ebdt_size ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + + if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || + FT_FRAME_EXTRACT( glyph_size, data ) ) + goto Exit; + + p = data; + p_limit = p + glyph_size; + + /* read the data, depending on the glyph format */ + switch ( glyph_format ) + { + case 1: + case 2: + case 8: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); + break; + + case 6: + case 7: + case 9: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); + break; + + default: + error = SFNT_Err_Ok; + } + + if ( error ) + goto Fail; + + { + TT_SBitDecoder_LoadFunc loader; + + + switch ( glyph_format ) + { + case 1: + case 6: + loader = tt_sbit_decoder_load_byte_aligned; + break; + + case 2: + case 5: + case 7: + loader = tt_sbit_decoder_load_bit_aligned; + break; + + case 8: + if ( p + 1 > p_limit ) + goto Fail; + + p += 1; /* skip padding */ + /* fall-through */ + + case 9: + loader = tt_sbit_decoder_load_compound; + break; + + default: + goto Fail; + } + + error = loader( decoder, p, p_limit, x_pos, y_pos ); + } + + Fail: + FT_FRAME_RELEASE( data ); + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ) + { + /* + * First, we find the correct strike range that applies to this + * glyph index. + */ + + FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; + FT_Byte* p_limit = decoder->eblc_limit; + FT_ULong num_ranges = decoder->strike_index_count; + FT_UInt start, end, index_format, image_format; + FT_ULong image_start = 0, image_end = 0, image_offset; + + + for ( ; num_ranges > 0; num_ranges-- ) + { + start = FT_NEXT_USHORT( p ); + end = FT_NEXT_USHORT( p ); + + if ( glyph_index >= start && glyph_index <= end ) + goto FoundRange; + + p += 4; /* ignore index offset */ + } + goto NoBitmap; + + FoundRange: + image_offset = FT_NEXT_ULONG( p ); + + /* overflow check */ + if ( decoder->eblc_base + decoder->strike_index_array + image_offset < + decoder->eblc_base ) + goto Failure; + + p = decoder->eblc_base + decoder->strike_index_array + image_offset; + if ( p + 8 > p_limit ) + goto NoBitmap; + + /* now find the glyph's location and extend within the ebdt table */ + index_format = FT_NEXT_USHORT( p ); + image_format = FT_NEXT_USHORT( p ); + image_offset = FT_NEXT_ULONG ( p ); + + switch ( index_format ) + { + case 1: /* 4-byte offsets relative to `image_offset' */ + { + p += 4 * ( glyph_index - start ); + if ( p + 8 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_ULONG( p ); + image_end = FT_NEXT_ULONG( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + } + break; + + case 2: /* big metrics, constant image size */ + { + FT_ULong image_size; + + + if ( p + 12 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + image_start = image_size * ( glyph_index - start ); + image_end = image_start + image_size; + } + break; + + case 3: /* 2-byte offsets relative to 'image_offset' */ + { + p += 2 * ( glyph_index - start ); + if ( p + 4 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_USHORT( p ); + image_end = FT_NEXT_USHORT( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + } + break; + + case 4: /* sparse glyph array with (glyph,offset) pairs */ + { + FT_ULong mm, num_glyphs; + + + if ( p + 4 > p_limit ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check */ + if ( p + ( num_glyphs + 1 ) * 4 < p ) + goto Failure; + + if ( p + ( num_glyphs + 1 ) * 4 > p_limit ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + { + image_start = FT_NEXT_USHORT( p ); + p += 2; + image_end = FT_PEEK_USHORT( p ); + break; + } + p += 2; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + } + break; + + case 5: /* constant metrics with sparse glyph codes */ + { + FT_ULong image_size, mm, num_glyphs; + + + if ( p + 16 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check */ + if ( p + 2 * num_glyphs < p ) + goto Failure; + + if ( p + 2 * num_glyphs > p_limit ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + break; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + + image_start = image_size * mm; + image_end = image_start + image_size; + } + break; + + default: + goto NoBitmap; + } + + if ( image_start > image_end ) + goto NoBitmap; + + image_end -= image_start; + image_start = image_offset + image_start; + + return tt_sbit_decoder_load_bitmap( decoder, + image_format, + image_start, + image_end, + x_pos, + y_pos ); + + Failure: + return SFNT_Err_Invalid_Table; + + NoBitmap: + return SFNT_Err_Invalid_Argument; + } + + + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + TT_SBitDecoderRec decoder[1]; + FT_Error error; + + FT_UNUSED( load_flags ); + FT_UNUSED( stream ); + FT_UNUSED( map ); + + + error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); + if ( !error ) + { + error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 ); + tt_sbit_decoder_done( decoder ); + } + + return error; + } + +/* EOF */ diff --git a/src/freetype2/sfnt/ttsbit0.h b/src/freetype2/sfnt/ttsbit0.h new file mode 100644 index 0000000..396ddc5 --- /dev/null +++ b/src/freetype2/sfnt/ttsbit0.h @@ -0,0 +1,7 @@ +/* + * ttsbit0.h + * + * This is a dummy file, used to please the build system. It is never + * included by the sfnt sources. + * + */ diff --git a/src/freetype2/smooth/ftgrays.c b/src/freetype2/smooth/ftgrays.c new file mode 100644 index 0000000..5a4a544 --- /dev/null +++ b/src/freetype2/smooth/ftgrays.c @@ -0,0 +1,1983 @@ +/***************************************************************************/ +/* */ +/* ftgrays.c */ +/* */ +/* A new `perfect' anti-aliasing renderer (body). */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file can be compiled without the rest of the FreeType engine, by */ + /* defining the _STANDALONE_ macro when compiling it. You also need to */ + /* put the files `ftgrays.h' and `ftimage.h' into the current */ + /* compilation directory. Typically, you could do something like */ + /* */ + /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */ + /* */ + /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */ + /* same directory */ + /* */ + /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ + /* */ + /* cc -c -D_STANDALONE_ ftgrays.c */ + /* */ + /* The renderer can be initialized with a call to */ + /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */ + /* with a call to `ft_gray_raster.raster_render'. */ + /* */ + /* See the comments and documentation in the file `ftimage.h' for more */ + /* details on how the raster works. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* This is a new anti-aliasing scan-converter for FreeType 2. The */ + /* algorithm used here is _very_ different from the one in the standard */ + /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ + /* coverage of the outline on each pixel cell. */ + /* */ + /* It is based on ideas that I initially found in Raph Levien's */ + /* excellent LibArt graphics library (see http://www.levien.com/libart */ + /* for more information, though the web pages do not tell anything */ + /* about the renderer; you'll have to dive into the source code to */ + /* understand how it works). */ + /* */ + /* Note, however, that this is a _very_ different implementation */ + /* compared to Raph's. Coverage information is stored in a very */ + /* different way, and I don't use sorted vector paths. Also, it doesn't */ + /* use floating point values. */ + /* */ + /* This renderer has the following advantages: */ + /* */ + /* - It doesn't need an intermediate bitmap. Instead, one can supply a */ + /* callback function that will be called by the renderer to draw gray */ + /* spans on any target surface. You can thus do direct composition on */ + /* any kind of bitmap, provided that you give the renderer the right */ + /* callback. */ + /* */ + /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ + /* each pixel cell. */ + /* */ + /* - It performs a single pass on the outline (the `standard' FT2 */ + /* renderer makes two passes). */ + /* */ + /* - It can easily be modified to render to _any_ number of gray levels */ + /* cheaply. */ + /* */ + /* - For small (< 20) pixel sizes, it is faster than the standard */ + /* renderer. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* 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_smooth + + + + +#ifdef _STANDALONE_ + +#include <string.h> /* for ft_memcpy() */ +#include <setjmp.h> +#include <limits.h> +#define FT_UINT_MAX UINT_MAX + +#define ft_memset memset + +#define ft_setjmp setjmp +#define ft_longjmp longjmp +#define ft_jmp_buf jmp_buf + + +#define ErrRaster_Invalid_Mode -2 +#define ErrRaster_Invalid_Outline -1 +#define ErrRaster_Invalid_Argument -3 +#define ErrRaster_Memory_Overflow -4 + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#include "ftimage.h" +#include "ftgrays.h" + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these two macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ +#endif + +#else /* !_STANDALONE_ */ + +#include <ft2build.h> +#include "ftgrays.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_OUTLINE_H + +#include "ftsmerrs.h" + +#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph +#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline +#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory +#define ErrRaster_Invalid_Argument Smooth_Err_Bad_Argument + +#endif /* !_STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + + /* define this to dump debugging information */ +#define xxxDEBUG_GRAYS + + + /* as usual, for the speed hungry :-) */ + +#ifndef FT_STATIC_RASTER + + +#define RAS_ARG PWorker worker +#define RAS_ARG_ PWorker worker, + +#define RAS_VAR worker +#define RAS_VAR_ worker, + +#define ras (*worker) + + +#else /* FT_STATIC_RASTER */ + + +#define RAS_ARG /* empty */ +#define RAS_ARG_ /* empty */ +#define RAS_VAR /* empty */ +#define RAS_VAR_ /* empty */ + + static TWorker ras; + + +#endif /* FT_STATIC_RASTER */ + + + /* must be at least 6 bits! */ +#define PIXEL_BITS 8 + +#define ONE_PIXEL ( 1L << PIXEL_BITS ) +#define PIXEL_MASK ( -1L << PIXEL_BITS ) +#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) +#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) +#define FLOOR( x ) ( (x) & -ONE_PIXEL ) +#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) +#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) +#endif + + + /*************************************************************************/ + /* */ + /* TYPE DEFINITIONS */ + /* */ + + /* don't change the following types to FT_Int or FT_Pos, since we might */ + /* need to define them to "float" or "double" when experimenting with */ + /* new algorithms */ + + typedef int TCoord; /* integer scanline/pixel coordinate */ + typedef long TPos; /* sub-pixel coordinate */ + + /* determine the type used to store cell areas. This normally takes at */ + /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ + /* `long' instead of `int', otherwise bad things happen */ + +#if PIXEL_BITS <= 7 + + typedef int TArea; + +#else /* PIXEL_BITS >= 8 */ + + /* approximately determine the size of integers using an ANSI-C header */ +#if FT_UINT_MAX == 0xFFFFU + typedef long TArea; +#else + typedef int TArea; +#endif + +#endif /* PIXEL_BITS >= 8 */ + + + /* maximal number of gray spans in a call to the span callback */ +#define FT_MAX_GRAY_SPANS 32 + + + typedef struct TCell_* PCell; + + typedef struct TCell_ + { + int x; + int cover; + TArea area; + PCell next; + + } TCell; + + + typedef struct TWorker_ + { + TCoord ex, ey; + TPos min_ex, max_ex; + TPos min_ey, max_ey; + TPos count_ex, count_ey; + + TArea area; + int cover; + int invalid; + + PCell cells; + int max_cells; + int num_cells; + + TCoord cx, cy; + TPos x, y; + + TPos last_ey; + + FT_Vector bez_stack[32 * 3 + 1]; + int lev_stack[32]; + + FT_Outline outline; + FT_Bitmap target; + FT_BBox clip_box; + + FT_Span gray_spans[FT_MAX_GRAY_SPANS]; + int num_gray_spans; + + FT_Raster_Span_Func render_span; + void* render_span_data; + int span_y; + + int band_size; + int band_shoot; + int conic_level; + int cubic_level; + + ft_jmp_buf jump_buffer; + + void* buffer; + long buffer_size; + + PCell* ycells; + int ycount; + + } TWorker, *PWorker; + + + typedef struct TRaster_ + { + void* buffer; + long buffer_size; + int band_size; + void* memory; + PWorker worker; + + } TRaster, *PRaster; + + + + /*************************************************************************/ + /* */ + /* Initialize the cells table. */ + /* */ + static void + gray_init_cells( RAS_ARG_ void* buffer, + long byte_size ) + { + ras.buffer = buffer; + ras.buffer_size = byte_size; + + ras.ycells = (PCell*) buffer; + ras.cells = NULL; + ras.max_cells = 0; + ras.num_cells = 0; + ras.area = 0; + ras.cover = 0; + ras.invalid = 1; + } + + + /*************************************************************************/ + /* */ + /* Compute the outline bounding box. */ + /* */ + static void + gray_compute_cbox( RAS_ARG ) + { + FT_Outline* outline = &ras.outline; + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + if ( outline->n_points <= 0 ) + { + ras.min_ex = ras.max_ex = 0; + ras.min_ey = ras.max_ey = 0; + return; + } + + ras.min_ex = ras.max_ex = vec->x; + ras.min_ey = ras.max_ey = vec->y; + + vec++; + + for ( ; vec < limit; vec++ ) + { + TPos x = vec->x; + TPos y = vec->y; + + + if ( x < ras.min_ex ) ras.min_ex = x; + if ( x > ras.max_ex ) ras.max_ex = x; + if ( y < ras.min_ey ) ras.min_ey = y; + if ( y > ras.max_ey ) ras.max_ey = y; + } + + /* truncate the bounding box to integer pixels */ + ras.min_ex = ras.min_ex >> 6; + ras.min_ey = ras.min_ey >> 6; + ras.max_ex = ( ras.max_ex + 63 ) >> 6; + ras.max_ey = ( ras.max_ey + 63 ) >> 6; + } + + + /*************************************************************************/ + /* */ + /* Record the current cell in the table. */ + /* */ + static PCell + gray_find_cell( RAS_ARG ) + { + PCell *pcell, cell; + int x = ras.ex; + + + if ( x > ras.max_ex ) + x = ras.max_ex; + + pcell = &ras.ycells[ras.ey]; + for (;;) + { + cell = *pcell; + if ( cell == NULL || cell->x > x ) + break; + + if ( cell->x == x ) + goto Exit; + + pcell = &cell->next; + } + + if ( ras.num_cells >= ras.max_cells ) + ft_longjmp( ras.jump_buffer, 1 ); + + cell = ras.cells + ras.num_cells++; + cell->x = x; + cell->area = 0; + cell->cover = 0; + + cell->next = *pcell; + *pcell = cell; + + Exit: + return cell; + } + + + static void + gray_record_cell( RAS_ARG ) + { + if ( !ras.invalid && ( ras.area | ras.cover ) ) + { + PCell cell = gray_find_cell( RAS_VAR ); + + + cell->area += ras.area; + cell->cover += ras.cover; + } + } + + + /*************************************************************************/ + /* */ + /* Set the current cell to a new position. */ + /* */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + /* Move the cell pointer to a new position. We set the `invalid' */ + /* flag to indicate that the cell isn't part of those we're interested */ + /* in during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + /* All cells that are on the left of the clipping region go to the */ + /* min_ex - 1 horizontal position. */ + ey -= ras.min_ey; + + if ( ex > ras.max_ex ) + ex = ras.max_ex; + + ex -= ras.min_ex; + if ( ex < 0 ) + ex = -1; + + /* are we moving to a different cell ? */ + if ( ex != ras.ex || ey != ras.ey ) + { + /* record the current one if it is valid */ + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + + ras.area = 0; + ras.cover = 0; + } + + ras.ex = ex; + ras.ey = ey; + ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || + ex >= ras.count_ex ); + } + + + /*************************************************************************/ + /* */ + /* Start a new contour at a given cell. */ + /* */ + static void + gray_start_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + if ( ex > ras.max_ex ) + ex = (TCoord)( ras.max_ex ); + + if ( ex < ras.min_ex ) + ex = (TCoord)( ras.min_ex - 1 ); + + ras.area = 0; + ras.cover = 0; + ras.ex = ex - ras.min_ex; + ras.ey = ey - ras.min_ey; + ras.last_ey = SUBPIXELS( ey ); + ras.invalid = 0; + + gray_set_cell( RAS_VAR_ ex, ey ); + } + + + /*************************************************************************/ + /* */ + /* Render a scanline as one or more cells. */ + /* */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, delta; + long p, first, dx; + int incr, lift, mod, rem; + + + dx = x2 - x1; + + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); + fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + { + delta = y2 - y1; + ras.area += (TArea)( fx1 + fx2 ) * delta; + ras.cover += delta; + return; + } + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); + first = ONE_PIXEL; + incr = 1; + + if ( dx < 0 ) + { + p = fx1 * ( y2 - y1 ); + first = 0; + incr = -1; + dx = -dx; + } + + delta = (TCoord)( p / dx ); + mod = (TCoord)( p % dx ); + if ( mod < 0 ) + { + delta--; + mod += (TCoord)dx; + } + + ras.area += (TArea)( fx1 + first ) * delta; + ras.cover += delta; + + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + y1 += delta; + + if ( ex1 != ex2 ) + { + p = ONE_PIXEL * ( y2 - y1 + delta ); + lift = (TCoord)( p / dx ); + rem = (TCoord)( p % dx ); + if ( rem < 0 ) + { + lift--; + rem += (TCoord)dx; + } + + mod -= (int)dx; + + while ( ex1 != ex2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (TCoord)dx; + delta++; + } + + ras.area += (TArea)ONE_PIXEL * delta; + ras.cover += delta; + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } + } + + delta = y2 - y1; + ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta; + ras.cover += delta; + } + + + /*************************************************************************/ + /* */ + /* Render a given line as a series of scanlines. */ + /* */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2; + TPos dx, dy, x, x2; + long p, first; + int delta, rem, mod, lift, incr; + + + ey1 = TRUNC( ras.last_ey ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + fy1 = (TCoord)( ras.y - ras.last_ey ); + fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* XXX: we should do something about the trivial case where dx == 0, */ + /* as it happens very often! */ + + /* perform vertical clipping */ + { + TCoord min, max; + + + min = ey1; + max = ey2; + if ( ey1 > ey2 ) + { + min = ey2; + max = ey1; + } + if ( min >= ras.max_ey || max < ras.min_ey ) + goto End; + } + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } + + /* vertical line - avoid calling gray_render_scanline */ + incr = 1; + + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); + TPos area; + + + first = ONE_PIXEL; + if ( dy < 0 ) + { + first = 0; + incr = -1; + } + + delta = (int)( first - fy1 ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + ey1 += incr; + + gray_set_cell( &ras, ex, ey1 ); + + delta = (int)( first + first - ONE_PIXEL ); + area = (TArea)two_fx * delta; + while ( ey1 != ey2 ) + { + ras.area += area; + ras.cover += delta; + ey1 += incr; + + gray_set_cell( &ras, ex, ey1 ); + } + + delta = (int)( fy2 - ONE_PIXEL + first ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + + goto End; + } + + /* ok, we have to render several scanlines */ + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + + if ( dy < 0 ) + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + delta = (int)( p / dy ); + mod = (int)( p % dy ); + if ( mod < 0 ) + { + delta--; + mod += (TCoord)dy; + } + + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + + if ( ey1 != ey2 ) + { + p = ONE_PIXEL * dx; + lift = (int)( p / dy ); + rem = (int)( p % dy ); + if ( rem < 0 ) + { + lift--; + rem += (int)dy; + } + mod -= (int)dy; + + while ( ey1 != ey2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (int)dy; + delta++; + } + + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), x2, + (TCoord)first ); + x = x2; + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } + } + + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), to_x, + fy2 ); + + End: + ras.x = to_x; + ras.y = to_y; + ras.last_ey = SUBPIXELS( ey2 ); + } + + + static void + gray_split_conic( FT_Vector* base ) + { + TPos a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + TPos dx, dy; + int top, level; + int* levels; + FT_Vector* arc; + + + dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + + level = 1; + dx = dx / ras.conic_level; + while ( dx > 0 ) + { + dx >>= 2; + level++; + } + + /* a shortcut to speed things up */ + if ( level <= 1 ) + { + /* we compute the mid-point directly in order to avoid */ + /* calling gray_split_conic() */ + TPos to_x, to_y, mid_x, mid_y; + + + to_x = UPSCALE( to->x ); + to_y = UPSCALE( to->y ); + mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4; + mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4; + + gray_render_line( RAS_VAR_ mid_x, mid_y ); + gray_render_line( RAS_VAR_ to_x, to_y ); + + return; + } + + arc = ras.bez_stack; + levels = ras.lev_stack; + top = 0; + levels[0] = level; + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + + while ( top >= 0 ) + { + level = levels[top]; + if ( level > 1 ) + { + /* check that the arc crosses the current band */ + TPos min, max, y; + + + min = max = arc[0].y; + + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) + goto Draw; + + gray_split_conic( arc ); + arc += 2; + top++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + + Draw: + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = arc[0].x; + to_y = arc[0].y; + mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4; + mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4; + + gray_render_line( RAS_VAR_ mid_x, mid_y ); + gray_render_line( RAS_VAR_ to_x, to_y ); + + top--; + arc -= 2; + } + } + + return; + } + + + static void + gray_split_cubic( FT_Vector* base ) + { + TPos a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + + + static void + gray_render_cubic( RAS_ARG_ const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to ) + { + TPos dx, dy, da, db; + int top, level; + int* levels; + FT_Vector* arc; + + + dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + da = dx; + + dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x ); + if ( dx < 0 ) + dx = -dx; + dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y ); + if ( dy < 0 ) + dy = -dy; + if ( dx < dy ) + dx = dy; + db = dx; + + level = 1; + da = da / ras.cubic_level; + db = db / ras.conic_level; + while ( da > 0 || db > 0 ) + { + da >>= 2; + db >>= 3; + level++; + } + + if ( level <= 1 ) + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = UPSCALE( to->x ); + to_y = UPSCALE( to->y ); + mid_x = ( ras.x + to_x + + 3 * UPSCALE( control1->x + control2->x ) ) / 8; + mid_y = ( ras.y + to_y + + 3 * UPSCALE( control1->y + control2->y ) ) / 8; + + gray_render_line( RAS_VAR_ mid_x, mid_y ); + gray_render_line( RAS_VAR_ to_x, to_y ); + return; + } + + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; + + levels = ras.lev_stack; + top = 0; + levels[0] = level; + + while ( top >= 0 ) + { + level = levels[top]; + if ( level > 1 ) + { + /* check that the arc crosses the current band */ + TPos min, max, y; + + + min = max = arc[0].y; + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + y = arc[3].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) + goto Draw; + gray_split_cubic( arc ); + arc += 3; + top ++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + + Draw: + { + TPos to_x, to_y, mid_x, mid_y; + + + to_x = arc[0].x; + to_y = arc[0].y; + mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8; + mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8; + + gray_render_line( RAS_VAR_ mid_x, mid_y ); + gray_render_line( RAS_VAR_ to_x, to_y ); + top --; + arc -= 3; + } + } + + return; + } + + + + static int + gray_move_to( const FT_Vector* to, + PWorker worker ) + { + TPos x, y; + + + /* record current cell, if any */ + gray_record_cell( worker ); + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + + gray_start_cell( worker, TRUNC( x ), TRUNC( y ) ); + + worker->x = x; + worker->y = y; + return 0; + } + + + static int + gray_line_to( const FT_Vector* to, + PWorker worker ) + { + gray_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) ); + return 0; + } + + + static int + gray_conic_to( const FT_Vector* control, + const FT_Vector* to, + PWorker worker ) + { + gray_render_conic( worker, control, to ); + return 0; + } + + + static int + gray_cubic_to( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + PWorker worker ) + { + gray_render_cubic( worker, control1, control2, to ); + return 0; + } + + + static void + gray_render_span( int y, + int count, + const FT_Span* spans, + PWorker worker ) + { + unsigned char* p; + FT_Bitmap* map = &worker->target; + + + /* first of all, compute the scanline offset */ + p = (unsigned char*)map->buffer - y * map->pitch; + if ( map->pitch >= 0 ) + p += ( map->rows - 1 ) * map->pitch; + + for ( ; count > 0; count--, spans++ ) + { + unsigned char coverage = spans->coverage; + + + if ( coverage ) + { + /* For small-spans it is faster to do it by ourselves than + * calling `memset'. This is mainly due to the cost of the + * function call. + */ + if ( spans->len >= 8 ) + FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); + else + { + unsigned char* q = p + spans->x; + + + switch ( spans->len ) + { + case 7: *q++ = (unsigned char)coverage; + case 6: *q++ = (unsigned char)coverage; + case 5: *q++ = (unsigned char)coverage; + case 4: *q++ = (unsigned char)coverage; + case 3: *q++ = (unsigned char)coverage; + case 2: *q++ = (unsigned char)coverage; + case 1: *q = (unsigned char)coverage; + default: + ; + } + } + } + } + } + + + static void + gray_hline( RAS_ARG_ TCoord x, + TCoord y, + TPos area, + int acount ) + { + FT_Span* span; + int count; + int coverage; + + + /* compute the coverage line's coverage, depending on the */ + /* outline fill rule */ + /* */ + /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ + /* */ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); + /* use range 0..256 */ + if ( coverage < 0 ) + coverage = -coverage; + + if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) + { + coverage &= 511; + + if ( coverage > 256 ) + coverage = 512 - coverage; + else if ( coverage == 256 ) + coverage = 255; + } + else + { + /* normal non-zero winding rule */ + if ( coverage >= 256 ) + coverage = 255; + } + + y += (TCoord)ras.min_ey; + x += (TCoord)ras.min_ex; + + /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ + if ( x >= 32768 ) + x = 32767; + + if ( coverage ) + { + /* see whether we can add this span to the current list */ + count = ras.num_gray_spans; + span = ras.gray_spans + count - 1; + if ( count > 0 && + ras.span_y == y && + (int)span->x + span->len == (int)x && + span->coverage == coverage ) + { + span->len = (unsigned short)( span->len + acount ); + return; + } + + if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) + { + if ( ras.render_span && count > 0 ) + ras.render_span( ras.span_y, count, ras.gray_spans, + ras.render_span_data ); + /* ras.render_span( span->y, ras.gray_spans, count ); */ + +#ifdef DEBUG_GRAYS + + if ( ras.span_y >= 0 ) + { + int n; + + + fprintf( stderr, "y=%3d ", ras.span_y ); + span = ras.gray_spans; + for ( n = 0; n < count; n++, span++ ) + fprintf( stderr, "[%d..%d]:%02x ", + span->x, span->x + span->len - 1, span->coverage ); + fprintf( stderr, "\n" ); + } + +#endif /* DEBUG_GRAYS */ + + ras.num_gray_spans = 0; + ras.span_y = y; + + count = 0; + span = ras.gray_spans; + } + else + span++; + + /* add a gray span to the current list */ + span->x = (short)x; + span->len = (unsigned short)acount; + span->coverage = (unsigned char)coverage; + + ras.num_gray_spans++; + } + } + + +#ifdef DEBUG_GRAYS + + /* to be called while in the debugger */ + gray_dump_cells( RAS_ARG ) + { + int yindex; + + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + { + PCell cell; + + + printf( "%3d:", yindex ); + + for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next ) + printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area ); + printf( "\n" ); + } + } + +#endif /* DEBUG_GRAYS */ + + + static void + gray_sweep( RAS_ARG_ const FT_Bitmap* target ) + { + int yindex; + + FT_UNUSED( target ); + + + if ( ras.num_cells == 0 ) + return; + + ras.num_gray_spans = 0; + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + { + PCell cell = ras.ycells[yindex]; + TCoord cover = 0; + TCoord x = 0; + + + for ( ; cell != NULL; cell = cell->next ) + { + TArea area; + + + if ( cell->x > x && cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + cell->x - x ); + + cover += cell->cover; + area = cover * ( ONE_PIXEL * 2 ) - cell->area; + + if ( area != 0 && cell->x >= 0 ) + gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); + + x = cell->x + 1; + } + + if ( cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + ras.count_ex - x ); + } + + if ( ras.render_span && ras.num_gray_spans > 0 ) + ras.render_span( ras.span_y, ras.num_gray_spans, + ras.gray_spans, ras.render_span_data ); + } + + +#ifdef _STANDALONE_ + + /*************************************************************************/ + /* */ + /* The following function should only compile in stand_alone mode, */ + /* i.e., when building this component without the rest of FreeType. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Decompose */ + /* */ + /* <Description> */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bezier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source target. */ + /* */ + /* func_interface :: A table of `emitters', i.e,. function pointers */ + /* called during decomposition to indicate path */ + /* operations. */ + /* */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + static + int FT_Outline_Decompose( const FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#if 0 +#define SCALED( x ) ( ( (x) << shift ) - delta ) +#else +#define SCALED( x ) (x) +#endif + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int error; + char tag; /* current point's state */ + +#if 0 + int shift = func_interface->shift; + TPos delta = func_interface->delta; +#endif + + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + int last; /* index of last point in contour */ + + + last = outline->contours[n]; + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + { + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + error = func_interface->conic_to( &v_control, &vec, + user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = func_interface->conic_to( &v_control, &v_middle, + user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = func_interface->conic_to( &v_control, &v_start, + user ); + goto Close; + } + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return ErrRaster_Invalid_Outline; + } + +#endif /* _STANDALONE_ */ + + + typedef struct TBand_ + { + TPos min, max; + + } TBand; + + + static int + gray_convert_glyph_inner( RAS_ARG ) + { + static + const FT_Outline_Funcs func_interface = + { + (FT_Outline_MoveTo_Func) gray_move_to, + (FT_Outline_LineTo_Func) gray_line_to, + (FT_Outline_ConicTo_Func)gray_conic_to, + (FT_Outline_CubicTo_Func)gray_cubic_to, + 0, + 0 + }; + + volatile int error = 0; + + if ( ft_setjmp( ras.jump_buffer ) == 0 ) + { + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + gray_record_cell( RAS_VAR ); + } + else + { + error = ErrRaster_Memory_Overflow; + } + + return error; + } + + + static int + gray_convert_glyph( RAS_ARG ) + { + TBand bands[40]; + TBand* volatile band; + int volatile n, num_bands; + TPos volatile min, max, max_y; + FT_BBox* clip; + + + /* Set up state in the raster object */ + gray_compute_cbox( RAS_VAR ); + + /* clip to target bitmap, exit if nothing to do */ + clip = &ras.clip_box; + + if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || + ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) + return 0; + + if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; + if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; + + if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; + if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; + + ras.count_ex = ras.max_ex - ras.min_ex; + ras.count_ey = ras.max_ey - ras.min_ey; + + /* simple heuristic used to speed-up the bezier decomposition -- see */ + /* the code in gray_render_conic() and gray_render_cubic() for more */ + /* details */ + ras.conic_level = 32; + ras.cubic_level = 16; + + { + int level = 0; + + + if ( ras.count_ex > 24 || ras.count_ey > 24 ) + level++; + if ( ras.count_ex > 120 || ras.count_ey > 120 ) + level++; + + ras.conic_level <<= level; + ras.cubic_level <<= level; + } + + /* setup vertical bands */ + num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); + if ( num_bands == 0 ) num_bands = 1; + if ( num_bands >= 39 ) num_bands = 39; + + ras.band_shoot = 0; + + min = ras.min_ey; + max_y = ras.max_ey; + + for ( n = 0; n < num_bands; n++, min = max ) + { + max = min + ras.band_size; + if ( n == num_bands - 1 || max > max_y ) + max = max_y; + + bands[0].min = min; + bands[0].max = max; + band = bands; + + while ( band >= bands ) + { + TPos bottom, top, middle; + int error; + + { + PCell cells_max; + int yindex; + long cell_start, cell_end, cell_mod; + + + ras.ycells = (PCell*)ras.buffer; + ras.ycount = band->max - band->min; + + cell_start = sizeof ( PCell ) * ras.ycount; + cell_mod = cell_start % sizeof ( TCell ); + if ( cell_mod > 0 ) + cell_start += sizeof ( TCell ) - cell_mod; + + cell_end = ras.buffer_size; + cell_end -= cell_end % sizeof( TCell ); + + cells_max = (PCell)( (char*)ras.buffer + cell_end ); + ras.cells = (PCell)( (char*)ras.buffer + cell_start ); + if ( ras.cells >= cells_max ) + goto ReduceBands; + + ras.max_cells = cells_max - ras.cells; + if ( ras.max_cells < 2 ) + goto ReduceBands; + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + ras.ycells[yindex] = NULL; + } + + ras.num_cells = 0; + ras.invalid = 1; + ras.min_ey = band->min; + ras.max_ey = band->max; + ras.count_ey = band->max - band->min; + + error = gray_convert_glyph_inner( RAS_VAR ); + + if ( !error ) + { + gray_sweep( RAS_VAR_ &ras.target ); + band--; + continue; + } + else if ( error != ErrRaster_Memory_Overflow ) + return 1; + + ReduceBands: + /* render pool overflow; we will reduce the render band by half */ + bottom = band->min; + top = band->max; + middle = bottom + ( ( top - bottom ) >> 1 ); + + /* This is too complex for a single scanline; there must */ + /* be some problems. */ + if ( middle == bottom ) + { +#ifdef DEBUG_GRAYS + fprintf( stderr, "Rotten glyph!\n" ); +#endif + return 1; + } + + if ( bottom-top >= ras.band_size ) + ras.band_shoot++; + + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + band++; + } + } + + if ( ras.band_shoot > 8 && ras.band_size > 16 ) + ras.band_size = ras.band_size / 2; + + return 0; + } + + + static int + gray_raster_render( PRaster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + PWorker worker; + + + if ( !raster || !raster->buffer || !raster->buffer_size ) + return ErrRaster_Invalid_Argument; + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return 0; + + if ( !outline || !outline->contours || !outline->points ) + return ErrRaster_Invalid_Outline; + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return ErrRaster_Invalid_Outline; + + worker = raster->worker; + + /* if direct mode is not set, we must have a target bitmap */ + if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 ) + { + if ( !target_map ) + return ErrRaster_Invalid_Argument; + + /* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return 0; + + if ( !target_map->buffer ) + return ErrRaster_Invalid_Argument; + } + + /* this version does not support monochrome rendering */ + if ( !( params->flags & FT_RASTER_FLAG_AA ) ) + return ErrRaster_Invalid_Mode; + + /* compute clipping box */ + if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 ) + { + /* compute clip box from target pixmap */ + ras.clip_box.xMin = 0; + ras.clip_box.yMin = 0; + ras.clip_box.xMax = target_map->width; + ras.clip_box.yMax = target_map->rows; + } + else if ( params->flags & FT_RASTER_FLAG_CLIP ) + { + ras.clip_box = params->clip_box; + } + else + { + ras.clip_box.xMin = -32768L; + ras.clip_box.yMin = -32768L; + ras.clip_box.xMax = 32767L; + ras.clip_box.yMax = 32767L; + } + + gray_init_cells( worker, raster->buffer, raster->buffer_size ); + + ras.outline = *outline; + ras.num_cells = 0; + ras.invalid = 1; + ras.band_size = raster->band_size; + ras.num_gray_spans = 0; + + if ( target_map ) + ras.target = *target_map; + + ras.render_span = (FT_Raster_Span_Func)gray_render_span; + ras.render_span_data = &ras; + + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + { + ras.render_span = (FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + } + + return gray_convert_glyph( worker ); + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + +#ifdef _STANDALONE_ + + static int + gray_raster_new( void* memory, + FT_Raster* araster ) + { + static TRaster the_raster; + + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); + + return 0; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + +#else /* _STANDALONE_ */ + + static int + gray_raster_new( FT_Memory memory, + FT_Raster* araster ) + { + FT_Error error; + PRaster raster; + + + *araster = 0; + if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) ) + { + raster->memory = memory; + *araster = (FT_Raster)raster; + } + + return error; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; + + + FT_FREE( raster ); + } + +#endif /* _STANDALONE_ */ + + + static void + gray_raster_reset( FT_Raster raster, + char* pool_base, + long pool_size ) + { + PRaster rast = (PRaster)raster; + + + if ( raster ) + { + if ( pool_base && pool_size >= (long)sizeof ( TWorker ) + 2048 ) + { + PWorker worker = (PWorker)pool_base; + + + rast->worker = worker; + rast->buffer = pool_base + + ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) & + ~( sizeof ( TCell ) - 1 ) ); + rast->buffer_size = (long)( ( pool_base + pool_size ) - + (char*)rast->buffer ) & + ~( sizeof ( TCell ) - 1 ); + rast->band_size = (int)( rast->buffer_size / + ( sizeof ( TCell ) * 8 ) ); + } + else + { + rast->buffer = NULL; + rast->buffer_size = 0; + rast->worker = NULL; + } + } + } + + + const FT_Raster_Funcs ft_grays_raster = + { + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) gray_raster_new, + (FT_Raster_Reset_Func) gray_raster_reset, + (FT_Raster_Set_Mode_Func)0, + (FT_Raster_Render_Func) gray_raster_render, + (FT_Raster_Done_Func) gray_raster_done + }; + + +/* END */ diff --git a/src/freetype2/smooth/ftgrays.h b/src/freetype2/smooth/ftgrays.h new file mode 100644 index 0000000..2d40954 --- /dev/null +++ b/src/freetype2/smooth/ftgrays.h @@ -0,0 +1,57 @@ +/***************************************************************************/ +/* */ +/* ftgrays.h */ +/* */ +/* FreeType smooth renderer declaration */ +/* */ +/* Copyright 1996-2001 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 __FTGRAYS_H__ +#define __FTGRAYS_H__ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifdef _STANDALONE_ +#include "ftimage.h" +#else +#include <ft2build.h> +#include FT_IMAGE_H +#endif + + + /*************************************************************************/ + /* */ + /* To make ftgrays.h independent from configuration files we check */ + /* whether FT_EXPORT_VAR has been defined already. */ + /* */ + /* On some systems and compilers (Win32 mostly), an extra keyword is */ + /* necessary to compile the library as a DLL. */ + /* */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; + + +#ifdef __cplusplus + } +#endif + +#endif /* __FTGRAYS_H__ */ + + +/* END */ diff --git a/src/freetype2/smooth/ftsmerrs.h b/src/freetype2/smooth/ftsmerrs.h new file mode 100644 index 0000000..0c2a2ec --- /dev/null +++ b/src/freetype2/smooth/ftsmerrs.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* ftsmerrs.h */ +/* */ +/* smooth renderer error codes (specification only). */ +/* */ +/* Copyright 2001 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 smooth renderer error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __FTSMERRS_H__ +#define __FTSMERRS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX Smooth_Err_ +#define FT_ERR_BASE FT_Mod_Err_Smooth + +#include FT_ERRORS_H + +#endif /* __FTSMERRS_H__ */ + + +/* END */ diff --git a/src/freetype2/smooth/ftsmooth.c b/src/freetype2/smooth/ftsmooth.c new file mode 100644 index 0000000..85d04eb --- /dev/null +++ b/src/freetype2/smooth/ftsmooth.c @@ -0,0 +1,467 @@ +/***************************************************************************/ +/* */ +/* ftsmooth.c */ +/* */ +/* Anti-aliasing renderer interface (body). */ +/* */ +/* Copyright 2000-2001, 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_OBJECTS_H +#include FT_OUTLINE_H +#include "ftsmooth.h" +#include "ftgrays.h" + +#include "ftsmerrs.h" + + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + + + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + + return 0; + } + + + /* sets render-specific mode */ + static FT_Error + ft_smooth_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + /* transform a given glyph image */ + static FT_Error + ft_smooth_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = Smooth_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = Smooth_Err_Invalid_Argument; + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_smooth_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_smooth_render_generic( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin, + FT_Render_Mode required_mode ) + { + FT_Error error; + FT_Outline* outline = NULL; + FT_BBox cbox; + FT_UInt width, height, height_org, width_org, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + FT_Int hmul = mode == FT_RENDER_MODE_LCD; + FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; + FT_Pos x_shift, y_shift, x_left, y_top; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = Smooth_Err_Invalid_Argument; + goto Exit; + } + + /* check mode */ + if ( mode != required_mode ) + return Smooth_Err_Cannot_Render_Glyph; + + outline = &slot->outline; + + /* translate the outline to the new origin if needed */ + if ( origin ) + FT_Outline_Translate( outline, origin->x, origin->y ); + + /* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); + + cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); + cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); + cbox.xMax = FT_PIX_CEIL( cbox.xMax ); + cbox.yMax = FT_PIX_CEIL( cbox.yMax ); + + width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); + height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); + bitmap = &slot->bitmap; + memory = render->root.memory; + + width_org = width; + height_org = height; + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* allocate new one, depends on pixel format */ + pitch = width; + if ( hmul ) + { + width = width * 3; + pitch = FT_PAD_CEIL( width, 4 ); + } + + if ( vmul ) + height *= 3; + + x_shift = (FT_Int) cbox.xMin; + y_shift = (FT_Int) cbox.yMin; + x_left = (FT_Int)( cbox.xMin >> 6 ); + y_top = (FT_Int)( cbox.yMax >> 6 ); + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + if ( slot->library->lcd_filter_func ) + { + FT_Int extra = slot->library->lcd_extra; + + + if ( hmul ) + { + x_shift -= 64 * ( extra >> 1 ); + width += 3 * extra; + pitch = FT_PAD_CEIL( width, 4 ); + x_left -= extra >> 1; + } + + if ( vmul ) + { + y_shift -= 64 * ( extra >> 1 ); + height += 3 * extra; + y_top += extra >> 1; + } + } + +#endif + + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; + + /* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* implode outline if needed */ + { + FT_Vector* points = outline->points; + FT_Vector* points_end = points + outline->n_points; + FT_Vector* vec; + + + if ( hmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->x *= 3; + + if ( vmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->y *= 3; + } + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline if needed */ + { + FT_Vector* points = outline->points; + FT_Vector* points_end = points + outline->n_points; + FT_Vector* vec; + + + if ( hmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->x /= 3; + + if ( vmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->y /= 3; + } + + if ( slot->library->lcd_filter_func ) + slot->library->lcd_filter_func( bitmap, mode, slot->library ); + +#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* render outline into bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* expand it horizontally */ + if ( hmul ) + { + FT_Byte* line = bitmap->buffer; + FT_UInt hh; + + + for ( hh = height_org; hh > 0; hh--, line += pitch ) + { + FT_UInt xx; + FT_Byte* end = line + width; + + + for ( xx = width_org; xx > 0; xx-- ) + { + FT_UInt pixel = line[xx-1]; + + + end[-3] = (FT_Byte)pixel; + end[-2] = (FT_Byte)pixel; + end[-1] = (FT_Byte)pixel; + end -= 3; + } + } + } + + /* expand it vertically */ + if ( vmul ) + { + FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; + FT_Byte* write = bitmap->buffer; + FT_UInt hh; + + + for ( hh = height_org; hh > 0; hh-- ) + { + memcpy( write, read, pitch ); + write += pitch; + + memcpy( write, read, pitch ); + write += pitch; + + memcpy( write, read, pitch ); + write += pitch; + read += pitch; + } + } + +#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + FT_Outline_Translate( outline, x_shift, y_shift ); + + if ( error ) + goto Exit; + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = x_left; + slot->bitmap_top = y_top; + + Exit: + if ( outline && origin ) + FT_Outline_Translate( outline, -origin->x, -origin->y ); + + return error; + } + + + /* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + if ( mode == FT_RENDER_MODE_LIGHT ) + mode = FT_RENDER_MODE_NORMAL; + + return ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_NORMAL ); + } + + + /* convert a slot's glyph image into a horizontal LCD bitmap */ + static FT_Error + ft_smooth_render_lcd( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + + error = ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_LCD ); + if ( !error ) + slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; + + return error; + } + + + /* convert a slot's glyph image into a vertical LCD bitmap */ + static FT_Error + ft_smooth_render_lcd_v( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + + error = ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_LCD_V ); + if ( !error ) + slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; + + return error; + } + + + FT_CALLBACK_TABLE_DEF + const FT_Renderer_Class ft_smooth_renderer_class = + { + { + FT_MODULE_RENDERER, + sizeof( FT_RendererRec ), + + "smooth", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_smooth_render, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + + (FT_Raster_Funcs*) &ft_grays_raster + }; + + + FT_CALLBACK_TABLE_DEF + const FT_Renderer_Class ft_smooth_lcd_renderer_class = + { + { + FT_MODULE_RENDERER, + sizeof( FT_RendererRec ), + + "smooth-lcd", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_smooth_render_lcd, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + + (FT_Raster_Funcs*) &ft_grays_raster + }; + + + + FT_CALLBACK_TABLE_DEF + const FT_Renderer_Class ft_smooth_lcdv_renderer_class = + { + { + FT_MODULE_RENDERER, + sizeof( FT_RendererRec ), + + "smooth-lcdv", + 0x10000L, + 0x20000L, + + 0, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + + (FT_Raster_Funcs*) &ft_grays_raster + }; + + +/* END */ diff --git a/src/freetype2/smooth/ftsmooth.h b/src/freetype2/smooth/ftsmooth.h new file mode 100644 index 0000000..62cced4 --- /dev/null +++ b/src/freetype2/smooth/ftsmooth.h @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* ftsmooth.h */ +/* */ +/* Anti-aliasing renderer interface (specification). */ +/* */ +/* Copyright 1996-2001 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 __FTSMOOTH_H__ +#define __FTSMOOTH_H__ + + +#include <ft2build.h> +#include FT_RENDER_H + + +FT_BEGIN_HEADER + + +#ifndef FT_CONFIG_OPTION_NO_STD_RASTER + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_std_renderer_class; +#endif + +#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_renderer_class; + + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_lcd_renderer_class; + + FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_lcd_v_renderer_class; +#endif + + + +FT_END_HEADER + +#endif /* __FTSMOOTH_H__ */ + + +/* END */ diff --git a/src/freetype2/smooth/smooth.c b/src/freetype2/smooth/smooth.c new file mode 100644 index 0000000..ff6be3e --- /dev/null +++ b/src/freetype2/smooth/smooth.c @@ -0,0 +1,26 @@ +/***************************************************************************/ +/* */ +/* smooth.c */ +/* */ +/* FreeType anti-aliasing rasterer module component (body only). */ +/* */ +/* Copyright 1996-2001 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 "ftgrays.c" +#include "ftsmooth.c" + + +/* END */ diff --git a/src/freetype2/truetype/truetype.c b/src/freetype2/truetype/truetype.c new file mode 100644 index 0000000..b36473a --- /dev/null +++ b/src/freetype2/truetype/truetype.c @@ -0,0 +1,36 @@ +/***************************************************************************/ +/* */ +/* truetype.c */ +/* */ +/* FreeType TrueType driver component (body only). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> +#include "ttdriver.c" /* driver interface */ +#include "ttpload.c" /* tables loader */ +#include "ttgload.c" /* glyph loader */ +#include "ttobjs.c" /* object manager */ + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.c" +#endif + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.c" /* gx distortable font */ +#endif + + +/* END */ diff --git a/src/freetype2/truetype/ttdriver.c b/src/freetype2/truetype/ttdriver.c new file mode 100644 index 0000000..c2cf452 --- /dev/null +++ b/src/freetype2/truetype/ttdriver.c @@ -0,0 +1,418 @@ +/***************************************************************************/ +/* */ +/* ttdriver.c */ +/* */ +/* TrueType font driver implementation (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_TRUETYPE_IDS_H +#include FT_SERVICE_XFREE86_NAME_H + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include FT_MULTIPLE_MASTERS_H +#include FT_SERVICE_MULTIPLE_MASTERS_H +#endif + +#include FT_SERVICE_TRUETYPE_ENGINE_H +#include FT_SERVICE_TRUETYPE_GLYF_H + +#include "ttdriver.h" +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.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_ttdriver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_get_kerning */ + /* */ + /* <Description> */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* <Output> */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings, are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static FT_Error + tt_get_kerning( FT_Face ttface, /* TT_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face face = (TT_Face)ttface; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + + return 0; + } + + +#undef PAIR_TAG + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S I Z E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + static FT_Error + tt_size_select( FT_Size size, + FT_ULong strike_index ) + { + TT_Face ttface = (TT_Face)size->face; + TT_Size ttsize = (TT_Size)size; + FT_Error error = TT_Err_Ok; + + + ttsize->strike_index = strike_index; + + if ( FT_IS_SCALABLE( size->face ) ) + { + /* use the scaled metrics, even when tt_size_reset fails */ + FT_Select_Metrics( size->face, strike_index ); + + tt_size_reset( ttsize ); + } + else + { + SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; + FT_Size_Metrics* metrics = &size->metrics; + + + error = sfnt->load_strike_metrics( ttface, strike_index, metrics ); + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + static FT_Error + tt_size_request( FT_Size size, + FT_Size_Request req ) + { + TT_Size ttsize = (TT_Size)size; + FT_Error error = TT_Err_Ok; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + TT_Face ttface = (TT_Face)size->face; + SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; + FT_ULong strike_index; + + + error = sfnt->set_sbit_strike( ttface, req, &strike_index ); + + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + else + return tt_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + FT_Request_Metrics( size->face, req ); + + if ( FT_IS_SCALABLE( size->face ) ) + error = tt_size_reset( ttsize ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Load_Glyph */ + /* */ + /* <Description> */ + /* A driver method used to load a glyph within a given glyph slot. */ + /* */ + /* <Input> */ + /* slot :: A handle to the target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled, loaded, etc. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FTLOAD_??? constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Load_Glyph( FT_GlyphSlot ttslot, /* TT_GlyphSlot */ + FT_Size ttsize, /* TT_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_GlyphSlot slot = (TT_GlyphSlot)ttslot; + TT_Size size = (TT_Size)ttsize; + FT_Face face = ttslot->face; + FT_Error error; + + + if ( !slot ) + return TT_Err_Invalid_Slot_Handle; + + if ( !size ) + return TT_Err_Invalid_Size_Handle; + + if ( !face || glyph_index >= (FT_UInt)face->num_glyphs ) + return TT_Err_Invalid_Argument; + + if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) ) + { + load_flags |= FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP | + FT_LOAD_NO_SCALE; + } + + /* now load the glyph outline if necessary */ + error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + static const FT_Service_MultiMastersRec tt_service_gx_multi_masters = + { + (FT_Get_MM_Func) NULL, + (FT_Set_MM_Design_Func) NULL, + (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, + (FT_Get_MM_Var_Func) TT_Get_MM_Var, + (FT_Set_Var_Design_Func)TT_Set_Var_Design + }; +#endif + + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = + { +#ifdef TT_USE_BYTECODE_INTERPRETER + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED +#else + FT_TRUETYPE_ENGINE_TYPE_PATENTED +#endif + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_TRUETYPE_ENGINE_TYPE_NONE + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + }; + + static const FT_Service_TTGlyfRec tt_service_truetype_glyf = + { + (TT_Glyf_GetLocationFunc)tt_face_get_location + }; + + static const FT_ServiceDescRec tt_services[] = + { + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE }, +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { FT_SERVICE_ID_MULTI_MASTERS, &tt_service_gx_multi_masters }, +#endif + { FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine }, + { FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + tt_get_interface( FT_Module driver, /* TT_Driver */ + const char* tt_interface ) + { + FT_Module_Interface result; + FT_Module sfntd; + SFNT_Service sfnt; + + + result = ft_service_list_lookup( tt_services, tt_interface ); + if ( result != NULL ) + return result; + + /* only return the default interface from the SFNT module */ + sfntd = FT_Get_Module( driver->library, "sfnt" ); + if ( sfntd ) + { + sfnt = (SFNT_Service)( sfntd->clazz->module_interface ); + if ( sfnt ) + return sfnt->get_interface( driver, tt_interface ); + } + + return 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec tt_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_MODULE_DRIVER_HAS_HINTER, +#else + 0, +#endif + + sizeof ( TT_DriverRec ), + + "truetype", /* driver name */ + 0x10000L, /* driver version == 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + (void*)0, /* driver specific interface */ + + tt_driver_init, + tt_driver_done, + tt_get_interface, + }, + + sizeof ( TT_FaceRec ), + sizeof ( TT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + tt_face_init, + tt_face_done, + tt_size_init, + tt_size_done, + tt_slot_init, + 0, /* FT_Slot_DoneFunc */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + Load_Glyph, + + tt_get_kerning, + 0, /* FT_Face_AttachFunc */ + 0, /* FT_Face_GetAdvancesFunc */ + + tt_size_request, +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + tt_size_select +#else + 0 /* FT_Size_SelectFunc */ +#endif + }; + + +/* END */ diff --git a/src/freetype2/truetype/ttdriver.h b/src/freetype2/truetype/ttdriver.h new file mode 100644 index 0000000..f6f26e4 --- /dev/null +++ b/src/freetype2/truetype/ttdriver.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* ttdriver.h */ +/* */ +/* High-level TrueType driver interface (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTDRIVER_H__ +#define __TTDRIVER_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) tt_driver_class; + + +FT_END_HEADER + +#endif /* __TTDRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/truetype/tterrors.h b/src/freetype2/truetype/tterrors.h new file mode 100644 index 0000000..d317c70 --- /dev/null +++ b/src/freetype2/truetype/tterrors.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* tterrors.h */ +/* */ +/* TrueType error codes (specification only). */ +/* */ +/* Copyright 2001 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 TrueType error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __TTERRORS_H__ +#define __TTERRORS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX TT_Err_ +#define FT_ERR_BASE FT_Mod_Err_TrueType + +#include FT_ERRORS_H + +#endif /* __TTERRORS_H__ */ + +/* END */ diff --git a/src/freetype2/truetype/ttgload.c b/src/freetype2/truetype/ttgload.c new file mode 100644 index 0000000..ae476a4 --- /dev/null +++ b/src/freetype2/truetype/ttgload.c @@ -0,0 +1,1957 @@ +/***************************************************************************/ +/* */ +/* ttgload.c */ +/* */ +/* TrueType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_TRUETYPE_TAGS_H +#include FT_OUTLINE_H + +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.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_ttgload + + + /*************************************************************************/ + /* */ + /* Composite font flags. */ + /* */ +#define ARGS_ARE_WORDS 0x0001 +#define ARGS_ARE_XY_VALUES 0x0002 +#define ROUND_XY_TO_GRID 0x0004 +#define WE_HAVE_A_SCALE 0x0008 +/* reserved 0x0010 */ +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_XY_SCALE 0x0040 +#define WE_HAVE_A_2X2 0x0080 +#define WE_HAVE_INSTR 0x0100 +#define USE_MY_METRICS 0x0200 +#define OVERLAP_COMPOUND 0x0400 +#define SCALED_COMPONENT_OFFSET 0x0800 +#define UNSCALED_COMPONENT_OFFSET 0x1000 + + + /*************************************************************************/ + /* */ + /* Returns the horizontal metrics in font units for a given glyph. If */ + /* `check' is true, take care of monospaced fonts by returning the */ + /* advance width maximum. */ + /* */ + static void + Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Bool check, + FT_Short* lsb, + FT_UShort* aw ) + { + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); + + if ( check && face->postscript.isFixedPitch ) + *aw = face->horizontal.advance_Width_Max; + } + + + /*************************************************************************/ + /* */ + /* Returns the vertical metrics in font units for a given glyph. */ + /* Greg Hitchcock from Microsoft told us that if there were no `vmtx' */ + /* table, typoAscender/Descender from the `OS/2' table would be used */ + /* instead, and if there were no `OS/2' table, use ascender/descender */ + /* from the `hhea' table. But that is not what Microsoft's rasterizer */ + /* apparently does: It uses the ppem value as the advance height, and */ + /* sets the top side bearing to be zero. */ + /* */ + /* The monospace `check' is probably not meaningful here, but we leave */ + /* it in for a consistent interface. */ + /* */ + static void + Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Bool check, + FT_Short* tsb, + FT_UShort* ah ) + { + FT_UNUSED( check ); + + if ( face->vertical_info ) + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); + +#if 1 /* Empirically determined, at variance with what MS said */ + + else + { + *tsb = 0; + *ah = face->root.units_per_EM; + } + +#else /* This is what MS said to do. It isn't what they do, however. */ + + else if ( face->os2.version != 0xFFFFU ) + { + *tsb = face->os2.sTypoAscender; + *ah = face->os2.sTypoAscender - face->os2.sTypoDescender; + } + else + { + *tsb = face->horizontal.Ascender; + *ah = face->horizontal.Ascender - face->horizontal.Descender; + } + +#endif + + } + + + /*************************************************************************/ + /* */ + /* Translates an array of coordinates. */ + /* */ + static void + translate_array( FT_UInt n, + FT_Vector* coords, + FT_Pos delta_x, + FT_Pos delta_y ) + { + FT_UInt k; + + + if ( delta_x ) + for ( k = 0; k < n; k++ ) + coords[k].x += delta_x; + + if ( delta_y ) + for ( k = 0; k < n; k++ ) + coords[k].y += delta_y; + } + + +#undef IS_HINTED +#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) + + + /*************************************************************************/ + /* */ + /* The following functions are used by default with TrueType fonts. */ + /* However, they can be replaced by alternatives if we need to support */ + /* TrueType-compressed formats (like MicroType) in the future. */ + /* */ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + TT_Access_Glyph_Frame( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ) + { + FT_Error error; + FT_Stream stream = loader->stream; + + /* for non-debug mode */ + FT_UNUSED( glyph_index ); + + + FT_TRACE5(( "Glyph %ld\n", glyph_index )); + + /* the following line sets the `error' variable through macros! */ + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) + return error; + + loader->cursor = stream->cursor; + loader->limit = stream->limit; + + return TT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + TT_Forget_Glyph_Frame( TT_Loader loader ) + { + FT_Stream stream = loader->stream; + + + FT_FRAME_EXIT(); + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Glyph_Header( TT_Loader loader ) + { + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + + + if ( p + 10 > limit ) + return TT_Err_Invalid_Outline; + + loader->n_contours = FT_NEXT_SHORT( p ); + + loader->bbox.xMin = FT_NEXT_SHORT( p ); + loader->bbox.yMin = FT_NEXT_SHORT( p ); + loader->bbox.xMax = FT_NEXT_SHORT( p ); + loader->bbox.yMax = FT_NEXT_SHORT( p ); + + FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); + FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, + loader->bbox.yMax )); + loader->cursor = p; + + return TT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Simple_Glyph( TT_Loader load ) + { + FT_Error error; + FT_Byte* p = load->cursor; + FT_Byte* limit = load->limit; + FT_GlyphLoader gloader = load->gloader; + FT_Int n_contours = load->n_contours; + FT_Outline* outline; + TT_Face face = (TT_Face)load->face; + FT_UShort n_ins; + FT_Int n_points; + + FT_Byte *flag, *flag_limit; + FT_Byte c, count; + FT_Vector *vec, *vec_limit; + FT_Pos x; + FT_Short *cont, *cont_limit, prev_cont; + FT_Int xy_size = 0; + + + /* check that we can add the contours to the glyph */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours ); + if ( error ) + goto Fail; + + /* reading the contours' endpoints & number of points */ + cont = gloader->current.outline.contours; + cont_limit = cont + n_contours; + + /* check space for contours array + instructions count */ + if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit ) + goto Invalid_Outline; + + cont[0] = prev_cont = FT_NEXT_USHORT( p ); + for ( cont++; cont < cont_limit; cont++ ) + { + cont[0] = FT_NEXT_USHORT( p ); + if ( cont[0] <= prev_cont ) + { + /* unordered contours: this is invalid */ + error = FT_Err_Invalid_Table; + goto Fail; + } + prev_cont = cont[0]; + } + + n_points = 0; + if ( n_contours > 0 ) + { + n_points = cont[-1] + 1; + if ( n_points < 0 ) + goto Invalid_Outline; + } + + /* note that we will add four phantom points later */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); + if ( error ) + goto Fail; + + /* we'd better check the contours table right now */ + outline = &gloader->current.outline; + + for ( cont = outline->contours + 1; cont < cont_limit; cont++ ) + if ( cont[-1] >= cont[0] ) + goto Invalid_Outline; + + /* reading the bytecode instructions */ + load->glyph->control_len = 0; + load->glyph->control_data = 0; + + if ( p + 2 > limit ) + goto Invalid_Outline; + + n_ins = FT_NEXT_USHORT( p ); + + FT_TRACE5(( " Instructions size: %u\n", n_ins )); + + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "TT_Load_Simple_Glyph: Too many instructions (%d)\n", + n_ins )); + error = TT_Err_Too_Many_Hints; + goto Fail; + } + + if ( ( limit - p ) < n_ins ) + { + FT_TRACE0(( "TT_Load_Simple_Glyph: Instruction count mismatch!\n" )); + error = TT_Err_Too_Many_Hints; + goto Fail; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( IS_HINTED( load->load_flags ) ) + { + load->glyph->control_len = n_ins; + load->glyph->control_data = load->exec->glyphIns; + + FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + p += n_ins; + + /* reading the point tags */ + flag = (FT_Byte*)outline->tags; + flag_limit = flag + n_points; + + FT_ASSERT( flag != NULL ); + + while ( flag < flag_limit ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + *flag++ = c = FT_NEXT_BYTE( p ); + if ( c & 8 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + count = FT_NEXT_BYTE( p ); + if ( flag + (FT_Int)count > flag_limit ) + goto Invalid_Outline; + + for ( ; count > 0; count-- ) + *flag++ = c; + } + } + + /* reading the X coordinates */ + + vec = outline->points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + x = 0; + + if ( p + xy_size > limit ) + goto Invalid_Outline; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos y = 0; + FT_Byte f = *flag; + + + if ( f & 2 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_BYTE( p ); + if ( ( f & 16 ) == 0 ) + y = -y; + } + else if ( ( f & 16 ) == 0 ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_SHORT( p ); + } + + x += y; + vec->x = x; + *flag = f & ~( 2 | 16 ); + } + + /* reading the Y coordinates */ + + vec = gloader->current.outline.points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + x = 0; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos y = 0; + FT_Byte f = *flag; + + + if ( f & 4 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_BYTE( p ); + if ( ( f & 32 ) == 0 ) + y = -y; + } + else if ( ( f & 32 ) == 0 ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + y = (FT_Pos)FT_NEXT_SHORT( p ); + } + + x += y; + vec->y = x; + *flag = f & FT_CURVE_TAG_ON; + } + + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_Short) n_contours; + + load->cursor = p; + + Fail: + return error; + + Invalid_Outline: + error = TT_Err_Invalid_Outline; + goto Fail; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Composite_Glyph( TT_Loader loader ) + { + FT_Error error; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + FT_GlyphLoader gloader = loader->gloader; + FT_SubGlyph subglyph; + FT_UInt num_subglyphs; + + + num_subglyphs = 0; + + do + { + FT_Fixed xx, xy, yy, yx; + FT_UInt count; + + + /* check that we can load a new subglyph */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 ); + if ( error ) + goto Fail; + + /* check space */ + if ( p + 4 > limit ) + goto Invalid_Composite; + + subglyph = gloader->current.subglyphs + num_subglyphs; + + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = FT_NEXT_USHORT( p ); + subglyph->index = FT_NEXT_USHORT( p ); + + /* check space */ + count = 2; + if ( subglyph->flags & ARGS_ARE_WORDS ) + count += 2; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + count += 2; + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + count += 4; + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + count += 8; + + if ( p + count > limit ) + goto Invalid_Composite; + + /* read arguments */ + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = FT_NEXT_SHORT( p ); + subglyph->arg2 = FT_NEXT_SHORT( p ); + } + else + { + subglyph->arg1 = FT_NEXT_CHAR( p ); + subglyph->arg2 = FT_NEXT_CHAR( p ); + } + + /* read transform */ + xx = yy = 0x10000L; + xy = yx = 0; + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = xx; + } + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + } + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + xy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + } + + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + + num_subglyphs++; + + } while ( subglyph->flags & MORE_COMPONENTS ); + + gloader->current.num_subglyphs = num_subglyphs; + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + FT_Stream stream = loader->stream; + + + /* we must undo the FT_FRAME_ENTER in order to point to the */ + /* composite instructions, if we find some. */ + /* we will process them later... */ + /* */ + loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + + p - limit ); + } + +#endif + + loader->cursor = p; + + Fail: + return error; + + Invalid_Composite: + error = TT_Err_Invalid_Composite; + goto Fail; + } + + + FT_LOCAL_DEF( void ) + TT_Init_Glyph_Loading( TT_Face face ) + { + face->access_glyph_frame = TT_Access_Glyph_Frame; + face->read_glyph_header = TT_Load_Glyph_Header; + face->read_simple_glyph = TT_Load_Simple_Glyph; + face->read_composite_glyph = TT_Load_Composite_Glyph; + face->forget_glyph_frame = TT_Forget_Glyph_Frame; + } + + + static void + tt_prepare_zone( TT_GlyphZone zone, + FT_GlyphLoad load, + FT_UInt start_point, + FT_UInt start_contour ) + { + zone->n_points = (FT_UShort)( load->outline.n_points - start_point ); + zone->n_contours = (FT_Short) ( load->outline.n_contours - + start_contour ); + zone->org = load->extra_points + start_point; + zone->cur = load->outline.points + start_point; + zone->orus = load->extra_points2 + start_point; + zone->tags = (FT_Byte*)load->outline.tags + start_point; + zone->contours = (FT_UShort*)load->outline.contours + start_contour; + zone->first_point = (FT_UShort)start_point; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Hint_Glyph */ + /* */ + /* <Description> */ + /* Hint the glyph using the zone prepared by the caller. Note that */ + /* the zone is supposed to include four phantom points. */ + /* */ + static FT_Error + TT_Hint_Glyph( TT_Loader loader, + FT_Bool is_composite ) + { + TT_GlyphZone zone = &loader->zone; + FT_Pos origin; + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_UInt n_ins; +#else + FT_UNUSED( is_composite ); +#endif + + +#ifdef TT_USE_BYTECODE_INTERPRETER + n_ins = loader->glyph->control_len; +#endif + + origin = zone->cur[zone->n_points - 4].x; + origin = FT_PIX_ROUND( origin ) - origin; + if ( origin ) + translate_array( zone->n_points, zone->cur, origin, 0 ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* save original point position in org */ + if ( n_ins > 0 ) + FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); +#endif + + /* round pp2 and pp4 */ + zone->cur[zone->n_points - 3].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); + zone->cur[zone->n_points - 1].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( n_ins > 0 ) + { + FT_Bool debug; + FT_Error error; + + + error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph, + loader->exec->glyphIns, n_ins ); + if ( error ) + return error; + + loader->exec->is_composite = is_composite; + loader->exec->pts = *zone; + + debug = FT_BOOL( !( loader->load_flags & FT_LOAD_NO_SCALE ) && + ((TT_Size)loader->size)->debug ); + + error = TT_Run_Context( loader->exec, debug ); + if ( error && loader->exec->pedantic_hinting ) + return error; + } + +#endif + + /* save glyph phantom points */ + if ( !loader->preserve_pps ) + { + loader->pp1 = zone->cur[zone->n_points - 4]; + loader->pp2 = zone->cur[zone->n_points - 3]; + loader->pp3 = zone->cur[zone->n_points - 2]; + loader->pp4 = zone->cur[zone->n_points - 1]; + } + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Process_Simple_Glyph */ + /* */ + /* <Description> */ + /* Once a simple glyph has been loaded, it needs to be processed. */ + /* Usually, this means scaling and hinting through bytecode */ + /* interpretation. */ + /* */ + static FT_Error + TT_Process_Simple_Glyph( TT_Loader loader ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Error error = TT_Err_Ok; + FT_Outline* outline; + FT_UInt n_points; + + + outline = &gloader->current.outline; + n_points = outline->n_points; + + /* set phantom points */ + + outline->points[n_points ] = loader->pp1; + outline->points[n_points + 1] = loader->pp2; + outline->points[n_points + 2] = loader->pp3; + outline->points[n_points + 3] = loader->pp4; + + outline->tags[n_points ] = 0; + outline->tags[n_points + 1] = 0; + outline->tags[n_points + 2] = 0; + outline->tags[n_points + 3] = 0; + + n_points += 4; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( ((TT_Face)loader->face)->doblend ) + { + /* Deltas apply to the unscaled data. */ + FT_Vector* deltas; + FT_Memory memory = loader->face->memory; + FT_UInt i; + + + error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), + loader->glyph_index, + &deltas, + n_points ); + if ( error ) + return error; + + for ( i = 0; i < n_points; ++i ) + { + outline->points[i].x += deltas[i].x; + outline->points[i].y += deltas[i].y; + } + + FT_FREE( deltas ); + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( IS_HINTED( loader->load_flags ) ) + { + tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); + + FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, + loader->zone.n_points + 4 ); + } + + /* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + FT_Vector* vec = outline->points; + FT_Vector* limit = outline->points + n_points; + FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; + FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; + + + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + } + + if ( IS_HINTED( loader->load_flags ) ) + { + loader->zone.n_points += 4; + + error = TT_Hint_Glyph( loader, 0 ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Process_Composite_Component */ + /* */ + /* <Description> */ + /* Once a composite component has been loaded, it needs to be */ + /* processed. Usually, this means transforming and translating. */ + /* */ + static FT_Error + TT_Process_Composite_Component( TT_Loader loader, + FT_SubGlyph subglyph, + FT_UInt start_point, + FT_UInt num_base_points ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Vector* base_vec = gloader->base.outline.points; + FT_UInt num_points = gloader->base.outline.n_points; + FT_Bool have_scale; + FT_Pos x, y; + + + have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ); + + /* perform the transform required for this subglyph */ + if ( have_scale ) + { + FT_UInt i; + + + for ( i = num_base_points; i < num_points; i++ ) + FT_Vector_Transform( base_vec + i, &subglyph->transform ); + } + + /* get offset */ + if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) + { + FT_UInt k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + /* match l-th point of the newly loaded component to the k-th point */ + /* of the previously loaded components. */ + + /* change to the point numbers used by our outline */ + k += start_point; + l += num_base_points; + if ( k >= num_base_points || + l >= num_points ) + return TT_Err_Invalid_Composite; + + p1 = gloader->base.outline.points + k; + p2 = gloader->base.outline.points + l; + + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + + if ( !x && !y ) + return TT_Err_Ok; + + /* Use a default value dependent on */ + /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old TT */ + /* fonts which don't set the xxx_COMPONENT_OFFSET bit. */ + + if ( have_scale && +#ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) ) +#else + ( subglyph->flags & SCALED_COMPONENT_OFFSET ) ) +#endif + { + +#if 0 + + /*************************************************************************/ + /* */ + /* This algorithm is what Apple documents. But it doesn't work. */ + /* */ + int a = subglyph->transform.xx > 0 ? subglyph->transform.xx + : -subglyph->transform.xx; + int b = subglyph->transform.yx > 0 ? subglyph->transform.yx + : -subglyph->transform.yx; + int c = subglyph->transform.xy > 0 ? subglyph->transform.xy + : -subglyph->transform.xy; + int d = subglyph->transform.yy > 0 ? subglyph->transform.yy + : -subglyph->transform.yy; + int m = a > b ? a : b; + int n = c > d ? c : d; + + + if ( a - b <= 33 && a - b >= -33 ) + m *= 2; + if ( c - d <= 33 && c - d >= -33 ) + n *= 2; + x = FT_MulFix( x, m ); + y = FT_MulFix( y, n ); + +#else /* 0 */ + + /*************************************************************************/ + /* */ + /* This algorithm is a guess and works much better than the above. */ + /* */ + FT_Fixed mac_xscale = FT_SqrtFixed( + FT_MulFix( subglyph->transform.xx, + subglyph->transform.xx ) + + FT_MulFix( subglyph->transform.xy, + subglyph->transform.xy ) ); + FT_Fixed mac_yscale = FT_SqrtFixed( + FT_MulFix( subglyph->transform.yy, + subglyph->transform.yy ) + + FT_MulFix( subglyph->transform.yx, + subglyph->transform.yx ) ); + + + x = FT_MulFix( x, mac_xscale ); + y = FT_MulFix( y, mac_yscale ); + +#endif /* 0 */ + + } + + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; + FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; + + + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + x = FT_PIX_ROUND( x ); + y = FT_PIX_ROUND( y ); + } + } + } + + if ( x || y ) + translate_array( num_points - num_base_points, + base_vec + num_base_points, + x, y ); + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Process_Composite_Glyph */ + /* */ + /* <Description> */ + /* This is slightly different from TT_Process_Simple_Glyph, in that */ + /* its sole purpose is to hint the glyph. Thus this function is */ + /* only available when bytecode interpreter is enabled. */ + /* */ + static FT_Error + TT_Process_Composite_Glyph( TT_Loader loader, + FT_UInt start_point, + FT_UInt start_contour ) + { + FT_Error error; + FT_Outline* outline; + FT_UInt i; + + + outline = &loader->gloader->base.outline; + + /* make room for phantom points */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, + outline->n_points + 4, + 0 ); + if ( error ) + return error; + + outline->points[outline->n_points ] = loader->pp1; + outline->points[outline->n_points + 1] = loader->pp2; + outline->points[outline->n_points + 2] = loader->pp3; + outline->points[outline->n_points + 3] = loader->pp4; + + outline->tags[outline->n_points ] = 0; + outline->tags[outline->n_points + 1] = 0; + outline->tags[outline->n_points + 2] = 0; + outline->tags[outline->n_points + 3] = 0; + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + FT_Stream stream = loader->stream; + FT_UShort n_ins; + + + /* TT_Load_Composite_Glyph only gives us the offset of instructions */ + /* so we read them here */ + if ( FT_STREAM_SEEK( loader->ins_pos ) || + FT_READ_USHORT( n_ins ) ) + return error; + + FT_TRACE5(( " Instructions size = %d\n", n_ins )); + + /* check it */ + if ( n_ins > ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "TT_Process_Composite_Glyph: Too many instructions (%d)\n", + n_ins )); + + return TT_Err_Too_Many_Hints; + } + else if ( n_ins == 0 ) + return TT_Err_Ok; + + if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) ) + return error; + + loader->glyph->control_data = loader->exec->glyphIns; + loader->glyph->control_len = n_ins; + } + +#endif + + tt_prepare_zone( &loader->zone, &loader->gloader->base, + start_point, start_contour ); + + /* Some points are likely touched during execution of */ + /* instructions on components. So let's untouch them. */ + for ( i = start_point; i < loader->zone.n_points; i++ ) + loader->zone.tags[i] &= ~( FT_CURVE_TAG_TOUCH_X | + FT_CURVE_TAG_TOUCH_Y ); + + loader->zone.n_points += 4; + + return TT_Hint_Glyph( loader, 1 ); + } + + + /* Calculate the four phantom points. */ + /* The first two stand for horizontal origin and advance. */ + /* The last two stand for vertical origin and advance. */ +#define TT_LOADER_SET_PP( loader ) \ + do { \ + (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ + (loader)->pp1.y = 0; \ + (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ + (loader)->pp2.y = 0; \ + (loader)->pp3.x = 0; \ + (loader)->pp3.y = (loader)->top_bearing + (loader)->bbox.yMax; \ + (loader)->pp4.x = 0; \ + (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ + } while ( 0 ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* load_truetype_glyph */ + /* */ + /* <Description> */ + /* Loads a given truetype glyph. Handles composites and uses a */ + /* TT_Loader object. */ + /* */ + static FT_Error + load_truetype_glyph( TT_Loader loader, + FT_UInt glyph_index, + FT_UInt recurse_count ) + { + FT_Error error; + FT_Fixed x_scale, y_scale; + FT_ULong offset; + TT_Face face = (TT_Face)loader->face; + FT_GlyphLoader gloader = loader->gloader; + FT_Bool opened_frame = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Vector* deltas = NULL; +#endif + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_StreamRec inc_stream; + FT_Data glyph_data; + FT_Bool glyph_data_loaded = 0; +#endif + + + if ( recurse_count > face->max_profile.maxComponentDepth ) + { + error = TT_Err_Invalid_Composite; + goto Exit; + } + + /* check glyph index */ + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = TT_Err_Invalid_Glyph_Index; + goto Exit; + } + + loader->glyph_index = glyph_index; + + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = ((TT_Size)loader->size)->metrics.x_scale; + y_scale = ((TT_Size)loader->size)->metrics.y_scale; + } + else + { + x_scale = 0x10000L; + y_scale = 0x10000L; + } + + /* get metrics, horizontal and vertical */ + { + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + + Get_HMetrics( face, glyph_index, + (FT_Bool)!( loader->load_flags & + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), + &left_bearing, + &advance_width ); + Get_VMetrics( face, glyph_index, + (FT_Bool)!( loader->load_flags & + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), + &top_bearing, + &advance_height ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* If this is an incrementally loaded font see if there are */ + /* overriding metrics for this glyph. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = left_bearing; + metrics.bearing_y = 0; + metrics.advance = advance_width; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + if ( error ) + goto Exit; + left_bearing = (FT_Short)metrics.bearing_x; + advance_width = (FT_UShort)metrics.advance; + +#if 0 + + /* GWW: Do I do the same for vertical metrics? */ + metrics.bearing_x = 0; + metrics.bearing_y = top_bearing; + metrics.advance = advance_height; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, TRUE, &metrics ); + if ( error ) + goto Exit; + top_bearing = (FT_Short)metrics.bearing_y; + advance_height = (FT_UShort)metrics.advance; + +#endif /* 0 */ + + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + + /* Set `offset' to the start of the glyph relative to the start of */ + /* the `glyf' table, and `byte_len' to the length of the glyph in */ + /* bytes. */ + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* If we are loading glyph data via the incremental interface, set */ + /* the loader stream to a memory stream reading the data returned */ + /* by the interface. */ + if ( face->root.internal->incremental_interface ) + { + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &glyph_data ); + if ( error ) + goto Exit; + + glyph_data_loaded = 1; + offset = 0; + loader->byte_len = glyph_data.length; + + FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) ); + FT_Stream_OpenMemory( &inc_stream, + glyph_data.pointer, glyph_data.length ); + + loader->stream = &inc_stream; + } + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + offset = tt_face_get_location( face, glyph_index, + (FT_UInt*)&loader->byte_len ); + + if ( loader->byte_len == 0 ) + { + /* as described by Frederic Loyer, these are spaces or */ + /* the unknown glyph. */ + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + + TT_LOADER_SET_PP( loader ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( ((TT_Face)(loader->face))->doblend ) + { + /* this must be done before scaling */ + FT_Memory memory = loader->face->memory; + + + error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), + glyph_index, &deltas, 4 ); + if ( error ) + goto Exit; + + loader->pp1.x += deltas[0].x; loader->pp1.y += deltas[0].y; + loader->pp2.x += deltas[1].x; loader->pp2.y += deltas[1].y; + loader->pp3.x += deltas[2].x; loader->pp3.y += deltas[2].y; + loader->pp4.x += deltas[3].x; loader->pp4.y += deltas[3].y; + + FT_FREE( deltas ); + } + +#endif + + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + error = TT_Err_Ok; + goto Exit; + } + + error = face->access_glyph_frame( loader, glyph_index, + loader->glyf_offset + offset, + loader->byte_len ); + if ( error ) + goto Exit; + + opened_frame = 1; + + /* read first glyph header */ + error = face->read_glyph_header( loader ); + if ( error ) + goto Exit; + + TT_LOADER_SET_PP( loader ); + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* if it is a simple glyph, load it */ + + if ( loader->n_contours >= 0 ) + { + error = face->read_simple_glyph( loader ); + if ( error ) + goto Exit; + + /* all data have been read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + + error = TT_Process_Simple_Glyph( loader ); + if ( error ) + goto Exit; + + FT_GlyphLoader_Add( gloader ); + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* otherwise, load a composite! */ + else if ( loader->n_contours == -1 ) + { + FT_UInt start_point; + FT_UInt start_contour; + FT_ULong ins_pos; /* position of composite instructions, if any */ + + + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; + + /* for each subglyph, read composite header */ + error = face->read_composite_glyph( loader ); + if ( error ) + goto Exit; + + /* store the offset of instructions */ + ins_pos = loader->ins_pos; + + /* all data we need are read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( face->doblend ) + { + FT_Int i, limit; + FT_SubGlyph subglyph; + FT_Memory memory = face->root.memory; + + + /* this provides additional offsets */ + /* for each component's translation */ + + if ( ( error = TT_Vary_Get_Glyph_Deltas( + face, + glyph_index, + &deltas, + gloader->current.num_subglyphs + 4 )) != 0 ) + goto Exit; + + subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs; + limit = gloader->current.num_subglyphs; + + for ( i = 0; i < limit; ++i, ++subglyph ) + { + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + subglyph->arg1 += deltas[i].x; + subglyph->arg2 += deltas[i].y; + } + } + + loader->pp1.x += deltas[i + 0].x; loader->pp1.y += deltas[i + 0].y; + loader->pp2.x += deltas[i + 1].x; loader->pp2.y += deltas[i + 1].y; + loader->pp3.x += deltas[i + 2].x; loader->pp3.y += deltas[i + 2].y; + loader->pp4.x += deltas[i + 3].x; loader->pp4.y += deltas[i + 3].y; + + FT_FREE( deltas ); + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ + /* `as is' in the glyph slot (the client application will be */ + /* responsible for interpreting these data)... */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + FT_GlyphLoader_Add( gloader ); + loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + goto Exit; + } + + /*********************************************************************/ + /*********************************************************************/ + /*********************************************************************/ + + { + FT_UInt n, num_base_points; + FT_SubGlyph subglyph = 0; + + FT_UInt num_points = start_point; + FT_UInt num_subglyphs = gloader->current.num_subglyphs; + FT_UInt num_base_subgs = gloader->base.num_subglyphs; + + FT_Stream old_stream = loader->stream; + + TT_GraphicsState saved_GS; + + + if ( loader->exec ) + saved_GS = loader->exec->GS; + + FT_GlyphLoader_Add( gloader ); + + /* read each subglyph independently */ + for ( n = 0; n < num_subglyphs; n++ ) + { + FT_Vector pp[4]; + + + /* reinitialize graphics state */ + if ( loader->exec ) + loader->exec->GS = saved_GS; + + /* Each time we call load_truetype_glyph in this loop, the */ + /* value of `gloader.base.subglyphs' can change due to table */ + /* reallocations. We thus need to recompute the subglyph */ + /* pointer on each iteration. */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + pp[0] = loader->pp1; + pp[1] = loader->pp2; + pp[2] = loader->pp3; + pp[3] = loader->pp4; + + num_base_points = gloader->base.outline.n_points; + + error = load_truetype_glyph( loader, subglyph->index, + recurse_count + 1 ); + if ( error ) + goto Exit; + + /* restore subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + if ( !( subglyph->flags & USE_MY_METRICS ) ) + { + loader->pp1 = pp[0]; + loader->pp2 = pp[1]; + loader->pp3 = pp[2]; + loader->pp4 = pp[3]; + } + + num_points = gloader->base.outline.n_points; + + if ( num_points == num_base_points ) + continue; + + /* gloader->base.outline consists of three parts: */ + /* 0 -(1)-> start_point -(2)-> num_base_points -(3)-> n_points. */ + /* */ + /* (1): exists from the beginning */ + /* (2): components that have been loaded so far */ + /* (3): the newly loaded component */ + TT_Process_Composite_Component( loader, subglyph, start_point, + num_base_points ); + } + + loader->stream = old_stream; + + /* process the glyph */ + loader->ins_pos = ins_pos; + if ( IS_HINTED( loader->load_flags ) && + +#ifdef TT_USE_BYTECODE_INTERPRETER + + subglyph->flags & WE_HAVE_INSTR && + +#endif + + num_points > start_point ) + TT_Process_Composite_Glyph( loader, start_point, start_contour ); + + } + } + else + { + /* invalid composite count (negative but not -1) */ + error = TT_Err_Invalid_Outline; + goto Exit; + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + Exit: + + if ( opened_frame ) + face->forget_glyph_frame( loader ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( glyph_data_loaded ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + +#endif + + return error; + } + + + static FT_Error + compute_glyph_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + FT_BBox bbox; + TT_Face face = (TT_Face)loader->face; + FT_Fixed y_scale; + TT_GlyphSlot glyph = loader->glyph; + TT_Size size = (TT_Size)loader->size; + + + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + y_scale = size->root.metrics.y_scale; + + if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + else + bbox = loader->bbox; + + /* get the device-independent horizontal advance; it is scaled later */ + /* by the base layer. */ + { + FT_Pos advance = loader->linear; + + + /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ + /* correctly support DynaLab fonts, which have an incorrect */ + /* `advance_Width_Max' field! It is used, to my knowledge, */ + /* exclusively in the X-TrueType font server. */ + /* */ + if ( face->postscript.isFixedPitch && + ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) + advance = face->horizontal.advance_Width_Max; + + /* we need to return the advance in font units in linearHoriAdvance, */ + /* it will be scaled later by the base layer. */ + glyph->linearHoriAdvance = advance; + } + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), make */ + /* up some metrics by `hand'... */ + + { + FT_Pos top; /* scaled vertical top side bearing */ + FT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled top bearing and advance height. */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + top = (FT_Short)FT_DivFix( loader->pp3.y - bbox.yMax, + y_scale ); + + if ( loader->pp3.y <= loader->pp4.y ) + advance = 0; + else + advance = (FT_UShort)FT_DivFix( loader->pp3.y - loader->pp4.y, + y_scale ); + } + else + { + FT_Pos height; + + + /* XXX Compute top side bearing and advance height in */ + /* Get_VMetrics instead of here. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them, if there is an OS/2 */ + /* table in the font. Otherwise, we use the */ + /* values defined in the horizontal header. */ + + height = (FT_Short)FT_DivFix( bbox.yMax - bbox.yMin, + y_scale ); + if ( face->os2.version != 0xFFFFU ) + advance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + advance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + + top = ( advance - height ) / 2; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + FT_Incremental_InterfaceRec* incr; + FT_Incremental_MetricsRec metrics; + FT_Error error; + + + incr = face->root.internal->incremental_interface; + + /* If this is an incrementally loaded font see if there are */ + /* overriding metrics for this glyph. */ + if ( incr && incr->funcs->get_glyph_metrics ) + { + metrics.bearing_x = 0; + metrics.bearing_y = top; + metrics.advance = advance; + + error = incr->funcs->get_glyph_metrics( incr->object, + glyph_index, + TRUE, + &metrics ); + if ( error ) + return error; + + top = metrics.bearing_y; + advance = metrics.advance; + } + } + + /* GWW: Do vertical metrics get loaded incrementally too? */ + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + glyph->linearVertAdvance = advance; + + /* scale the metrics */ + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + top = FT_MulFix( top, y_scale ); + advance = FT_MulFix( advance, y_scale ); + } + + /* XXX: for now, we have no better algorithm for the lsb, but it */ + /* should work fine. */ + /* */ + glyph->metrics.vertBearingX = ( bbox.xMin - bbox.xMax ) / 2; + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + /* adjust advance width to the value contained in the hdmx table */ + if ( !face->postscript.isFixedPitch && + IS_HINTED( loader->load_flags ) ) + { + FT_Byte* widthp; + + + widthp = tt_face_get_device_metrics( face, + size->root.metrics.x_ppem, + glyph_index ); + + if ( widthp ) + glyph->metrics.horiAdvance = *widthp << 6; + } + + /* set glyph dimensions */ + glyph->metrics.width = bbox.xMax - bbox.xMin; + glyph->metrics.height = bbox.yMax - bbox.yMin; + + return 0; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + static FT_Error + load_sbit_image( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face; + SFNT_Service sfnt; + FT_Stream stream; + FT_Error error; + TT_SBit_MetricsRec metrics; + + + face = (TT_Face)glyph->face; + sfnt = (SFNT_Service)face->sfnt; + stream = face->root.stream; + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_Int)load_flags, + stream, + &glyph->bitmap, + &metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (FT_Pos)metrics.width << 6; + glyph->metrics.height = (FT_Pos)metrics.height << 6; + + glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + + glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->bitmap_left = metrics.vertBearingX; + glyph->bitmap_top = metrics.vertBearingY; + } + else + { + glyph->bitmap_left = metrics.horiBearingX; + glyph->bitmap_top = metrics.horiBearingY; + } + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + static FT_Error + tt_loader_init( TT_Loader loader, + TT_Size size, + TT_GlyphSlot glyph, + FT_Int32 load_flags ) + { + TT_Face face; + FT_Stream stream; + + + face = (TT_Face)glyph->face; + stream = face->root.stream; + + FT_MEM_ZERO( loader, sizeof ( TT_LoaderRec ) ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /* load execution context */ + if ( IS_HINTED( load_flags ) ) + { + TT_ExecContext exec; + FT_Bool grayscale; + + + if ( !size->cvt_ready ) + { + FT_Error error = tt_size_ready_bytecode( size ); + if ( error ) + return error; + } + + /* query new execution context */ + exec = size->debug ? size->context + : ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + grayscale = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); + + TT_Load_Context( exec, face, size ); + + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_UInt i; + + + exec->grayscale = grayscale; + + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + tt_size_run_prep( size ); + } + + /* see whether the cvt program has disabled hinting */ + if ( exec->GS.instruct_control & 1 ) + load_flags |= FT_LOAD_NO_HINTING; + + /* load default graphics state -- if needed */ + if ( exec->GS.instruct_control & 2 ) + exec->GS = tt_default_graphics_state; + + exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + loader->exec = exec; + loader->instructions = exec->glyphIns; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + /* seek to the beginning of the glyph table -- for Type 42 fonts */ + /* the table might be accessed from a Postscript stream or something */ + /* else... */ + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( face->root.internal->incremental_interface ) + loader->glyf_offset = 0; + else + +#endif + + { + FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 ); + + + if ( error ) + { + FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" )); + return error; + } + loader->glyf_offset = FT_STREAM_POS(); + } + + /* get face's glyph loader */ + { + FT_GlyphLoader gloader = glyph->internal->loader; + + + FT_GlyphLoader_Rewind( gloader ); + loader->gloader = gloader; + } + + loader->load_flags = load_flags; + + loader->face = (FT_Face)face; + loader->size = (FT_Size)size; + loader->glyph = (FT_GlyphSlot)glyph; + loader->stream = stream; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Load_Glyph */ + /* */ + /* <Description> */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size. */ + /* */ + /* <Input> */ + /* glyph :: A handle to a target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled/loaded. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face; + FT_Error error; + TT_LoaderRec loader; + + + face = (TT_Face)glyph->face; + error = TT_Err_Ok; + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap if any */ + /* */ + /* XXX: The convention should be emphasized in */ + /* the documents because it can be confusing. */ + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = load_sbit_image( size, glyph, glyph_index, load_flags ); + if ( !error ) + return TT_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) + return TT_Err_Invalid_Size_Handle; + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return TT_Err_Invalid_Argument; + + error = tt_loader_init( &loader, size, glyph, load_flags ); + if ( error ) + return error; + + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->num_subglyphs = 0; + glyph->outline.flags = 0; + + /* main loading loop */ + error = load_truetype_glyph( &loader, glyph_index, 0 ); + if ( !error ) + { + if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE ) + { + glyph->num_subglyphs = loader.gloader->base.num_subglyphs; + glyph->subglyphs = loader.gloader->base.subglyphs; + } + else + { + glyph->outline = loader.gloader->base.outline; + glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; + + /* In case bit 1 of the `flags' field in the `head' table isn't */ + /* set, translate array so that (0,0) is the glyph's origin. */ + if ( ( face->header.Flags & 2 ) == 0 && loader.pp1.x ) + FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); + } + + compute_glyph_metrics( &loader, glyph_index ); + } + + /* Set the `high precision' bit flag. */ + /* This is _critical_ to get correct output for monochrome */ + /* TrueType glyphs at all sizes using the bytecode interpreter. */ + /* */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && + size->root.metrics.y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + return error; + } + + +/* END */ diff --git a/src/freetype2/truetype/ttgload.h b/src/freetype2/truetype/ttgload.h new file mode 100644 index 0000000..b261e97 --- /dev/null +++ b/src/freetype2/truetype/ttgload.h @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* ttgload.h */ +/* */ +/* TrueType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTGLOAD_H__ +#define __TTGLOAD_H__ + + +#include <ft2build.h> +#include "ttobjs.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + TT_Init_Glyph_Loading( TT_Face face ); + + FT_LOCAL( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* __TTGLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/truetype/ttgxvar.c b/src/freetype2/truetype/ttgxvar.c new file mode 100644 index 0000000..0dc2c4f --- /dev/null +++ b/src/freetype2/truetype/ttgxvar.c @@ -0,0 +1,1536 @@ +/***************************************************************************/ +/* */ +/* ttgxvar.c */ +/* */ +/* TrueType GX Font Variation loader */ +/* */ +/* Copyright 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ +/* */ +/* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ +/* */ +/* The documentation for `fvar' is inconsistent. At one point it says */ +/* that `countSizePairs' should be 3, at another point 2. It should be 2. */ +/* */ +/* The documentation for `gvar' is not intelligible; `cvar' refers you to */ +/* `gvar' and is thus also incomprehensible. */ +/* */ +/* The documentation for `avar' appears correct, but Apple has no fonts */ +/* with an `avar' table, so it is hard to test. */ +/* */ +/* Many thanks to John Jenkins (at Apple) in figuring this out. */ +/* */ +/* */ +/* Apple's `kern' table has some references to tuple indices, but as there */ +/* is no indication where these indices are defined, nor how to */ +/* interpolate the kerning values (different tuples have different */ +/* classes) this issue is ignored. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_TRUETYPE_IDS_H +#include FT_TRUETYPE_TAGS_H +#include FT_MULTIPLE_MASTERS_H + +#include "ttdriver.h" +#include "ttpload.h" +#include "ttgxvar.h" + +#include "tterrors.h" + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + +#define FT_Stream_FTell( stream ) \ + ( (stream)->cursor - (stream)->base ) +#define FT_Stream_SeekSet( stream, off ) \ + ( (stream)->cursor = (stream)->base+(off) ) + + + /*************************************************************************/ + /* */ + /* 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_ttgxvar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Internal Routines *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ + /* indicates that there is a delta for every point without needing to */ + /* enumerate all of them. */ + /* */ +#define ALL_POINTS (FT_UShort*)( -1 ) + + + enum + { + GX_PT_POINTS_ARE_WORDS = 0x80, + GX_PT_POINT_RUN_COUNT_MASK = 0x7F + }; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_readpackedpoints */ + /* */ + /* <Description> */ + /* Read a set of points to which the following deltas will apply. */ + /* Points are packed with a run length encoding. */ + /* */ + /* <Input> */ + /* stream :: The data stream. */ + /* */ + /* <Output> */ + /* point_cnt :: The number of points read. A zero value means that */ + /* all points in the glyph will be affected, without */ + /* enumerating them individually. */ + /* */ + /* <Return> */ + /* An array of FT_UShort containing the affected points or the */ + /* special value ALL_POINTS. */ + /* */ + static FT_UShort* + ft_var_readpackedpoints( FT_Stream stream, + FT_UInt *point_cnt ) + { + FT_UShort *points; + FT_Int n; + FT_Int runcnt; + FT_Int i; + FT_Int j; + FT_Int first; + FT_Memory memory = stream->memory; + FT_Error error = TT_Err_Ok; + + FT_UNUSED( error ); + + + *point_cnt = n = FT_GET_BYTE(); + if ( n == 0 ) + return ALL_POINTS; + + if ( n & GX_PT_POINTS_ARE_WORDS ) + n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); + + if ( FT_NEW_ARRAY( points, n ) ) + return NULL; + + i = 0; + while ( i < n ) + { + runcnt = FT_GET_BYTE(); + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) + { + runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; + first = points[i++] = FT_GET_USHORT(); + + /* first point not included in runcount */ + for ( j = 0; j < runcnt; ++j ) + points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); + } + else + { + first = points[i++] = FT_GET_BYTE(); + + for ( j = 0; j < runcnt; ++j ) + points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); + } + } + + return points; + } + + + enum + { + GX_DT_DELTAS_ARE_ZERO = 0x80, + GX_DT_DELTAS_ARE_WORDS = 0x40, + GX_DT_DELTA_RUN_COUNT_MASK = 0x3F + }; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_readpackeddeltas */ + /* */ + /* <Description> */ + /* Read a set of deltas. These are packed slightly differently than */ + /* points. In particular there is no overall count. */ + /* */ + /* <Input> */ + /* stream :: The data stream. */ + /* */ + /* delta_cnt :: The number of to be read. */ + /* */ + /* <Return> */ + /* An array of FT_Short containing the deltas for the affected */ + /* points. (This only gets the deltas for one dimension. It will */ + /* generally be called twice, once for x, once for y. When used in */ + /* cvt table, it will only be called once.) */ + /* */ + static FT_Short* + ft_var_readpackeddeltas( FT_Stream stream, + FT_Int delta_cnt ) + { + FT_Short *deltas; + FT_Int runcnt; + FT_Int i; + FT_Int j; + FT_Memory memory = stream->memory; + FT_Error error = TT_Err_Ok; + + FT_UNUSED( error ); + + + if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) + return NULL; + + i = 0; + while ( i < delta_cnt ) + { + runcnt = FT_GET_BYTE(); + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) + { + /* runcnt zeroes get added */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = 0; + } + else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) + { + /* runcnt shorts from the stack */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = FT_GET_SHORT(); + } + else + { + /* runcnt signed bytes from the stack */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = FT_GET_CHAR(); + } + + if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) + { + /* Bad format */ + FT_FREE( deltas ); + return NULL; + } + } + + return deltas; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_load_avar */ + /* */ + /* <Description> */ + /* Parse the `avar' table if present. It need not be, so we return */ + /* nothing. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + static void + ft_var_load_avar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM(face); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + GX_AVarSegment segment; + FT_Error error = TT_Err_Ok; + FT_ULong version; + FT_Long axisCount; + FT_Int i, j; + FT_ULong table_len; + + FT_UNUSED( error ); + + + blend->avar_checked = TRUE; + if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 ) + return; + + if ( FT_FRAME_ENTER( table_len ) ) + return; + + version = FT_GET_LONG(); + axisCount = FT_GET_LONG(); + + if ( version != 0x00010000L || + axisCount != (FT_Long)blend->mmvar->num_axis ) + goto Exit; + + if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) + goto Exit; + + segment = &blend->avar_segment[0]; + for ( i = 0; i < axisCount; ++i, ++segment ) + { + segment->pairCount = FT_GET_USHORT(); + if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) + { + /* Failure. Free everything we have done so far. We must do */ + /* it right now since loading the `avar' table is optional. */ + + for ( j = i - 1; j >= 0; --j ) + FT_FREE( blend->avar_segment[j].correspondence ); + + FT_FREE( blend->avar_segment ); + blend->avar_segment = NULL; + goto Exit; + } + + for ( j = 0; j < segment->pairCount; ++j ) + { + segment->correspondence[j].fromCoord = + FT_GET_SHORT() << 2; /* convert to Fixed */ + segment->correspondence[j].toCoord = + FT_GET_SHORT()<<2; /* convert to Fixed */ + } + } + + Exit: + FT_FRAME_EXIT(); + } + + + typedef struct GX_GVar_Head_ { + FT_Long version; + FT_UShort axisCount; + FT_UShort globalCoordCount; + FT_ULong offsetToCoord; + FT_UShort glyphCount; + FT_UShort flags; + FT_ULong offsetToData; + + } GX_GVar_Head; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_load_gvar */ + /* */ + /* <Description> */ + /* Parses the `gvar' table if present. If `fvar' is there, `gvar' */ + /* had better be there too. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + ft_var_load_gvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM(face); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Error error; + FT_UInt i, j; + FT_ULong table_len; + FT_ULong gvar_start; + FT_ULong offsetToData; + GX_GVar_Head gvar_head; + + static const FT_Frame_Field gvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_GVar_Head + + FT_FRAME_START( 20 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( globalCoordCount ), + FT_FRAME_ULONG ( offsetToCoord ), + FT_FRAME_USHORT( glyphCount ), + FT_FRAME_USHORT( flags ), + FT_FRAME_ULONG ( offsetToData ), + FT_FRAME_END + }; + + if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) + goto Exit; + + gvar_start = FT_STREAM_POS( ); + if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) + goto Exit; + + blend->tuplecount = gvar_head.globalCoordCount; + blend->gv_glyphcnt = gvar_head.glyphCount; + offsetToData = gvar_start + gvar_head.offsetToData; + + if ( gvar_head.version != (FT_Long)0x00010000L || + gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) + { + error = TT_Err_Invalid_Table; + goto Exit; + } + + if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) + goto Exit; + + if ( gvar_head.flags & 1 ) + { + /* long offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) + goto Exit; + + for ( i = 0; i <= blend->gv_glyphcnt; ++i ) + blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); + + FT_FRAME_EXIT(); + } + else + { + /* short offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) + goto Exit; + + for ( i = 0; i <= blend->gv_glyphcnt; ++i ) + blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; + /* XXX: Undocumented: `*2'! */ + + FT_FRAME_EXIT(); + } + + if ( blend->tuplecount != 0 ) + { + if ( FT_NEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * blend->tuplecount ) ) + goto Exit; + + if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || + FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) + goto Exit; + + for ( i = 0; i < blend->tuplecount; ++i ) + for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) + blend->tuplecoords[i * gvar_head.axisCount + j] = + FT_GET_SHORT() << 2; /* convert to FT_Fixed */ + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_apply_tuple */ + /* */ + /* <Description> */ + /* Figure out whether a given tuple (design) applies to the current */ + /* blend, and if so, what is the scaling factor. */ + /* */ + /* <Input> */ + /* blend :: The current blend of the font. */ + /* */ + /* tupleIndex :: A flag saying whether this is an intermediate */ + /* tuple or not. */ + /* */ + /* tuple_coords :: The coordinates of the tuple in normalized axis */ + /* units. */ + /* */ + /* im_start_coords :: The initial coordinates where this tuple starts */ + /* to apply (for intermediate coordinates). */ + /* */ + /* im_end_coords :: The final coordinates after which this tuple no */ + /* longer applies (for intermediate coordinates). */ + /* */ + /* <Return> */ + /* An FT_Fixed value containing the scaling factor. */ + /* */ + static FT_Fixed + ft_var_apply_tuple( GX_Blend blend, + FT_UShort tupleIndex, + FT_Fixed* tuple_coords, + FT_Fixed* im_start_coords, + FT_Fixed* im_end_coords ) + { + FT_UInt i; + FT_Fixed apply; + FT_Fixed temp; + + + apply = 0x10000L; + for ( i = 0; i < blend->num_axis; ++i ) + { + if ( tuple_coords[i] == 0 ) + /* It's not clear why (for intermediate tuples) we don't need */ + /* to check against start/end -- the documentation says we don't. */ + /* Similarly, it's unclear why we don't need to scale along the */ + /* axis. */ + continue; + + else if ( blend->normalizedcoords[i] == 0 || + ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || + ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) + { + apply = 0; + break; + } + + else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) + /* not an intermediate tuple */ + apply = FT_MulDiv( apply, + blend->normalizedcoords[i] > 0 + ? blend->normalizedcoords[i] + : -blend->normalizedcoords[i], + 0x10000L ); + + else if ( blend->normalizedcoords[i] <= im_start_coords[i] || + blend->normalizedcoords[i] >= im_end_coords[i] ) + { + apply = 0; + break; + } + + else if ( blend->normalizedcoords[i] < tuple_coords[i] ) + { + temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i], + 0x10000L, + tuple_coords[i] - im_start_coords[i]); + apply = FT_MulDiv( apply, temp, 0x10000L ); + } + + else + { + temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i], + 0x10000L, + im_end_coords[i] - tuple_coords[i] ); + apply = FT_MulDiv( apply, temp, 0x10000L ); + } + } + + return apply; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct GX_FVar_Head_ { + FT_Long version; + FT_UShort offsetToData; + FT_UShort countSizePairs; + FT_UShort axisCount; + FT_UShort axisSize; + FT_UShort instanceCount; + FT_UShort instanceSize; + + } GX_FVar_Head; + + + typedef struct fvar_axis { + FT_ULong axisTag; + FT_ULong minValue; + FT_ULong defaultValue; + FT_ULong maxValue; + FT_UShort flags; + FT_UShort nameID; + + } GX_FVar_Axis; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Get_MM_Var */ + /* */ + /* <Description> */ + /* Check that the font's `fvar' table is valid, parse it, and return */ + /* those data. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* TT_Get_MM_Var initializes the blend structure. */ + /* */ + /* <Output> */ + /* master :: The `fvar' data (must be freed by caller). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Var( TT_Face face, + FT_MM_Var* *master ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + FT_ULong table_len; + FT_Error error = TT_Err_Ok; + FT_ULong fvar_start; + FT_Int i, j; + FT_MM_Var* mmvar; + FT_Fixed* next_coords; + FT_String* next_name; + FT_Var_Axis* a; + FT_Var_Named_Style* ns; + GX_FVar_Head fvar_head; + + static const FT_Frame_Field fvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Head + + FT_FRAME_START( 16 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( offsetToData ), + FT_FRAME_USHORT( countSizePairs ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( axisSize ), + FT_FRAME_USHORT( instanceCount ), + FT_FRAME_USHORT( instanceSize ), + FT_FRAME_END + }; + + static const FT_Frame_Field fvaraxis_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Axis + + FT_FRAME_START( 20 ), + FT_FRAME_ULONG ( axisTag ), + FT_FRAME_ULONG ( minValue ), + FT_FRAME_ULONG ( defaultValue ), + FT_FRAME_ULONG ( maxValue ), + FT_FRAME_USHORT( flags ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_END + }; + + + if ( face->blend == NULL ) + { + /* both `fvar' and `gvar' must be present */ + if ( (error = face->goto_table( face, TTAG_gvar, + stream, &table_len )) != 0 ) + goto Exit; + + if ( (error = face->goto_table( face, TTAG_fvar, + stream, &table_len )) != 0 ) + goto Exit; + + fvar_start = FT_STREAM_POS( ); + + if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) + goto Exit; + + if ( fvar_head.version != (FT_Long)0x00010000L || + fvar_head.countSizePairs != 2 || + fvar_head.axisSize != 20 || + fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || + fvar_head.offsetToData + fvar_head.axisCount * 20U + + fvar_head.instanceCount * fvar_head.instanceSize > table_len ) + { + error = TT_Err_Invalid_Table; + goto Exit; + } + + if ( FT_NEW( face->blend ) ) + goto Exit; + + /* XXX: TODO - check for overflows */ + face->blend->mmvar_len = + sizeof ( FT_MM_Var ) + + fvar_head.axisCount * sizeof ( FT_Var_Axis ) + + fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + + fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + + 5 * fvar_head.axisCount; + + if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + goto Exit; + face->blend->mmvar = mmvar; + + mmvar->num_axis = + fvar_head.axisCount; + mmvar->num_designs = + (FT_UInt)-1; /* meaningless in this context; each glyph */ + /* may have a different number of designs */ + /* (or tuples, as called by Apple) */ + mmvar->num_namedstyles = + fvar_head.instanceCount; + mmvar->axis = + (FT_Var_Axis*)&(mmvar[1]); + mmvar->namedstyle = + (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); + + next_coords = + (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); + for ( i = 0; i < fvar_head.instanceCount; ++i ) + { + mmvar->namedstyle[i].coords = next_coords; + next_coords += fvar_head.axisCount; + } + + next_name = (FT_String*)next_coords; + for ( i = 0; i < fvar_head.axisCount; ++i ) + { + mmvar->axis[i].name = next_name; + next_name += 5; + } + + if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) + goto Exit; + + a = mmvar->axis; + for ( i = 0; i < fvar_head.axisCount; ++i ) + { + GX_FVar_Axis axis_rec; + + + if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) + goto Exit; + a->tag = axis_rec.axisTag; + a->minimum = axis_rec.minValue; /* A Fixed */ + a->def = axis_rec.defaultValue; /* A Fixed */ + a->maximum = axis_rec.maxValue; /* A Fixed */ + a->strid = axis_rec.nameID; + + a->name[0] = (FT_String)( a->tag >> 24 ); + a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); + a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); + a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); + a->name[4] = 0; + + ++a; + } + + ns = mmvar->namedstyle; + for ( i = 0; i < fvar_head.instanceCount; ++i ) + { + if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) + goto Exit; + + ns->strid = FT_GET_USHORT(); + (void) /* flags = */ FT_GET_USHORT(); + + for ( j = 0; j < fvar_head.axisCount; ++j ) + ns->coords[j] = FT_GET_ULONG(); /* A Fixed */ + + FT_FRAME_EXIT(); + } + } + + if ( master != NULL ) + { + FT_UInt n; + + + if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + goto Exit; + FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); + + mmvar->axis = + (FT_Var_Axis*)&(mmvar[1]); + mmvar->namedstyle = + (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); + next_coords = + (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); + + for ( n = 0; n < mmvar->num_namedstyles; ++n ) + { + mmvar->namedstyle[n].coords = next_coords; + next_coords += mmvar->num_axis; + } + + a = mmvar->axis; + next_name = (FT_String*)next_coords; + for ( n = 0; n < mmvar->num_axis; ++n ) + { + a->name = next_name; + + /* standard PostScript names for some standard apple tags */ + if ( a->tag == TTAG_wght ) + a->name = (char *)"Weight"; + else if ( a->tag == TTAG_wdth ) + a->name = (char *)"Width"; + else if ( a->tag == TTAG_opsz ) + a->name = (char *)"OpticalSize"; + else if ( a->tag == TTAG_slnt ) + a->name = (char *)"Slant"; + + next_name += 5; + ++a; + } + + *master = mmvar; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Set_MM_Blend */ + /* */ + /* <Description> */ + /* Set the blend (normalized) coordinates for this instance of the */ + /* font. Check that the `gvar' table is reasonable and does some */ + /* initial preparation. */ + /* */ + /* <InOut> */ + /* face :: The font. */ + /* Initialize the blend structure with `gvar' data. */ + /* */ + /* <Input> */ + /* num_coords :: Must be the axis count of the font. */ + /* */ + /* coords :: An array of num_coords, each between [-1,1]. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = TT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + FT_Memory memory = face->root.memory; + + enum + { + mcvt_retain, + mcvt_modify, + mcvt_load + + } manageCvt; + + + face->doblend = FALSE; + + if ( face->blend == NULL ) + { + if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) + goto Exit; + } + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords != mmvar->num_axis ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + + for ( i = 0; i < num_coords; ++i ) + if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + + if ( blend->glyphoffsets == NULL ) + if ( (error = ft_var_load_gvar( face )) != 0 ) + goto Exit; + + if ( blend->normalizedcoords == NULL ) + { + if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) + goto Exit; + + manageCvt = mcvt_modify; + + /* If we have not set the blend coordinates before this, then the */ + /* cvt table will still be what we read from the `cvt ' table and */ + /* we don't need to reload it. We may need to change it though... */ + } + else + { + for ( i = 0; + i < num_coords && blend->normalizedcoords[i] == coords[i]; + ++i ); + if ( i == num_coords ) + manageCvt = mcvt_retain; + else + manageCvt = mcvt_load; + + /* If we don't change the blend coords then we don't need to do */ + /* anything to the cvt table. It will be correct. Otherwise we */ + /* no longer have the original cvt (it was modified when we set */ + /* the blend last time), so we must reload and then modify it. */ + } + + blend->num_axis = num_coords; + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); + + face->doblend = TRUE; + + if ( face->cvt != NULL ) + { + switch ( manageCvt ) + { + case mcvt_load: + /* The cvt table has been loaded already; every time we change the */ + /* blend we may need to reload and remodify the cvt table. */ + FT_FREE( face->cvt ); + face->cvt = NULL; + + tt_face_load_cvt( face, face->root.stream ); + break; + + case mcvt_modify: + /* The original cvt table is in memory. All we need to do is */ + /* apply the `cvar' table (if any). */ + tt_face_vary_cvt( face, face->root.stream ); + break; + + case mcvt_retain: + /* The cvt table is correct for this set of coordinates. */ + break; + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Set_Var_Design */ + /* */ + /* <Description> */ + /* Set the coordinates for the instance, measured in the user */ + /* coordinate system. Parse the `avar' table (if present) to convert */ + /* from user to normalized coordinates. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* Initialize the blend struct with `gvar' data. */ + /* */ + /* <Input> */ + /* num_coords :: This must be the axis count of the font. */ + /* */ + /* coords :: A coordinate array with `num_coords' elements. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = TT_Err_Ok; + FT_Fixed* normalized = NULL; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i, j; + FT_Var_Axis* a; + GX_AVarSegment av; + FT_Memory memory = face->root.memory; + + + if ( face->blend == NULL ) + { + if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) + goto Exit; + } + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords != mmvar->num_axis ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + + /* Axis normalization is a two stage process. First we normalize */ + /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ + /* Then, if there's an `avar' table, we renormalize this range. */ + + if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) + goto Exit; + + a = mmvar->axis; + for ( i = 0; i < mmvar->num_axis; ++i, ++a ) + { + if ( coords[i] > a->maximum || coords[i] < a->minimum ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + + if ( coords[i] < a->def ) + { + normalized[i] = -FT_MulDiv( coords[i] - a->def, + 0x10000L, + a->minimum - a->def ); + } + else if ( a->maximum == a->def ) + normalized[i] = 0; + else + { + normalized[i] = FT_MulDiv( coords[i] - a->def, + 0x10000L, + a->maximum - a->def ); + } + } + + if ( !blend->avar_checked ) + ft_var_load_avar( face ); + + if ( blend->avar_segment != NULL ) + { + av = blend->avar_segment; + for ( i = 0; i < mmvar->num_axis; ++i, ++av ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) + if ( normalized[i] < av->correspondence[j].fromCoord ) + { + normalized[i] = + FT_MulDiv( + FT_MulDiv( + normalized[i] - av->correspondence[j - 1].fromCoord, + 0x10000L, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ), + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + 0x10000L ) + + av->correspondence[j - 1].toCoord; + break; + } + } + } + + error = TT_Set_MM_Blend( face, num_coords, normalized ); + + Exit: + FT_FREE( normalized ); + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GX VAR PARSING ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_vary_cvt */ + /* */ + /* <Description> */ + /* Modify the loaded cvt table according to the `cvar' table and the */ + /* font's blend. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* Most errors are ignored. It is perfectly valid not to have a */ + /* `cvar' table even if there is a `gvar' and `fvar' table. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_start; + FT_ULong table_len; + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong here; + FT_UInt i, j; + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + GX_Blend blend = face->blend; + FT_UInt point_count; + FT_UShort* localpoints; + FT_Short* deltas; + + + FT_TRACE2(( "CVAR " )); + + if ( blend == NULL ) + { + FT_TRACE2(( "no blend specified!\n" )); + + error = TT_Err_Ok; + goto Exit; + } + + if ( face->cvt == NULL ) + { + FT_TRACE2(( "no `cvt ' table!\n" )); + + error = TT_Err_Ok; + goto Exit; + } + + error = face->goto_table( face, TTAG_cvar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing!\n" )); + + error = TT_Err_Ok; + goto Exit; + } + + if ( FT_FRAME_ENTER( table_len ) ) + { + error = TT_Err_Ok; + goto Exit; + } + + table_start = FT_Stream_FTell( stream ); + if ( FT_GET_LONG() != 0x00010000L ) + { + FT_TRACE2(( "bad table version!\n" )); + + error = TT_Err_Ok; + goto FExit; + } + + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto FExit; + + tupleCount = FT_GET_USHORT(); + offsetToData = table_start + FT_GET_USHORT(); + + /* The documentation implies there are flags packed into the */ + /* tuplecount, but John Jenkins says that shared points don't apply */ + /* to `cvar', and no other flags are defined. */ + + for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + /* There is no provision here for a global tuple coordinate section, */ + /* so John says. There are no tuple indices, just embedded tuples. */ + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; ++j ) + tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ + /* short frac to fixed */ + } + else + { + /* skip this tuple; it makes no sense */ + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + for ( j = 0; j < 2 * blend->num_axis; ++j ) + (void)FT_GET_SHORT(); + + offsetToData += tupleDataSize; + continue; + } + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; ++j ) + im_start_coords[j] = FT_GET_SHORT() << 2; + for ( j = 0; j < blend->num_axis; ++j ) + im_end_coords[j] = FT_GET_SHORT() << 2; + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + if ( /* tuple isn't active for our blend */ + apply == 0 || + /* global points not allowed, */ + /* if they aren't local, makes no sense */ + !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + localpoints = ft_var_readpackedpoints( stream, &point_count ); + deltas = ft_var_readpackeddeltas( stream, + point_count == 0 ? face->cvt_size + : point_count ); + if ( localpoints == NULL || deltas == NULL ) + /* failure, ignore it */; + + else if ( localpoints == ALL_POINTS ) + { + /* this means that there are deltas for every entry in cvt */ + for ( j = 0; j < face->cvt_size; ++j ) + face->cvt[j] = (FT_Short)( face->cvt[j] + + FT_MulFix( deltas[j], apply ) ); + } + + else + { + for ( j = 0; j < point_count; ++j ) + { + int pindex = localpoints[j]; + + face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + + FT_MulFix( deltas[j], apply ) ); + } + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + FExit: + FT_FRAME_EXIT(); + + Exit: + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Vary_Get_Glyph_Deltas */ + /* */ + /* <Description> */ + /* Load the appropriate deltas for the current glyph. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* glyph_index :: The index of the glyph being modified. */ + /* */ + /* n_points :: The number of the points in the glyph, including */ + /* phantom points. */ + /* */ + /* <Output> */ + /* deltas :: The array of points to change. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Vary_Get_Glyph_Deltas( TT_Face face, + FT_UInt glyph_index, + FT_Vector* *deltas, + FT_UInt n_points ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Vector* delta_xy; + + FT_Error error; + FT_ULong glyph_start; + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong here; + FT_UInt i, j; + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + FT_UInt point_count, spoint_count = 0; + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + FT_Short *deltas_x, *deltas_y; + + + if ( !face->doblend || blend == NULL ) + return TT_Err_Invalid_Argument; + + /* to be freed by the caller */ + if ( FT_NEW_ARRAY( delta_xy, n_points ) ) + goto Exit; + *deltas = delta_xy; + + if ( glyph_index >= blend->gv_glyphcnt || + blend->glyphoffsets[glyph_index] == + blend->glyphoffsets[glyph_index + 1] ) + return TT_Err_Ok; /* no variation data for this glyph */ + + if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || + FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - + blend->glyphoffsets[glyph_index] ) ) + goto Fail1; + + glyph_start = FT_Stream_FTell( stream ); + + /* each set of glyph variation data is formatted similarly to `cvar' */ + /* (except we get shared points and global tuples) */ + + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto Fail2; + + tupleCount = FT_GET_USHORT(); + offsetToData = glyph_start + FT_GET_USHORT(); + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; ++j ) + tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ + /* short frac to fixed */ + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + { + error = TT_Err_Invalid_Table; + goto Fail3; + } + else + { + FT_MEM_COPY( + tuple_coords, + &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], + blend->num_axis * sizeof ( FT_Fixed ) ); + } + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; ++j ) + im_start_coords[j] = FT_GET_SHORT() << 2; + for ( j = 0; j < blend->num_axis; ++j ) + im_end_coords[j] = FT_GET_SHORT() << 2; + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + + if ( apply == 0 ) /* tuple isn't active for our blend */ + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + FT_Stream_SeekSet( stream, offsetToData ); + + localpoints = ft_var_readpackedpoints( stream, &point_count ); + points = localpoints; + } + else + { + points = sharedpoints; + point_count = spoint_count; + } + + deltas_x = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + deltas_y = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + + if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) + ; /* failure, ignore it */ + + else if ( points == ALL_POINTS ) + { + /* this means that there are deltas for every point in the glyph */ + for ( j = 0; j < n_points; ++j ) + { + delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); + delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); + } + } + + else + { + for ( j = 0; j < point_count; ++j ) + { + delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); + delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); + } + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas_x ); + FT_FREE( deltas_y ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + Fail3: + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + + Fail2: + FT_FRAME_EXIT(); + + Fail1: + if ( error ) + { + FT_FREE( delta_xy ); + *deltas = NULL; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_done_blend */ + /* */ + /* <Description> */ + /* Frees the blend internal data structure. */ + /* */ + FT_LOCAL_DEF( void ) + tt_done_blend( FT_Memory memory, + GX_Blend blend ) + { + if ( blend != NULL ) + { + FT_UInt i; + + + FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->mmvar ); + + if ( blend->avar_segment != NULL ) + { + for ( i = 0; i < blend->num_axis; ++i ) + FT_FREE( blend->avar_segment[i].correspondence ); + FT_FREE( blend->avar_segment ); + } + + FT_FREE( blend->tuplecoords ); + FT_FREE( blend->glyphoffsets ); + FT_FREE( blend ); + } + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + +/* END */ diff --git a/src/freetype2/truetype/ttgxvar.h b/src/freetype2/truetype/ttgxvar.h new file mode 100644 index 0000000..706cb4d --- /dev/null +++ b/src/freetype2/truetype/ttgxvar.h @@ -0,0 +1,182 @@ +/***************************************************************************/ +/* */ +/* ttgxvar.h */ +/* */ +/* TrueType GX Font Variation loader (specification) */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, Werner Lemberg and George Williams. */ +/* */ +/* 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 __TTGXVAR_H__ +#define __TTGXVAR_H__ + + +#include <ft2build.h> +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* GX_AVarCorrespondenceRec */ + /* */ + /* <Description> */ + /* A data structure representing `shortFracCorrespondence' in `avar' */ + /* table according to the specifications from Apple. */ + /* */ + typedef struct GX_AVarCorrespondenceRec_ + { + FT_Fixed fromCoord; + FT_Fixed toCoord; + + } GX_AVarCorrespondenceRec_, *GX_AVarCorrespondence; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* GX_AVarRec */ + /* */ + /* <Description> */ + /* Data from the segment field of `avar' table. */ + /* There is one of these for each axis. */ + /* */ + typedef struct GX_AVarSegmentRec_ + { + FT_UShort pairCount; + GX_AVarCorrespondence correspondence; /* array with pairCount entries */ + + } GX_AVarSegmentRec, *GX_AVarSegment; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* GX_BlendRec */ + /* */ + /* <Description> */ + /* Data for interpolating a font from a distortable font specified */ + /* by the GX *var tables ([fgca]var). */ + /* */ + /* <Fields> */ + /* num_axis :: The number of axes along which interpolation */ + /* may happen */ + /* */ + /* normalizedcoords :: A normalized value (between [-1,1]) indicating */ + /* the contribution along each axis to the final */ + /* interpolated font. */ + /* */ + typedef struct GX_BlendRec_ + { + FT_UInt num_axis; + FT_Fixed* normalizedcoords; + + FT_MM_Var* mmvar; + FT_Int mmvar_len; + + FT_Bool avar_checked; + GX_AVarSegment avar_segment; + + FT_UInt tuplecount; /* shared tuples in `gvar' */ + FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + + FT_UInt gv_glyphcnt; + FT_ULong* glyphoffsets; + + } GX_BlendRec; + + + /*************************************************************************/ + /* */ + /* <enum> */ + /* GX_TupleCountFlags */ + /* */ + /* <Description> */ + /* Flags used within the `TupleCount' field of the `gvar' table. */ + /* */ + typedef enum GX_TupleCountFlags_ + { + GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000, + GX_TC_RESERVED_TUPLE_FLAGS = 0x7000, + GX_TC_TUPLE_COUNT_MASK = 0x0FFF + + } GX_TupleCountFlags; + + + /*************************************************************************/ + /* */ + /* <enum> */ + /* GX_TupleIndexFlags */ + /* */ + /* <Description> */ + /* Flags used within the `TupleIndex' field of the `gvar' and `cvar' */ + /* tables. */ + /* */ + typedef enum GX_TupleIndexFlags_ + { + GX_TI_EMBEDDED_TUPLE_COORD = 0x8000, + GX_TI_INTERMEDIATE_TUPLE = 0x4000, + GX_TI_PRIVATE_POINT_NUMBERS = 0x2000, + GX_TI_RESERVED_TUPLE_FLAG = 0x1000, + GX_TI_TUPLE_INDEX_MASK = 0x0FFF + + } GX_TupleIndexFlags; + + +#define TTAG_wght FT_MAKE_TAG( 'w', 'g', 'h', 't' ) +#define TTAG_wdth FT_MAKE_TAG( 'w', 'd', 't', 'h' ) +#define TTAG_opsz FT_MAKE_TAG( 'o', 'p', 's', 'z' ) +#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' ) + + + FT_LOCAL( FT_Error ) + TT_Set_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Get_MM_Var( TT_Face face, + FT_MM_Var* *master ); + + + FT_LOCAL( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + TT_Vary_Get_Glyph_Deltas( TT_Face face, + FT_UInt glyph_index, + FT_Vector* *deltas, + FT_UInt n_points ); + + + FT_LOCAL( void ) + tt_done_blend( FT_Memory memory, + GX_Blend blend ); + + +FT_END_HEADER + + +#endif /* __TTGXVAR_H__ */ + + +/* END */ diff --git a/src/freetype2/truetype/ttinterp.c b/src/freetype2/truetype/ttinterp.c new file mode 100644 index 0000000..85c8529 --- /dev/null +++ b/src/freetype2/truetype/ttinterp.c @@ -0,0 +1,7809 @@ +/***************************************************************************/ +/* */ +/* ttinterp.c */ +/* */ +/* TrueType bytecode interpreter (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_TRIGONOMETRY_H +#include FT_SYSTEM_H + +#include "ttinterp.h" + +#include "tterrors.h" + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + +#define TT_MULFIX FT_MulFix +#define TT_MULDIV FT_MulDiv +#define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round + + + /*************************************************************************/ + /* */ + /* 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_ttinterp + + /*************************************************************************/ + /* */ + /* In order to detect infinite loops in the code, we set up a counter */ + /* within the run loop. A single stroke of interpretation is now */ + /* limited to a maximal number of opcodes defined below. */ + /* */ +#define MAX_RUNNABLE_OPCODES 1000000L + + + /*************************************************************************/ + /* */ + /* There are two kinds of implementations: */ + /* */ + /* a. static implementation */ + /* */ + /* The current execution context is a static variable, which fields */ + /* are accessed directly by the interpreter during execution. The */ + /* context is named `cur'. */ + /* */ + /* This version is non-reentrant, of course. */ + /* */ + /* b. indirect implementation */ + /* */ + /* The current execution context is passed to _each_ function as its */ + /* first argument, and each field is thus accessed indirectly. */ + /* */ + /* This version is fully re-entrant. */ + /* */ + /* The idea is that an indirect implementation may be slower to execute */ + /* on low-end processors that are used in some systems (like 386s or */ + /* even 486s). */ + /* */ + /* As a consequence, the indirect implementation is now the default, as */ + /* its performance costs can be considered negligible in our context. */ + /* Note, however, that we kept the same source with macros because: */ + /* */ + /* - The code is kept very close in design to the Pascal code used for */ + /* development. */ + /* */ + /* - It's much more readable that way! */ + /* */ + /* - It's still open to experimentation and tuning. */ + /* */ + /*************************************************************************/ + + +#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */ + +#define CUR (*exc) /* see ttobjs.h */ + + /*************************************************************************/ + /* */ + /* This macro is used whenever `exec' is unused in a function, to avoid */ + /* stupid warnings from pedantic compilers. */ + /* */ +#define FT_UNUSED_EXEC FT_UNUSED( exc ) + +#else /* static implementation */ + +#define CUR cur + +#define FT_UNUSED_EXEC int __dummy = __dummy + + static + TT_ExecContextRec cur; /* static exec. context variable */ + + /* apparently, we have a _lot_ of direct indexing when accessing */ + /* the static `cur', which makes the code bigger (due to all the */ + /* four bytes addresses). */ + +#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* The instruction argument stack. */ + /* */ +#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */ + + + /*************************************************************************/ + /* */ + /* This macro is used whenever `args' is unused in a function, to avoid */ + /* stupid warnings from pedantic compilers. */ + /* */ +#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args ) + + + /*************************************************************************/ + /* */ + /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */ + /* increase readability of the code. */ + /* */ + /*************************************************************************/ + + +#define SKIP_Code() \ + SkipCode( EXEC_ARG ) + +#define GET_ShortIns() \ + GetShortIns( EXEC_ARG ) + +#define NORMalize( x, y, v ) \ + Normalize( EXEC_ARG_ x, y, v ) + +#define SET_SuperRound( scale, flags ) \ + SetSuperRound( EXEC_ARG_ scale, flags ) + +#define ROUND_None( d, c ) \ + Round_None( EXEC_ARG_ d, c ) + +#define INS_Goto_CodeRange( range, ip ) \ + Ins_Goto_CodeRange( EXEC_ARG_ range, ip ) + +#define CUR_Func_move( z, p, d ) \ + CUR.func_move( EXEC_ARG_ z, p, d ) + +#define CUR_Func_move_orig( z, p, d ) \ + CUR.func_move_orig( EXEC_ARG_ z, p, d ) + +#define CUR_Func_round( d, c ) \ + CUR.func_round( EXEC_ARG_ d, c ) + +#define CUR_Func_read_cvt( index ) \ + CUR.func_read_cvt( EXEC_ARG_ index ) + +#define CUR_Func_write_cvt( index, val ) \ + CUR.func_write_cvt( EXEC_ARG_ index, val ) + +#define CUR_Func_move_cvt( index, val ) \ + CUR.func_move_cvt( EXEC_ARG_ index, val ) + +#define CURRENT_Ratio() \ + Current_Ratio( EXEC_ARG ) + +#define CURRENT_Ppem() \ + Current_Ppem( EXEC_ARG ) + +#define CUR_Ppem() \ + Cur_PPEM( EXEC_ARG ) + +#define INS_SxVTL( a, b, c, d ) \ + Ins_SxVTL( EXEC_ARG_ a, b, c, d ) + +#define COMPUTE_Funcs() \ + Compute_Funcs( EXEC_ARG ) + +#define COMPUTE_Round( a ) \ + Compute_Round( EXEC_ARG_ a ) + +#define COMPUTE_Point_Displacement( a, b, c, d ) \ + Compute_Point_Displacement( EXEC_ARG_ a, b, c, d ) + +#define MOVE_Zp2_Point( a, b, c, t ) \ + Move_Zp2_Point( EXEC_ARG_ a, b, c, t ) + + +#define CUR_Func_project( v1, v2 ) \ + CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y ) + +#define CUR_Func_dualproj( v1, v2 ) \ + CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y ) + +#define CUR_fast_project( v ) \ + CUR.func_project( EXEC_ARG_ (v)->x, (v)->y ) + +#define CUR_fast_dualproj( v ) \ + CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y ) + + + /*************************************************************************/ + /* */ + /* Instruction dispatch function, as used by the interpreter. */ + /* */ + typedef void (*TInstruction_Function)( INS_ARG ); + + + /*************************************************************************/ + /* */ + /* A simple bounds-checking macro. */ + /* */ +#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) + +#undef SUCCESS +#define SUCCESS 0 + +#undef FAILURE +#define FAILURE 1 + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING +#define GUESS_VECTOR( V ) \ + if ( CUR.face->unpatented_hinting ) \ + { \ + CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \ + CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \ + } +#else +#define GUESS_VECTOR( V ) +#endif + + /*************************************************************************/ + /* */ + /* CODERANGE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Goto_CodeRange */ + /* */ + /* <Description> */ + /* Switches to a new code range (updates the code related elements in */ + /* `exec', and `IP'). */ + /* */ + /* <Input> */ + /* range :: The new execution code range. */ + /* */ + /* IP :: The new IP in the new code range. */ + /* */ + /* <InOut> */ + /* exec :: The target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ) + { + TT_CodeRange* coderange; + + + FT_ASSERT( range >= 1 && range <= 3 ); + + coderange = &exec->codeRangeTable[range - 1]; + + FT_ASSERT( coderange->base != NULL ); + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for IP <= Size instead of IP < Size. */ + /* */ + FT_ASSERT( (FT_ULong)IP <= coderange->size ); + + exec->code = coderange->base; + exec->codeSize = coderange->size; + exec->IP = IP; + exec->curRange = range; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Set_CodeRange */ + /* */ + /* <Description> */ + /* Sets a code range. */ + /* */ + /* <Input> */ + /* range :: The code range index. */ + /* */ + /* base :: The new code base. */ + /* */ + /* length :: The range size in bytes. */ + /* */ + /* <InOut> */ + /* exec :: The target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].size = length; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Clear_CodeRange */ + /* */ + /* <Description> */ + /* Clears a code range. */ + /* */ + /* <Input> */ + /* range :: The code range index. */ + /* */ + /* <InOut> */ + /* exec :: The target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Does not set the Error variable. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = NULL; + exec->codeRangeTable[range - 1].size = 0; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* EXECUTION CONTEXT ROUTINES */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Done_Context */ + /* */ + /* <Description> */ + /* Destroys a given context. */ + /* */ + /* <Input> */ + /* exec :: A handle to the target execution context. */ + /* */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Done_Context( TT_ExecContext exec ) + { + FT_Memory memory = exec->memory; + + + /* points zone */ + exec->maxPoints = 0; + exec->maxContours = 0; + + /* free stack */ + FT_FREE( exec->stack ); + exec->stackSize = 0; + + /* free call stack */ + FT_FREE( exec->callStack ); + exec->callSize = 0; + exec->callTop = 0; + + /* free glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->size = NULL; + exec->face = NULL; + + FT_FREE( exec ); + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Init_Context */ + /* */ + /* <Description> */ + /* Initializes a context object. */ + /* */ + /* <Input> */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* <InOut> */ + /* exec :: A handle to the target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Init_Context( TT_ExecContext exec, + FT_Memory memory ) + { + FT_Error error; + + + FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec )); + + exec->memory = memory; + exec->callSize = 32; + + if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) ) + goto Fail_Memory; + + /* all values in the context are set to 0 already, but this is */ + /* here as a remainder */ + exec->maxPoints = 0; + exec->maxContours = 0; + + exec->stackSize = 0; + exec->glyphSize = 0; + + exec->stack = NULL; + exec->glyphIns = NULL; + + exec->face = NULL; + exec->size = NULL; + + return TT_Err_Ok; + + Fail_Memory: + FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n", + (FT_Long)exec )); + TT_Done_Context( exec ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Update_Max */ + /* */ + /* <Description> */ + /* Checks the size of a buffer and reallocates it if necessary. */ + /* */ + /* <Input> */ + /* memory :: A handle to the parent memory object. */ + /* */ + /* multiplier :: The size in bytes of each element in the buffer. */ + /* */ + /* new_max :: The new capacity (size) of the buffer. */ + /* */ + /* <InOut> */ + /* size :: The address of the buffer's current size expressed */ + /* in elements. */ + /* */ + /* buff :: The address of the buffer base pointer. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + Update_Max( FT_Memory memory, + FT_ULong* size, + FT_Long multiplier, + void* _pbuff, + FT_ULong new_max ) + { + FT_Error error; + void** pbuff = (void**)_pbuff; + + + if ( *size < new_max ) + { + if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) ) + return error; + *size = new_max; + } + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Load_Context */ + /* */ + /* <Description> */ + /* Prepare an execution context for glyph hinting. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* size :: A handle to the source size object. */ + /* */ + /* <InOut> */ + /* exec :: A handle to the target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ) + { + FT_Int i; + FT_ULong tmp; + TT_MaxProfile* maxp; + FT_Error error; + + + exec->face = face; + maxp = &face->max_profile; + exec->size = size; + + if ( size ) + { + exec->numFDefs = size->num_function_defs; + exec->maxFDefs = size->max_function_defs; + exec->numIDefs = size->num_instruction_defs; + exec->maxIDefs = size->max_instruction_defs; + exec->FDefs = size->function_defs; + exec->IDefs = size->instruction_defs; + exec->tt_metrics = size->ttmetrics; + exec->metrics = size->metrics; + + exec->maxFunc = size->max_func; + exec->maxIns = size->max_ins; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + exec->codeRangeTable[i] = size->codeRangeTable[i]; + + /* set graphics state */ + exec->GS = size->GS; + + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + + exec->storeSize = size->storage_size; + exec->storage = size->storage; + + exec->twilight = size->twilight; + } + + /* XXX: We reserve a little more elements on the stack to deal safely */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + tmp = exec->stackSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_F26Dot6 ), + (void*)&exec->stack, + maxp->maxStackElements + 32 ); + exec->stackSize = (FT_UInt)tmp; + if ( error ) + return error; + + tmp = exec->glyphSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&exec->glyphIns, + maxp->maxSizeOfInstructions ); + exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; + + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + exec->zp0 = exec->pts; + + exec->instruction_trap = FALSE; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Save_Context */ + /* */ + /* <Description> */ + /* Saves the code ranges in a `size' object. */ + /* */ + /* <Input> */ + /* exec :: A handle to the source execution context. */ + /* */ + /* <InOut> */ + /* size :: A handle to the target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Save_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_Int i; + + + /* XXXX: Will probably disappear soon with all the code range */ + /* management, which is now rather obsolete. */ + /* */ + size->num_function_defs = exec->numFDefs; + size->num_instruction_defs = exec->numIDefs; + + size->max_func = exec->maxFunc; + size->max_ins = exec->maxIns; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + size->codeRangeTable[i] = exec->codeRangeTable[i]; + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Run_Context */ + /* */ + /* <Description> */ + /* Executes one or more instructions in the execution context. */ + /* */ + /* <Input> */ + /* debug :: A Boolean flag. If set, the function sets some internal */ + /* variables and returns immediately, otherwise TT_RunIns() */ + /* is called. */ + /* */ + /* This is commented out currently. */ + /* */ + /* <Input> */ + /* exec :: A handle to the target execution context. */ + /* */ + /* <Return> */ + /* TrueTyoe error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ) + { + FT_Error error; + + + if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) ) + != TT_Err_Ok ) + return error; + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0000; + + exec->GS.freeVector = exec->GS.projVector; + exec->GS.dualVector = exec->GS.projVector; + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + exec->GS.both_x_axis = TRUE; +#endif + + exec->GS.round_state = 1; + exec->GS.loop = 1; + + /* some glyphs leave something on the stack. so we clean it */ + /* before a new execution. */ + exec->top = 0; + exec->callTop = 0; + +#if 1 + FT_UNUSED( debug ); + + return exec->face->interpreter( exec ); +#else + if ( !debug ) + return TT_RunIns( exec ); + else + return TT_Err_Ok; +#endif + } + + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, + { 0x4000, 0 }, + { 0x4000, 0 }, + { 0x4000, 0 }, + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + TRUE, +#endif + + 1, 64, 1, + TRUE, 68, 0, 0, 9, 3, + 0, FALSE, 2, 1, 1, 1 + }; + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( TT_ExecContext ) + TT_New_Context( TT_Driver driver ) + { + TT_ExecContext exec; + FT_Memory memory; + + + memory = driver->root.root.memory; + exec = driver->context; + + if ( !driver->context ) + { + FT_Error error; + + + /* allocate object */ + if ( FT_NEW( exec ) ) + goto Exit; + + /* initialize it */ + error = Init_Context( exec, memory ); + if ( error ) + goto Fail; + + /* store it into the driver */ + driver->context = exec; + } + + Exit: + return driver->context; + + Fail: + FT_FREE( exec ); + + return 0; + } + + + /*************************************************************************/ + /* */ + /* Before an opcode is executed, the interpreter verifies that there are */ + /* enough arguments on the stack, with the help of the `Pop_Push_Count' */ + /* table. */ + /* */ + /* For each opcode, the first column gives the number of arguments that */ + /* are popped from the stack; the second one gives the number of those */ + /* that are pushed in result. */ + /* */ + /* Opcodes which have a varying number of parameters in the data stream */ + /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */ + /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */ + /* to zero. */ + /* */ + /*************************************************************************/ + + +#undef PACK +#define PACK( x, y ) ( ( x << 4 ) | y ) + + + static + const FT_Byte Pop_Push_Count[256] = + { + /* opcodes are gathered in groups of 16 */ + /* please keep the spaces as they are */ + + /* SVTCA y */ PACK( 0, 0 ), + /* SVTCA x */ PACK( 0, 0 ), + /* SPvTCA y */ PACK( 0, 0 ), + /* SPvTCA x */ PACK( 0, 0 ), + /* SFvTCA y */ PACK( 0, 0 ), + /* SFvTCA x */ PACK( 0, 0 ), + /* SPvTL // */ PACK( 2, 0 ), + /* SPvTL + */ PACK( 2, 0 ), + /* SFvTL // */ PACK( 2, 0 ), + /* SFvTL + */ PACK( 2, 0 ), + /* SPvFS */ PACK( 2, 0 ), + /* SFvFS */ PACK( 2, 0 ), + /* GPV */ PACK( 0, 2 ), + /* GFV */ PACK( 0, 2 ), + /* SFvTPv */ PACK( 0, 0 ), + /* ISECT */ PACK( 5, 0 ), + + /* SRP0 */ PACK( 1, 0 ), + /* SRP1 */ PACK( 1, 0 ), + /* SRP2 */ PACK( 1, 0 ), + /* SZP0 */ PACK( 1, 0 ), + /* SZP1 */ PACK( 1, 0 ), + /* SZP2 */ PACK( 1, 0 ), + /* SZPS */ PACK( 1, 0 ), + /* SLOOP */ PACK( 1, 0 ), + /* RTG */ PACK( 0, 0 ), + /* RTHG */ PACK( 0, 0 ), + /* SMD */ PACK( 1, 0 ), + /* ELSE */ PACK( 0, 0 ), + /* JMPR */ PACK( 1, 0 ), + /* SCvTCi */ PACK( 1, 0 ), + /* SSwCi */ PACK( 1, 0 ), + /* SSW */ PACK( 1, 0 ), + + /* DUP */ PACK( 1, 2 ), + /* POP */ PACK( 1, 0 ), + /* CLEAR */ PACK( 0, 0 ), + /* SWAP */ PACK( 2, 2 ), + /* DEPTH */ PACK( 0, 1 ), + /* CINDEX */ PACK( 1, 1 ), + /* MINDEX */ PACK( 1, 0 ), + /* AlignPTS */ PACK( 2, 0 ), + /* INS_$28 */ PACK( 0, 0 ), + /* UTP */ PACK( 1, 0 ), + /* LOOPCALL */ PACK( 2, 0 ), + /* CALL */ PACK( 1, 0 ), + /* FDEF */ PACK( 1, 0 ), + /* ENDF */ PACK( 0, 0 ), + /* MDAP[0] */ PACK( 1, 0 ), + /* MDAP[1] */ PACK( 1, 0 ), + + /* IUP[0] */ PACK( 0, 0 ), + /* IUP[1] */ PACK( 0, 0 ), + /* SHP[0] */ PACK( 0, 0 ), + /* SHP[1] */ PACK( 0, 0 ), + /* SHC[0] */ PACK( 1, 0 ), + /* SHC[1] */ PACK( 1, 0 ), + /* SHZ[0] */ PACK( 1, 0 ), + /* SHZ[1] */ PACK( 1, 0 ), + /* SHPIX */ PACK( 1, 0 ), + /* IP */ PACK( 0, 0 ), + /* MSIRP[0] */ PACK( 2, 0 ), + /* MSIRP[1] */ PACK( 2, 0 ), + /* AlignRP */ PACK( 0, 0 ), + /* RTDG */ PACK( 0, 0 ), + /* MIAP[0] */ PACK( 2, 0 ), + /* MIAP[1] */ PACK( 2, 0 ), + + /* NPushB */ PACK( 0, 0 ), + /* NPushW */ PACK( 0, 0 ), + /* WS */ PACK( 2, 0 ), + /* RS */ PACK( 1, 1 ), + /* WCvtP */ PACK( 2, 0 ), + /* RCvt */ PACK( 1, 1 ), + /* GC[0] */ PACK( 1, 1 ), + /* GC[1] */ PACK( 1, 1 ), + /* SCFS */ PACK( 2, 0 ), + /* MD[0] */ PACK( 2, 1 ), + /* MD[1] */ PACK( 2, 1 ), + /* MPPEM */ PACK( 0, 1 ), + /* MPS */ PACK( 0, 1 ), + /* FlipON */ PACK( 0, 0 ), + /* FlipOFF */ PACK( 0, 0 ), + /* DEBUG */ PACK( 1, 0 ), + + /* LT */ PACK( 2, 1 ), + /* LTEQ */ PACK( 2, 1 ), + /* GT */ PACK( 2, 1 ), + /* GTEQ */ PACK( 2, 1 ), + /* EQ */ PACK( 2, 1 ), + /* NEQ */ PACK( 2, 1 ), + /* ODD */ PACK( 1, 1 ), + /* EVEN */ PACK( 1, 1 ), + /* IF */ PACK( 1, 0 ), + /* EIF */ PACK( 0, 0 ), + /* AND */ PACK( 2, 1 ), + /* OR */ PACK( 2, 1 ), + /* NOT */ PACK( 1, 1 ), + /* DeltaP1 */ PACK( 1, 0 ), + /* SDB */ PACK( 1, 0 ), + /* SDS */ PACK( 1, 0 ), + + /* ADD */ PACK( 2, 1 ), + /* SUB */ PACK( 2, 1 ), + /* DIV */ PACK( 2, 1 ), + /* MUL */ PACK( 2, 1 ), + /* ABS */ PACK( 1, 1 ), + /* NEG */ PACK( 1, 1 ), + /* FLOOR */ PACK( 1, 1 ), + /* CEILING */ PACK( 1, 1 ), + /* ROUND[0] */ PACK( 1, 1 ), + /* ROUND[1] */ PACK( 1, 1 ), + /* ROUND[2] */ PACK( 1, 1 ), + /* ROUND[3] */ PACK( 1, 1 ), + /* NROUND[0] */ PACK( 1, 1 ), + /* NROUND[1] */ PACK( 1, 1 ), + /* NROUND[2] */ PACK( 1, 1 ), + /* NROUND[3] */ PACK( 1, 1 ), + + /* WCvtF */ PACK( 2, 0 ), + /* DeltaP2 */ PACK( 1, 0 ), + /* DeltaP3 */ PACK( 1, 0 ), + /* DeltaCn[0] */ PACK( 1, 0 ), + /* DeltaCn[1] */ PACK( 1, 0 ), + /* DeltaCn[2] */ PACK( 1, 0 ), + /* SROUND */ PACK( 1, 0 ), + /* S45Round */ PACK( 1, 0 ), + /* JROT */ PACK( 2, 0 ), + /* JROF */ PACK( 2, 0 ), + /* ROFF */ PACK( 0, 0 ), + /* INS_$7B */ PACK( 0, 0 ), + /* RUTG */ PACK( 0, 0 ), + /* RDTG */ PACK( 0, 0 ), + /* SANGW */ PACK( 1, 0 ), + /* AA */ PACK( 1, 0 ), + + /* FlipPT */ PACK( 0, 0 ), + /* FlipRgON */ PACK( 2, 0 ), + /* FlipRgOFF */ PACK( 2, 0 ), + /* INS_$83 */ PACK( 0, 0 ), + /* INS_$84 */ PACK( 0, 0 ), + /* ScanCTRL */ PACK( 1, 0 ), + /* SDVPTL[0] */ PACK( 2, 0 ), + /* SDVPTL[1] */ PACK( 2, 0 ), + /* GetINFO */ PACK( 1, 1 ), + /* IDEF */ PACK( 1, 0 ), + /* ROLL */ PACK( 3, 3 ), + /* MAX */ PACK( 2, 1 ), + /* MIN */ PACK( 2, 1 ), + /* ScanTYPE */ PACK( 1, 0 ), + /* InstCTRL */ PACK( 2, 0 ), + /* INS_$8F */ PACK( 0, 0 ), + + /* INS_$90 */ PACK( 0, 0 ), + /* INS_$91 */ PACK( 0, 0 ), + /* INS_$92 */ PACK( 0, 0 ), + /* INS_$93 */ PACK( 0, 0 ), + /* INS_$94 */ PACK( 0, 0 ), + /* INS_$95 */ PACK( 0, 0 ), + /* INS_$96 */ PACK( 0, 0 ), + /* INS_$97 */ PACK( 0, 0 ), + /* INS_$98 */ PACK( 0, 0 ), + /* INS_$99 */ PACK( 0, 0 ), + /* INS_$9A */ PACK( 0, 0 ), + /* INS_$9B */ PACK( 0, 0 ), + /* INS_$9C */ PACK( 0, 0 ), + /* INS_$9D */ PACK( 0, 0 ), + /* INS_$9E */ PACK( 0, 0 ), + /* INS_$9F */ PACK( 0, 0 ), + + /* INS_$A0 */ PACK( 0, 0 ), + /* INS_$A1 */ PACK( 0, 0 ), + /* INS_$A2 */ PACK( 0, 0 ), + /* INS_$A3 */ PACK( 0, 0 ), + /* INS_$A4 */ PACK( 0, 0 ), + /* INS_$A5 */ PACK( 0, 0 ), + /* INS_$A6 */ PACK( 0, 0 ), + /* INS_$A7 */ PACK( 0, 0 ), + /* INS_$A8 */ PACK( 0, 0 ), + /* INS_$A9 */ PACK( 0, 0 ), + /* INS_$AA */ PACK( 0, 0 ), + /* INS_$AB */ PACK( 0, 0 ), + /* INS_$AC */ PACK( 0, 0 ), + /* INS_$AD */ PACK( 0, 0 ), + /* INS_$AE */ PACK( 0, 0 ), + /* INS_$AF */ PACK( 0, 0 ), + + /* PushB[0] */ PACK( 0, 1 ), + /* PushB[1] */ PACK( 0, 2 ), + /* PushB[2] */ PACK( 0, 3 ), + /* PushB[3] */ PACK( 0, 4 ), + /* PushB[4] */ PACK( 0, 5 ), + /* PushB[5] */ PACK( 0, 6 ), + /* PushB[6] */ PACK( 0, 7 ), + /* PushB[7] */ PACK( 0, 8 ), + /* PushW[0] */ PACK( 0, 1 ), + /* PushW[1] */ PACK( 0, 2 ), + /* PushW[2] */ PACK( 0, 3 ), + /* PushW[3] */ PACK( 0, 4 ), + /* PushW[4] */ PACK( 0, 5 ), + /* PushW[5] */ PACK( 0, 6 ), + /* PushW[6] */ PACK( 0, 7 ), + /* PushW[7] */ PACK( 0, 8 ), + + /* MDRP[00] */ PACK( 1, 0 ), + /* MDRP[01] */ PACK( 1, 0 ), + /* MDRP[02] */ PACK( 1, 0 ), + /* MDRP[03] */ PACK( 1, 0 ), + /* MDRP[04] */ PACK( 1, 0 ), + /* MDRP[05] */ PACK( 1, 0 ), + /* MDRP[06] */ PACK( 1, 0 ), + /* MDRP[07] */ PACK( 1, 0 ), + /* MDRP[08] */ PACK( 1, 0 ), + /* MDRP[09] */ PACK( 1, 0 ), + /* MDRP[10] */ PACK( 1, 0 ), + /* MDRP[11] */ PACK( 1, 0 ), + /* MDRP[12] */ PACK( 1, 0 ), + /* MDRP[13] */ PACK( 1, 0 ), + /* MDRP[14] */ PACK( 1, 0 ), + /* MDRP[15] */ PACK( 1, 0 ), + + /* MDRP[16] */ PACK( 1, 0 ), + /* MDRP[17] */ PACK( 1, 0 ), + /* MDRP[18] */ PACK( 1, 0 ), + /* MDRP[19] */ PACK( 1, 0 ), + /* MDRP[20] */ PACK( 1, 0 ), + /* MDRP[21] */ PACK( 1, 0 ), + /* MDRP[22] */ PACK( 1, 0 ), + /* MDRP[23] */ PACK( 1, 0 ), + /* MDRP[24] */ PACK( 1, 0 ), + /* MDRP[25] */ PACK( 1, 0 ), + /* MDRP[26] */ PACK( 1, 0 ), + /* MDRP[27] */ PACK( 1, 0 ), + /* MDRP[28] */ PACK( 1, 0 ), + /* MDRP[29] */ PACK( 1, 0 ), + /* MDRP[30] */ PACK( 1, 0 ), + /* MDRP[31] */ PACK( 1, 0 ), + + /* MIRP[00] */ PACK( 2, 0 ), + /* MIRP[01] */ PACK( 2, 0 ), + /* MIRP[02] */ PACK( 2, 0 ), + /* MIRP[03] */ PACK( 2, 0 ), + /* MIRP[04] */ PACK( 2, 0 ), + /* MIRP[05] */ PACK( 2, 0 ), + /* MIRP[06] */ PACK( 2, 0 ), + /* MIRP[07] */ PACK( 2, 0 ), + /* MIRP[08] */ PACK( 2, 0 ), + /* MIRP[09] */ PACK( 2, 0 ), + /* MIRP[10] */ PACK( 2, 0 ), + /* MIRP[11] */ PACK( 2, 0 ), + /* MIRP[12] */ PACK( 2, 0 ), + /* MIRP[13] */ PACK( 2, 0 ), + /* MIRP[14] */ PACK( 2, 0 ), + /* MIRP[15] */ PACK( 2, 0 ), + + /* MIRP[16] */ PACK( 2, 0 ), + /* MIRP[17] */ PACK( 2, 0 ), + /* MIRP[18] */ PACK( 2, 0 ), + /* MIRP[19] */ PACK( 2, 0 ), + /* MIRP[20] */ PACK( 2, 0 ), + /* MIRP[21] */ PACK( 2, 0 ), + /* MIRP[22] */ PACK( 2, 0 ), + /* MIRP[23] */ PACK( 2, 0 ), + /* MIRP[24] */ PACK( 2, 0 ), + /* MIRP[25] */ PACK( 2, 0 ), + /* MIRP[26] */ PACK( 2, 0 ), + /* MIRP[27] */ PACK( 2, 0 ), + /* MIRP[28] */ PACK( 2, 0 ), + /* MIRP[29] */ PACK( 2, 0 ), + /* MIRP[30] */ PACK( 2, 0 ), + /* MIRP[31] */ PACK( 2, 0 ) + }; + + + static + const FT_Char opcode_length[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + +#undef PACK + +#if 1 + + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 sign; + FT_UInt32 ah, al, mid, lo, hi; + + + sign = a ^ b; + + if ( a < 0 ) + a = -a; + if ( b < 0 ) + b = -b; + + ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); + al = (FT_UInt32)( a & 0xFFFFU ); + + lo = al * b; + mid = ah * b; + hi = mid >> 16; + mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */ + lo += mid; + if ( lo < mid ) + hi += 1; + + mid = ( lo >> 14 ) | ( hi << 18 ); + + return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; + } + +#else + + /* compute (a*b)/2^14 with maximal accuracy and rounding */ + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 m, s, hi; + FT_UInt32 l, lo; + + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( a & 0xFFFFU ) * b ); + m = ( a >> 16 ) * b; + + lo = l + (FT_UInt32)( m << 16 ); + hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l ); + + /* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + + l = lo + 0x2000U; + hi += l < lo; + + return ( hi << 18 ) | ( l >> 14 ); + } +#endif + + + /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */ + static FT_Int32 + TT_DotFix14( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + FT_Int32 m, s, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); + m = ( ax >> 16 ) * bx; + + lo1 = l + (FT_UInt32)( m << 16 ); + hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l ); + + /* compute ay*by as 64-bit value */ + l = (FT_UInt32)( ( ay & 0xFFFFU ) * by ); + m = ( ay >> 16 ) * by; + + lo2 = l + (FT_UInt32)( m << 16 ); + hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l ); + + /* add them */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); + + /* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + + l = lo + 0x2000U; + hi += ( l < lo ); + + return ( hi << 18 ) | ( l >> 14 ); + } + + + /* return length of given vector */ + +#if 0 + + static FT_Int32 + TT_VecLen( FT_Int32 x, + FT_Int32 y ) + { + FT_Int32 m, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + + /* compute x*x as 64-bit value */ + lo = (FT_UInt32)( x & 0xFFFFU ); + hi = x >> 16; + + l = lo * lo; + m = hi * lo; + hi = hi * hi; + + lo1 = l + (FT_UInt32)( m << 17 ); + hi1 = hi + ( m >> 15 ) + ( lo1 < l ); + + /* compute y*y as 64-bit value */ + lo = (FT_UInt32)( y & 0xFFFFU ); + hi = y >> 16; + + l = lo * lo; + m = hi * lo; + hi = hi * hi; + + lo2 = l + (FT_UInt32)( m << 17 ); + hi2 = hi + ( m >> 15 ) + ( lo2 < l ); + + /* add them to get 'x*x+y*y' as 64-bit value */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); + + /* compute the square root of this value */ + { + FT_UInt32 root, rem, test_div; + FT_Int count; + + + root = 0; + + { + rem = 0; + count = 32; + do + { + rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 ); + hi = ( hi << 2 ) | ( lo >> 30 ); + lo <<= 2; + root <<= 1; + test_div = ( root << 1 ) + 1; + + if ( rem >= test_div ) + { + rem -= test_div; + root += 1; + } + } while ( --count ); + } + + return (FT_Int32)root; + } + } + +#else + + /* this version uses FT_Vector_Length which computes the same value */ + /* much, much faster.. */ + /* */ + static FT_F26Dot6 + TT_VecLen( FT_F26Dot6 X, + FT_F26Dot6 Y ) + { + FT_Vector v; + + + v.x = X; + v.y = Y; + + return FT_Vector_Length( &v ); + } + +#endif + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Current_Ratio */ + /* */ + /* <Description> */ + /* Returns the current aspect ratio scaling factor depending on the */ + /* projection vector's state and device resolutions. */ + /* */ + /* <Return> */ + /* The aspect ratio in 16.16 format, always <= 1.0 . */ + /* */ + static FT_Long + Current_Ratio( EXEC_OP ) + { + if ( !CUR.tt_metrics.ratio ) + { +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( CUR.face->unpatented_hinting ) + { + if ( CUR.GS.both_x_axis ) + CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio; + else + CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio; + } + else +#endif + { + if ( CUR.GS.projVector.y == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio; + + else if ( CUR.GS.projVector.x == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio; + + else + { + FT_Long x, y; + + + x = TT_MULDIV( CUR.GS.projVector.x, + CUR.tt_metrics.x_ratio, 0x4000 ); + y = TT_MULDIV( CUR.GS.projVector.y, + CUR.tt_metrics.y_ratio, 0x4000 ); + CUR.tt_metrics.ratio = TT_VecLen( x, y ); + } + } + } + return CUR.tt_metrics.ratio; + } + + + static FT_Long + Current_Ppem( EXEC_OP ) + { + return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() ); + } + + + /*************************************************************************/ + /* */ + /* Functions related to the control value table (CVT). */ + /* */ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT( EXEC_OP_ FT_ULong idx ) + { + return CUR.cvt[idx]; + } + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT_Stretched( EXEC_OP_ FT_ULong idx ) + { + return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() ); + } + + + FT_CALLBACK_DEF( void ) + Write_CVT( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] = value; + } + + + FT_CALLBACK_DEF( void ) + Write_CVT_Stretched( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() ); + } + + + FT_CALLBACK_DEF( void ) + Move_CVT( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] += value; + } + + + FT_CALLBACK_DEF( void ) + Move_CVT_Stretched( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* GetShortIns */ + /* */ + /* <Description> */ + /* Returns a short integer taken from the instruction stream at */ + /* address IP. */ + /* */ + /* <Return> */ + /* Short read at code[IP]. */ + /* */ + /* <Note> */ + /* This one could become a macro. */ + /* */ + static FT_Short + GetShortIns( EXEC_OP ) + { + /* Reading a byte stream so there is no endianess (DaveP) */ + CUR.IP += 2; + return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) + + CUR.code[CUR.IP - 1] ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Ins_Goto_CodeRange */ + /* */ + /* <Description> */ + /* Goes to a certain code range in the instruction stream. */ + /* */ + /* <Input> */ + /* aRange :: The index of the code range. */ + /* */ + /* aIP :: The new IP address in the code range. */ + /* */ + /* <Return> */ + /* SUCCESS or FAILURE. */ + /* */ + static FT_Bool + Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange, + FT_ULong aIP ) + { + TT_CodeRange* range; + + + if ( aRange < 1 || aRange > 3 ) + { + CUR.error = TT_Err_Bad_Argument; + return FAILURE; + } + + range = &CUR.codeRangeTable[aRange - 1]; + + if ( range->base == NULL ) /* invalid coderange */ + { + CUR.error = TT_Err_Invalid_CodeRange; + return FAILURE; + } + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for AIP <= Size, instead of AIP < Size. */ + + if ( aIP > range->size ) + { + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } + + CUR.code = range->base; + CUR.codeSize = range->size; + CUR.IP = aIP; + CUR.curRange = aRange; + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Direct_Move */ + /* */ + /* <Description> */ + /* Moves a point by a given distance along the freedom vector. The */ + /* point will be `touched'. */ + /* */ + /* <Input> */ + /* point :: The index of the point to move. */ + /* */ + /* distance :: The distance to apply. */ + /* */ + /* <InOut> */ + /* zone :: The affected glyph zone. */ + /* */ + static void + Direct_Move( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + FT_ASSERT( !CUR.face->unpatented_hinting ); +#endif + + v = CUR.GS.freeVector.x; + + if ( v != 0 ) + { + zone->cur[point].x += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + v = CUR.GS.freeVector.y; + + if ( v != 0 ) + { + zone->cur[point].y += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Direct_Move_Orig */ + /* */ + /* <Description> */ + /* Moves the *original* position of a point by a given distance along */ + /* the freedom vector. Obviously, the point will not be `touched'. */ + /* */ + /* <Input> */ + /* point :: The index of the point to move. */ + /* */ + /* distance :: The distance to apply. */ + /* */ + /* <InOut> */ + /* zone :: The affected glyph zone. */ + /* */ + static void + Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + FT_ASSERT( !CUR.face->unpatented_hinting ); +#endif + + v = CUR.GS.freeVector.x; + + if ( v != 0 ) + zone->org[point].x += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + + v = CUR.GS.freeVector.y; + + if ( v != 0 ) + zone->org[point].y += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + } + + + /*************************************************************************/ + /* */ + /* Special versions of Direct_Move() */ + /* */ + /* The following versions are used whenever both vectors are both */ + /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ + /* */ + /*************************************************************************/ + + + static void + Direct_Move_X( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->cur[point].x += distance; + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + + static void + Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->cur[point].y += distance; + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + + + /*************************************************************************/ + /* */ + /* Special versions of Direct_Move_Orig() */ + /* */ + /* The following versions are used whenever both vectors are both */ + /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ + /* */ + /*************************************************************************/ + + + static void + Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->org[point].x += distance; + } + + + static void + Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + + zone->org[point].y += distance; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_None */ + /* */ + /* <Description> */ + /* Does not round, but adds engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance (not) to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* The compensated distance. */ + /* */ + /* <Note> */ + /* The TrueType specification says very few about the relationship */ + /* between rounding and engine compensation. However, it seems from */ + /* the description of super round that we should add the compensation */ + /* before rounding. */ + /* */ + static FT_F26Dot6 + Round_None( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation; + if ( distance && val < 0 ) + val = 0; + } + else { + val = distance - compensation; + if ( val > 0 ) + val = 0; + } + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_To_Grid */ + /* */ + /* <Description> */ + /* Rounds value to grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + static FT_F26Dot6 + Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation + 32; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -FT_PIX_ROUND( compensation - distance ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_To_Half_Grid */ + /* */ + /* <Description> */ + /* Rounds value to half grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + static FT_F26Dot6 + Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = FT_PIX_FLOOR( distance + compensation ) + 32; + if ( distance && val < 0 ) + val = 0; + } + else + { + val = -( FT_PIX_FLOOR( compensation - distance ) + 32 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_Down_To_Grid */ + /* */ + /* <Description> */ + /* Rounds value down to grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + static FT_F26Dot6 + Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -( ( compensation - distance ) & -64 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_Up_To_Grid */ + /* */ + /* <Description> */ + /* Rounds value up to grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + static FT_F26Dot6 + Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation + 63; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = - FT_PIX_CEIL( compensation - distance ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_To_Double_Grid */ + /* */ + /* <Description> */ + /* Rounds value to double grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + static FT_F26Dot6 + Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + + if ( distance >= 0 ) + { + val = distance + compensation + 16; + if ( distance && val > 0 ) + val &= ~31; + else + val = 0; + } + else + { + val = -FT_PAD_ROUND( compensation - distance, 32 ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_Super */ + /* */ + /* <Description> */ + /* Super-rounds value to grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + /* <Note> */ + /* The TrueType specification says very few about the relationship */ + /* between rounding and engine compensation. However, it seems from */ + /* the description of super round that we should add the compensation */ + /* before rounding. */ + /* */ + static FT_F26Dot6 + Round_Super( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( distance - CUR.phase + CUR.threshold + compensation ) & + -CUR.period; + if ( distance && val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( CUR.threshold - CUR.phase - distance + compensation ) & + -CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Round_Super_45 */ + /* */ + /* <Description> */ + /* Super-rounds value to grid after adding engine compensation. */ + /* */ + /* <Input> */ + /* distance :: The distance to round. */ + /* */ + /* compensation :: The engine compensation. */ + /* */ + /* <Return> */ + /* Rounded distance. */ + /* */ + /* <Note> */ + /* There is a separate function for Round_Super_45() as we may need */ + /* greater precision. */ + /* */ + static FT_F26Dot6 + Round_Super_45( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( ( distance - CUR.phase + CUR.threshold + compensation ) / + CUR.period ) * CUR.period; + if ( distance && val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) / + CUR.period ) * CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + + return val; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Compute_Round */ + /* */ + /* <Description> */ + /* Sets the rounding mode. */ + /* */ + /* <Input> */ + /* round_mode :: The rounding mode to be used. */ + /* */ + static void + Compute_Round( EXEC_OP_ FT_Byte round_mode ) + { + switch ( round_mode ) + { + case TT_Round_Off: + CUR.func_round = (TT_Round_Func)Round_None; + break; + + case TT_Round_To_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Grid; + break; + + case TT_Round_Up_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + break; + + case TT_Round_Down_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + break; + + case TT_Round_To_Half_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + break; + + case TT_Round_To_Double_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + break; + + case TT_Round_Super: + CUR.func_round = (TT_Round_Func)Round_Super; + break; + + case TT_Round_Super_45: + CUR.func_round = (TT_Round_Func)Round_Super_45; + break; + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* SetSuperRound */ + /* */ + /* <Description> */ + /* Sets Super Round parameters. */ + /* */ + /* <Input> */ + /* GridPeriod :: Grid period */ + /* selector :: SROUND opcode */ + /* */ + static void + SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod, + FT_Long selector ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { + case 0: + CUR.period = GridPeriod / 2; + break; + + case 0x40: + CUR.period = GridPeriod; + break; + + case 0x80: + CUR.period = GridPeriod * 2; + break; + + /* This opcode is reserved, but... */ + + case 0xC0: + CUR.period = GridPeriod; + break; + } + + switch ( (FT_Int)( selector & 0x30 ) ) + { + case 0: + CUR.phase = 0; + break; + + case 0x10: + CUR.phase = CUR.period / 4; + break; + + case 0x20: + CUR.phase = CUR.period / 2; + break; + + case 0x30: + CUR.phase = CUR.period * 3 / 4; + break; + } + + if ( ( selector & 0x0F ) == 0 ) + CUR.threshold = CUR.period - 1; + else + CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8; + + CUR.period /= 256; + CUR.phase /= 256; + CUR.threshold /= 256; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Project */ + /* */ + /* <Description> */ + /* Computes the projection of vector given by (v2-v1) along the */ + /* current projection vector. */ + /* */ + /* <Input> */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* <Return> */ + /* The distance in F26dot6 format. */ + /* */ + static FT_F26Dot6 + Project( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + FT_ASSERT( !CUR.face->unpatented_hinting ); +#endif + + return TT_DotFix14( dx, dy, + CUR.GS.projVector.x, + CUR.GS.projVector.y ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Dual_Project */ + /* */ + /* <Description> */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* current dual vector. */ + /* */ + /* <Input> */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* <Return> */ + /* The distance in F26dot6 format. */ + /* */ + static FT_F26Dot6 + Dual_Project( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( dx, dy, + CUR.GS.dualVector.x, + CUR.GS.dualVector.y ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Project_x */ + /* */ + /* <Description> */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* horizontal axis. */ + /* */ + /* <Input> */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* <Return> */ + /* The distance in F26dot6 format. */ + /* */ + static FT_F26Dot6 + Project_x( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED_EXEC; + FT_UNUSED( dy ); + + return dx; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Project_y */ + /* */ + /* <Description> */ + /* Computes the projection of the vector given by (v2-v1) along the */ + /* vertical axis. */ + /* */ + /* <Input> */ + /* v1 :: First input vector. */ + /* v2 :: Second input vector. */ + /* */ + /* <Return> */ + /* The distance in F26dot6 format. */ + /* */ + static FT_F26Dot6 + Project_y( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED_EXEC; + FT_UNUSED( dx ); + + return dy; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Compute_Funcs */ + /* */ + /* <Description> */ + /* Computes the projection and movement function pointers according */ + /* to the current graphics state. */ + /* */ + static void + Compute_Funcs( EXEC_OP ) + { +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( CUR.face->unpatented_hinting ) + { + /* If both vectors point rightwards along the x axis, set */ + /* `both-x-axis' true, otherwise set it false. The x values only */ + /* need be tested because the vector has been normalised to a unit */ + /* vector of length 0x4000 = unity. */ + CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 && + CUR.GS.freeVector.x == 0x4000 ); + + /* Throw away projection and freedom vector information */ + /* because the patents don't allow them to be stored. */ + /* The relevant US Patents are 5155805 and 5325479. */ + CUR.GS.projVector.x = 0; + CUR.GS.projVector.y = 0; + CUR.GS.freeVector.x = 0; + CUR.GS.freeVector.y = 0; + + if ( CUR.GS.both_x_axis ) + { + CUR.func_project = Project_x; + CUR.func_move = Direct_Move_X; + CUR.func_move_orig = Direct_Move_Orig_X; + } + else + { + CUR.func_project = Project_y; + CUR.func_move = Direct_Move_Y; + CUR.func_move_orig = Direct_Move_Orig_Y; + } + + if ( CUR.GS.dualVector.x == 0x4000 ) + CUR.func_dualproj = Project_x; + else + { + if ( CUR.GS.dualVector.y == 0x4000 ) + CUR.func_dualproj = Project_y; + else + CUR.func_dualproj = Dual_Project; + } + + /* Force recalculation of cached aspect ratio */ + CUR.tt_metrics.ratio = 0; + + return; + } +#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */ + + if ( CUR.GS.freeVector.x == 0x4000 ) + CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L; + else + { + if ( CUR.GS.freeVector.y == 0x4000 ) + CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L; + else + CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 + + (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4; + } + + if ( CUR.GS.projVector.x == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_x; + else + { + if ( CUR.GS.projVector.y == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_y; + else + CUR.func_project = (TT_Project_Func)Project; + } + + if ( CUR.GS.dualVector.x == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_x; + else + { + if ( CUR.GS.dualVector.y == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_y; + else + CUR.func_dualproj = (TT_Project_Func)Dual_Project; + } + + CUR.func_move = (TT_Move_Func)Direct_Move; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig; + + if ( CUR.F_dot_P == 0x40000000L ) + { + if ( CUR.GS.freeVector.x == 0x4000 ) + { + CUR.func_move = (TT_Move_Func)Direct_Move_X; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else + { + if ( CUR.GS.freeVector.y == 0x4000 ) + { + CUR.func_move = (TT_Move_Func)Direct_Move_Y; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + } + } + + /* at small sizes, F_dot_P can become too small, resulting */ + /* in overflows and `spikes' in a number of glyphs like `w'. */ + + if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L ) + CUR.F_dot_P = 0x40000000L; + + /* Disable cached aspect ratio */ + CUR.tt_metrics.ratio = 0; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Normalize */ + /* */ + /* <Description> */ + /* Norms a vector. */ + /* */ + /* <Input> */ + /* Vx :: The horizontal input vector coordinate. */ + /* Vy :: The vertical input vector coordinate. */ + /* */ + /* <Output> */ + /* R :: The normed unit vector. */ + /* */ + /* <Return> */ + /* Returns FAILURE if a vector parameter is zero. */ + /* */ + /* <Note> */ + /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */ + /* R is undefined. */ + /* */ + + + static FT_Bool + Normalize( EXEC_OP_ FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_F26Dot6 W; + FT_Bool S1, S2; + + FT_UNUSED_EXEC; + + + if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L ) + { + Vx *= 0x100; + Vy *= 0x100; + + W = TT_VecLen( Vx, Vy ); + + if ( W == 0 ) + { + /* XXX: UNDOCUMENTED! It seems that it is possible to try */ + /* to normalize the vector (0,0). Return immediately. */ + return SUCCESS; + } + + R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W ); + R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W ); + + return SUCCESS; + } + + W = TT_VecLen( Vx, Vy ); + + Vx = FT_MulDiv( Vx, 0x4000L, W ); + Vy = FT_MulDiv( Vy, 0x4000L, W ); + + W = Vx * Vx + Vy * Vy; + + /* Now, we want that Sqrt( W ) = 0x4000 */ + /* Or 0x10000000 <= W < 0x10004000 */ + + if ( Vx < 0 ) + { + Vx = -Vx; + S1 = TRUE; + } + else + S1 = FALSE; + + if ( Vy < 0 ) + { + Vy = -Vy; + S2 = TRUE; + } + else + S2 = FALSE; + + while ( W < 0x10000000L ) + { + /* We need to increase W by a minimal amount */ + if ( Vx < Vy ) + Vx++; + else + Vy++; + + W = Vx * Vx + Vy * Vy; + } + + while ( W >= 0x10004000L ) + { + /* We need to decrease W by a minimal amount */ + if ( Vx < Vy ) + Vx--; + else + Vy--; + + W = Vx * Vx + Vy * Vy; + } + + /* Note that in various cases, we can only */ + /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */ + + if ( S1 ) + Vx = -Vx; + + if ( S2 ) + Vy = -Vy; + + R->x = (FT_F2Dot14)Vx; /* Type conversion */ + R->y = (FT_F2Dot14)Vy; /* Type conversion */ + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* Here we start with the implementation of the various opcodes. */ + /* */ + /*************************************************************************/ + + + static FT_Bool + Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1, + FT_UShort aIdx2, + FT_Int aOpc, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; + + + if ( BOUNDS( aIdx1, CUR.zp2.n_points ) || + BOUNDS( aIdx2, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return FAILURE; + } + + p1 = CUR.zp1.cur + aIdx2; + p2 = CUR.zp2.cur + aIdx1; + + A = p1->x - p2->x; + B = p1->y - p2->y; + + if ( ( aOpc & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, Vec ); + + return SUCCESS; + } + + + /* When not using the big switch statements, the interpreter uses a */ + /* call table defined later below in this source. Each opcode must */ + /* thus have a corresponding function, even trivial ones. */ + /* */ + /* They are all defined there. */ + +#define DO_SVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.freeVector.y = B; \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SPVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + GUESS_VECTOR( freeVector ); \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.freeVector.y = B; \ + \ + GUESS_VECTOR( projVector ); \ + \ + COMPUTE_Funcs(); \ + } + + +#define DO_SPVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.projVector ) == SUCCESS ) \ + { \ + CUR.GS.dualVector = CUR.GS.projVector; \ + GUESS_VECTOR( freeVector ); \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.freeVector ) == SUCCESS ) \ + { \ + GUESS_VECTOR( projVector ); \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVTPV \ + GUESS_VECTOR( projVector ); \ + CUR.GS.freeVector = CUR.GS.projVector; \ + COMPUTE_Funcs(); + + +#define DO_SPVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ + /* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = (FT_Long)S; \ + \ + NORMalize( X, Y, &CUR.GS.projVector ); \ + \ + CUR.GS.dualVector = CUR.GS.projVector; \ + GUESS_VECTOR( freeVector ); \ + COMPUTE_Funcs(); \ + } + + +#define DO_SFVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ + /* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = S; \ + \ + NORMalize( X, Y, &CUR.GS.freeVector ); \ + GUESS_VECTOR( projVector ); \ + COMPUTE_Funcs(); \ + } + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING +#define DO_GPV \ + if ( CUR.face->unpatented_hinting ) \ + { \ + args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \ + args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \ + } \ + else \ + { \ + args[0] = CUR.GS.projVector.x; \ + args[1] = CUR.GS.projVector.y; \ + } +#else +#define DO_GPV \ + args[0] = CUR.GS.projVector.x; \ + args[1] = CUR.GS.projVector.y; +#endif + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING +#define DO_GFV \ + if ( CUR.face->unpatented_hinting ) \ + { \ + args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \ + args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \ + } \ + else \ + { \ + args[0] = CUR.GS.freeVector.x; \ + args[1] = CUR.GS.freeVector.y; \ + } +#else +#define DO_GFV \ + args[0] = CUR.GS.freeVector.x; \ + args[1] = CUR.GS.freeVector.y; +#endif + + +#define DO_SRP0 \ + CUR.GS.rp0 = (FT_UShort)args[0]; + + +#define DO_SRP1 \ + CUR.GS.rp1 = (FT_UShort)args[0]; + + +#define DO_SRP2 \ + CUR.GS.rp2 = (FT_UShort)args[0]; + + +#define DO_RTHG \ + CUR.GS.round_state = TT_Round_To_Half_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + + +#define DO_RTG \ + CUR.GS.round_state = TT_Round_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Grid; + + +#define DO_RTDG \ + CUR.GS.round_state = TT_Round_To_Double_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + + +#define DO_RUTG \ + CUR.GS.round_state = TT_Round_Up_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + + +#define DO_RDTG \ + CUR.GS.round_state = TT_Round_Down_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + + +#define DO_ROFF \ + CUR.GS.round_state = TT_Round_Off; \ + CUR.func_round = (TT_Round_Func)Round_None; + + +#define DO_SROUND \ + SET_SuperRound( 0x4000, args[0] ); \ + CUR.GS.round_state = TT_Round_Super; \ + CUR.func_round = (TT_Round_Func)Round_Super; + + +#define DO_S45ROUND \ + SET_SuperRound( 0x2D41, args[0] ); \ + CUR.GS.round_state = TT_Round_Super_45; \ + CUR.func_round = (TT_Round_Func)Round_Super_45; + + +#define DO_SLOOP \ + if ( args[0] < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + else \ + CUR.GS.loop = args[0]; + + +#define DO_SMD \ + CUR.GS.minimum_distance = args[0]; + + +#define DO_SCVTCI \ + CUR.GS.control_value_cutin = (FT_F26Dot6)args[0]; + + +#define DO_SSWCI \ + CUR.GS.single_width_cutin = (FT_F26Dot6)args[0]; + + + /* XXX: UNDOCUMENTED! or bug in the Windows engine? */ + /* */ + /* It seems that the value that is read here is */ + /* expressed in 16.16 format rather than in font */ + /* units. */ + /* */ +#define DO_SSW \ + CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 ); + + +#define DO_FLIPON \ + CUR.GS.auto_flip = TRUE; + + +#define DO_FLIPOFF \ + CUR.GS.auto_flip = FALSE; + + +#define DO_SDB \ + CUR.GS.delta_base = (FT_Short)args[0]; + + +#define DO_SDS \ + CUR.GS.delta_shift = (FT_Short)args[0]; + + +#define DO_MD /* nothing */ + + +#define DO_MPPEM \ + args[0] = CURRENT_Ppem(); + + + /* Note: The pointSize should be irrelevant in a given font program; */ + /* we thus decide to return only the ppem. */ +#if 0 + +#define DO_MPS \ + args[0] = CUR.metrics.pointSize; + +#else + +#define DO_MPS \ + args[0] = CURRENT_Ppem(); + +#endif /* 0 */ + + +#define DO_DUP \ + args[1] = args[0]; + + +#define DO_CLEAR \ + CUR.new_top = 0; + + +#define DO_SWAP \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + args[0] = args[1]; \ + args[1] = L; \ + } + + +#define DO_DEPTH \ + args[0] = CUR.top; + + +#define DO_CINDEX \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + \ + if ( L <= 0 || L > CUR.args ) \ + CUR.error = TT_Err_Invalid_Reference; \ + else \ + args[0] = CUR.stack[CUR.args - L]; \ + } + + +#define DO_JROT \ + if ( args[1] != 0 ) \ + { \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; \ + } + + +#define DO_JMPR \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; + + +#define DO_JROF \ + if ( args[1] == 0 ) \ + { \ + CUR.IP += args[0]; \ + CUR.step_ins = FALSE; \ + } + + +#define DO_LT \ + args[0] = ( args[0] < args[1] ); + + +#define DO_LTEQ \ + args[0] = ( args[0] <= args[1] ); + + +#define DO_GT \ + args[0] = ( args[0] > args[1] ); + + +#define DO_GTEQ \ + args[0] = ( args[0] >= args[1] ); + + +#define DO_EQ \ + args[0] = ( args[0] == args[1] ); + + +#define DO_NEQ \ + args[0] = ( args[0] != args[1] ); + + +#define DO_ODD \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 ); + + +#define DO_EVEN \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 ); + + +#define DO_AND \ + args[0] = ( args[0] && args[1] ); + + +#define DO_OR \ + args[0] = ( args[0] || args[1] ); + + +#define DO_NOT \ + args[0] = !args[0]; + + +#define DO_ADD \ + args[0] += args[1]; + + +#define DO_SUB \ + args[0] -= args[1]; + + +#define DO_DIV \ + if ( args[1] == 0 ) \ + CUR.error = TT_Err_Divide_By_Zero; \ + else \ + args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] ); + + +#define DO_MUL \ + args[0] = TT_MULDIV( args[0], args[1], 64L ); + + +#define DO_ABS \ + args[0] = FT_ABS( args[0] ); + + +#define DO_NEG \ + args[0] = -args[0]; + + +#define DO_FLOOR \ + args[0] = FT_PIX_FLOOR( args[0] ); + + +#define DO_CEILING \ + args[0] = FT_PIX_CEIL( args[0] ); + + +#define DO_RS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR.storage[I]; \ + } + + +#define DO_WS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.storage[I] = args[1]; \ + } + + +#define DO_RCVT \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR_Func_read_cvt( I ); \ + } + + +#define DO_WCVTP \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR_Func_write_cvt( I, args[1] ); \ + } + + +#define DO_WCVTF \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDS( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \ + } + + +#define DO_DEBUG \ + CUR.error = TT_Err_Debug_OpCode; + + +#define DO_ROUND \ + args[0] = CUR_Func_round( \ + args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x68] ); + + +#define DO_NROUND \ + args[0] = ROUND_None( args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x6C] ); + + +#define DO_MAX \ + if ( args[1] > args[0] ) \ + args[0] = args[1]; + + +#define DO_MIN \ + if ( args[1] < args[0] ) \ + args[0] = args[1]; + + +#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + +#undef ARRAY_BOUND_ERROR +#define ARRAY_BOUND_ERROR \ + { \ + CUR.error = TT_Err_Invalid_Reference; \ + return; \ + } + + + /*************************************************************************/ + /* */ + /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */ + /* Opcode range: 0x00-0x01 */ + /* Stack: --> */ + /* */ + static void + Ins_SVTCA( INS_ARG ) + { + DO_SVTCA + } + + + /*************************************************************************/ + /* */ + /* SPVTCA[a]: Set PVector to Coordinate Axis */ + /* Opcode range: 0x02-0x03 */ + /* Stack: --> */ + /* */ + static void + Ins_SPVTCA( INS_ARG ) + { + DO_SPVTCA + } + + + /*************************************************************************/ + /* */ + /* SFVTCA[a]: Set FVector to Coordinate Axis */ + /* Opcode range: 0x04-0x05 */ + /* Stack: --> */ + /* */ + static void + Ins_SFVTCA( INS_ARG ) + { + DO_SFVTCA + } + + + /*************************************************************************/ + /* */ + /* SPVTL[a]: Set PVector To Line */ + /* Opcode range: 0x06-0x07 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_SPVTL( INS_ARG ) + { + DO_SPVTL + } + + + /*************************************************************************/ + /* */ + /* SFVTL[a]: Set FVector To Line */ + /* Opcode range: 0x08-0x09 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_SFVTL( INS_ARG ) + { + DO_SFVTL + } + + + /*************************************************************************/ + /* */ + /* SFVTPV[]: Set FVector To PVector */ + /* Opcode range: 0x0E */ + /* Stack: --> */ + /* */ + static void + Ins_SFVTPV( INS_ARG ) + { + DO_SFVTPV + } + + + /*************************************************************************/ + /* */ + /* SPVFS[]: Set PVector From Stack */ + /* Opcode range: 0x0A */ + /* Stack: f2.14 f2.14 --> */ + /* */ + static void + Ins_SPVFS( INS_ARG ) + { + DO_SPVFS + } + + + /*************************************************************************/ + /* */ + /* SFVFS[]: Set FVector From Stack */ + /* Opcode range: 0x0B */ + /* Stack: f2.14 f2.14 --> */ + /* */ + static void + Ins_SFVFS( INS_ARG ) + { + DO_SFVFS + } + + + /*************************************************************************/ + /* */ + /* GPV[]: Get Projection Vector */ + /* Opcode range: 0x0C */ + /* Stack: ef2.14 --> ef2.14 */ + /* */ + static void + Ins_GPV( INS_ARG ) + { + DO_GPV + } + + + /*************************************************************************/ + /* GFV[]: Get Freedom Vector */ + /* Opcode range: 0x0D */ + /* Stack: ef2.14 --> ef2.14 */ + /* */ + static void + Ins_GFV( INS_ARG ) + { + DO_GFV + } + + + /*************************************************************************/ + /* */ + /* SRP0[]: Set Reference Point 0 */ + /* Opcode range: 0x10 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP0( INS_ARG ) + { + DO_SRP0 + } + + + /*************************************************************************/ + /* */ + /* SRP1[]: Set Reference Point 1 */ + /* Opcode range: 0x11 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP1( INS_ARG ) + { + DO_SRP1 + } + + + /*************************************************************************/ + /* */ + /* SRP2[]: Set Reference Point 2 */ + /* Opcode range: 0x12 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP2( INS_ARG ) + { + DO_SRP2 + } + + + /*************************************************************************/ + /* */ + /* RTHG[]: Round To Half Grid */ + /* Opcode range: 0x19 */ + /* Stack: --> */ + /* */ + static void + Ins_RTHG( INS_ARG ) + { + DO_RTHG + } + + + /*************************************************************************/ + /* */ + /* RTG[]: Round To Grid */ + /* Opcode range: 0x18 */ + /* Stack: --> */ + /* */ + static void + Ins_RTG( INS_ARG ) + { + DO_RTG + } + + + /*************************************************************************/ + /* RTDG[]: Round To Double Grid */ + /* Opcode range: 0x3D */ + /* Stack: --> */ + /* */ + static void + Ins_RTDG( INS_ARG ) + { + DO_RTDG + } + + + /*************************************************************************/ + /* RUTG[]: Round Up To Grid */ + /* Opcode range: 0x7C */ + /* Stack: --> */ + /* */ + static void + Ins_RUTG( INS_ARG ) + { + DO_RUTG + } + + + /*************************************************************************/ + /* */ + /* RDTG[]: Round Down To Grid */ + /* Opcode range: 0x7D */ + /* Stack: --> */ + /* */ + static void + Ins_RDTG( INS_ARG ) + { + DO_RDTG + } + + + /*************************************************************************/ + /* */ + /* ROFF[]: Round OFF */ + /* Opcode range: 0x7A */ + /* Stack: --> */ + /* */ + static void + Ins_ROFF( INS_ARG ) + { + DO_ROFF + } + + + /*************************************************************************/ + /* */ + /* SROUND[]: Super ROUND */ + /* Opcode range: 0x76 */ + /* Stack: Eint8 --> */ + /* */ + static void + Ins_SROUND( INS_ARG ) + { + DO_SROUND + } + + + /*************************************************************************/ + /* */ + /* S45ROUND[]: Super ROUND 45 degrees */ + /* Opcode range: 0x77 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_S45ROUND( INS_ARG ) + { + DO_S45ROUND + } + + + /*************************************************************************/ + /* */ + /* SLOOP[]: Set LOOP variable */ + /* Opcode range: 0x17 */ + /* Stack: int32? --> */ + /* */ + static void + Ins_SLOOP( INS_ARG ) + { + DO_SLOOP + } + + + /*************************************************************************/ + /* */ + /* SMD[]: Set Minimum Distance */ + /* Opcode range: 0x1A */ + /* Stack: f26.6 --> */ + /* */ + static void + Ins_SMD( INS_ARG ) + { + DO_SMD + } + + + /*************************************************************************/ + /* */ + /* SCVTCI[]: Set Control Value Table Cut In */ + /* Opcode range: 0x1D */ + /* Stack: f26.6 --> */ + /* */ + static void + Ins_SCVTCI( INS_ARG ) + { + DO_SCVTCI + } + + + /*************************************************************************/ + /* */ + /* SSWCI[]: Set Single Width Cut In */ + /* Opcode range: 0x1E */ + /* Stack: f26.6 --> */ + /* */ + static void + Ins_SSWCI( INS_ARG ) + { + DO_SSWCI + } + + + /*************************************************************************/ + /* */ + /* SSW[]: Set Single Width */ + /* Opcode range: 0x1F */ + /* Stack: int32? --> */ + /* */ + static void + Ins_SSW( INS_ARG ) + { + DO_SSW + } + + + /*************************************************************************/ + /* */ + /* FLIPON[]: Set auto-FLIP to ON */ + /* Opcode range: 0x4D */ + /* Stack: --> */ + /* */ + static void + Ins_FLIPON( INS_ARG ) + { + DO_FLIPON + } + + + /*************************************************************************/ + /* */ + /* FLIPOFF[]: Set auto-FLIP to OFF */ + /* Opcode range: 0x4E */ + /* Stack: --> */ + /* */ + static void + Ins_FLIPOFF( INS_ARG ) + { + DO_FLIPOFF + } + + + /*************************************************************************/ + /* */ + /* SANGW[]: Set ANGle Weight */ + /* Opcode range: 0x7E */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SANGW( INS_ARG ) + { + /* instruction not supported anymore */ + } + + + /*************************************************************************/ + /* */ + /* SDB[]: Set Delta Base */ + /* Opcode range: 0x5E */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SDB( INS_ARG ) + { + DO_SDB + } + + + /*************************************************************************/ + /* */ + /* SDS[]: Set Delta Shift */ + /* Opcode range: 0x5F */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SDS( INS_ARG ) + { + DO_SDS + } + + + /*************************************************************************/ + /* */ + /* MPPEM[]: Measure Pixel Per EM */ + /* Opcode range: 0x4B */ + /* Stack: --> Euint16 */ + /* */ + static void + Ins_MPPEM( INS_ARG ) + { + DO_MPPEM + } + + + /*************************************************************************/ + /* */ + /* MPS[]: Measure Point Size */ + /* Opcode range: 0x4C */ + /* Stack: --> Euint16 */ + /* */ + static void + Ins_MPS( INS_ARG ) + { + DO_MPS + } + + + /*************************************************************************/ + /* */ + /* DUP[]: DUPlicate the top stack's element */ + /* Opcode range: 0x20 */ + /* Stack: StkElt --> StkElt StkElt */ + /* */ + static void + Ins_DUP( INS_ARG ) + { + DO_DUP + } + + + /*************************************************************************/ + /* */ + /* POP[]: POP the stack's top element */ + /* Opcode range: 0x21 */ + /* Stack: StkElt --> */ + /* */ + static void + Ins_POP( INS_ARG ) + { + /* nothing to do */ + } + + + /*************************************************************************/ + /* */ + /* CLEAR[]: CLEAR the entire stack */ + /* Opcode range: 0x22 */ + /* Stack: StkElt... --> */ + /* */ + static void + Ins_CLEAR( INS_ARG ) + { + DO_CLEAR + } + + + /*************************************************************************/ + /* */ + /* SWAP[]: SWAP the stack's top two elements */ + /* Opcode range: 0x23 */ + /* Stack: 2 * StkElt --> 2 * StkElt */ + /* */ + static void + Ins_SWAP( INS_ARG ) + { + DO_SWAP + } + + + /*************************************************************************/ + /* */ + /* DEPTH[]: return the stack DEPTH */ + /* Opcode range: 0x24 */ + /* Stack: --> uint32 */ + /* */ + static void + Ins_DEPTH( INS_ARG ) + { + DO_DEPTH + } + + + /*************************************************************************/ + /* */ + /* CINDEX[]: Copy INDEXed element */ + /* Opcode range: 0x25 */ + /* Stack: int32 --> StkElt */ + /* */ + static void + Ins_CINDEX( INS_ARG ) + { + DO_CINDEX + } + + + /*************************************************************************/ + /* */ + /* EIF[]: End IF */ + /* Opcode range: 0x59 */ + /* Stack: --> */ + /* */ + static void + Ins_EIF( INS_ARG ) + { + /* nothing to do */ + } + + + /*************************************************************************/ + /* */ + /* JROT[]: Jump Relative On True */ + /* Opcode range: 0x78 */ + /* Stack: StkElt int32 --> */ + /* */ + static void + Ins_JROT( INS_ARG ) + { + DO_JROT + } + + + /*************************************************************************/ + /* */ + /* JMPR[]: JuMP Relative */ + /* Opcode range: 0x1C */ + /* Stack: int32 --> */ + /* */ + static void + Ins_JMPR( INS_ARG ) + { + DO_JMPR + } + + + /*************************************************************************/ + /* */ + /* JROF[]: Jump Relative On False */ + /* Opcode range: 0x79 */ + /* Stack: StkElt int32 --> */ + /* */ + static void + Ins_JROF( INS_ARG ) + { + DO_JROF + } + + + /*************************************************************************/ + /* */ + /* LT[]: Less Than */ + /* Opcode range: 0x50 */ + /* Stack: int32? int32? --> bool */ + /* */ + static void + Ins_LT( INS_ARG ) + { + DO_LT + } + + + /*************************************************************************/ + /* */ + /* LTEQ[]: Less Than or EQual */ + /* Opcode range: 0x51 */ + /* Stack: int32? int32? --> bool */ + /* */ + static void + Ins_LTEQ( INS_ARG ) + { + DO_LTEQ + } + + + /*************************************************************************/ + /* */ + /* GT[]: Greater Than */ + /* Opcode range: 0x52 */ + /* Stack: int32? int32? --> bool */ + /* */ + static void + Ins_GT( INS_ARG ) + { + DO_GT + } + + + /*************************************************************************/ + /* */ + /* GTEQ[]: Greater Than or EQual */ + /* Opcode range: 0x53 */ + /* Stack: int32? int32? --> bool */ + /* */ + static void + Ins_GTEQ( INS_ARG ) + { + DO_GTEQ + } + + + /*************************************************************************/ + /* */ + /* EQ[]: EQual */ + /* Opcode range: 0x54 */ + /* Stack: StkElt StkElt --> bool */ + /* */ + static void + Ins_EQ( INS_ARG ) + { + DO_EQ + } + + + /*************************************************************************/ + /* */ + /* NEQ[]: Not EQual */ + /* Opcode range: 0x55 */ + /* Stack: StkElt StkElt --> bool */ + /* */ + static void + Ins_NEQ( INS_ARG ) + { + DO_NEQ + } + + + /*************************************************************************/ + /* */ + /* ODD[]: Is ODD */ + /* Opcode range: 0x56 */ + /* Stack: f26.6 --> bool */ + /* */ + static void + Ins_ODD( INS_ARG ) + { + DO_ODD + } + + + /*************************************************************************/ + /* */ + /* EVEN[]: Is EVEN */ + /* Opcode range: 0x57 */ + /* Stack: f26.6 --> bool */ + /* */ + static void + Ins_EVEN( INS_ARG ) + { + DO_EVEN + } + + + /*************************************************************************/ + /* */ + /* AND[]: logical AND */ + /* Opcode range: 0x5A */ + /* Stack: uint32 uint32 --> uint32 */ + /* */ + static void + Ins_AND( INS_ARG ) + { + DO_AND + } + + + /*************************************************************************/ + /* */ + /* OR[]: logical OR */ + /* Opcode range: 0x5B */ + /* Stack: uint32 uint32 --> uint32 */ + /* */ + static void + Ins_OR( INS_ARG ) + { + DO_OR + } + + + /*************************************************************************/ + /* */ + /* NOT[]: logical NOT */ + /* Opcode range: 0x5C */ + /* Stack: StkElt --> uint32 */ + /* */ + static void + Ins_NOT( INS_ARG ) + { + DO_NOT + } + + + /*************************************************************************/ + /* */ + /* ADD[]: ADD */ + /* Opcode range: 0x60 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static void + Ins_ADD( INS_ARG ) + { + DO_ADD + } + + + /*************************************************************************/ + /* */ + /* SUB[]: SUBtract */ + /* Opcode range: 0x61 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static void + Ins_SUB( INS_ARG ) + { + DO_SUB + } + + + /*************************************************************************/ + /* */ + /* DIV[]: DIVide */ + /* Opcode range: 0x62 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static void + Ins_DIV( INS_ARG ) + { + DO_DIV + } + + + /*************************************************************************/ + /* */ + /* MUL[]: MULtiply */ + /* Opcode range: 0x63 */ + /* Stack: f26.6 f26.6 --> f26.6 */ + /* */ + static void + Ins_MUL( INS_ARG ) + { + DO_MUL + } + + + /*************************************************************************/ + /* */ + /* ABS[]: ABSolute value */ + /* Opcode range: 0x64 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_ABS( INS_ARG ) + { + DO_ABS + } + + + /*************************************************************************/ + /* */ + /* NEG[]: NEGate */ + /* Opcode range: 0x65 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_NEG( INS_ARG ) + { + DO_NEG + } + + + /*************************************************************************/ + /* */ + /* FLOOR[]: FLOOR */ + /* Opcode range: 0x66 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_FLOOR( INS_ARG ) + { + DO_FLOOR + } + + + /*************************************************************************/ + /* */ + /* CEILING[]: CEILING */ + /* Opcode range: 0x67 */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_CEILING( INS_ARG ) + { + DO_CEILING + } + + + /*************************************************************************/ + /* */ + /* RS[]: Read Store */ + /* Opcode range: 0x43 */ + /* Stack: uint32 --> uint32 */ + /* */ + static void + Ins_RS( INS_ARG ) + { + DO_RS + } + + + /*************************************************************************/ + /* */ + /* WS[]: Write Store */ + /* Opcode range: 0x42 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_WS( INS_ARG ) + { + DO_WS + } + + + /*************************************************************************/ + /* */ + /* WCVTP[]: Write CVT in Pixel units */ + /* Opcode range: 0x44 */ + /* Stack: f26.6 uint32 --> */ + /* */ + static void + Ins_WCVTP( INS_ARG ) + { + DO_WCVTP + } + + + /*************************************************************************/ + /* */ + /* WCVTF[]: Write CVT in Funits */ + /* Opcode range: 0x70 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_WCVTF( INS_ARG ) + { + DO_WCVTF + } + + + /*************************************************************************/ + /* */ + /* RCVT[]: Read CVT */ + /* Opcode range: 0x45 */ + /* Stack: uint32 --> f26.6 */ + /* */ + static void + Ins_RCVT( INS_ARG ) + { + DO_RCVT + } + + + /*************************************************************************/ + /* */ + /* AA[]: Adjust Angle */ + /* Opcode range: 0x7F */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_AA( INS_ARG ) + { + /* intentionally no longer supported */ + } + + + /*************************************************************************/ + /* */ + /* DEBUG[]: DEBUG. Unsupported. */ + /* Opcode range: 0x4F */ + /* Stack: uint32 --> */ + /* */ + /* Note: The original instruction pops a value from the stack. */ + /* */ + static void + Ins_DEBUG( INS_ARG ) + { + DO_DEBUG + } + + + /*************************************************************************/ + /* */ + /* ROUND[ab]: ROUND value */ + /* Opcode range: 0x68-0x6B */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_ROUND( INS_ARG ) + { + DO_ROUND + } + + + /*************************************************************************/ + /* */ + /* NROUND[ab]: No ROUNDing of value */ + /* Opcode range: 0x6C-0x6F */ + /* Stack: f26.6 --> f26.6 */ + /* */ + static void + Ins_NROUND( INS_ARG ) + { + DO_NROUND + } + + + /*************************************************************************/ + /* */ + /* MAX[]: MAXimum */ + /* Opcode range: 0x68 */ + /* Stack: int32? int32? --> int32 */ + /* */ + static void + Ins_MAX( INS_ARG ) + { + DO_MAX + } + + + /*************************************************************************/ + /* */ + /* MIN[]: MINimum */ + /* Opcode range: 0x69 */ + /* Stack: int32? int32? --> int32 */ + /* */ + static void + Ins_MIN( INS_ARG ) + { + DO_MIN + } + + +#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + + /*************************************************************************/ + /* */ + /* The following functions are called as is within the switch statement. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* MINDEX[]: Move INDEXed element */ + /* Opcode range: 0x26 */ + /* Stack: int32? --> StkElt */ + /* */ + static void + Ins_MINDEX( INS_ARG ) + { + FT_Long L, K; + + + L = args[0]; + + if ( L <= 0 || L > CUR.args ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + K = CUR.stack[CUR.args - L]; + + FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ], + &CUR.stack[CUR.args - L + 1], + ( L - 1 ) ); + + CUR.stack[CUR.args - 1] = K; + } + + + /*************************************************************************/ + /* */ + /* ROLL[]: ROLL top three elements */ + /* Opcode range: 0x8A */ + /* Stack: 3 * StkElt --> 3 * StkElt */ + /* */ + static void + Ins_ROLL( INS_ARG ) + { + FT_Long A, B, C; + + FT_UNUSED_EXEC; + + + A = args[2]; + B = args[1]; + C = args[0]; + + args[2] = C; + args[1] = A; + args[0] = B; + } + + + /*************************************************************************/ + /* */ + /* MANAGING THE FLOW OF CONTROL */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + static FT_Bool + SkipCode( EXEC_OP ) + { + CUR.IP += CUR.length; + + if ( CUR.IP < CUR.codeSize ) + { + CUR.opcode = CUR.code[CUR.IP]; + + CUR.length = opcode_length[CUR.opcode]; + if ( CUR.length < 0 ) + { + if ( CUR.IP + 1 > CUR.codeSize ) + goto Fail_Overflow; + CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; + } + + if ( CUR.IP + CUR.length <= CUR.codeSize ) + return SUCCESS; + } + + Fail_Overflow: + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } + + + /*************************************************************************/ + /* */ + /* IF[]: IF test */ + /* Opcode range: 0x58 */ + /* Stack: StkElt --> */ + /* */ + static void + Ins_IF( INS_ARG ) + { + FT_Int nIfs; + FT_Bool Out; + + + if ( args[0] != 0 ) + return; + + nIfs = 1; + Out = 0; + + do + { + if ( SKIP_Code() == FAILURE ) + return; + + switch ( CUR.opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x1B: /* ELSE */ + Out = FT_BOOL( nIfs == 1 ); + break; + + case 0x59: /* EIF */ + nIfs--; + Out = FT_BOOL( nIfs == 0 ); + break; + } + } while ( Out == 0 ); + } + + + /*************************************************************************/ + /* */ + /* ELSE[]: ELSE */ + /* Opcode range: 0x1B */ + /* Stack: --> */ + /* */ + static void + Ins_ELSE( INS_ARG ) + { + FT_Int nIfs; + + FT_UNUSED_ARG; + + + nIfs = 1; + + do + { + if ( SKIP_Code() == FAILURE ) + return; + + switch ( CUR.opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x59: /* EIF */ + nIfs--; + break; + } + } while ( nIfs != 0 ); + } + + + /*************************************************************************/ + /* */ + /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* FDEF[]: Function DEFinition */ + /* Opcode range: 0x2C */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_FDEF( INS_ARG ) + { + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; + + + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ + + rec = CUR.FDefs; + limit = rec + CUR.numFDefs; + n = args[0]; + + for ( ; rec < limit; rec++ ) + { + if ( rec->opc == n ) + break; + } + + if ( rec == limit ) + { + /* check that there is enough room for new functions */ + if ( CUR.numFDefs >= CUR.maxFDefs ) + { + CUR.error = TT_Err_Too_Many_Function_Defs; + return; + } + CUR.numFDefs++; + } + + rec->range = CUR.curRange; + rec->opc = n; + rec->start = CUR.IP + 1; + rec->active = TRUE; + + if ( n > CUR.maxFunc ) + CUR.maxFunc = n; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFS & FDEFs. */ + + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + CUR.error = TT_Err_Nested_DEFS; + return; + + case 0x2D: /* ENDF */ + return; + } + } + } + + + /*************************************************************************/ + /* */ + /* ENDF[]: END Function definition */ + /* Opcode range: 0x2D */ + /* Stack: --> */ + /* */ + static void + Ins_ENDF( INS_ARG ) + { + TT_CallRec* pRec; + + FT_UNUSED_ARG; + + + if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */ + { + CUR.error = TT_Err_ENDF_In_Exec_Stream; + return; + } + + CUR.callTop--; + + pRec = &CUR.callStack[CUR.callTop]; + + pRec->Cur_Count--; + + CUR.step_ins = FALSE; + + if ( pRec->Cur_Count > 0 ) + { + CUR.callTop++; + CUR.IP = pRec->Cur_Restart; + } + else + /* Loop through the current function */ + INS_Goto_CodeRange( pRec->Caller_Range, + pRec->Caller_IP ); + + /* Exit the current call frame. */ + + /* NOTE: If the last instruction of a program is a */ + /* CALL or LOOPCALL, the return address is */ + /* always out of the code range. This is a */ + /* valid address, and it is why we do not test */ + /* the result of Ins_Goto_CodeRange() here! */ + } + + + /*************************************************************************/ + /* */ + /* CALL[]: CALL function */ + /* Opcode range: 0x2B */ + /* Stack: uint32? --> */ + /* */ + static void + Ins_CALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + + F = args[0]; + if ( BOUNDS( F, CUR.maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* CUR.maxFunc+1 == CUR.numFDefs */ + /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = CUR.FDefs; + limit = def + CUR.numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check the call stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + pCrec = CUR.callStack + CUR.callTop; + + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = 1; + pCrec->Cur_Restart = def->start; + + CUR.callTop++; + + INS_Goto_CodeRange( def->range, + def->start ); + + CUR.step_ins = FALSE; + return; + + Fail: + CUR.error = TT_Err_Invalid_Reference; + } + + + /*************************************************************************/ + /* */ + /* LOOPCALL[]: LOOP and CALL function */ + /* Opcode range: 0x2A */ + /* Stack: uint32? Eint16? --> */ + /* */ + static void + Ins_LOOPCALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + F = args[1]; + if ( BOUNDS( F, CUR.maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* CUR.maxFunc+1 == CUR.numFDefs */ + /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = CUR.FDefs; + limit = def + CUR.numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + if ( args[0] > 0 ) + { + pCrec = CUR.callStack + CUR.callTop; + + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Cur_Restart = def->start; + + CUR.callTop++; + + INS_Goto_CodeRange( def->range, def->start ); + + CUR.step_ins = FALSE; + } + return; + + Fail: + CUR.error = TT_Err_Invalid_Reference; + } + + + /*************************************************************************/ + /* */ + /* IDEF[]: Instruction DEFinition */ + /* Opcode range: 0x89 */ + /* Stack: Eint8 --> */ + /* */ + static void + Ins_IDEF( INS_ARG ) + { + TT_DefRecord* def; + TT_DefRecord* limit; + + + /* First of all, look for the same function in our table */ + + def = CUR.IDefs; + limit = def + CUR.numIDefs; + + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + + if ( def == limit ) + { + /* check that there is enough room for a new instruction */ + if ( CUR.numIDefs >= CUR.maxIDefs ) + { + CUR.error = TT_Err_Too_Many_Instruction_Defs; + return; + } + CUR.numIDefs++; + } + + def->opc = args[0]; + def->start = CUR.IP+1; + def->range = CUR.curRange; + def->active = TRUE; + + if ( (FT_ULong)args[0] > CUR.maxIns ) + CUR.maxIns = args[0]; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFs & FDEFs. */ + + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + CUR.error = TT_Err_Nested_DEFS; + return; + case 0x2D: /* ENDF */ + return; + } + } + } + + + /*************************************************************************/ + /* */ + /* PUSHING DATA ONTO THE INTERPRETER STACK */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* NPUSHB[]: PUSH N Bytes */ + /* Opcode range: 0x40 */ + /* Stack: --> uint32... */ + /* */ + static void + Ins_NPUSHB( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.code[CUR.IP + 1]; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K + 1]; + + CUR.new_top += L; + } + + + /*************************************************************************/ + /* */ + /* NPUSHW[]: PUSH N Words */ + /* Opcode range: 0x41 */ + /* Stack: --> int32... */ + /* */ + static void + Ins_NPUSHW( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)CUR.code[CUR.IP + 1]; + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + CUR.IP += 2; + + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + + CUR.step_ins = FALSE; + CUR.new_top += L; + } + + + /*************************************************************************/ + /* */ + /* PUSHB[abc]: PUSH Bytes */ + /* Opcode range: 0xB0-0xB7 */ + /* Stack: --> uint32... */ + /* */ + static void + Ins_PUSHB( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)( CUR.opcode - 0xB0 + 1 ); + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K]; + } + + + /*************************************************************************/ + /* */ + /* PUSHW[abc]: PUSH Words */ + /* Opcode range: 0xB8-0xBF */ + /* Stack: --> int32... */ + /* */ + static void + Ins_PUSHW( INS_ARG ) + { + FT_UShort L, K; + + + L = (FT_UShort)( CUR.opcode - 0xB8 + 1 ); + + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + CUR.IP++; + + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + + CUR.step_ins = FALSE; + } + + + /*************************************************************************/ + /* */ + /* MANAGING THE GRAPHICS STATE */ + /* */ + /* Instructions appear in the specs' order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* GC[a]: Get Coordinate projected onto */ + /* Opcode range: 0x46-0x47 */ + /* Stack: uint32 --> f26.6 */ + /* */ + /* BULLSHIT: Measures from the original glyph must be taken along the */ + /* dual projection vector! */ + /* */ + static void + Ins_GC( INS_ARG ) + { + FT_ULong L; + FT_F26Dot6 R; + + + L = (FT_ULong)args[0]; + + if ( BOUNDS( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + else + R = 0; + } + else + { + if ( CUR.opcode & 1 ) + R = CUR_fast_dualproj( &CUR.zp2.org[L] ); + else + R = CUR_fast_project( &CUR.zp2.cur[L] ); + } + + args[0] = R; + } + + + /*************************************************************************/ + /* */ + /* SCFS[]: Set Coordinate From Stack */ + /* Opcode range: 0x48 */ + /* Stack: f26.6 uint32 --> */ + /* */ + /* Formula: */ + /* */ + /* OA := OA + ( value - OA.p )/( f.p ) * f */ + /* */ + static void + Ins_SCFS( INS_ARG ) + { + FT_Long K; + FT_UShort L; + + + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + K = CUR_fast_project( &CUR.zp2.cur[L] ); + + CUR_Func_move( &CUR.zp2, L, args[1] - K ); + + /* not part of the specs, but here for safety */ + + if ( CUR.GS.gep2 == 0 ) + CUR.zp2.org[L] = CUR.zp2.cur[L]; + } + + + /*************************************************************************/ + /* */ + /* MD[a]: Measure Distance */ + /* Opcode range: 0x49-0x4A */ + /* Stack: uint32 uint32 --> f26.6 */ + /* */ + /* BULLSHIT: Measure taken in the original glyph must be along the dual */ + /* projection vector. */ + /* */ + /* Second BULLSHIT: Flag attributes are inverted! */ + /* 0 => measure distance in original outline */ + /* 1 => measure distance in grid-fitted outline */ + /* */ + /* Third one: `zp0 - zp1', and not `zp2 - zp1! */ + /* */ + static void + Ins_MD( INS_ARG ) + { + FT_UShort K, L; + FT_F26Dot6 D; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if( BOUNDS( L, CUR.zp0.n_points ) || + BOUNDS( K, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + D = 0; + } + else + { + if ( CUR.opcode & 1 ) + D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K ); + else + D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K ); + } + + args[0] = D; + } + + + /*************************************************************************/ + /* */ + /* SDPVTL[a]: Set Dual PVector to Line */ + /* Opcode range: 0x86-0x87 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_SDPVTL( INS_ARG ) + { + FT_Long A, B, C; + FT_UShort p1, p2; /* was FT_Int in pas type ERROR */ + + + p1 = (FT_UShort)args[1]; + p2 = (FT_UShort)args[0]; + + if ( BOUNDS( p2, CUR.zp1.n_points ) || + BOUNDS( p1, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + { + FT_Vector* v1 = CUR.zp1.org + p2; + FT_Vector* v2 = CUR.zp2.org + p1; + + + A = v1->x - v2->x; + B = v1->y - v2->y; + } + + if ( ( CUR.opcode & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, &CUR.GS.dualVector ); + + { + FT_Vector* v1 = CUR.zp1.cur + p2; + FT_Vector* v2 = CUR.zp2.cur + p1; + + + A = v1->x - v2->x; + B = v1->y - v2->y; + } + + if ( ( CUR.opcode & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } + + NORMalize( A, B, &CUR.GS.projVector ); + + GUESS_VECTOR( freeVector ); + + COMPUTE_Funcs(); + } + + + /*************************************************************************/ + /* */ + /* SZP0[]: Set Zone Pointer 0 */ + /* Opcode range: 0x13 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SZP0( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + + case 1: + CUR.zp0 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep0 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZP1[]: Set Zone Pointer 1 */ + /* Opcode range: 0x14 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SZP1( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp1 = CUR.twilight; + break; + + case 1: + CUR.zp1 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep1 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZP2[]: Set Zone Pointer 2 */ + /* Opcode range: 0x15 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SZP2( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp2 = CUR.twilight; + break; + + case 1: + CUR.zp2 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.GS.gep2 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SZPS[]: Set Zone PointerS */ + /* Opcode range: 0x16 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SZPS( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + + case 1: + CUR.zp0 = CUR.pts; + break; + + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + CUR.zp1 = CUR.zp0; + CUR.zp2 = CUR.zp0; + + CUR.GS.gep0 = (FT_UShort)args[0]; + CUR.GS.gep1 = (FT_UShort)args[0]; + CUR.GS.gep2 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* INSTCTRL[]: INSTruction ConTRoL */ + /* Opcode range: 0x8e */ + /* Stack: int32 int32 --> */ + /* */ + static void + Ins_INSTCTRL( INS_ARG ) + { + FT_Long K, L; + + + K = args[1]; + L = args[0]; + + if ( K < 1 || K > 2 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( L != 0 ) + L = K; + + CUR.GS.instruct_control = FT_BOOL( + ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L ); + } + + + /*************************************************************************/ + /* */ + /* SCANCTRL[]: SCAN ConTRoL */ + /* Opcode range: 0x85 */ + /* Stack: uint32? --> */ + /* */ + static void + Ins_SCANCTRL( INS_ARG ) + { + FT_Int A; + + + /* Get Threshold */ + A = (FT_Int)( args[0] & 0xFF ); + + if ( A == 0xFF ) + { + CUR.GS.scan_control = TRUE; + return; + } + else if ( A == 0 ) + { + CUR.GS.scan_control = FALSE; + return; + } + + A *= 64; + +#if 0 + if ( ( args[0] & 0x100 ) != 0 && CUR.metrics.pointSize <= A ) + CUR.GS.scan_control = TRUE; +#endif + + if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = TRUE; + + if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = TRUE; + +#if 0 + if ( ( args[0] & 0x800 ) != 0 && CUR.metrics.pointSize > A ) + CUR.GS.scan_control = FALSE; +#endif + + if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = FALSE; + + if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = FALSE; + } + + + /*************************************************************************/ + /* */ + /* SCANTYPE[]: SCAN TYPE */ + /* Opcode range: 0x8D */ + /* Stack: uint32? --> */ + /* */ + static void + Ins_SCANTYPE( INS_ARG ) + { + /* for compatibility with future enhancements, */ + /* we must ignore new modes */ + + if ( args[0] >= 0 && args[0] <= 5 ) + { + if ( args[0] == 3 ) + args[0] = 2; + + CUR.GS.scan_type = (FT_Int)args[0]; + } + } + + + /*************************************************************************/ + /* */ + /* MANAGING OUTLINES */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* FLIPPT[]: FLIP PoinT */ + /* Opcode range: 0x80 */ + /* Stack: uint32... --> */ + /* */ + static void + Ins_FLIPPT( INS_ARG ) + { + FT_UShort point; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + CUR.pts.tags[point] ^= FT_CURVE_TAG_ON; + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* FLIPRGON[]: FLIP RanGe ON */ + /* Opcode range: 0x81 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_FLIPRGON( INS_ARG ) + { + FT_UShort I, K, L; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] |= FT_CURVE_TAG_ON; + } + + + /*************************************************************************/ + /* */ + /* FLIPRGOFF: FLIP RanGe OFF */ + /* Opcode range: 0x82 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_FLIPRGOFF( INS_ARG ) + { + FT_UShort I, K, L; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON; + } + + + static FT_Bool + Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x, + FT_F26Dot6* y, + TT_GlyphZone zone, + FT_UShort* refp ) + { + TT_GlyphZoneRec zp; + FT_UShort p; + FT_F26Dot6 d; + + + if ( CUR.opcode & 1 ) + { + zp = CUR.zp0; + p = CUR.GS.rp1; + } + else + { + zp = CUR.zp1; + p = CUR.GS.rp2; + } + + if ( BOUNDS( p, zp.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + *refp = 0; + return FAILURE; + } + + *zone = zp; + *refp = p; + + d = CUR_Func_project( zp.cur + p, zp.org + p ); + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( CUR.face->unpatented_hinting ) + { + if ( CUR.GS.both_x_axis ) + { + *x = d; + *y = 0; + } + else + { + *x = 0; + *y = d; + } + } + else +#endif + { + *x = TT_MULDIV( d, + (FT_Long)CUR.GS.freeVector.x * 0x10000L, + CUR.F_dot_P ); + *y = TT_MULDIV( d, + (FT_Long)CUR.GS.freeVector.y * 0x10000L, + CUR.F_dot_P ); + } + + return SUCCESS; + } + + + static void + Move_Zp2_Point( EXEC_OP_ FT_UShort point, + FT_F26Dot6 dx, + FT_F26Dot6 dy, + FT_Bool touch ) + { +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( CUR.face->unpatented_hinting ) + { + if ( CUR.GS.both_x_axis ) + { + CUR.zp2.cur[point].x += dx; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + else + { + CUR.zp2.cur[point].y += dy; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + return; + } +#endif + + if ( CUR.GS.freeVector.x != 0 ) + { + CUR.zp2.cur[point].x += dx; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + if ( CUR.GS.freeVector.y != 0 ) + { + CUR.zp2.cur[point].y += dy; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /*************************************************************************/ + /* */ + /* SHP[a]: SHift Point by the last point */ + /* Opcode range: 0x32-0x33 */ + /* Stack: uint32... --> */ + /* */ + static void + Ins_SHP( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + + FT_F26Dot6 dx, + dy; + FT_UShort point; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + /* XXX: UNDOCUMENTED! SHP touches the points */ + MOVE_Zp2_Point( point, dx, dy, TRUE ); + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* SHC[a]: SHift Contour */ + /* Opcode range: 0x34-35 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SHC( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_Short contour; + FT_UShort first_point, last_point, i; + + + contour = (FT_UShort)args[0]; + + if ( BOUNDS( contour, CUR.pts.n_contours ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + if ( contour == 0 ) + first_point = 0; + else + first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 - + CUR.pts.first_point ); + + last_point = (FT_UShort)( CUR.pts.contours[contour] - + CUR.pts.first_point ); + + /* XXX: this is probably wrong... at least it prevents memory */ + /* corruption when zp2 is the twilight zone */ + if ( last_point > CUR.zp2.n_points ) + { + if ( CUR.zp2.n_points > 0 ) + last_point = (FT_UShort)(CUR.zp2.n_points - 1); + else + last_point = 0; + } + + /* XXX: UNDOCUMENTED! SHC touches the points */ + for ( i = first_point; i <= last_point; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, TRUE ); + } + } + + + /*************************************************************************/ + /* */ + /* SHZ[a]: SHift Zone */ + /* Opcode range: 0x36-37 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SHZ( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_UShort last_point, i; + + + if ( BOUNDS( args[0], 2 ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + + /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ + /* Twilight zone has no contours, so use `n_points'. */ + /* Normal zone's `n_points' includes phantoms, so must */ + /* use end of last contour. */ + if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 ) + last_point = (FT_UShort)( CUR.zp2.n_points - 1 ); + else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 ) + last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] ); + else + last_point = 0; + + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ + for ( i = 0; i <= last_point; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, FALSE ); + } + } + + + /*************************************************************************/ + /* */ + /* SHPIX[]: SHift points by a PIXel amount */ + /* Opcode range: 0x38 */ + /* Stack: f26.6 uint32... --> */ + /* */ + static void + Ins_SHPIX( INS_ARG ) + { + FT_F26Dot6 dx, dy; + FT_UShort point; + + + if ( CUR.top < CUR.GS.loop + 1 ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( CUR.face->unpatented_hinting ) + { + if ( CUR.GS.both_x_axis ) + { + dx = TT_MulFix14( args[0], 0x4000 ); + dy = 0; + } + else + { + dx = 0; + dy = TT_MulFix14( args[0], 0x4000 ); + } + } + else +#endif + { + dx = TT_MulFix14( args[0], CUR.GS.freeVector.x ); + dy = TT_MulFix14( args[0], CUR.GS.freeVector.y ); + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + MOVE_Zp2_Point( point, dx, dy, TRUE ); + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* MSIRP[a]: Move Stack Indirect Relative Position */ + /* Opcode range: 0x3A-0x3B */ + /* Stack: f26.6 uint32 --> */ + /* */ + static void + Ins_MSIRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: UNDOCUMENTED! behaviour */ + if ( CUR.GS.gep1 == 0 ) /* if the point that is to be moved */ + /* is in twilight zone */ + { + CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0]; + CUR_Func_move_orig( &CUR.zp1, point, args[1] ); + CUR.zp1.cur[point] = CUR.zp1.org[point]; + } + + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, args[1] - distance ); + + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + + if ( ( CUR.opcode & 1 ) != 0 ) + CUR.GS.rp0 = point; + } + + + /*************************************************************************/ + /* */ + /* MDAP[a]: Move Direct Absolute Point */ + /* Opcode range: 0x2E-0x2F */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_MDAP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 cur_dist, + distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? ? */ + if ( ( CUR.opcode & 1 ) != 0 ) + { + cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); + distance = CUR_Func_round( cur_dist, + CUR.tt_metrics.compensations[0] ) - cur_dist; + } + else + distance = 0; + + CUR_Func_move( &CUR.zp0, point, distance ); + + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } + + + /*************************************************************************/ + /* */ + /* MIAP[a]: Move Indirect Absolute Point */ + /* Opcode range: 0x3E-0x3F */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_MIAP( INS_ARG ) + { + FT_ULong cvtEntry; + FT_UShort point; + FT_F26Dot6 distance, + org_dist; + + + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) || + BOUNDS( cvtEntry, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: UNDOCUMENTED! */ + /* */ + /* The behaviour of an MIAP instruction is quite */ + /* different when used in the twilight zone. */ + /* */ + /* First, no control value cut-in test is performed */ + /* as it would fail anyway. Second, the original */ + /* point, i.e. (org_x,org_y) of zp0.point, is set */ + /* to the absolute, unrounded distance found in */ + /* the CVT. */ + /* */ + /* This is used in the CVT programs of the Microsoft */ + /* fonts Arial, Times, etc., in order to re-adjust */ + /* some key font heights. It allows the use of the */ + /* IP instruction in the twilight zone, which */ + /* otherwise would be `illegal' according to the */ + /* specification. */ + /* */ + /* We implement it with a special sequence for the */ + /* twilight zone. This is a bad hack, but it seems */ + /* to work. */ + + distance = CUR_Func_read_cvt( cvtEntry ); + + if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ + { + CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x ); + CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ), + CUR.zp0.cur[point] = CUR.zp0.org[point]; + } + + org_dist = CUR_fast_project( &CUR.zp0.cur[point] ); + + if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */ + { + if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin ) + distance = org_dist; + + distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] ); + } + + CUR_Func_move( &CUR.zp0, point, distance - org_dist ); + + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } + + + /*************************************************************************/ + /* */ + /* MDRP[abcde]: Move Direct Relative Point */ + /* Opcode range: 0xC0-0xDF */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_MDRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 org_dist, distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? */ + + /* XXX: UNDOCUMENTED: twilight zone special case */ + + if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 ) + { + FT_Vector* vec1 = &CUR.zp1.org[point]; + FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0]; + + + org_dist = CUR_Func_dualproj( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = &CUR.zp1.orus[point]; + FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0]; + + + if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) + { + /* this should be faster */ + org_dist = CUR_Func_dualproj( vec1, vec2 ); + org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale ); + } + else + { + FT_Vector vec; + + + vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale ); + vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale ); + + org_dist = CUR_fast_dualproj( &vec ); + } + } + + /* single width cut-in test */ + + if ( FT_ABS( org_dist - CUR.GS.single_width_value ) < + CUR.GS.single_width_cutin ) + { + if ( org_dist >= 0 ) + org_dist = CUR.GS.single_width_value; + else + org_dist = -CUR.GS.single_width_value; + } + + /* round flag */ + + if ( ( CUR.opcode & 4 ) != 0 ) + distance = CUR_Func_round( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + else + distance = ROUND_None( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + + /* minimum distance flag */ + + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } + } + + /* now move the point */ + + org_dist = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, distance - org_dist ); + + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + } + + + /*************************************************************************/ + /* */ + /* MIRP[abcde]: Move Indirect Relative Point */ + /* Opcode range: 0xE0-0xFF */ + /* Stack: int32? uint32 --> */ + /* */ + static void + Ins_MIRP( INS_ARG ) + { + FT_UShort point; + FT_ULong cvtEntry; + + FT_F26Dot6 cvt_dist, + distance, + cur_dist, + org_dist; + + + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( args[1] + 1 ); + + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( cvtEntry, CUR.cvtSize + 1 ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( !cvtEntry ) + cvt_dist = 0; + else + cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 ); + + /* single width test */ + + if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) < + CUR.GS.single_width_cutin ) + { + if ( cvt_dist >= 0 ) + cvt_dist = CUR.GS.single_width_value; + else + cvt_dist = -CUR.GS.single_width_value; + } + + /* XXX: UNDOCUMENTED! -- twilight zone */ + + if ( CUR.GS.gep1 == 0 ) + { + CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x + + TT_MulFix14( cvt_dist, CUR.GS.freeVector.x ); + + CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + + TT_MulFix14( cvt_dist, CUR.GS.freeVector.y ); + + CUR.zp1.cur[point] = CUR.zp0.cur[point]; + } + + org_dist = CUR_Func_dualproj( &CUR.zp1.org[point], + &CUR.zp0.org[CUR.GS.rp0] ); + cur_dist = CUR_Func_project ( &CUR.zp1.cur[point], + &CUR.zp0.cur[CUR.GS.rp0] ); + + /* auto-flip test */ + + if ( CUR.GS.auto_flip ) + { + if ( ( org_dist ^ cvt_dist ) < 0 ) + cvt_dist = -cvt_dist; + } + + /* control value cutin and round */ + + if ( ( CUR.opcode & 4 ) != 0 ) + { + /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ + /* refer to the same zone. */ + + if ( CUR.GS.gep0 == CUR.GS.gep1 ) + if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) + cvt_dist = org_dist; + + distance = CUR_Func_round( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } + else + distance = ROUND_None( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + + /* minimum distance test */ + + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } + } + + CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + + CUR.GS.rp1 = CUR.GS.rp0; + + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + + /* XXX: UNDOCUMENTED! */ + CUR.GS.rp2 = point; + } + + + /*************************************************************************/ + /* */ + /* ALIGNRP[]: ALIGN Relative Point */ + /* Opcode range: 0x3C */ + /* Stack: uint32 uint32... --> */ + /* */ + static void + Ins_ALIGNRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + + point = (FT_UShort)CUR.stack[CUR.args]; + + if ( BOUNDS( point, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + + CUR_Func_move( &CUR.zp1, point, -distance ); + } + + CUR.GS.loop--; + } + + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* ISECT[]: moves point to InterSECTion */ + /* Opcode range: 0x0F */ + /* Stack: 5 * uint32 --> */ + /* */ + static void + Ins_ISECT( INS_ARG ) + { + FT_UShort point, + a0, a1, + b0, b1; + + FT_F26Dot6 discriminant; + + FT_F26Dot6 dx, dy, + dax, day, + dbx, dby; + + FT_F26Dot6 val; + + FT_Vector R; + + + point = (FT_UShort)args[0]; + + a0 = (FT_UShort)args[1]; + a1 = (FT_UShort)args[2]; + b0 = (FT_UShort)args[3]; + b1 = (FT_UShort)args[4]; + + if ( BOUNDS( b0, CUR.zp0.n_points ) || + BOUNDS( b1, CUR.zp0.n_points ) || + BOUNDS( a0, CUR.zp1.n_points ) || + BOUNDS( a1, CUR.zp1.n_points ) || + BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x; + dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y; + + dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x; + day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y; + + dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x; + dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y; + + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; + + discriminant = TT_MULDIV( dax, -dby, 0x40 ) + + TT_MULDIV( day, dbx, 0x40 ); + + if ( FT_ABS( discriminant ) >= 0x40 ) + { + val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 ); + + R.x = TT_MULDIV( val, dax, discriminant ); + R.y = TT_MULDIV( val, day, discriminant ); + + CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x; + CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y; + } + else + { + /* else, take the middle of the middles of A and B */ + + CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x + + CUR.zp1.cur[a1].x + + CUR.zp0.cur[b0].x + + CUR.zp0.cur[b1].x ) / 4; + CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y + + CUR.zp1.cur[a1].y + + CUR.zp0.cur[b0].y + + CUR.zp0.cur[b1].y ) / 4; + } + } + + + /*************************************************************************/ + /* */ + /* ALIGNPTS[]: ALIGN PoinTS */ + /* Opcode range: 0x27 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_ALIGNPTS( INS_ARG ) + { + FT_UShort p1, p2; + FT_F26Dot6 distance; + + + p1 = (FT_UShort)args[0]; + p2 = (FT_UShort)args[1]; + + if ( BOUNDS( args[0], CUR.zp1.n_points ) || + BOUNDS( args[1], CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + distance = CUR_Func_project( CUR.zp0.cur + p2, + CUR.zp1.cur + p1 ) / 2; + + CUR_Func_move( &CUR.zp1, p1, distance ); + CUR_Func_move( &CUR.zp0, p2, -distance ); + } + + + /*************************************************************************/ + /* */ + /* IP[]: Interpolate Point */ + /* Opcode range: 0x39 */ + /* Stack: uint32... --> */ + /* */ + + /* SOMETIMES, DUMBER CODE IS BETTER CODE */ + + static void + Ins_IP( INS_ARG ) + { + FT_F26Dot6 old_range, cur_range; + FT_Vector* orus_base; + FT_Vector* cur_base; + FT_Int twilight; + + FT_UNUSED_ARG; + + + if ( CUR.top < CUR.GS.loop ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + + /* + * We need to deal in a special way with the twilight zone. + * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0), + * for every n. + */ + twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0; + + if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + if ( twilight ) + orus_base = &CUR.zp0.org[CUR.GS.rp1]; + else + orus_base = &CUR.zp0.orus[CUR.GS.rp1]; + + cur_base = &CUR.zp0.cur[CUR.GS.rp1]; + + /* XXX: There are some glyphs in some braindead but popular */ + /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ + /* calling IP[] with bad values of rp[12]. */ + /* Do something sane when this odd thing happens. */ + if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) || + BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) ) + { + old_range = 0; + cur_range = 0; + } + else + { + if ( twilight ) + old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2], + orus_base ); + else + old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2], + orus_base ); + + cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base ); + } + + for ( ; CUR.GS.loop > 0; --CUR.GS.loop ) + { + FT_UInt point = (FT_UInt)CUR.stack[--CUR.args]; + FT_F26Dot6 org_dist, cur_dist, new_dist; + + + /* check point bounds */ + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + continue; + } + + if ( twilight ) + org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base ); + else + org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base ); + + cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base ); + new_dist = ( old_range != 0 ) + ? TT_MULDIV( org_dist, cur_range, old_range ) + : cur_dist; + + CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist ); + } + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* UTP[a]: UnTouch Point */ + /* Opcode range: 0x29 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_UTP( INS_ARG ) + { + FT_UShort point; + FT_Byte mask; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + + mask = 0xFF; + + if ( CUR.GS.freeVector.x != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_X; + + if ( CUR.GS.freeVector.y != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_Y; + + CUR.zp0.tags[point] &= mask; + } + + + /* Local variables for Ins_IUP: */ + typedef struct + { + FT_Vector* orgs; /* original and current coordinate */ + FT_Vector* curs; /* arrays */ + FT_Vector* orus; + FT_UInt max_points; + + } IUP_WorkerRec, *IUP_Worker; + + + static void + _iup_worker_shift( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt p ) + { + FT_UInt i; + FT_F26Dot6 dx; + + + dx = worker->curs[p].x - worker->orgs[p].x; + if ( dx != 0 ) + { + for ( i = p1; i < p; i++ ) + worker->curs[i].x += dx; + + for ( i = p + 1; i <= p2; i++ ) + worker->curs[i].x += dx; + } + } + + + static void + _iup_worker_interpolate( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2 ) + { + FT_UInt i; + FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2; + + + if ( p1 > p2 ) + return; + + if ( BOUNDS( ref1, worker->max_points ) || + BOUNDS( ref2, worker->max_points ) ) + return; + + orus1 = worker->orus[ref1].x; + orus2 = worker->orus[ref2].x; + + if ( orus1 > orus2 ) + { + FT_F26Dot6 tmp_o; + FT_UInt tmp_r; + + + tmp_o = orus1; + orus1 = orus2; + orus2 = tmp_o; + + tmp_r = ref1; + ref1 = ref2; + ref2 = tmp_r; + } + + org1 = worker->orgs[ref1].x; + org2 = worker->orgs[ref2].x; + delta1 = worker->curs[ref1].x - org1; + delta2 = worker->curs[ref2].x - org2; + + if ( orus1 == orus2 ) + { + /* simple shift of untouched points */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x += delta1; + else + x += delta2; + + worker->curs[i].x = x; + } + } + else + { + FT_Fixed scale = 0; + FT_Bool scale_valid = 0; + + + /* interpolation */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x += delta1; + + else if ( x >= org2 ) + x += delta2; + + else + { + if ( !scale_valid ) + { + scale_valid = 1; + scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ), + 0x10000, orus2 - orus1 ); + } + + x = ( org1 + delta1 ) + + TT_MULFIX( worker->orus[i].x - orus1, scale ); + } + worker->curs[i].x = x; + } + } + } + + + /*************************************************************************/ + /* */ + /* IUP[a]: Interpolate Untouched Points */ + /* Opcode range: 0x30-0x31 */ + /* Stack: --> */ + /* */ + static void + Ins_IUP( INS_ARG ) + { + IUP_WorkerRec V; + FT_Byte mask; + + FT_UInt first_point; /* first point of contour */ + FT_UInt end_point; /* end point (last+1) of contour */ + + FT_UInt first_touched; /* first touched point in contour */ + FT_UInt cur_touched; /* current touched point in contour */ + + FT_UInt point; /* current point */ + FT_Short contour; /* current contour */ + + FT_UNUSED_ARG; + + + /* ignore empty outlines */ + if ( CUR.pts.n_contours == 0 ) + return; + + if ( CUR.opcode & 1 ) + { + mask = FT_CURVE_TAG_TOUCH_X; + V.orgs = CUR.pts.org; + V.curs = CUR.pts.cur; + V.orus = CUR.pts.orus; + } + else + { + mask = FT_CURVE_TAG_TOUCH_Y; + V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 ); + V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 ); + V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 ); + } + V.max_points = CUR.pts.n_points; + + contour = 0; + point = 0; + + do + { + end_point = CUR.pts.contours[contour] - CUR.pts.first_point; + first_point = point; + + while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 ) + point++; + + if ( point <= end_point ) + { + first_touched = point; + cur_touched = point; + + point++; + + while ( point <= end_point ) + { + if ( ( CUR.pts.tags[point] & mask ) != 0 ) + { + if ( point > 0 ) + _iup_worker_interpolate( &V, + cur_touched + 1, + point - 1, + cur_touched, + point ); + cur_touched = point; + } + + point++; + } + + if ( cur_touched == first_touched ) + _iup_worker_shift( &V, first_point, end_point, cur_touched ); + else + { + _iup_worker_interpolate( &V, + (FT_UShort)( cur_touched + 1 ), + end_point, + cur_touched, + first_touched ); + + if ( first_touched > 0 ) + _iup_worker_interpolate( &V, + first_point, + first_touched - 1, + cur_touched, + first_touched ); + } + } + contour++; + } while ( contour < CUR.pts.n_contours ); + } + + + /*************************************************************************/ + /* */ + /* DELTAPn[]: DELTA exceptions P1, P2, P3 */ + /* Opcode range: 0x5D,0x71,0x72 */ + /* Stack: uint32 (2 * uint32)... --> */ + /* */ + static void + Ins_DELTAP( INS_ARG ) + { + FT_ULong k, nump; + FT_UShort A; + FT_ULong C; + FT_Long B; + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + /* Delta hinting is covered by US Patent 5159668. */ + if ( CUR.face->unpatented_hinting ) + { + FT_Long n = args[0] * 2; + + + if ( CUR.args < n ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= n; + CUR.new_top = CUR.args; + return; + } +#endif + + nump = (FT_ULong)args[0]; /* some points theoretically may occur more + than once, thus UShort isn't enough */ + + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= 2; + + A = (FT_UShort)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; + + /* XXX: Because some popular fonts contain some invalid DeltaP */ + /* instructions, we simply ignore them when the stacked */ + /* point reference is off limit, rather than returning an */ + /* error. As a delta instruction doesn't change a glyph */ + /* in great ways, this shouldn't be a problem. */ + + if ( !BOUNDS( A, CUR.zp0.n_points ) ) + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( CUR.opcode ) + { + case 0x5D: + break; + + case 0x71: + C += 16; + break; + + case 0x72: + C += 32; + break; + } + + C += CUR.GS.delta_base; + + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + + CUR_Func_move( &CUR.zp0, A, B ); + } + } + else + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + } + + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* DELTACn[]: DELTA exceptions C1, C2, C3 */ + /* Opcode range: 0x73,0x74,0x75 */ + /* Stack: uint32 (2 * uint32)... --> */ + /* */ + static void + Ins_DELTAC( INS_ARG ) + { + FT_ULong nump, k; + FT_ULong A, C; + FT_Long B; + + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + /* Delta hinting is covered by US Patent 5159668. */ + if ( CUR.face->unpatented_hinting ) + { + FT_Long n = args[0] * 2; + + + if ( CUR.args < n ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= n; + CUR.new_top = CUR.args; + return; + } +#endif + + nump = (FT_ULong)args[0]; + + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + return; + } + + CUR.args -= 2; + + A = (FT_ULong)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; + + if ( BOUNDS( A, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( CUR.opcode ) + { + case 0x73: + break; + + case 0x74: + C += 16; + break; + + case 0x75: + C += 32; + break; + } + + C += CUR.GS.delta_base; + + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + + CUR_Func_move_cvt( A, B ); + } + } + } + + CUR.new_top = CUR.args; + } + + + /*************************************************************************/ + /* */ + /* MISC. INSTRUCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* GETINFO[]: GET INFOrmation */ + /* Opcode range: 0x88 */ + /* Stack: uint32 --> uint32 */ + /* */ + static void + Ins_GETINFO( INS_ARG ) + { + FT_Long K; + + + K = 0; + + /* We return MS rasterizer version 1.7 for the font scaler. */ + if ( ( args[0] & 1 ) != 0 ) + K = 35; + + /* Has the glyph been rotated? */ + if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated ) + K |= 0x80; + + /* Has the glyph been stretched? */ + if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched ) + K |= 1 << 8; + + /* Are we hinting for grayscale? */ + if ( ( args[0] & 32 ) != 0 && CUR.grayscale ) + K |= 1 << 12; + + args[0] = K; + } + + + static void + Ins_UNKNOWN( INS_ARG ) + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + + FT_UNUSED_ARG; + + + for ( ; def < limit; def++ ) + { + if ( (FT_Byte)def->opc == CUR.opcode && def->active ) + { + TT_CallRec* call; + + + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + + call = CUR.callStack + CUR.callTop++; + + call->Caller_Range = CUR.curRange; + call->Caller_IP = CUR.IP+1; + call->Cur_Count = 1; + call->Cur_Restart = def->start; + + INS_Goto_CodeRange( def->range, def->start ); + + CUR.step_ins = FALSE; + return; + } + } + + CUR.error = TT_Err_Invalid_Opcode; + } + + +#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + static + TInstruction_Function Instruct_Dispatch[256] = + { + /* Opcodes are gathered in groups of 16. */ + /* Please keep the spaces as they are. */ + + /* SVTCA y */ Ins_SVTCA, + /* SVTCA x */ Ins_SVTCA, + /* SPvTCA y */ Ins_SPVTCA, + /* SPvTCA x */ Ins_SPVTCA, + /* SFvTCA y */ Ins_SFVTCA, + /* SFvTCA x */ Ins_SFVTCA, + /* SPvTL // */ Ins_SPVTL, + /* SPvTL + */ Ins_SPVTL, + /* SFvTL // */ Ins_SFVTL, + /* SFvTL + */ Ins_SFVTL, + /* SPvFS */ Ins_SPVFS, + /* SFvFS */ Ins_SFVFS, + /* GPV */ Ins_GPV, + /* GFV */ Ins_GFV, + /* SFvTPv */ Ins_SFVTPV, + /* ISECT */ Ins_ISECT, + + /* SRP0 */ Ins_SRP0, + /* SRP1 */ Ins_SRP1, + /* SRP2 */ Ins_SRP2, + /* SZP0 */ Ins_SZP0, + /* SZP1 */ Ins_SZP1, + /* SZP2 */ Ins_SZP2, + /* SZPS */ Ins_SZPS, + /* SLOOP */ Ins_SLOOP, + /* RTG */ Ins_RTG, + /* RTHG */ Ins_RTHG, + /* SMD */ Ins_SMD, + /* ELSE */ Ins_ELSE, + /* JMPR */ Ins_JMPR, + /* SCvTCi */ Ins_SCVTCI, + /* SSwCi */ Ins_SSWCI, + /* SSW */ Ins_SSW, + + /* DUP */ Ins_DUP, + /* POP */ Ins_POP, + /* CLEAR */ Ins_CLEAR, + /* SWAP */ Ins_SWAP, + /* DEPTH */ Ins_DEPTH, + /* CINDEX */ Ins_CINDEX, + /* MINDEX */ Ins_MINDEX, + /* AlignPTS */ Ins_ALIGNPTS, + /* INS_0x28 */ Ins_UNKNOWN, + /* UTP */ Ins_UTP, + /* LOOPCALL */ Ins_LOOPCALL, + /* CALL */ Ins_CALL, + /* FDEF */ Ins_FDEF, + /* ENDF */ Ins_ENDF, + /* MDAP[0] */ Ins_MDAP, + /* MDAP[1] */ Ins_MDAP, + + /* IUP[0] */ Ins_IUP, + /* IUP[1] */ Ins_IUP, + /* SHP[0] */ Ins_SHP, + /* SHP[1] */ Ins_SHP, + /* SHC[0] */ Ins_SHC, + /* SHC[1] */ Ins_SHC, + /* SHZ[0] */ Ins_SHZ, + /* SHZ[1] */ Ins_SHZ, + /* SHPIX */ Ins_SHPIX, + /* IP */ Ins_IP, + /* MSIRP[0] */ Ins_MSIRP, + /* MSIRP[1] */ Ins_MSIRP, + /* AlignRP */ Ins_ALIGNRP, + /* RTDG */ Ins_RTDG, + /* MIAP[0] */ Ins_MIAP, + /* MIAP[1] */ Ins_MIAP, + + /* NPushB */ Ins_NPUSHB, + /* NPushW */ Ins_NPUSHW, + /* WS */ Ins_WS, + /* RS */ Ins_RS, + /* WCvtP */ Ins_WCVTP, + /* RCvt */ Ins_RCVT, + /* GC[0] */ Ins_GC, + /* GC[1] */ Ins_GC, + /* SCFS */ Ins_SCFS, + /* MD[0] */ Ins_MD, + /* MD[1] */ Ins_MD, + /* MPPEM */ Ins_MPPEM, + /* MPS */ Ins_MPS, + /* FlipON */ Ins_FLIPON, + /* FlipOFF */ Ins_FLIPOFF, + /* DEBUG */ Ins_DEBUG, + + /* LT */ Ins_LT, + /* LTEQ */ Ins_LTEQ, + /* GT */ Ins_GT, + /* GTEQ */ Ins_GTEQ, + /* EQ */ Ins_EQ, + /* NEQ */ Ins_NEQ, + /* ODD */ Ins_ODD, + /* EVEN */ Ins_EVEN, + /* IF */ Ins_IF, + /* EIF */ Ins_EIF, + /* AND */ Ins_AND, + /* OR */ Ins_OR, + /* NOT */ Ins_NOT, + /* DeltaP1 */ Ins_DELTAP, + /* SDB */ Ins_SDB, + /* SDS */ Ins_SDS, + + /* ADD */ Ins_ADD, + /* SUB */ Ins_SUB, + /* DIV */ Ins_DIV, + /* MUL */ Ins_MUL, + /* ABS */ Ins_ABS, + /* NEG */ Ins_NEG, + /* FLOOR */ Ins_FLOOR, + /* CEILING */ Ins_CEILING, + /* ROUND[0] */ Ins_ROUND, + /* ROUND[1] */ Ins_ROUND, + /* ROUND[2] */ Ins_ROUND, + /* ROUND[3] */ Ins_ROUND, + /* NROUND[0] */ Ins_NROUND, + /* NROUND[1] */ Ins_NROUND, + /* NROUND[2] */ Ins_NROUND, + /* NROUND[3] */ Ins_NROUND, + + /* WCvtF */ Ins_WCVTF, + /* DeltaP2 */ Ins_DELTAP, + /* DeltaP3 */ Ins_DELTAP, + /* DeltaCn[0] */ Ins_DELTAC, + /* DeltaCn[1] */ Ins_DELTAC, + /* DeltaCn[2] */ Ins_DELTAC, + /* SROUND */ Ins_SROUND, + /* S45Round */ Ins_S45ROUND, + /* JROT */ Ins_JROT, + /* JROF */ Ins_JROF, + /* ROFF */ Ins_ROFF, + /* INS_0x7B */ Ins_UNKNOWN, + /* RUTG */ Ins_RUTG, + /* RDTG */ Ins_RDTG, + /* SANGW */ Ins_SANGW, + /* AA */ Ins_AA, + + /* FlipPT */ Ins_FLIPPT, + /* FlipRgON */ Ins_FLIPRGON, + /* FlipRgOFF */ Ins_FLIPRGOFF, + /* INS_0x83 */ Ins_UNKNOWN, + /* INS_0x84 */ Ins_UNKNOWN, + /* ScanCTRL */ Ins_SCANCTRL, + /* SDPVTL[0] */ Ins_SDPVTL, + /* SDPVTL[1] */ Ins_SDPVTL, + /* GetINFO */ Ins_GETINFO, + /* IDEF */ Ins_IDEF, + /* ROLL */ Ins_ROLL, + /* MAX */ Ins_MAX, + /* MIN */ Ins_MIN, + /* ScanTYPE */ Ins_SCANTYPE, + /* InstCTRL */ Ins_INSTCTRL, + /* INS_0x8F */ Ins_UNKNOWN, + + /* INS_0x90 */ Ins_UNKNOWN, + /* INS_0x91 */ Ins_UNKNOWN, + /* INS_0x92 */ Ins_UNKNOWN, + /* INS_0x93 */ Ins_UNKNOWN, + /* INS_0x94 */ Ins_UNKNOWN, + /* INS_0x95 */ Ins_UNKNOWN, + /* INS_0x96 */ Ins_UNKNOWN, + /* INS_0x97 */ Ins_UNKNOWN, + /* INS_0x98 */ Ins_UNKNOWN, + /* INS_0x99 */ Ins_UNKNOWN, + /* INS_0x9A */ Ins_UNKNOWN, + /* INS_0x9B */ Ins_UNKNOWN, + /* INS_0x9C */ Ins_UNKNOWN, + /* INS_0x9D */ Ins_UNKNOWN, + /* INS_0x9E */ Ins_UNKNOWN, + /* INS_0x9F */ Ins_UNKNOWN, + + /* INS_0xA0 */ Ins_UNKNOWN, + /* INS_0xA1 */ Ins_UNKNOWN, + /* INS_0xA2 */ Ins_UNKNOWN, + /* INS_0xA3 */ Ins_UNKNOWN, + /* INS_0xA4 */ Ins_UNKNOWN, + /* INS_0xA5 */ Ins_UNKNOWN, + /* INS_0xA6 */ Ins_UNKNOWN, + /* INS_0xA7 */ Ins_UNKNOWN, + /* INS_0xA8 */ Ins_UNKNOWN, + /* INS_0xA9 */ Ins_UNKNOWN, + /* INS_0xAA */ Ins_UNKNOWN, + /* INS_0xAB */ Ins_UNKNOWN, + /* INS_0xAC */ Ins_UNKNOWN, + /* INS_0xAD */ Ins_UNKNOWN, + /* INS_0xAE */ Ins_UNKNOWN, + /* INS_0xAF */ Ins_UNKNOWN, + + /* PushB[0] */ Ins_PUSHB, + /* PushB[1] */ Ins_PUSHB, + /* PushB[2] */ Ins_PUSHB, + /* PushB[3] */ Ins_PUSHB, + /* PushB[4] */ Ins_PUSHB, + /* PushB[5] */ Ins_PUSHB, + /* PushB[6] */ Ins_PUSHB, + /* PushB[7] */ Ins_PUSHB, + /* PushW[0] */ Ins_PUSHW, + /* PushW[1] */ Ins_PUSHW, + /* PushW[2] */ Ins_PUSHW, + /* PushW[3] */ Ins_PUSHW, + /* PushW[4] */ Ins_PUSHW, + /* PushW[5] */ Ins_PUSHW, + /* PushW[6] */ Ins_PUSHW, + /* PushW[7] */ Ins_PUSHW, + + /* MDRP[00] */ Ins_MDRP, + /* MDRP[01] */ Ins_MDRP, + /* MDRP[02] */ Ins_MDRP, + /* MDRP[03] */ Ins_MDRP, + /* MDRP[04] */ Ins_MDRP, + /* MDRP[05] */ Ins_MDRP, + /* MDRP[06] */ Ins_MDRP, + /* MDRP[07] */ Ins_MDRP, + /* MDRP[08] */ Ins_MDRP, + /* MDRP[09] */ Ins_MDRP, + /* MDRP[10] */ Ins_MDRP, + /* MDRP[11] */ Ins_MDRP, + /* MDRP[12] */ Ins_MDRP, + /* MDRP[13] */ Ins_MDRP, + /* MDRP[14] */ Ins_MDRP, + /* MDRP[15] */ Ins_MDRP, + + /* MDRP[16] */ Ins_MDRP, + /* MDRP[17] */ Ins_MDRP, + /* MDRP[18] */ Ins_MDRP, + /* MDRP[19] */ Ins_MDRP, + /* MDRP[20] */ Ins_MDRP, + /* MDRP[21] */ Ins_MDRP, + /* MDRP[22] */ Ins_MDRP, + /* MDRP[23] */ Ins_MDRP, + /* MDRP[24] */ Ins_MDRP, + /* MDRP[25] */ Ins_MDRP, + /* MDRP[26] */ Ins_MDRP, + /* MDRP[27] */ Ins_MDRP, + /* MDRP[28] */ Ins_MDRP, + /* MDRP[29] */ Ins_MDRP, + /* MDRP[30] */ Ins_MDRP, + /* MDRP[31] */ Ins_MDRP, + + /* MIRP[00] */ Ins_MIRP, + /* MIRP[01] */ Ins_MIRP, + /* MIRP[02] */ Ins_MIRP, + /* MIRP[03] */ Ins_MIRP, + /* MIRP[04] */ Ins_MIRP, + /* MIRP[05] */ Ins_MIRP, + /* MIRP[06] */ Ins_MIRP, + /* MIRP[07] */ Ins_MIRP, + /* MIRP[08] */ Ins_MIRP, + /* MIRP[09] */ Ins_MIRP, + /* MIRP[10] */ Ins_MIRP, + /* MIRP[11] */ Ins_MIRP, + /* MIRP[12] */ Ins_MIRP, + /* MIRP[13] */ Ins_MIRP, + /* MIRP[14] */ Ins_MIRP, + /* MIRP[15] */ Ins_MIRP, + + /* MIRP[16] */ Ins_MIRP, + /* MIRP[17] */ Ins_MIRP, + /* MIRP[18] */ Ins_MIRP, + /* MIRP[19] */ Ins_MIRP, + /* MIRP[20] */ Ins_MIRP, + /* MIRP[21] */ Ins_MIRP, + /* MIRP[22] */ Ins_MIRP, + /* MIRP[23] */ Ins_MIRP, + /* MIRP[24] */ Ins_MIRP, + /* MIRP[25] */ Ins_MIRP, + /* MIRP[26] */ Ins_MIRP, + /* MIRP[27] */ Ins_MIRP, + /* MIRP[28] */ Ins_MIRP, + /* MIRP[29] */ Ins_MIRP, + /* MIRP[30] */ Ins_MIRP, + /* MIRP[31] */ Ins_MIRP + }; + + +#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + + /*************************************************************************/ + /* */ + /* RUN */ + /* */ + /* This function executes a run of opcodes. It will exit in the */ + /* following cases: */ + /* */ + /* - Errors (in which case it returns FALSE). */ + /* */ + /* - Reaching the end of the main code range (returns TRUE). */ + /* Reaching the end of a code range within a function call is an */ + /* error. */ + /* */ + /* - After executing one single opcode, if the flag `Instruction_Trap' */ + /* is set to TRUE (returns TRUE). */ + /* */ + /* On exit with TRUE, test IP < CodeSize to know whether it comes from */ + /* an instruction trap or a normal termination. */ + /* */ + /* */ + /* Note: The documented DEBUG opcode pops a value from the stack. This */ + /* behaviour is unsupported; here a DEBUG opcode is always an */ + /* error. */ + /* */ + /* */ + /* THIS IS THE INTERPRETER'S MAIN LOOP. */ + /* */ + /* Instructions appear in the specification's order. */ + /* */ + /*************************************************************************/ + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( FT_Error ) + TT_RunIns( TT_ExecContext exc ) + { + FT_Long ins_counter = 0; /* executed instructions counter */ + + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + cur = *exc; +#endif + + /* set CVT functions */ + CUR.tt_metrics.ratio = 0; + if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + CUR.func_read_cvt = Read_CVT_Stretched; + CUR.func_write_cvt = Write_CVT_Stretched; + CUR.func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + CUR.func_read_cvt = Read_CVT; + CUR.func_write_cvt = Write_CVT; + CUR.func_move_cvt = Move_CVT; + } + + COMPUTE_Funcs(); + COMPUTE_Round( (FT_Byte)exc->GS.round_state ); + + do + { + CUR.opcode = CUR.code[CUR.IP]; + + if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 ) + { + if ( CUR.IP + 1 > CUR.codeSize ) + goto LErrorCodeOverflow_; + + CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; + } + + if ( CUR.IP + CUR.length > CUR.codeSize ) + goto LErrorCodeOverflow_; + + /* First, let's check for empty stack and overflow */ + CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 ); + + /* `args' is the top of the stack once arguments have been popped. */ + /* One can also interpret it as the index of the last argument. */ + if ( CUR.args < 0 ) + { + CUR.error = TT_Err_Too_Few_Arguments; + goto LErrorLabel_; + } + + CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 ); + + /* `new_top' is the new top of the stack, after the instruction's */ + /* execution. `top' will be set to `new_top' after the `switch' */ + /* statement. */ + if ( CUR.new_top > CUR.stackSize ) + { + CUR.error = TT_Err_Stack_Overflow; + goto LErrorLabel_; + } + + CUR.step_ins = TRUE; + CUR.error = TT_Err_Ok; + +#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH + + { + FT_Long* args = CUR.stack + CUR.args; + FT_Byte opcode = CUR.opcode; + + +#undef ARRAY_BOUND_ERROR +#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref + + + switch ( opcode ) + { + case 0x00: /* SVTCA y */ + case 0x01: /* SVTCA x */ + case 0x02: /* SPvTCA y */ + case 0x03: /* SPvTCA x */ + case 0x04: /* SFvTCA y */ + case 0x05: /* SFvTCA x */ + { + FT_Short AA, BB; + + + AA = (FT_Short)( ( opcode & 1 ) << 14 ); + BB = (FT_Short)( AA ^ 0x4000 ); + + if ( opcode < 4 ) + { + CUR.GS.projVector.x = AA; + CUR.GS.projVector.y = BB; + + CUR.GS.dualVector.x = AA; + CUR.GS.dualVector.y = BB; + } + else + { + GUESS_VECTOR( projVector ); + } + + if ( ( opcode & 2 ) == 0 ) + { + CUR.GS.freeVector.x = AA; + CUR.GS.freeVector.y = BB; + } + else + { + GUESS_VECTOR( freeVector ); + } + + COMPUTE_Funcs(); + } + break; + + case 0x06: /* SPvTL // */ + case 0x07: /* SPvTL + */ + DO_SPVTL + break; + + case 0x08: /* SFvTL // */ + case 0x09: /* SFvTL + */ + DO_SFVTL + break; + + case 0x0A: /* SPvFS */ + DO_SPVFS + break; + + case 0x0B: /* SFvFS */ + DO_SFVFS + break; + + case 0x0C: /* GPV */ + DO_GPV + break; + + case 0x0D: /* GFV */ + DO_GFV + break; + + case 0x0E: /* SFvTPv */ + DO_SFVTPV + break; + + case 0x0F: /* ISECT */ + Ins_ISECT( EXEC_ARG_ args ); + break; + + case 0x10: /* SRP0 */ + DO_SRP0 + break; + + case 0x11: /* SRP1 */ + DO_SRP1 + break; + + case 0x12: /* SRP2 */ + DO_SRP2 + break; + + case 0x13: /* SZP0 */ + Ins_SZP0( EXEC_ARG_ args ); + break; + + case 0x14: /* SZP1 */ + Ins_SZP1( EXEC_ARG_ args ); + break; + + case 0x15: /* SZP2 */ + Ins_SZP2( EXEC_ARG_ args ); + break; + + case 0x16: /* SZPS */ + Ins_SZPS( EXEC_ARG_ args ); + break; + + case 0x17: /* SLOOP */ + DO_SLOOP + break; + + case 0x18: /* RTG */ + DO_RTG + break; + + case 0x19: /* RTHG */ + DO_RTHG + break; + + case 0x1A: /* SMD */ + DO_SMD + break; + + case 0x1B: /* ELSE */ + Ins_ELSE( EXEC_ARG_ args ); + break; + + case 0x1C: /* JMPR */ + DO_JMPR + break; + + case 0x1D: /* SCVTCI */ + DO_SCVTCI + break; + + case 0x1E: /* SSWCI */ + DO_SSWCI + break; + + case 0x1F: /* SSW */ + DO_SSW + break; + + case 0x20: /* DUP */ + DO_DUP + break; + + case 0x21: /* POP */ + /* nothing :-) */ + break; + + case 0x22: /* CLEAR */ + DO_CLEAR + break; + + case 0x23: /* SWAP */ + DO_SWAP + break; + + case 0x24: /* DEPTH */ + DO_DEPTH + break; + + case 0x25: /* CINDEX */ + DO_CINDEX + break; + + case 0x26: /* MINDEX */ + Ins_MINDEX( EXEC_ARG_ args ); + break; + + case 0x27: /* ALIGNPTS */ + Ins_ALIGNPTS( EXEC_ARG_ args ); + break; + + case 0x28: /* ???? */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x29: /* UTP */ + Ins_UTP( EXEC_ARG_ args ); + break; + + case 0x2A: /* LOOPCALL */ + Ins_LOOPCALL( EXEC_ARG_ args ); + break; + + case 0x2B: /* CALL */ + Ins_CALL( EXEC_ARG_ args ); + break; + + case 0x2C: /* FDEF */ + Ins_FDEF( EXEC_ARG_ args ); + break; + + case 0x2D: /* ENDF */ + Ins_ENDF( EXEC_ARG_ args ); + break; + + case 0x2E: /* MDAP */ + case 0x2F: /* MDAP */ + Ins_MDAP( EXEC_ARG_ args ); + break; + + + case 0x30: /* IUP */ + case 0x31: /* IUP */ + Ins_IUP( EXEC_ARG_ args ); + break; + + case 0x32: /* SHP */ + case 0x33: /* SHP */ + Ins_SHP( EXEC_ARG_ args ); + break; + + case 0x34: /* SHC */ + case 0x35: /* SHC */ + Ins_SHC( EXEC_ARG_ args ); + break; + + case 0x36: /* SHZ */ + case 0x37: /* SHZ */ + Ins_SHZ( EXEC_ARG_ args ); + break; + + case 0x38: /* SHPIX */ + Ins_SHPIX( EXEC_ARG_ args ); + break; + + case 0x39: /* IP */ + Ins_IP( EXEC_ARG_ args ); + break; + + case 0x3A: /* MSIRP */ + case 0x3B: /* MSIRP */ + Ins_MSIRP( EXEC_ARG_ args ); + break; + + case 0x3C: /* AlignRP */ + Ins_ALIGNRP( EXEC_ARG_ args ); + break; + + case 0x3D: /* RTDG */ + DO_RTDG + break; + + case 0x3E: /* MIAP */ + case 0x3F: /* MIAP */ + Ins_MIAP( EXEC_ARG_ args ); + break; + + case 0x40: /* NPUSHB */ + Ins_NPUSHB( EXEC_ARG_ args ); + break; + + case 0x41: /* NPUSHW */ + Ins_NPUSHW( EXEC_ARG_ args ); + break; + + case 0x42: /* WS */ + DO_WS + break; + + Set_Invalid_Ref: + CUR.error = TT_Err_Invalid_Reference; + break; + + case 0x43: /* RS */ + DO_RS + break; + + case 0x44: /* WCVTP */ + DO_WCVTP + break; + + case 0x45: /* RCVT */ + DO_RCVT + break; + + case 0x46: /* GC */ + case 0x47: /* GC */ + Ins_GC( EXEC_ARG_ args ); + break; + + case 0x48: /* SCFS */ + Ins_SCFS( EXEC_ARG_ args ); + break; + + case 0x49: /* MD */ + case 0x4A: /* MD */ + Ins_MD( EXEC_ARG_ args ); + break; + + case 0x4B: /* MPPEM */ + DO_MPPEM + break; + + case 0x4C: /* MPS */ + DO_MPS + break; + + case 0x4D: /* FLIPON */ + DO_FLIPON + break; + + case 0x4E: /* FLIPOFF */ + DO_FLIPOFF + break; + + case 0x4F: /* DEBUG */ + DO_DEBUG + break; + + case 0x50: /* LT */ + DO_LT + break; + + case 0x51: /* LTEQ */ + DO_LTEQ + break; + + case 0x52: /* GT */ + DO_GT + break; + + case 0x53: /* GTEQ */ + DO_GTEQ + break; + + case 0x54: /* EQ */ + DO_EQ + break; + + case 0x55: /* NEQ */ + DO_NEQ + break; + + case 0x56: /* ODD */ + DO_ODD + break; + + case 0x57: /* EVEN */ + DO_EVEN + break; + + case 0x58: /* IF */ + Ins_IF( EXEC_ARG_ args ); + break; + + case 0x59: /* EIF */ + /* do nothing */ + break; + + case 0x5A: /* AND */ + DO_AND + break; + + case 0x5B: /* OR */ + DO_OR + break; + + case 0x5C: /* NOT */ + DO_NOT + break; + + case 0x5D: /* DELTAP1 */ + Ins_DELTAP( EXEC_ARG_ args ); + break; + + case 0x5E: /* SDB */ + DO_SDB + break; + + case 0x5F: /* SDS */ + DO_SDS + break; + + case 0x60: /* ADD */ + DO_ADD + break; + + case 0x61: /* SUB */ + DO_SUB + break; + + case 0x62: /* DIV */ + DO_DIV + break; + + case 0x63: /* MUL */ + DO_MUL + break; + + case 0x64: /* ABS */ + DO_ABS + break; + + case 0x65: /* NEG */ + DO_NEG + break; + + case 0x66: /* FLOOR */ + DO_FLOOR + break; + + case 0x67: /* CEILING */ + DO_CEILING + break; + + case 0x68: /* ROUND */ + case 0x69: /* ROUND */ + case 0x6A: /* ROUND */ + case 0x6B: /* ROUND */ + DO_ROUND + break; + + case 0x6C: /* NROUND */ + case 0x6D: /* NROUND */ + case 0x6E: /* NRRUND */ + case 0x6F: /* NROUND */ + DO_NROUND + break; + + case 0x70: /* WCVTF */ + DO_WCVTF + break; + + case 0x71: /* DELTAP2 */ + case 0x72: /* DELTAP3 */ + Ins_DELTAP( EXEC_ARG_ args ); + break; + + case 0x73: /* DELTAC0 */ + case 0x74: /* DELTAC1 */ + case 0x75: /* DELTAC2 */ + Ins_DELTAC( EXEC_ARG_ args ); + break; + + case 0x76: /* SROUND */ + DO_SROUND + break; + + case 0x77: /* S45Round */ + DO_S45ROUND + break; + + case 0x78: /* JROT */ + DO_JROT + break; + + case 0x79: /* JROF */ + DO_JROF + break; + + case 0x7A: /* ROFF */ + DO_ROFF + break; + + case 0x7B: /* ???? */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x7C: /* RUTG */ + DO_RUTG + break; + + case 0x7D: /* RDTG */ + DO_RDTG + break; + + case 0x7E: /* SANGW */ + case 0x7F: /* AA */ + /* nothing - obsolete */ + break; + + case 0x80: /* FLIPPT */ + Ins_FLIPPT( EXEC_ARG_ args ); + break; + + case 0x81: /* FLIPRGON */ + Ins_FLIPRGON( EXEC_ARG_ args ); + break; + + case 0x82: /* FLIPRGOFF */ + Ins_FLIPRGOFF( EXEC_ARG_ args ); + break; + + case 0x83: /* UNKNOWN */ + case 0x84: /* UNKNOWN */ + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + case 0x85: /* SCANCTRL */ + Ins_SCANCTRL( EXEC_ARG_ args ); + break; + + case 0x86: /* SDPVTL */ + case 0x87: /* SDPVTL */ + Ins_SDPVTL( EXEC_ARG_ args ); + break; + + case 0x88: /* GETINFO */ + Ins_GETINFO( EXEC_ARG_ args ); + break; + + case 0x89: /* IDEF */ + Ins_IDEF( EXEC_ARG_ args ); + break; + + case 0x8A: /* ROLL */ + Ins_ROLL( EXEC_ARG_ args ); + break; + + case 0x8B: /* MAX */ + DO_MAX + break; + + case 0x8C: /* MIN */ + DO_MIN + break; + + case 0x8D: /* SCANTYPE */ + Ins_SCANTYPE( EXEC_ARG_ args ); + break; + + case 0x8E: /* INSTCTRL */ + Ins_INSTCTRL( EXEC_ARG_ args ); + break; + + case 0x8F: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + + default: + if ( opcode >= 0xE0 ) + Ins_MIRP( EXEC_ARG_ args ); + else if ( opcode >= 0xC0 ) + Ins_MDRP( EXEC_ARG_ args ); + else if ( opcode >= 0xB8 ) + Ins_PUSHW( EXEC_ARG_ args ); + else if ( opcode >= 0xB0 ) + Ins_PUSHB( EXEC_ARG_ args ); + else + Ins_UNKNOWN( EXEC_ARG_ args ); + } + + } + +#else + + Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] ); + +#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */ + + if ( CUR.error != TT_Err_Ok ) + { + switch ( CUR.error ) + { + case TT_Err_Invalid_Opcode: /* looking for redefined instructions */ + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + + + for ( ; def < limit; def++ ) + { + if ( def->active && CUR.opcode == (FT_Byte)def->opc ) + { + TT_CallRec* callrec; + + + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Invalid_Reference; + goto LErrorLabel_; + } + + callrec = &CUR.callStack[CUR.callTop]; + + callrec->Caller_Range = CUR.curRange; + callrec->Caller_IP = CUR.IP + 1; + callrec->Cur_Count = 1; + callrec->Cur_Restart = def->start; + + if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE ) + goto LErrorLabel_; + + goto LSuiteLabel_; + } + } + } + + CUR.error = TT_Err_Invalid_Opcode; + goto LErrorLabel_; + +#if 0 + break; /* Unreachable code warning suppression. */ + /* Leave to remind in case a later change the editor */ + /* to consider break; */ +#endif + + default: + goto LErrorLabel_; + +#if 0 + break; +#endif + } + } + + CUR.top = CUR.new_top; + + if ( CUR.step_ins ) + CUR.IP += CUR.length; + + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > MAX_RUNNABLE_OPCODES ) + return TT_Err_Execution_Too_Long; + + LSuiteLabel_: + if ( CUR.IP >= CUR.codeSize ) + { + if ( CUR.callTop > 0 ) + { + CUR.error = TT_Err_Code_Overflow; + goto LErrorLabel_; + } + else + goto LNo_Error_; + } + } while ( !CUR.instruction_trap ); + + LNo_Error_: + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif + + return TT_Err_Ok; + + LErrorCodeOverflow_: + CUR.error = TT_Err_Code_Overflow; + + LErrorLabel_: + +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif + + return CUR.error; + } + + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + +/* END */ diff --git a/src/freetype2/truetype/ttinterp.h b/src/freetype2/truetype/ttinterp.h new file mode 100644 index 0000000..07a8972 --- /dev/null +++ b/src/freetype2/truetype/ttinterp.h @@ -0,0 +1,311 @@ +/***************************************************************************/ +/* */ +/* ttinterp.h */ +/* */ +/* TrueType bytecode interpreter (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTINTERP_H__ +#define __TTINTERP_H__ + +#include <ft2build.h> +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + +#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */ + +#define EXEC_OP_ TT_ExecContext exc, +#define EXEC_OP TT_ExecContext exc +#define EXEC_ARG_ exc, +#define EXEC_ARG exc + +#else /* static implementation */ + +#define EXEC_OP_ /* void */ +#define EXEC_OP /* void */ +#define EXEC_ARG_ /* void */ +#define EXEC_ARG /* void */ + +#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* Rounding mode constants. */ + /* */ +#define TT_Round_Off 5 +#define TT_Round_To_Half_Grid 0 +#define TT_Round_To_Grid 1 +#define TT_Round_To_Double_Grid 2 +#define TT_Round_Up_To_Grid 4 +#define TT_Round_Down_To_Grid 3 +#define TT_Round_Super 6 +#define TT_Round_Super_45 7 + + + /*************************************************************************/ + /* */ + /* Function types used by the interpreter, depending on various modes */ + /* (e.g. the rounding mode, whether to render a vertical or horizontal */ + /* line etc). */ + /* */ + /*************************************************************************/ + + /* Rounding function */ + typedef FT_F26Dot6 + (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ); + + /* Point displacement along the freedom vector routine */ + typedef void + (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ); + + /* Distance projection along one of the projection vectors */ + typedef FT_F26Dot6 + (*TT_Project_Func)( EXEC_OP_ FT_Pos dx, + FT_Pos dy ); + + /* reading a cvt value. Take care of non-square pixels if necessary */ + typedef FT_F26Dot6 + (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong idx ); + + /* setting or moving a cvt value. Take care of non-square pixels */ + /* if necessary */ + typedef void + (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ); + + + /*************************************************************************/ + /* */ + /* This structure defines a call record, used to manage function calls. */ + /* */ + typedef struct TT_CallRec_ + { + FT_Int Caller_Range; + FT_Long Caller_IP; + FT_Long Cur_Count; + FT_Long Cur_Restart; + + } TT_CallRec, *TT_CallStack; + + + /*************************************************************************/ + /* */ + /* The main structure for the interpreter which collects all necessary */ + /* variables and states. */ + /* */ + typedef struct TT_ExecContextRec_ + { + TT_Face face; + TT_Size size; + FT_Memory memory; + + /* instructions state */ + + FT_Error error; /* last execution error */ + + FT_Long top; /* top of exec. stack */ + + FT_UInt stackSize; /* size of exec. stack */ + FT_Long* stack; /* current exec. stack */ + + FT_Long args; + FT_UInt new_top; /* new top after exec. */ + + TT_GlyphZoneRec zp0, /* zone records */ + zp1, + zp2, + pts, + twilight; + + FT_Size_Metrics metrics; + TT_Size_Metrics tt_metrics; /* size metrics */ + + TT_GraphicsState GS; /* current graphics state */ + + FT_Int curRange; /* current code range number */ + FT_Byte* code; /* current code range */ + FT_Long IP; /* current instruction pointer */ + FT_Long codeSize; /* size of current range */ + + FT_Byte opcode; /* current opcode */ + FT_Int length; /* length of current opcode */ + + FT_Bool step_ins; /* true if the interpreter must */ + /* increment IP after ins. exec */ + FT_Long cvtSize; + FT_Long* cvt; + + FT_UInt glyphSize; /* glyph instructions buffer size */ + FT_Byte* glyphIns; /* glyph instructions buffer */ + + FT_UInt numFDefs; /* number of function defs */ + FT_UInt maxFDefs; /* maximum number of function defs */ + TT_DefArray FDefs; /* table of FDefs entries */ + + FT_UInt numIDefs; /* number of instruction defs */ + FT_UInt maxIDefs; /* maximum number of ins defs */ + TT_DefArray IDefs; /* table of IDefs entries */ + + FT_UInt maxFunc; /* maximum function index */ + FT_UInt maxIns; /* maximum instruction index */ + + FT_Int callTop, /* top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ + + FT_UShort maxPoints; /* capacity of this context's `pts' */ + FT_Short maxContours; /* record, expressed in points and */ + /* contours. */ + + TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */ + /* useful for the debugger */ + + FT_UShort storeSize; /* size of current storage */ + FT_Long* storage; /* storage area */ + + FT_F26Dot6 period; /* values used for the */ + FT_F26Dot6 phase; /* `SuperRounding' */ + FT_F26Dot6 threshold; + +#if 0 + /* this seems to be unused */ + FT_Int cur_ppem; /* ppem along the current proj vector */ +#endif + + FT_Bool instruction_trap; /* If `True', the interpreter will */ + /* exit after each instruction */ + + TT_GraphicsState default_GS; /* graphics state resulting from */ + /* the prep program */ + FT_Bool is_composite; /* true if the glyph is composite */ + FT_Bool pedantic_hinting; /* true if pedantic interpretation */ + + /* latest interpreter additions */ + + FT_Long F_dot_P; /* dot product of freedom and projection */ + /* vectors */ + TT_Round_Func func_round; /* current rounding function */ + + TT_Project_Func func_project, /* current projection function */ + func_dualproj, /* current dual proj. function */ + func_freeProj; /* current freedom proj. func */ + + TT_Move_Func func_move; /* current point move function */ + TT_Move_Func func_move_orig; /* move original position function */ + + TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ + TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ + + FT_Bool grayscale; /* are we hinting for grayscale? */ + + } TT_ExecContextRec; + + + extern const TT_GraphicsState tt_default_graphics_state; + + + FT_LOCAL( FT_Error ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ); + + FT_LOCAL( FT_Error ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ); + + FT_LOCAL( FT_Error ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_New_Context */ + /* */ + /* <Description> */ + /* Queries the face context for a given font. Note that there is */ + /* now a _single_ execution context in the TrueType driver which is */ + /* shared among faces. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Return> */ + /* A handle to the execution context. Initialized for `face'. */ + /* */ + /* <Note> */ + /* Only the glyph loader and debugger should call this function. */ + /* */ + FT_EXPORT( TT_ExecContext ) + TT_New_Context( TT_Driver driver ); + + FT_LOCAL( FT_Error ) + TT_Done_Context( TT_ExecContext exec ); + + FT_LOCAL( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ); + + FT_LOCAL( FT_Error ) + TT_Save_Context( TT_ExecContext exec, + TT_Size ins ); + + FT_LOCAL( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_RunIns */ + /* */ + /* <Description> */ + /* Executes one or more instruction in the execution context. This */ + /* is the main function of the TrueType opcode interpreter. */ + /* */ + /* <Input> */ + /* exec :: A handle to the target execution context. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only the object manager and debugger should call this function. */ + /* */ + /* This function is publicly exported because it is directly */ + /* invoked by the TrueType debugger. */ + /* */ + FT_EXPORT( FT_Error ) + TT_RunIns( TT_ExecContext exec ); + + +FT_END_HEADER + +#endif /* __TTINTERP_H__ */ + + +/* END */ diff --git a/src/freetype2/truetype/ttobjs.c b/src/freetype2/truetype/ttobjs.c new file mode 100644 index 0000000..0294a1b --- /dev/null +++ b/src/freetype2/truetype/ttobjs.c @@ -0,0 +1,937 @@ +/***************************************************************************/ +/* */ +/* ttobjs.c */ +/* */ +/* Objects manager (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_IDS_H +#include FT_TRUETYPE_TAGS_H +#include FT_INTERNAL_SFNT_H + +#include "ttgload.h" +#include "ttpload.h" + +#include "tterrors.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING +#include FT_TRUETYPE_UNPATENTED_H +#endif + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + + /*************************************************************************/ + /* */ + /* 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_ttobjs + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /*************************************************************************/ + /* */ + /* GLYPH ZONE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_glyphzone_done */ + /* */ + /* <Description> */ + /* Deallocate a glyph zone. */ + /* */ + /* <Input> */ + /* zone :: A pointer to the target glyph zone. */ + /* */ + FT_LOCAL_DEF( void ) + tt_glyphzone_done( TT_GlyphZone zone ) + { + FT_Memory memory = zone->memory; + + + if ( memory ) + { + FT_FREE( zone->contours ); + FT_FREE( zone->tags ); + FT_FREE( zone->cur ); + FT_FREE( zone->org ); + FT_FREE( zone->orus ); + + zone->max_points = zone->n_points = 0; + zone->max_contours = zone->n_contours = 0; + zone->memory = NULL; + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_glyphzone_new */ + /* */ + /* <Description> */ + /* Allocate a new glyph zone. */ + /* */ + /* <Input> */ + /* memory :: A handle to the current memory object. */ + /* */ + /* maxPoints :: The capacity of glyph zone in points. */ + /* */ + /* maxContours :: The capacity of glyph zone in contours. */ + /* */ + /* <Output> */ + /* zone :: A pointer to the target glyph zone record. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ) + { + FT_Error error; + + + FT_MEM_ZERO( zone, sizeof ( *zone ) ); + zone->memory = memory; + + if ( FT_NEW_ARRAY( zone->org, maxPoints ) || + FT_NEW_ARRAY( zone->cur, maxPoints ) || + FT_NEW_ARRAY( zone->orus, maxPoints ) || + FT_NEW_ARRAY( zone->tags, maxPoints ) || + FT_NEW_ARRAY( zone->contours, maxContours ) ) + { + tt_glyphzone_done( zone ); + } + else + { + zone->max_points = maxPoints; + zone->max_contours = maxContours; + } + + return error; + } +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_init */ + /* */ + /* <Description> */ + /* Initialize a given TrueType face object. */ + /* */ + /* <Input> */ + /* stream :: The source font stream. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* <InOut> */ + /* face :: The newly built face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library; + SFNT_Service sfnt; + TT_Face face = (TT_Face)ttface; + + + library = face->root.driver->root.library; + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + goto Bad_Format; + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check that we have a valid TrueType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + + /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ + /* The 0x00020000 tag is completely undocumented; some fonts from */ + /* Arphic made for Chinese Windows 3.1 have this. */ + if ( face->format_tag != 0x00010000L && /* MS fonts */ + face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ + face->format_tag != TTAG_true ) /* Mac fonts */ + { + FT_TRACE2(( "[not a valid TTF font]\n" )); + goto Bad_Format; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + face->root.face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return TT_Err_Ok; + + /* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + + error = tt_face_load_hdmx( face, stream ); + if ( error ) + goto Exit; + + if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE ) + { + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( !face->root.internal->incremental_interface ) + error = tt_face_load_loca( face, stream ); + if ( !error ) + error = tt_face_load_cvt( face, stream ) || + tt_face_load_fpgm( face, stream ) || + tt_face_load_prep( face, stream ); + +#else + + if ( !error ) + error = tt_face_load_loca( face, stream ) || + tt_face_load_cvt( face, stream ) || + tt_face_load_fpgm( face, stream ) || + tt_face_load_prep( face, stream ); + +#endif + + } + +#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ + !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) + + { + FT_Bool unpatented_hinting; + int i; + + + /* Determine whether unpatented hinting is to be used for this face. */ + unpatented_hinting = FT_BOOL + ( library->debug_hooks[FT_DEBUG_HOOK_UNPATENTED_HINTING] != NULL ); + + for ( i = 0; i < num_params && !face->unpatented_hinting; i++ ) + if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING ) + unpatented_hinting = TRUE; + + /* Compare the face with a list of well-known `tricky' fonts. */ + /* This list shall be expanded as we find more of them. */ + if ( !unpatented_hinting ) + { + static const char* const trick_names[] = + { + "DFKaiSho-SB", /* dfkaisb.ttf */ + "DFKai-SB", /* kaiu.ttf */ + "HuaTianSongTi?", /* htst3.ttf */ + "MingLiU", /* mingliu.ttf & mingliu.ttc */ + "PMingLiU", /* mingliu.ttc */ + "MingLi43", /* mingli.ttf */ + NULL + }; + int nn; + + + /* Note that we only check the face name at the moment; it might */ + /* be worth to do more checks for a few special cases. */ + for ( nn = 0; trick_names[nn] != NULL; nn++ ) + { + if ( ttface->family_name && + ft_strstr( ttface->family_name, trick_names[nn] ) ) + { + unpatented_hinting = 1; + break; + } + } + } + + ttface->internal->ignore_unpatented_hinter = + FT_BOOL( !unpatented_hinting ); + } + +#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING && + !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /* initialize standard glyph loading routines */ + TT_Init_Glyph_Loading( face ); + + Exit: + return error; + + Bad_Format: + error = TT_Err_Unknown_File_Format; + goto Exit; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_done */ + /* */ + /* <Description> */ + /* Finalize a given face object. */ + /* */ + /* <Input> */ + /* face :: A pointer to the face object to destroy. */ + /* */ + FT_LOCAL_DEF( void ) + tt_face_done( FT_Face ttface ) /* TT_Face */ + { + TT_Face face = (TT_Face)ttface; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + /* for `extended TrueType formats' (i.e. compressed versions) */ + if ( face->extra.finalizer ) + face->extra.finalizer( face->extra.data ); + + if ( sfnt ) + sfnt->done_face( face ); + + /* freeing the locations table */ + tt_face_done_loca( face ); + + tt_face_free_hdmx( face ); + + /* freeing the CVT */ + FT_FREE( face->cvt ); + face->cvt_size = 0; + + /* freeing the programs */ + FT_FRAME_RELEASE( face->font_program ); + FT_FRAME_RELEASE( face->cvt_program ); + face->font_program_size = 0; + face->cvt_program_size = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + tt_done_blend( memory, face->blend ); + face->blend = NULL; +#endif + } + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /*************************************************************************/ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_size_run_fpgm */ + /* */ + /* <Description> */ + /* Run the font program. */ + /* */ + /* <Input> */ + /* size :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_fpgm( TT_Size size ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + + + /* debugging instances have their own context */ + if ( size->debug ) + exec = size->context; + else + exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( exec, face, size ); + + exec->callTop = 0; + exec->top = 0; + + exec->period = 64; + exec->phase = 0; + exec->threshold = 0; + + exec->instruction_trap = FALSE; + exec->F_dot_P = 0x10000L; + + { + FT_Size_Metrics* metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + + + metrics->x_ppem = 0; + metrics->y_ppem = 0; + metrics->x_scale = 0; + metrics->y_scale = 0; + + tt_metrics->ppem = 0; + tt_metrics->scale = 0; + tt_metrics->ratio = 0x10000L; + } + + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + face->font_program_size ); + + /* disable CVT and glyph programs coderange */ + TT_Clear_CodeRange( exec, tt_coderange_cvt ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->font_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + + if ( !error ) + error = face->interpreter( exec ); + } + else + error = TT_Err_Ok; + + if ( !error ) + TT_Save_Context( exec, size ); + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_size_run_prep */ + /* */ + /* <Description> */ + /* Run the control value program. */ + /* */ + /* <Input> */ + /* size :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_prep( TT_Size size ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + + + /* debugging instances have their own context */ + if ( size->debug ) + exec = size->context; + else + exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( exec, face, size ); + + exec->callTop = 0; + exec->top = 0; + + exec->instruction_trap = FALSE; + + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + face->cvt_program_size ); + + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->cvt_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + + if ( !error && !size->debug ) + error = face->interpreter( exec ); + } + else + error = TT_Err_Ok; + + /* save as default graphics state */ + size->GS = exec->GS; + + TT_Save_Context( exec, size ); + + return error; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + static void + tt_size_done_bytecode( FT_Size ftsize ) + { + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + + + if ( size->debug ) + { + /* the debug context must be deleted by the debugger itself */ + size->context = NULL; + size->debug = FALSE; + } + + FT_FREE( size->cvt ); + size->cvt_size = 0; + + /* free storage area */ + FT_FREE( size->storage ); + size->storage_size = 0; + + /* twilight zone */ + tt_glyphzone_done( &size->twilight ); + + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + + size->num_function_defs = 0; + size->max_function_defs = 0; + size->num_instruction_defs = 0; + size->max_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->bytecode_ready = 0; + size->cvt_ready = 0; + } + + + /* Initialize bytecode-related fields in the size object. */ + /* We do this only if bytecode interpretation is really needed. */ + static FT_Error + tt_size_init_bytecode( FT_Size ftsize ) + { + FT_Error error; + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + FT_Int i; + + FT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; + + + size->bytecode_ready = 1; + size->cvt_ready = 0; + + size->max_function_defs = maxp->maxFunctionDefs; + size->max_instruction_defs = maxp->maxInstructionDefs; + + size->num_function_defs = 0; + size->num_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->cvt_size = face->cvt_size; + size->storage_size = maxp->maxStorage; + + /* Set default metrics */ + { + FT_Size_Metrics* metrics = &size->metrics; + TT_Size_Metrics* metrics2 = &size->ttmetrics; + + metrics->x_ppem = 0; + metrics->y_ppem = 0; + + metrics2->rotated = FALSE; + metrics2->stretched = FALSE; + + /* set default compensation (all 0) */ + for ( i = 0; i < 4; i++ ) + metrics2->compensations[i] = 0; + } + + /* allocate function defs, instruction defs, cvt, and storage area */ + if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || + FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || + FT_NEW_ARRAY( size->cvt, size->cvt_size ) || + FT_NEW_ARRAY( size->storage, size->storage_size ) ) + goto Exit; + + /* reserve twilight zone */ + n_twilight = maxp->maxTwilightPoints; + + /* there are 4 phantom points (do we need this?) */ + n_twilight += 4; + + error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); + if ( error ) + goto Exit; + + size->twilight.n_points = n_twilight; + + size->GS = tt_default_graphics_state; + + /* set `face->interpreter' according to the debug hook present */ + { + FT_Library library = face->root.driver->root.library; + + + face->interpreter = (TT_Interpreter) + library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + if ( !face->interpreter ) + face->interpreter = (TT_Interpreter)TT_RunIns; + } + + /* Fine, now run the font program! */ + error = tt_size_run_fpgm( size ); + + Exit: + if ( error ) + tt_size_done_bytecode( ftsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_size_ready_bytecode( TT_Size size ) + { + FT_Error error = TT_Err_Ok; + + + if ( !size->bytecode_ready ) + { + error = tt_size_init_bytecode( (FT_Size)size ); + if ( error ) + goto Exit; + } + + /* rescale CVT when needed */ + if ( !size->cvt_ready ) + { + FT_UInt i; + TT_Face face = (TT_Face) size->root.face; + + + /* Scale the cvt values to the new ppem. */ + /* We use by default the y ppem to scale the CVT. */ + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + + /* all twilight points are originally zero */ + for ( i = 0; i < (FT_UInt)size->twilight.n_points; i++ ) + { + size->twilight.org[i].x = 0; + size->twilight.org[i].y = 0; + size->twilight.cur[i].x = 0; + size->twilight.cur[i].y = 0; + } + + /* clear storage area */ + for ( i = 0; i < (FT_UInt)size->storage_size; i++ ) + size->storage[i] = 0; + + size->GS = tt_default_graphics_state; + + error = tt_size_run_prep( size ); + if ( !error ) + size->cvt_ready = 1; + } + Exit: + return error; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_size_init */ + /* */ + /* <Description> */ + /* Initialize a new TrueType size object. */ + /* */ + /* <InOut> */ + /* size :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_init( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + FT_Error error = TT_Err_Ok; + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->bytecode_ready = 0; + size->cvt_ready = 0; +#endif + + size->ttmetrics.valid = FALSE; + size->strike_index = 0xFFFFFFFFUL; + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_size_done */ + /* */ + /* <Description> */ + /* The TrueType size object finalizer. */ + /* */ + /* <Input> */ + /* size :: A handle to the target size object. */ + /* */ + FT_LOCAL_DEF( void ) + tt_size_done( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + if ( size->bytecode_ready ) + tt_size_done_bytecode( ttsize ); +#endif + + size->ttmetrics.valid = FALSE; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_size_reset */ + /* */ + /* <Description> */ + /* Reset a TrueType size when resolutions and character dimensions */ + /* have been changed. */ + /* */ + /* <Input> */ + /* size :: A handle to the target size object. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset( TT_Size size ) + { + TT_Face face; + FT_Error error = TT_Err_Ok; + FT_Size_Metrics* metrics; + + + size->ttmetrics.valid = FALSE; + + face = (TT_Face)size->root.face; + + metrics = &size->metrics; + + /* copy the result from base layer */ + *metrics = size->root.metrics; + + if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + return TT_Err_Invalid_PPem; + + /* This bit flag, if set, indicates that the ppems must be */ + /* rounded to integers. Nearly all TrueType fonts have this bit */ + /* set, as hinting won't work really well otherwise. */ + /* */ + if ( face->header.Flags & 8 ) + { + metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, + face->root.units_per_EM ); + metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, + face->root.units_per_EM ); + + metrics->ascender = + FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) ); + metrics->descender = + FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) ); + metrics->height = + FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) ); + metrics->max_advance = + FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width, + metrics->x_scale ) ); + } + + /* compute new transformation */ + if ( metrics->x_ppem >= metrics->y_ppem ) + { + size->ttmetrics.scale = metrics->x_scale; + size->ttmetrics.ppem = metrics->x_ppem; + size->ttmetrics.x_ratio = 0x10000L; + size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem, + 0x10000L, + metrics->x_ppem ); + } + else + { + size->ttmetrics.scale = metrics->y_scale; + size->ttmetrics.ppem = metrics->y_ppem; + size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem, + 0x10000L, + metrics->y_ppem ); + size->ttmetrics.y_ratio = 0x10000L; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->cvt_ready = 0; +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + if ( !error ) + size->ttmetrics.valid = TRUE; + + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_driver_init */ + /* */ + /* <Description> */ + /* Initialize a given TrueType driver object. */ + /* */ + /* <Input> */ + /* driver :: A handle to the target driver object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_driver_init( FT_Module ttdriver ) /* TT_Driver */ + { + +#ifdef TT_USE_BYTECODE_INTERPRETER + + TT_Driver driver = (TT_Driver)ttdriver; + + + if ( !TT_New_Context( driver ) ) + return TT_Err_Could_Not_Find_Context; + +#else + + FT_UNUSED( ttdriver ); + +#endif + + return TT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_driver_done */ + /* */ + /* <Description> */ + /* Finalize a given TrueType driver. */ + /* */ + /* <Input> */ + /* driver :: A handle to the target TrueType driver. */ + /* */ + FT_LOCAL_DEF( void ) + tt_driver_done( FT_Module ttdriver ) /* TT_Driver */ + { +#ifdef TT_USE_BYTECODE_INTERPRETER + TT_Driver driver = (TT_Driver)ttdriver; + + + /* destroy the execution context */ + if ( driver->context ) + { + TT_Done_Context( driver->context ); + driver->context = NULL; + } +#else + FT_UNUSED( ttdriver ); +#endif + + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_slot_init */ + /* */ + /* <Description> */ + /* Initialize a new slot object. */ + /* */ + /* <InOut> */ + /* slot :: A handle to the slot object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ) + { + return FT_GlyphLoader_CreateExtra( slot->internal->loader ); + } + + +/* END */ diff --git a/src/freetype2/truetype/ttobjs.h b/src/freetype2/truetype/ttobjs.h new file mode 100644 index 0000000..6971013 --- /dev/null +++ b/src/freetype2/truetype/ttobjs.h @@ -0,0 +1,459 @@ +/***************************************************************************/ +/* */ +/* ttobjs.h */ +/* */ +/* Objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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 __TTOBJS_H__ +#define __TTOBJS_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_Driver */ + /* */ + /* <Description> */ + /* A handle to a TrueType driver object. */ + /* */ + typedef struct TT_DriverRec_* TT_Driver; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_Instance */ + /* */ + /* <Description> */ + /* A handle to a TrueType size object. */ + /* */ + typedef struct TT_SizeRec_* TT_Size; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_GlyphSlot */ + /* */ + /* <Description> */ + /* A handle to a TrueType glyph slot object. */ + /* */ + /* <Note> */ + /* This is a direct typedef of FT_GlyphSlot, as there is nothing */ + /* specific about the TrueType glyph slot. */ + /* */ + typedef FT_GlyphSlot TT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GraphicsState */ + /* */ + /* <Description> */ + /* The TrueType graphics state used during bytecode interpretation. */ + /* */ + typedef struct TT_GraphicsState_ + { + FT_UShort rp0; + FT_UShort rp1; + FT_UShort rp2; + + FT_UnitVector dualVector; + FT_UnitVector projVector; + FT_UnitVector freeVector; + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + FT_Bool both_x_axis; +#endif + + FT_Long loop; + FT_F26Dot6 minimum_distance; + FT_Int round_state; + + FT_Bool auto_flip; + FT_F26Dot6 control_value_cutin; + FT_F26Dot6 single_width_cutin; + FT_F26Dot6 single_width_value; + FT_Short delta_base; + FT_Short delta_shift; + + FT_Byte instruct_control; + FT_Bool scan_control; + FT_Int scan_type; + + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + + } TT_GraphicsState; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( void ) + tt_glyphzone_done( TT_GlyphZone zone ); + + FT_LOCAL( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + + /*************************************************************************/ + /* */ + /* EXECUTION SUBTABLES */ + /* */ + /* These sub-tables relate to instruction execution. */ + /* */ + /*************************************************************************/ + + +#define TT_MAX_CODE_RANGES 3 + + + /*************************************************************************/ + /* */ + /* There can only be 3 active code ranges at once: */ + /* - the Font Program */ + /* - the CVT Program */ + /* - a glyph's instructions set */ + /* */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + + } TT_CodeRange_Tag; + + + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_ULong size; + + } TT_CodeRange; + + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; + + + /*************************************************************************/ + /* */ + /* Defines a function/instruction definition record. */ + /* */ + typedef struct TT_DefRecord_ + { + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + + /*************************************************************************/ + /* */ + /* Subglyph transformation record. */ + /* */ + typedef struct TT_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } TT_Transform; + + + /*************************************************************************/ + /* */ + /* Subglyph loading record. Used to load composite components. */ + /* */ + typedef struct TT_SubglyphRec_ + { + FT_Long index; /* subglyph index; initialized with -1 */ + FT_Bool is_scaled; /* is the subglyph scaled? */ + FT_Bool is_hinted; /* should it be hinted? */ + FT_Bool preserve_pps; /* preserve phantom points? */ + + FT_Long file_offset; + + FT_BBox bbox; + FT_Pos left_bearing; + FT_Pos advance; + + TT_GlyphZoneRec zone; + + FT_Long arg1; /* first argument */ + FT_Long arg2; /* second argument */ + + FT_UShort element_flag; /* current load element flag */ + + TT_Transform transform; /* transformation matrix */ + + FT_Vector pp1, pp2; /* phantom points (horizontal) */ + FT_Vector pp3, pp4; /* phantom points (vertical) */ + + } TT_SubGlyphRec, *TT_SubGlyph_Stack; + + + /*************************************************************************/ + /* */ + /* A note regarding non-squared pixels: */ + /* */ + /* (This text will probably go into some docs at some time; for now, it */ + /* is kept here to explain some definitions in the TIns_Metrics */ + /* record). */ + /* */ + /* The CVT is a one-dimensional array containing values that control */ + /* certain important characteristics in a font, like the height of all */ + /* capitals, all lowercase letter, default spacing or stem width/height. */ + /* */ + /* These values are found in FUnits in the font file, and must be scaled */ + /* to pixel coordinates before being used by the CVT and glyph programs. */ + /* Unfortunately, when using distinct x and y resolutions (or distinct x */ + /* and y pointsizes), there are two possible scalings. */ + /* */ + /* A first try was to implement a `lazy' scheme where all values were */ + /* scaled when first used. However, while some values are always used */ + /* in the same direction, some others are used under many different */ + /* circumstances and orientations. */ + /* */ + /* I have found a simpler way to do the same, and it even seems to work */ + /* in most of the cases: */ + /* */ + /* - All CVT values are scaled to the maximum ppem size. */ + /* */ + /* - When performing a read or write in the CVT, a ratio factor is used */ + /* to perform adequate scaling. Example: */ + /* */ + /* x_ppem = 14 */ + /* y_ppem = 10 */ + /* */ + /* We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */ + /* entries are scaled to it. */ + /* */ + /* x_ratio = 1.0 */ + /* y_ratio = y_ppem/ppem (< 1.0) */ + /* */ + /* We compute the current ratio like: */ + /* */ + /* - If projVector is horizontal, */ + /* ratio = x_ratio = 1.0 */ + /* */ + /* - if projVector is vertical, */ + /* ratio = y_ratio */ + /* */ + /* - else, */ + /* ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */ + /* */ + /* Reading a cvt value returns */ + /* ratio * cvt[index] */ + /* */ + /* Writing a cvt value in pixels: */ + /* cvt[index] / ratio */ + /* */ + /* The current ppem is simply */ + /* ratio * ppem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Metrics used by the TrueType size and context objects. */ + /* */ + typedef struct TT_Size_Metrics_ + { + /* for non-square pixels */ + FT_Long x_ratio; + FT_Long y_ratio; + + FT_UShort ppem; /* maximum ppem size */ + FT_Long ratio; /* current ratio */ + FT_Fixed scale; + + FT_F26Dot6 compensations[4]; /* device-specific compensations */ + + FT_Bool valid; + + FT_Bool rotated; /* `is the glyph rotated?'-flag */ + FT_Bool stretched; /* `is the glyph stretched?'-flag */ + + } TT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* TrueType size class. */ + /* */ + typedef struct TT_SizeRec_ + { + FT_SizeRec root; + + /* we have our own copy of metrics so that we can modify */ + /* it without affecting auto-hinting (when used) */ + FT_Size_Metrics metrics; + + TT_Size_Metrics ttmetrics; + + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_UInt num_function_defs; /* number of function definitions */ + FT_UInt max_function_defs; + TT_DefArray function_defs; /* table of function definitions */ + + FT_UInt num_instruction_defs; /* number of ins. definitions */ + FT_UInt max_instruction_defs; + TT_DefArray instruction_defs; /* table of ins. definitions */ + + FT_UInt max_func; + FT_UInt max_ins; + + TT_CodeRangeTable codeRangeTable; + + TT_GraphicsState GS; + + FT_ULong cvt_size; /* the scaled control value table */ + FT_Long* cvt; + + FT_UShort storage_size; /* The storage area is now part of */ + FT_Long* storage; /* the instance */ + + TT_GlyphZoneRec twilight; /* The instance's twilight zone */ + + /* debugging variables */ + + /* When using the debugger, we must keep the */ + /* execution context tied to the instance */ + /* object rather than asking it on demand. */ + + FT_Bool debug; + TT_ExecContext context; + + FT_Bool bytecode_ready; + FT_Bool cvt_ready; + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + } TT_SizeRec; + + + /*************************************************************************/ + /* */ + /* TrueType driver class. */ + /* */ + typedef struct TT_DriverRec_ + { + FT_DriverRec root; + TT_ExecContext context; /* execution context */ + TT_GlyphZoneRec zone; /* glyph loader points zone */ + + void* extension_component; + + } TT_DriverRec; + + + /* Note: All of the functions below (except tt_size_reset()) are used */ + /* as function pointers in a FT_Driver_ClassRec. Therefore their */ + /* parameters are of types FT_Face, FT_Size, etc., rather than TT_Face, */ + /* TT_Size, etc., so that the compiler can confirm that the types and */ + /* number of parameters are correct. In all cases the FT_xxx types are */ + /* cast to their TT_xxx counterparts inside the functions since FreeType */ + /* will always use the TT driver to create them. */ + + + /*************************************************************************/ + /* */ + /* Face functions */ + /* */ + FT_LOCAL( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + tt_face_done( FT_Face ttface ); /* TT_Face */ + + + /*************************************************************************/ + /* */ + /* Size functions */ + /* */ + FT_LOCAL( FT_Error ) + tt_size_init( FT_Size ttsize ); /* TT_Size */ + + FT_LOCAL( void ) + tt_size_done( FT_Size ttsize ); /* TT_Size */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( FT_Error ) + tt_size_run_fpgm( TT_Size size ); + + FT_LOCAL( FT_Error ) + tt_size_run_prep( TT_Size size ); + + FT_LOCAL( FT_Error ) + tt_size_ready_bytecode( TT_Size size ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + FT_LOCAL( FT_Error ) + tt_size_reset( TT_Size size ); + + + /*************************************************************************/ + /* */ + /* Driver functions */ + /* */ + FT_LOCAL( FT_Error ) + tt_driver_init( FT_Module ttdriver ); /* TT_Driver */ + + FT_LOCAL( void ) + tt_driver_done( FT_Module ttdriver ); /* TT_Driver */ + + + /*************************************************************************/ + /* */ + /* Slot functions */ + /* */ + FT_LOCAL( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ); + + +FT_END_HEADER + +#endif /* __TTOBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/truetype/ttpload.c b/src/freetype2/truetype/ttpload.c new file mode 100644 index 0000000..9d3381b --- /dev/null +++ b/src/freetype2/truetype/ttpload.c @@ -0,0 +1,523 @@ +/***************************************************************************/ +/* */ +/* ttpload.c */ +/* */ +/* TrueType-specific tables loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H + +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.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_ttpload + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_loca */ + /* */ + /* <Description> */ + /* Load the locations table. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + + + /* we need the size of the `glyf' table for malformed `loca' tables */ + error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); + if ( error ) + goto Exit; + + FT_TRACE2(( "Locations " )); + error = face->goto_table( face, TTAG_loca, stream, &table_len ); + if ( error ) + { + error = TT_Err_Locations_Missing; + goto Exit; + } + + if ( face->header.Index_To_Loc_Format != 0 ) + { + if ( table_len >= 0x40000L ) + { + FT_TRACE2(( "table too large!\n" )); + error = TT_Err_Invalid_Table; + goto Exit; + } + face->num_locations = (FT_UInt)( table_len >> 2 ); + } + else + { + if ( table_len >= 0x20000L ) + { + FT_TRACE2(( "table too large!\n" )); + error = TT_Err_Invalid_Table; + goto Exit; + } + face->num_locations = (FT_UInt)( table_len >> 1 ); + } + + /* + * Extract the frame. We don't need to decompress it since + * we are able to parse it directly. + */ + if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) + goto Exit; + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_ULong ) + tt_face_get_location( TT_Face face, + FT_UInt gindex, + FT_UInt *asize ) + { + FT_ULong pos1, pos2; + FT_Byte* p; + FT_Byte* p_limit; + + + pos1 = pos2 = 0; + + if ( gindex < face->num_locations ) + { + if ( face->header.Index_To_Loc_Format != 0 ) + { + p = face->glyph_locations + gindex * 4; + p_limit = face->glyph_locations + face->num_locations * 4; + + pos1 = FT_NEXT_ULONG( p ); + pos2 = pos1; + + if ( p + 4 <= p_limit ) + pos2 = FT_NEXT_ULONG( p ); + } + else + { + p = face->glyph_locations + gindex * 2; + p_limit = face->glyph_locations + face->num_locations * 2; + + pos1 = FT_NEXT_USHORT( p ); + pos2 = pos1; + + if ( p + 2 <= p_limit ) + pos2 = FT_NEXT_USHORT( p ); + + pos1 <<= 1; + pos2 <<= 1; + } + } + + /* It isn't mentioned explicitly that the `loca' table must be */ + /* ordered, but implicitly it refers to the length of an entry */ + /* as the difference between the current and the next position. */ + /* Anyway, there do exist (malformed) fonts which don't obey */ + /* this rule, so we are only able to provide an upper bound for */ + /* the size. */ + if ( pos2 >= pos1 ) + *asize = (FT_UInt)( pos2 - pos1 ); + else + *asize = (FT_UInt)( face->glyf_len - pos1 ); + + return pos1; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_loca( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->glyph_locations ); + face->num_locations = 0; + } + + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_cvt */ + /* */ + /* <Description> */ + /* Load the control value table into a face object. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_len; + + + FT_TRACE2(( "CVT " )); + + error = face->goto_table( face, TTAG_cvt, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing!\n" )); + + face->cvt_size = 0; + face->cvt = NULL; + error = TT_Err_Ok; + + goto Exit; + } + + face->cvt_size = table_len / 2; + + if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) + goto Exit; + + if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) + goto Exit; + + { + FT_Short* cur = face->cvt; + FT_Short* limit = cur + face->cvt_size; + + + for ( ; cur < limit; cur++ ) + *cur = FT_GET_SHORT(); + } + + FT_FRAME_EXIT(); + FT_TRACE2(( "loaded\n" )); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( face->doblend ) + error = tt_face_vary_cvt( face, stream ); +#endif + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return TT_Err_Ok; + +#endif + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_fpgm */ + /* */ + /* <Description> */ + /* Load the font program. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Font program " )); + + /* The font program is optional */ + error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); + if ( error ) + { + face->font_program = NULL; + face->font_program_size = 0; + error = TT_Err_Ok; + + FT_TRACE2(( "is missing!\n" )); + } + else + { + face->font_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return TT_Err_Ok; + +#endif + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_prep */ + /* */ + /* <Description> */ + /* Load the cvt program. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Prep program " )); + + error = face->goto_table( face, TTAG_prep, stream, &table_len ); + if ( error ) + { + face->cvt_program = NULL; + face->cvt_program_size = 0; + error = TT_Err_Ok; + + FT_TRACE2(( "is missing!\n" )); + } + else + { + face->cvt_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return TT_Err_Ok; + +#endif + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_face_load_hdmx */ + /* */ + /* <Description> */ + /* Load the `hdmx' table into the face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: A handle to the input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt version, nn, num_records; + FT_ULong table_size, record_size; + FT_Byte* p; + FT_Byte* limit; + + + /* this table is optional */ + error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); + if ( error || table_size < 8 ) + return TT_Err_Ok; + + if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) + goto Exit; + + p = face->hdmx_table; + limit = p + table_size; + + version = FT_NEXT_USHORT( p ); + num_records = FT_NEXT_USHORT( p ); + record_size = FT_NEXT_ULONG( p ); + + /* The maximum number of bytes in an hdmx device record is the */ + /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */ + /* the reason why `record_size' is a long (which we read as */ + /* unsigned long for convenience). In practice, two bytes */ + /* sufficient to hold the size value. */ + /* */ + /* There are at least two fonts, HANNOM-A and HANNOM-B version */ + /* 2.0 (2005), which get this wrong: The upper two bytes of */ + /* the size value are set to 0xFF instead of 0x00. We catch */ + /* and fix this. */ + + if ( record_size >= 0xFFFF0000UL ) + record_size &= 0xFFFFU; + + /* The limit for `num_records' is a heuristic value. */ + + if ( version != 0 || num_records > 255 || record_size > 0x10001L ) + { + error = TT_Err_Invalid_File_Format; + goto Fail; + } + + if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) + goto Fail; + + for ( nn = 0; nn < num_records; nn++ ) + { + if ( p + record_size > limit ) + break; + + face->hdmx_record_sizes[nn] = p[0]; + p += record_size; + } + + face->hdmx_record_count = nn; + face->hdmx_table_size = table_size; + face->hdmx_record_size = record_size; + + Exit: + return error; + + Fail: + FT_FRAME_RELEASE( face->hdmx_table ); + face->hdmx_table_size = 0; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_hdmx( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + + + FT_FREE( face->hdmx_record_sizes ); + FT_FRAME_RELEASE( face->hdmx_table ); + } + + + /*************************************************************************/ + /* */ + /* Return the advance width table for a given pixel size if it is found */ + /* in the font's `hdmx' table (if any). */ + /* */ + FT_LOCAL_DEF( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ) + { + FT_UInt nn; + FT_Byte* result = NULL; + FT_ULong record_size = face->hdmx_record_size; + FT_Byte* record = face->hdmx_table + 8; + + + for ( nn = 0; nn < face->hdmx_record_count; nn++ ) + if ( face->hdmx_record_sizes[nn] == ppem ) + { + gindex += 2; + if ( gindex < record_size ) + result = record + nn * record_size + gindex; + break; + } + + return result; + } + + +/* END */ diff --git a/src/freetype2/truetype/ttpload.h b/src/freetype2/truetype/ttpload.h new file mode 100644 index 0000000..f61ac07 --- /dev/null +++ b/src/freetype2/truetype/ttpload.h @@ -0,0 +1,75 @@ +/***************************************************************************/ +/* */ +/* ttpload.h */ +/* */ +/* TrueType-specific tables loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTPLOAD_H__ +#define __TTPLOAD_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_ULong ) + tt_face_get_location( TT_Face face, + FT_UInt gindex, + FT_UInt *asize ); + + FT_LOCAL( void ) + tt_face_done_loca( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( void ) + tt_face_free_hdmx( TT_Face face ); + + + FT_LOCAL( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ); + +FT_END_HEADER + +#endif /* __TTPLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1afm.c b/src/freetype2/type1/t1afm.c new file mode 100644 index 0000000..b81a8df --- /dev/null +++ b/src/freetype2/type1/t1afm.c @@ -0,0 +1,385 @@ +/***************************************************************************/ +/* */ +/* t1afm.c */ +/* */ +/* AFM support for Type 1 fonts (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include "t1afm.h" +#include "t1errors.h" +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_POSTSCRIPT_AUX_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_t1afm + + + FT_LOCAL_DEF( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi ); + } + + + /* read a glyph name and return the equivalent glyph index */ + static FT_Int + t1_get_index( const char* name, + FT_UInt len, + void* user_data ) + { + T1_Font type1 = (T1_Font)user_data; + FT_Int n; + + + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == name[0] && + ft_strlen( gname ) == len && + ft_strncmp( gname, name, len ) == 0 ) + return n; + } + + return 0; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + /* compare two kerning pairs */ + FT_CALLBACK_DEF( int ) + compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair pair1 = (AFM_KernPair)a; + AFM_KernPair pair2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); + FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); + + + return (int)( index1 - index2 ); + } + + + /* parse a PFM file -- for now, only read the kerning pairs */ + static FT_Error + T1_Read_PFM( FT_Face t1_face, + FT_Stream stream, + AFM_FontInfo fi ) + { + FT_Error error = T1_Err_Ok; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + AFM_KernPair kp; + FT_Int width_table_length; + FT_CharMap oldcharmap; + FT_CharMap charmap; + FT_Int n; + + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* Figure out how long the width table is. */ + /* This info is a little-endian short at offset 99. */ + p = start + 99; + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + width_table_length = FT_PEEK_USHORT_LE( p ); + + p += 18 + width_table_length; + if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) + /* extension table is probably optional */ + goto Exit; + + /* Kerning offset is 14 bytes from start of extensions table. */ + p += 14; + p = start + FT_PEEK_ULONG_LE( p ); + + if ( p == start ) + /* zero offset means no table */ + goto Exit; + + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + + fi->NumKernPair = FT_PEEK_USHORT_LE( p ); + p += 2; + if ( p + 4 * fi->NumKernPair > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + + /* Actually, kerning pairs are simply optional! */ + if ( fi->NumKernPair == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + goto Exit; + + /* now, read each kern pair */ + kp = fi->KernPairs; + limit = p + 4 * fi->NumKernPair; + + /* PFM kerning data are stored by encoding rather than glyph index, */ + /* so find the PostScript charmap of this font and install it */ + /* temporarily. If we find no PostScript charmap, then just use */ + /* the default and hope it is the right one. */ + oldcharmap = t1_face->charmap; + charmap = NULL; + + for ( n = 0; n < t1_face->num_charmaps; n++ ) + { + charmap = t1_face->charmaps[n]; + /* check against PostScript pseudo platform */ + if ( charmap->platform_id == 7 ) + { + error = FT_Set_Charmap( t1_face, charmap ); + if ( error ) + goto Exit; + break; + } + } + + /* Kerning info is stored as: */ + /* */ + /* encoding of first glyph (1 byte) */ + /* encoding of second glyph (1 byte) */ + /* offset (little-endian short) */ + for ( ; p < limit ; p += 4 ) + { + kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); + kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); + + kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); + kp->y = 0; + + kp++; + } + + if ( oldcharmap != NULL ) + error = FT_Set_Charmap( t1_face, oldcharmap ); + if ( error ) + goto Exit; + + /* now, sort the kern pairs according to their glyph indices */ + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), + compare_kern_pairs ); + + Exit: + if ( error ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + } + + return error; + } + + + /* parse a metrics file -- either AFM or PFM depending on what */ + /* it turns out to be */ + FT_LOCAL_DEF( FT_Error ) + T1_Read_Metrics( FT_Face t1_face, + FT_Stream stream ) + { + PSAux_Service psaux; + FT_Memory memory = stream->memory; + AFM_ParserRec parser; + AFM_FontInfo fi; + FT_Error error = T1_Err_Unknown_File_Format; + T1_Font t1_font = &( (T1_Face)t1_face )->type1; + + + if ( FT_NEW( fi ) || + FT_FRAME_ENTER( stream->size ) ) + goto Exit; + + fi->FontBBox = t1_font->font_bbox; + fi->Ascender = t1_font->font_bbox.yMax; + fi->Descender = t1_font->font_bbox.yMin; + + psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux; + if ( psaux && psaux->afm_parser_funcs ) + { + error = psaux->afm_parser_funcs->init( &parser, + stream->memory, + stream->cursor, + stream->limit ); + + if ( !error ) + { + parser.FontInfo = fi; + parser.get_index = t1_get_index; + parser.user_data = t1_font; + + error = psaux->afm_parser_funcs->parse( &parser ); + psaux->afm_parser_funcs->done( &parser ); + } + } + + if ( error == T1_Err_Unknown_File_Format ) + { + FT_Byte* start = stream->cursor; + + + /* MS Windows allows versions up to 0x3FF without complaining */ + if ( stream->size > 6 && + start[1] < 4 && + FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) + error = T1_Read_PFM( t1_face, stream, fi ); + } + + if ( !error ) + { + t1_font->font_bbox = fi->FontBBox; + + t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; + t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; + t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFFU ) >> 16; + t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFFU ) >> 16; + + t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000U ) >> 16 ); + t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000U ) >> 16 ); + + if ( fi->NumKernPair ) + { + t1_face->face_flags |= FT_FACE_FLAG_KERNING; + ( (T1_Face)t1_face )->afm_data = fi; + fi = NULL; + } + } + + FT_FRAME_EXIT(); + + Exit: + if ( fi != NULL ) + T1_Done_Metrics( memory, fi ); + + return error; + } + + + /* find the kerning for a given glyph pair */ + FT_LOCAL_DEF( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + AFM_KernPair min, mid, max; + FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = fi->KernPairs; + max = min + fi->NumKernPair - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->index1, mid->index2 ); + + if ( midi == idx ) + { + kerning->x = mid->x; + kerning->y = mid->y; + + return; + } + + if ( midi < idx ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ) + { + AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; + FT_Int i; + + + if ( !fi ) + return T1_Err_Invalid_Argument; + + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + + + if ( tk->degree != degree ) + continue; + + if ( ptsize < tk->min_ptsize ) + *kerning = tk->min_kern; + else if ( ptsize > tk->max_ptsize ) + *kerning = tk->max_kern; + else + { + *kerning = FT_MulDiv( ptsize - tk->min_ptsize, + tk->max_kern - tk->min_kern, + tk->max_ptsize - tk->min_ptsize ) + + tk->min_kern; + } + } + + return T1_Err_Ok; + } + + +/* END */ diff --git a/src/freetype2/type1/t1afm.h b/src/freetype2/type1/t1afm.h new file mode 100644 index 0000000..8eb1764 --- /dev/null +++ b/src/freetype2/type1/t1afm.h @@ -0,0 +1,54 @@ +/***************************************************************************/ +/* */ +/* t1afm.h */ +/* */ +/* AFM support for Type 1 fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1AFM_H__ +#define __T1AFM_H__ + +#include <ft2build.h> +#include "t1objs.h" +#include FT_INTERNAL_TYPE1_TYPES_H + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Read_Metrics( FT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ); + + FT_LOCAL( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + FT_LOCAL( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ); + +FT_END_HEADER + +#endif /* __T1AFM_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1driver.c b/src/freetype2/type1/t1driver.c new file mode 100644 index 0000000..3ca21dc --- /dev/null +++ b/src/freetype2/type1/t1driver.c @@ -0,0 +1,313 @@ +/***************************************************************************/ +/* */ +/* t1driver.c */ +/* */ +/* Type 1 driver interface (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 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 <ft2build.h> +#include "t1driver.h" +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H + +#include FT_SERVICE_MULTIPLE_MASTERS_H +#include FT_SERVICE_GLYPH_DICT_H +#include FT_SERVICE_XFREE86_NAME_H +#include FT_SERVICE_POSTSCRIPT_NAME_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_SERVICE_POSTSCRIPT_INFO_H +#include FT_SERVICE_KERNING_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_t1driver + + /* + * GLYPH DICT SERVICE + * + */ + + static FT_Error + t1_get_glyph_name( T1_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + + return T1_Err_Ok; + } + + + static FT_UInt + t1_get_name_index( T1_Face face, + FT_String* glyph_name ) + { + FT_Int i; + FT_String* gname; + + + for ( i = 0; i < face->type1.num_glyphs; i++ ) + { + gname = face->type1.glyph_names[i]; + + if ( !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)i; + } + + return 0; + } + + static const FT_Service_GlyphDictRec t1_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t1_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)t1_get_name_index + }; + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + t1_get_ps_name( T1_Face face ) + { + return (const char*) face->type1.font_name; + } + + static const FT_Service_PsFontNameRec t1_service_ps_name = + { + (FT_PsName_GetFunc)t1_get_ps_name + }; + + + /* + * MULTIPLE MASTERS SERVICE + * + */ + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + static const FT_Service_MultiMastersRec t1_service_multi_masters = + { + (FT_Get_MM_Func) T1_Get_Multi_Master, + (FT_Set_MM_Design_Func) T1_Set_MM_Design, + (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, + (FT_Get_MM_Var_Func) T1_Get_MM_Var, + (FT_Set_Var_Design_Func)T1_Set_Var_Design + }; +#endif + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Error + t1_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T1_Face)face)->type1.font_info; + return 0; + } + + + static FT_Int + t1_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + return 1; + } + + + static FT_Error + t1_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T1_Face)face)->type1.private_dict; + return 0; + } + + + static const FT_Service_PsInfoRec t1_service_ps_info = + { + (PS_GetFontInfoFunc) t1_ps_get_font_info, + (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names, + (PS_GetFontPrivateFunc)t1_ps_get_font_private, + }; + +#ifndef T1_CONFIG_OPTION_NO_AFM + static const FT_Service_KerningRec t1_service_kerning = + { + T1_Get_Track_Kerning, + }; +#endif + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t1_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t1_service_ps_name }, + { FT_SERVICE_ID_GLYPH_DICT, &t1_service_glyph_dict }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TYPE_1 }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t1_service_ps_info }, + +#ifndef T1_CONFIG_OPTION_NO_AFM + { FT_SERVICE_ID_KERNING, &t1_service_kerning }, +#endif + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + { FT_SERVICE_ID_MULTI_MASTERS, &t1_service_multi_masters }, +#endif + { NULL, NULL } + }; + + + static FT_Module_Interface + Get_Interface( FT_Driver driver, + const FT_String* t1_interface ) + { + FT_UNUSED( driver ); + + return ft_service_list_lookup( t1_services, t1_interface ); + } + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + /*************************************************************************/ + /* */ + /* <Function> */ + /* Get_Kerning */ + /* */ + /* <Description> */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* <Output> */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static FT_Error + Get_Kerning( T1_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + kerning->x = 0; + kerning->y = 0; + + if ( face->afm_data ) + T1_Get_Kerning( (AFM_FontInfo)face->afm_data, + left_glyph, + right_glyph, + kerning ); + + return T1_Err_Ok; + } + + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + + sizeof( FT_DriverRec ), + + "type1", + 0x10000L, + 0x20000L, + + 0, /* format interface */ + + (FT_Module_Constructor)T1_Driver_Init, + (FT_Module_Destructor) T1_Driver_Done, + (FT_Module_Requester) Get_Interface, + }, + + sizeof( T1_FaceRec ), + sizeof( T1_SizeRec ), + sizeof( T1_GlyphSlotRec ), + + (FT_Face_InitFunc) T1_Face_Init, + (FT_Face_DoneFunc) T1_Face_Done, + (FT_Size_InitFunc) T1_Size_Init, + (FT_Size_DoneFunc) T1_Size_Done, + (FT_Slot_InitFunc) T1_GlyphSlot_Init, + (FT_Slot_DoneFunc) T1_GlyphSlot_Done, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + (FT_Slot_LoadFunc) T1_Load_Glyph, + +#ifdef T1_CONFIG_OPTION_NO_AFM + (FT_Face_GetKerningFunc) 0, + (FT_Face_AttachFunc) 0, +#else + (FT_Face_GetKerningFunc) Get_Kerning, + (FT_Face_AttachFunc) T1_Read_Metrics, +#endif + (FT_Face_GetAdvancesFunc) 0, + (FT_Size_RequestFunc) T1_Size_Request, + (FT_Size_SelectFunc) 0 + }; + + +/* END */ diff --git a/src/freetype2/type1/t1driver.h b/src/freetype2/type1/t1driver.h new file mode 100644 index 0000000..ad42944 --- /dev/null +++ b/src/freetype2/type1/t1driver.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* t1driver.h */ +/* */ +/* High-level Type 1 driver interface (specification). */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1DRIVER_H__ +#define __T1DRIVER_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t1_driver_class; + + +FT_END_HEADER + +#endif /* __T1DRIVER_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1errors.h b/src/freetype2/type1/t1errors.h new file mode 100644 index 0000000..81221c3 --- /dev/null +++ b/src/freetype2/type1/t1errors.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* t1errors.h */ +/* */ +/* Type 1 error codes (specification only). */ +/* */ +/* Copyright 2001 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 Type 1 error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __T1ERRORS_H__ +#define __T1ERRORS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX T1_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type1 + +#include FT_ERRORS_H + +#endif /* __T1ERRORS_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1gload.c b/src/freetype2/type1/t1gload.c new file mode 100644 index 0000000..e08a428 --- /dev/null +++ b/src/freetype2/type1/t1gload.c @@ -0,0 +1,422 @@ +/***************************************************************************/ +/* */ +/* t1gload.c */ +/* */ +/* Type 1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 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 "t1gload.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_OUTLINE_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H + +#include "t1errors.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_t1gload + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + T1_Parse_Glyph_And_Get_Char_String( T1_Decoder decoder, + FT_UInt glyph_index, + FT_Data* char_string ) + { + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + FT_Error error = T1_Err_Ok; + + + decoder->font_matrix = type1->font_matrix; + decoder->font_offset = type1->font_offset; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, char_string ); + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* For ordinary fonts get the character data stored in the face record. */ + { + char_string->pointer = type1->charstrings[glyph_index]; + char_string->length = (FT_Int)type1->charstrings_len[glyph_index]; + } + + if ( !error ) + error = decoder->funcs.parse_charstrings( + decoder, (FT_Byte*)char_string->pointer, + char_string->length ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = decoder->builder.left_bearing.x; + metrics.bearing_y = decoder->builder.left_bearing.y; + metrics.advance = decoder->builder.advance.x; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + decoder->builder.left_bearing.x = metrics.bearing_x; + decoder->builder.left_bearing.y = metrics.bearing_y; + decoder->builder.advance.x = metrics.advance; + decoder->builder.advance.y = 0; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + T1_Parse_Glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + FT_Data glyph_data; + FT_Error error = T1_Parse_Glyph_And_Get_Char_String( + decoder, glyph_index, &glyph_data ); + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( !error ) + { + T1_Face face = (T1_Face)decoder->builder.face; + + + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + *max_advance = 0; + + /* initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + *max_advance = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + error = T1_Parse_Glyph( &decoder, glyph_index ); + if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance ) + *max_advance = decoder.builder.advance.x; + + /* ignore the error if one occurred - skip to next glyph */ + } + + psaux->t1_decoder_funcs->done( &decoder ); + + return T1_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + T1_DecoderRec decoder; + T1_Face face = (T1_Face)glyph->root.face; + FT_Bool hinting; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Data glyph_data; + FT_Bool must_finish_decoder = FALSE; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Bool glyph_data_loaded = 0; +#endif + + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = T1_Err_Invalid_Argument; + goto Exit; + } + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + error = decoder_funcs->init( &decoder, + (FT_Face)face, + (FT_Size)size, + (FT_GlyphSlot)glyph, + (FT_Byte**)type1->glyph_names, + face->blend, + FT_BOOL( hinting ), + FT_LOAD_TARGET_MODE( load_flags ), + T1_Parse_Glyph ); + if ( error ) + goto Exit; + + must_finish_decoder = TRUE; + + decoder.builder.no_recurse = FT_BOOL( + ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + /* now load the unscaled outline */ + error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, + &glyph_data ); + if ( error ) + goto Exit; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + glyph_data_loaded = 1; +#endif + + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + decoder_funcs->done( &decoder ); + + must_finish_decoder = FALSE; + + /* now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + if ( !error ) + { + glyph->root.outline.flags &= FT_OUTLINE_OWNER; + glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = glyph->root.internal; + + + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.builder.advance.x; + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + FT_Vector advance; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + glyph->root.linearHoriAdvance = decoder.builder.advance.x; + glyph->root.internal->glyph_transformed = 0; + + /* make up vertical ones */ + metrics->vertAdvance = ( face->type1.font_bbox.yMax - + face->type1.font_bbox.yMin ) >> 16; + glyph->root.linearVertAdvance = metrics->vertAdvance; + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + +#if 1 + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != font_matrix.xx || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + FT_Outline_Transform( &glyph->root.outline, &font_matrix ); + + if ( font_offset.x || font_offset.y ) + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, + font_offset.y ); + + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + font_offset.y; +#endif + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points, if we are not hinting */ + if ( !hinting || ! decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + + /* Set control data to the glyph charstrings. Note that this is */ + /* _not_ zero-terminated. */ + glyph->root.control_data = (FT_Byte*)glyph_data.pointer; + glyph->root.control_len = glyph_data.length; + } + + + Exit: + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_data_loaded && face->root.internal->incremental_interface ) + { + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + + /* Set the control data to null - it is no longer available if */ + /* loaded incrementally. */ + glyph->root.control_data = 0; + glyph->root.control_len = 0; + } +#endif + + if ( must_finish_decoder ) + decoder_funcs->done( &decoder ); + + return error; + } + + +/* END */ diff --git a/src/freetype2/type1/t1gload.h b/src/freetype2/type1/t1gload.h new file mode 100644 index 0000000..de87896 --- /dev/null +++ b/src/freetype2/type1/t1gload.h @@ -0,0 +1,46 @@ +/***************************************************************************/ +/* */ +/* t1gload.h */ +/* */ +/* Type 1 Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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 __T1GLOAD_H__ +#define __T1GLOAD_H__ + + +#include <ft2build.h> +#include "t1objs.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ); + + FT_LOCAL( FT_Error ) + T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* __T1GLOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1load.c b/src/freetype2/type1/t1load.c new file mode 100644 index 0000000..55177ee --- /dev/null +++ b/src/freetype2/type1/t1load.c @@ -0,0 +1,2221 @@ +/***************************************************************************/ +/* */ +/* t1load.c */ +/* */ +/* Type 1 font loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This is the new and improved Type 1 data loader for FreeType 2. The */ + /* old loader has several problems: it is slow, complex, difficult to */ + /* maintain, and contains incredible hacks to make it accept some */ + /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ + /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ + /* */ + /* This version is much simpler, much faster and also easier to read and */ + /* maintain by a great order of magnitude. The idea behind it is to */ + /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ + /* a Postscript-like interpreter) but rather to perform simple pattern */ + /* matching. */ + /* */ + /* Indeed, nearly all data definitions follow a simple pattern like */ + /* */ + /* ... /Field <data> ... */ + /* */ + /* where <data> can be a number, a boolean, a string, or an array of */ + /* numbers. There are a few exceptions, namely the encoding, font name, */ + /* charstrings, and subrs; they are handled with a special pattern */ + /* matching routine. */ + /* */ + /* All other common cases are handled very simply. The matching rules */ + /* are defined in the file `t1tokens.h' through the use of several */ + /* macros calls PARSE_XXX. This file is included twice here; the first */ + /* time to generate parsing callback functions, the second time to */ + /* generate a table of keywords (with pointers to the associated */ + /* callback functions). */ + /* */ + /* The function `parse_dict' simply scans *linearly* a given dictionary */ + /* (either the top-level or private one) and calls the appropriate */ + /* callback when it encounters an immediate keyword. */ + /* */ + /* This is by far the fastest way one can find to parse and read all */ + /* data. */ + /* */ + /* This led to tremendous code size reduction. Note that later, the */ + /* glyph loader will also be _greatly_ simplified, and the automatic */ + /* hinter will replace the clumsy `t1hinter'. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_CONFIG_CONFIG_H +#include FT_MULTIPLE_MASTERS_H +#include FT_INTERNAL_TYPE1_TYPES_H + +#include "t1load.h" +#include "t1errors.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_t1load + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SUPPORT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_allocate_blend( T1_Face face, + FT_UInt num_designs, + FT_UInt num_axis ) + { + PS_Blend blend; + FT_Memory memory = face->root.memory; + FT_Error error = T1_Err_Ok; + + + blend = face->blend; + if ( !blend ) + { + if ( FT_NEW( blend ) ) + goto Exit; + + blend->num_default_design_vector = 0; + + face->blend = blend; + } + + /* allocate design data if needed */ + if ( num_designs > 0 ) + { + if ( blend->num_designs == 0 ) + { + FT_UInt nn; + + + /* allocate the blend `private' and `font_info' dictionaries */ + if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || + FT_NEW_ARRAY( blend->privates[1], num_designs ) || + FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || + FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + blend->bboxes [0] = &face->type1.font_bbox; + + for ( nn = 2; nn <= num_designs; nn++ ) + { + blend->privates[nn] = blend->privates [nn - 1] + 1; + blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; + blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; + } + + blend->num_designs = num_designs; + } + else if ( blend->num_designs != num_designs ) + goto Fail; + } + + /* allocate axis data if needed */ + if ( num_axis > 0 ) + { + if ( blend->num_axis != 0 && blend->num_axis != num_axis ) + goto Fail; + + blend->num_axis = num_axis; + } + + /* allocate the blend design pos table if needed */ + num_designs = blend->num_designs; + num_axis = blend->num_axis; + if ( num_designs && num_axis && blend->design_pos[0] == 0 ) + { + FT_UInt n; + + + if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) + goto Exit; + + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = blend->design_pos[0] + num_axis * n; + } + + Exit: + return error; + + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ) + { + PS_Blend blend = face->blend; + FT_UInt n; + FT_Error error; + + + error = T1_Err_Invalid_Argument; + + if ( blend ) + { + master->num_axis = blend->num_axis; + master->num_designs = blend->num_designs; + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_MM_Axis* axis = master->axis + n; + PS_DesignMap map = blend->design_map + n; + + + axis->name = blend->axis_names[n]; + axis->minimum = map->design_points[0]; + axis->maximum = map->design_points[map->num_points - 1]; + } + + error = T1_Err_Ok; + } + + return error; + } + + +#define FT_INT_TO_FIXED( a ) ( (a) << 16 ) +#define FT_FIXED_TO_INT( a ) ( FT_RoundFix( a ) >> 16 ) + + + /*************************************************************************/ + /* */ + /* Given a normalized (blend) coordinate, figure out the design */ + /* coordinate appropriate for that value. */ + /* */ + FT_LOCAL_DEF( FT_Fixed ) + mm_axis_unmap( PS_DesignMap axismap, + FT_Fixed ncv ) + { + int j; + + + if ( ncv <= axismap->blend_points[0] ) + return axismap->design_points[0]; + + for ( j = 1; j < axismap->num_points; ++j ) + { + if ( ncv <= axismap->blend_points[j] ) + { + FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1], + 0x10000L, + axismap->blend_points[j] - + axismap->blend_points[j - 1] ); + + + return axismap->design_points[j - 1] + + FT_MulDiv( t, + axismap->design_points[j] - + axismap->design_points[j - 1], + 1L ); + } + } + + return axismap->design_points[axismap->num_points - 1]; + } + + + /*************************************************************************/ + /* */ + /* Given a vector of weights, one for each design, figure out the */ + /* normalized axis coordinates which gave rise to those weights. */ + /* */ + FT_LOCAL_DEF( void ) + mm_weights_unmap( FT_Fixed* weights, + FT_Fixed* axiscoords, + FT_UInt axis_count ) + { + FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); + + if ( axis_count == 1 ) + axiscoords[0] = weights[1]; + + else if ( axis_count == 2 ) + { + axiscoords[0] = weights[3] + weights[1]; + axiscoords[1] = weights[3] + weights[2]; + } + + else if ( axis_count == 3 ) + { + axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; + } + + else + { + axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + + weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + + weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[7] + weights[6] + weights[5] + weights[4]; + axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[11] + weights[10] + weights[9] + weights[8]; + } + } + + + /*************************************************************************/ + /* */ + /* Just a wrapper around T1_Get_Multi_Master to support the different */ + /* arguments needed by the GX var distortable fonts. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( T1_Face face, + FT_MM_Var* *master ) + { + FT_Memory memory = face->root.memory; + FT_MM_Var *mmvar; + FT_Multi_Master mmaster; + FT_Error error; + FT_UInt i; + FT_Fixed axiscoords[T1_MAX_MM_AXIS]; + PS_Blend blend = face->blend; + + + error = T1_Get_Multi_Master( face, &mmaster ); + if ( error ) + goto Exit; + if ( FT_ALLOC( mmvar, + sizeof ( FT_MM_Var ) + + mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) + goto Exit; + + mmvar->num_axis = mmaster.num_axis; + mmvar->num_designs = mmaster.num_designs; + mmvar->num_namedstyles = (FT_UInt)-1; /* Does not apply */ + mmvar->axis = (FT_Var_Axis*)&mmvar[1]; + /* Point to axes after MM_Var struct */ + mmvar->namedstyle = NULL; + + for ( i = 0 ; i < mmaster.num_axis; ++i ) + { + mmvar->axis[i].name = mmaster.axis[i].name; + mmvar->axis[i].minimum = FT_INT_TO_FIXED( mmaster.axis[i].minimum); + mmvar->axis[i].maximum = FT_INT_TO_FIXED( mmaster.axis[i].maximum); + mmvar->axis[i].def = ( mmvar->axis[i].minimum + + mmvar->axis[i].maximum ) / 2; + /* Does not apply. But this value is in range */ + mmvar->axis[i].strid = 0xFFFFFFFFUL; /* Does not apply */ + mmvar->axis[i].tag = 0xFFFFFFFFUL; /* Does not apply */ + + if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); + else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); + } + + if ( blend->num_designs == 1U << blend->num_axis ) + { + mm_weights_unmap( blend->default_weight_vector, + axiscoords, + blend->num_axis ); + + for ( i = 0; i < mmaster.num_axis; ++i ) + mmvar->axis[i].def = + FT_INT_TO_FIXED( mm_axis_unmap( &blend->design_map[i], + axiscoords[i] ) ); + } + + *master = mmvar; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + PS_Blend blend = face->blend; + FT_Error error; + FT_UInt n, m; + + + error = T1_Err_Invalid_Argument; + + if ( blend && blend->num_axis == num_coords ) + { + /* recompute the weight vector from the blend coordinates */ + error = T1_Err_Ok; + + for ( n = 0; n < blend->num_designs; n++ ) + { + FT_Fixed result = 0x10000L; /* 1.0 fixed */ + + + for ( m = 0; m < blend->num_axis; m++ ) + { + FT_Fixed factor; + + + /* get current blend axis position */ + factor = coords[m]; + if ( factor < 0 ) factor = 0; + if ( factor > 0x10000L ) factor = 0x10000L; + + if ( ( n & ( 1 << m ) ) == 0 ) + factor = 0x10000L - factor; + + result = FT_MulFix( result, factor ); + } + blend->weight_vector[n] = result; + } + + error = T1_Err_Ok; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + PS_Blend blend = face->blend; + FT_Error error; + FT_UInt n, p; + + + error = T1_Err_Invalid_Argument; + if ( blend && blend->num_axis == num_coords ) + { + /* compute the blend coordinates through the blend design map */ + FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; + + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_Long design = coords[n]; + FT_Fixed the_blend; + PS_DesignMap map = blend->design_map + n; + FT_Long* designs = map->design_points; + FT_Fixed* blends = map->blend_points; + FT_Int before = -1, after = -1; + + + for ( p = 0; p < (FT_UInt)map->num_points; p++ ) + { + FT_Long p_design = designs[p]; + + + /* exact match? */ + if ( design == p_design ) + { + the_blend = blends[p]; + goto Found; + } + + if ( design < p_design ) + { + after = p; + break; + } + + before = p; + } + + /* now interpolate if necessary */ + if ( before < 0 ) + the_blend = blends[0]; + + else if ( after < 0 ) + the_blend = blends[map->num_points - 1]; + + else + the_blend = FT_MulDiv( design - designs[before], + blends [after] - blends [before], + designs[after] - designs[before] ); + + Found: + final_blends[n] = the_blend; + } + + error = T1_Set_MM_Blend( face, num_coords, final_blends ); + } + + return error; + } + + + /*************************************************************************/ + /* */ + /* Just a wrapper around T1_Set_MM_Design to support the different */ + /* arguments needed by the GX var distortable fonts. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Long lcoords[4]; /* maximum axis count is 4 */ + FT_UInt i; + FT_Error error; + + + error = T1_Err_Invalid_Argument; + if ( num_coords <= 4 && num_coords > 0 ) + { + for ( i = 0; i < num_coords; ++i ) + lcoords[i] = FT_FIXED_TO_INT( coords[i] ); + error = T1_Set_MM_Design( face, num_coords, lcoords ); + } + + return error; + } + + + FT_LOCAL_DEF( void ) + T1_Done_Blend( T1_Face face ) + { + FT_Memory memory = face->root.memory; + PS_Blend blend = face->blend; + + + if ( blend ) + { + FT_UInt num_designs = blend->num_designs; + FT_UInt num_axis = blend->num_axis; + FT_UInt n; + + + /* release design pos table */ + FT_FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = 0; + + /* release blend `private' and `font info' dictionaries */ + FT_FREE( blend->privates[1] ); + FT_FREE( blend->font_infos[1] ); + FT_FREE( blend->bboxes[1] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = 0; + blend->font_infos[n] = 0; + blend->bboxes [n] = 0; + } + + /* release weight vectors */ + FT_FREE( blend->weight_vector ); + blend->default_weight_vector = 0; + + /* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FT_FREE( blend->axis_names[n] ); + + /* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap dmap = blend->design_map + n; + + + FT_FREE( dmap->design_points ); + dmap->num_points = 0; + } + + FT_FREE( face->blend ); + } + } + + + static void + parse_blend_axis_types( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Error error = T1_Err_Ok; + PS_Blend blend; + FT_Memory memory; + + + /* take an array of objects */ + T1_ToTokenArray( &loader->parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* allocate blend if necessary */ + error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + blend = face->blend; + memory = face->root.memory; + + /* each token is an immediate containing the name of the axis */ + for ( n = 0; n < num_axis; n++ ) + { + T1_Token token = axis_tokens + n; + FT_Byte* name; + FT_PtrDist len; + + + /* skip first slash, if any */ + if ( token->start[0] == '/' ) + token->start++; + + len = token->limit - token->start; + if ( len == 0 ) + { + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) + goto Exit; + + name = (FT_Byte*)blend->axis_names[n]; + FT_MEM_COPY( name, token->start, len ); + name[len] = 0; + } + + Exit: + loader->parser.root.error = error; + } + + + static void + parse_blend_design_positions( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Int num_axis; + T1_Parser parser = &loader->parser; + + FT_Error error = T1_Err_Ok; + PS_Blend blend; + + + /* get the array of design tokens -- compute number of designs */ + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_blend_design_positions:" )); + FT_ERROR(( " incorrect number of designs: %d\n", + num_designs )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + { + FT_Byte* old_cursor = parser->root.cursor; + FT_Byte* old_limit = parser->root.limit; + FT_Int n; + + + blend = face->blend; + num_axis = 0; /* make compiler happy */ + + for ( n = 0; n < num_designs; n++ ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_DESIGNS]; + T1_Token token; + FT_Int axis, n_axis; + + + /* read axis/coordinates tokens */ + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); + + if ( n == 0 ) + { + num_axis = n_axis; + error = t1_allocate_blend( face, num_designs, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + } + else if ( n_axis != num_axis ) + { + FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* now read each axis token into the design position */ + for ( axis = 0; axis < n_axis; axis++ ) + { + T1_Token token2 = axis_tokens + axis; + + + parser->root.cursor = token2->start; + parser->root.limit = token2->limit; + blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); + } + } + + loader->parser.root.cursor = old_cursor; + loader->parser.root.limit = old_limit; + } + + Exit: + loader->parser.root.error = error; + } + + + static void + parse_blend_design_map( T1_Face face, + T1_Loader loader ) + { + FT_Error error = T1_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Byte* old_cursor; + FT_Byte* old_limit; + FT_Memory memory = face->root.memory; + + + T1_ToTokenArray( parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + error = t1_allocate_blend( face, 0, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + + /* now read each axis design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap map = blend->design_map + n; + T1_Token axis_token; + T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; + FT_Int p, num_points; + + + axis_token = axis_tokens + n; + + parser->root.cursor = axis_token->start; + parser->root.limit = axis_token->limit; + T1_ToTokenArray( parser, point_tokens, + T1_MAX_MM_MAP_POINTS, &num_points ); + + if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + /* allocate design map data */ + if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) + goto Exit; + map->blend_points = map->design_points + num_points; + map->num_points = (FT_Byte)num_points; + + for ( p = 0; p < num_points; p++ ) + { + T1_Token point_token; + + + point_token = point_tokens + p; + + /* don't include delimiting brackets */ + parser->root.cursor = point_token->start + 1; + parser->root.limit = point_token->limit - 1; + + map->design_points[p] = T1_ToInt( parser ); + map->blend_points [p] = T1_ToFixed( parser, 0 ); + } + } + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + static void + parse_weight_vector( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Error error = T1_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend = face->blend; + T1_Token token; + FT_Int n; + FT_Byte* old_cursor; + FT_Byte* old_limit; + + + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_weight_vector:" )); + FT_ERROR(( " incorrect number of designs: %d\n", + num_designs )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + if ( !blend || !blend->num_designs ) + { + error = t1_allocate_blend( face, num_designs, 0 ); + if ( error ) + goto Exit; + blend = face->blend; + } + else if ( blend->num_designs != (FT_UInt)num_designs ) + { + FT_ERROR(( "parse_weight_vector:" + " /BlendDesignPosition and /WeightVector have\n" )); + FT_ERROR(( " " + " different number of elements!\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + for ( n = 0; n < num_designs; n++ ) + { + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + + blend->default_weight_vector[n] = + blend->weight_vector[n] = T1_ToFixed( parser, 0 ); + } + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ + /* we're only interested in the number of array elements */ + static void + parse_buildchar( T1_Face face, + T1_Loader loader ) + { + face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); + + return; + } + + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_load_keyword( T1_Face face, + T1_Loader loader, + const T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects; + PS_Blend blend = face->blend; + + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields; */ + /* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_PRIVATE: + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->bboxes; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_LOADER: + dummy_object = loader; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_FACE: + dummy_object = face; + objects = &dummy_object; + max_objects = 0; + break; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + case T1_FIELD_LOCATION_BLEND: + dummy_object = face->blend; + objects = &dummy_object; + max_objects = 0; + break; +#endif + + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + static void + parse_private( T1_Face face, + T1_Loader loader ) + { + FT_UNUSED( face ); + + loader->keywords_encountered |= T1_PRIVATE; + } + + + static int + read_binary_data( T1_Parser parser, + FT_Long* size, + FT_Byte** base ) + { + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + + /* the binary data has one of the following formats */ + /* */ + /* `size' [white*] RD white ....... ND */ + /* `size' [white*] -| white ....... |- */ + /* */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + + if ( cur < limit && ft_isdigit( *cur ) ) + { + *size = T1_ToInt( parser ); + + T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ + + /* there is only one whitespace char after the */ + /* `RD' or `-|' token */ + *base = parser->root.cursor + 1; + + parser->root.cursor += *size + 1; + return !parser->root.error; + } + + FT_ERROR(( "read_binary_data: invalid size field\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return 0; + } + + + /* We now define the routines to handle the `/Encoding', `/Subrs', */ + /* and `/CharStrings' dictionaries. */ + + static void + parse_font_matrix( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + FT_Vector* offset = &face->type1.font_offset; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + + + result = T1_ToFixedArray( parser, 6, temp, 3 ); + + if ( result < 0 ) + { + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "parse_font_matrix: invalid font matrix\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + + /* Set Units per EM based on FontMatrix values. We set the value to */ + /* 1000 / temp_scale, because temp_scale was already multiplied by */ + /* 1000 (in t1_tofixed, from psobjs.c). */ + + root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, + temp_scale ) >> 16 ); + + /* we need to scale the values by 1.0/temp_scale */ + if ( temp_scale != 0x10000L ) + { + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + parse_encoding( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "parse_encoding: out of bounds!\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &face->type1.encoding; + FT_Int count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_NEW_ARRAY( encode->char_index, count ) || + FT_NEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + { + char* notdef = (char *)".notdef"; + + + T1_Add_Table( char_table, n, notdef, 8 ); + } + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type1 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter a `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + IS_PS_DELIM( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we've found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + } + + cur = parser->root.cursor; + + if ( *cur == '/' && cur + 2 < limit && n < count ) + { + FT_PtrDist len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + + len = parser->root.cursor - cur; + + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + + n++; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + + face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + + else + parser->root.error = T1_Err_Ignore; + } + } + + + static void + parse_subrs( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + PS_Table table = &loader->subrs; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Int n, num_subrs; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + T1_Skip_Spaces( parser ); + + /* test for empty array */ + if ( parser->root.cursor < parser->root.limit && + *parser->root.cursor == '[' ) + { + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor >= parser->root.limit || + *parser->root.cursor != ']' ) + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + + num_subrs = (FT_Int)T1_ToInt( parser ); + + /* position the parser right before the `dup' of the first subr */ + T1_Skip_PS_Token( parser ); /* `array' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + + /* initialize subrs array -- with synthetic fonts it is possible */ + /* we get here twice */ + if ( !loader->num_subrs ) + { + error = psaux->ps_table_funcs->init( table, num_subrs, memory ); + if ( error ) + goto Fail; + } + + /* the format is simple: */ + /* */ + /* `index' + binary data */ + /* */ + for ( n = 0; n < num_subrs; n++ ) + { + FT_Long idx, size; + FT_Byte* base; + + + /* If the next token isn't `dup', we are also done. This */ + /* happens when there are `holes' in the Subrs array. */ + if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) + break; + + T1_Skip_PS_Token( parser ); /* `dup' */ + + idx = T1_ToInt( parser ); + + if ( !read_binary_data( parser, &size, &base ) ) + return; + + /* The binary string is followed by one token, e.g. `NP' */ + /* (bound to `noaccess put') or by two separate tokens: */ + /* `noaccess' & `put'. We position the parser right */ + /* before the next `dup', if any. */ + T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces ( parser ); + + if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) + { + T1_Skip_PS_Token( parser ); /* skip `put' */ + T1_Skip_Spaces ( parser ); + } + + /* with synthetic fonts it is possible we get here twice */ + if ( loader->num_subrs ) + continue; + + /* some fonts use a value of -1 for lenIV to indicate that */ + /* the charstrings are unencoded */ + /* */ + /* thanks to Tom Kacvinsky for pointing this out */ + /* */ + if ( face->type1.private_dict.lenIV >= 0 ) + { + FT_Byte* temp; + + + if ( size <= face->type1.private_dict.lenIV ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_ALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= face->type1.private_dict.lenIV; + error = T1_Add_Table( table, (FT_Int)idx, + temp + face->type1.private_dict.lenIV, size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( table, (FT_Int)idx, base, size ); + if ( error ) + goto Fail; + } + + if ( !loader->num_subrs ) + loader->num_subrs = num_subrs; + + return; + + Fail: + parser->root.error = error; + } + + +#define TABLE_EXTEND 5 + + + static void + parse_charstrings( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Int n, num_glyphs; + FT_UInt notdef_index = 0; + FT_Byte notdef_found = 0; + + + num_glyphs = (FT_Int)T1_ToInt( parser ); + /* some fonts like Optima-Oblique not only define the /CharStrings */ + /* array but access it also */ + if ( num_glyphs == 0 || parser->root.error ) + return; + + /* initialize tables, leaving space for addition of .notdef, */ + /* if necessary, and a few other glyphs to handle buggy */ + /* fonts which have more glyphs than specified. */ + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( !loader->num_glyphs ) + { + error = psaux->ps_table_funcs->init( + code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( + name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + } + + n = 0; + + for (;;) + { + FT_Long size; + FT_Byte* base; + + + /* the format is simple: */ + /* `/glyphname' + binary data */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* we stop when we find a `def' or `end' keyword */ + if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) + { + if ( cur[0] == 'd' && + cur[1] == 'e' && + cur[2] == 'f' ) + { + /* There are fonts which have this: */ + /* */ + /* /CharStrings 118 dict def */ + /* Private begin */ + /* CharStrings begin */ + /* ... */ + /* */ + /* To catch this we ignore `def' if */ + /* no charstring has actually been */ + /* seen. */ + if ( n ) + break; + } + + if ( cur[0] == 'e' && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + + if ( *cur == '/' ) + { + FT_PtrDist len; + + + if ( cur + 1 >= limit ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + cur++; /* skip `/' */ + len = parser->root.cursor - cur; + + if ( !read_binary_data( parser, &size, &base ) ) + return; + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( loader->num_glyphs ) + continue; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)(name_table->elements[n]) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + if ( face->type1.private_dict.lenIV >= 0 && + n < num_glyphs + TABLE_EXTEND ) + { + FT_Byte* temp; + + + if ( size <= face->type1.private_dict.lenIV ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_ALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= face->type1.private_dict.lenIV; + error = T1_Add_Table( code_table, n, + temp + face->type1.private_dict.lenIV, size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( code_table, n, base, size ); + if ( error ) + goto Fail; + + n++; + } + } + + if ( loader->num_glyphs ) + return; + else + loader->num_glyphs = n; + + /* if /.notdef is found but does not occupy index 0, do our magic. */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)name_table->elements[0] ) && + notdef_found ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + else if ( !notdef_found ) + { + /* notdef_index is already 0, or /.notdef is undefined in */ + /* charstrings dictionary. Worry about /.notdef undefined. */ + /* We take index 0 and add it to the end of the table(s) */ + /* and add our own /.notdef glyph to index 0. */ + + /* 0 333 hsbw endchar */ + FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E}; + char* notdef_name = (char *)".notdef"; + + + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, notdef_name, 8 ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); + + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, n, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, n, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + /* we added a glyph. */ + loader->num_glyphs = n + 1; + } + + return; + + Fail: + parser->root.error = error; + } + + + /*************************************************************************/ + /* */ + /* Define the token field static variables. This is a set of */ + /* T1_FieldRec variables. */ + /* */ + /*************************************************************************/ + + + static + const T1_FieldRec t1_keywords[] = + { + +#include "t1tokens.h" + + /* now add the special functions... */ + T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Encoding", parse_encoding, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Subrs", parse_subrs, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "Private", parse_private, + T1_FIELD_DICT_FONTDICT ) + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, + T1_FIELD_DICT_PRIVATE ) +#endif + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + +#define T1_FIELD_COUNT \ + ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) ) + + + static FT_Error + parse_dict( T1_Face face, + T1_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T1_Parser parser = &loader->parser; + FT_Byte *limit, *start_binary = NULL; + FT_Bool have_integer = 0; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = T1_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `eexec' */ + if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) + break; + + /* look for `closefile' which ends the eexec section */ + else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) + break; + + /* in a synthetic font the base font starts after a */ + /* `FontDictionary' token that is placed after a Private dict */ + else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) + { + if ( loader->keywords_encountered & T1_PRIVATE ) + loader->keywords_encountered |= + T1_FONTDIR_AFTER_PRIVATE; + parser->root.cursor += 13; + } + + /* check whether we have an integer */ + else if ( ft_isdigit( *cur ) ) + { + start_binary = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 1; + } + + /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ + /* since those tokens are handled by parse_subrs and */ + /* parse_charstrings */ + else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } + + else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = parser->root.cursor - cur; + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)t1_keywords; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == (FT_PtrDist)ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { + /* We found it -- run the parsing callback! */ + /* We record every instance of every field */ + /* (until we reach the base font of a */ + /* synthetic font) to deal adequately with */ + /* multiple master fonts; this is also */ + /* necessary because later PostScript */ + /* definitions override earlier ones. */ + + /* Once we encounter `FontDirectory' after */ + /* `/Private', we know that this is a synthetic */ + /* font; except for `/CharStrings' we are not */ + /* interested in anything that follows this */ + /* `FontDirectory'. */ + + /* MM fonts have more than one /Private token at */ + /* the top level; let's hope that all the junk */ + /* that follows the first /Private token is not */ + /* interesting to us. */ + + /* According to Adobe Tech Note #5175 (CID-Keyed */ + /* Font Installation for ATM Software) a `begin' */ + /* must be followed by exactly one `end', and */ + /* `begin' -- `end' pairs must be accurately */ + /* paired. We could use this to distinguish */ + /* between the global Private and the Private */ + /* dict that is a member of the Blend dict. */ + + const FT_UInt dict = + ( loader->keywords_encountered & T1_PRIVATE ) + ? T1_FIELD_DICT_PRIVATE + : T1_FIELD_DICT_FONTDICT; + + if ( !( dict & keyword->dict ) ) + { + FT_TRACE1(( "parse_dict: found %s but ignoring it " + "since it is in the wrong dictionary\n", + keyword->ident )); + break; + } + + if ( !( loader->keywords_encountered & + T1_FONTDIR_AFTER_PRIVATE ) || + ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) + { + parser->root.error = t1_load_keyword( face, + loader, + keyword ); + if ( parser->root.error != T1_Err_Ok ) + { + if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore ) + parser->root.error = T1_Err_Ok; + else + return parser->root.error; + } + } + break; + } + + keyword++; + } + } + + have_integer = 0; + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 0; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + static void + t1_init_loader( T1_Loader loader, + T1_Face face ) + { + FT_UNUSED( face ); + + FT_MEM_ZERO( loader, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + loader->subrs.init = 0; + loader->swap_table.init = 0; + loader->fontdata = 0; + loader->keywords_encountered = 0; + } + + + static void + t1_done_loader( T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + T1_Release_Table( &loader->subrs ); + + /* finalize parser */ + T1_Finalize_Parser( parser ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Open_Face( T1_Face face ) + { + T1_LoaderRec loader; + T1_Parser parser; + T1_Font type1 = &face->type1; + PS_Private priv = &type1->private_dict; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t1_init_loader( &loader, face ); + + /* default values */ + face->ndv_idx = -1; + face->cdv_idx = -1; + face->len_buildchar = 0; + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = 4; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + parser = &loader.parser; + error = T1_New_Parser( parser, + face->root.stream, + face->root.memory, + psaux ); + if ( error ) + goto Exit; + + error = parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + error = T1_Get_Private_Dict( parser, psaux ); + if ( error ) + goto Exit; + + error = parse_dict( face, &loader, + parser->private_dict, parser->private_len ); + if ( error ) + goto Exit; + + /* ensure even-ness of `num_blue_values' */ + priv->num_blue_values &= ~1; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + if ( face->blend && + face->blend->num_default_design_vector != 0 && + face->blend->num_default_design_vector != face->blend->num_axis ) + { + /* we don't use it currently so just warn, reset, and ignore */ + FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " + "while there are %u axes.\n", + face->blend->num_default_design_vector, + face->blend->num_axis )); + + face->blend->num_default_design_vector = 0; + } + + /* the following can happen for MM instances; we then treat the */ + /* font as a normal PS font */ + if ( face->blend && + ( !face->blend->num_designs || !face->blend->num_axis ) ) + T1_Done_Blend( face ); + + /* another safety check */ + if ( face->blend ) + { + FT_UInt i; + + + for ( i = 0; i < face->blend->num_axis; i++ ) + if ( !face->blend->design_map[i].num_points ) + { + T1_Done_Blend( face ); + break; + } + } + + if ( face->blend ) + { + if ( face->len_buildchar > 0 ) + { + FT_Memory memory = face->root.memory; + + + if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) + { + FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); + face->len_buildchar = 0; + goto Exit; + } + } + } + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + /* now, propagate the subrs, charstrings, and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( loader.subrs.init ) + { + loader.subrs.init = 0; + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !face->root.internal->incremental_interface ) +#endif + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face!\n" )); + error = T1_Err_Invalid_File_Format; + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* the index is then stored in type1.encoding.char_index, and */ + /* a the name to type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode > max_char ) + max_char = charcode; + } + break; + } + } + } + + /* + * Yes, this happens: Certain PDF-embedded fonts have only a + * `.notdef' glyph defined! + */ + + if ( min_char > max_char ) + { + min_char = 0; + max_char = loader.encoding_table.max_elems; + } + + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/src/freetype2/type1/t1load.h b/src/freetype2/type1/t1load.h new file mode 100644 index 0000000..546fc33 --- /dev/null +++ b/src/freetype2/type1/t1load.h @@ -0,0 +1,102 @@ +/***************************************************************************/ +/* */ +/* t1load.h */ +/* */ +/* Type 1 font loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 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 __T1LOAD_H__ +#define __T1LOAD_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_MULTIPLE_MASTERS_H + +#include "t1parse.h" + + +FT_BEGIN_HEADER + + + typedef struct T1_Loader_ + { + T1_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + FT_Int num_subrs; + PS_TableRec subrs; + FT_Bool fontdata; + + FT_UInt keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */ + + } T1_LoaderRec, *T1_Loader; + + + /* treatment of some keywords differs depending on whether */ + /* they precede or follow certain other keywords */ + +#define T1_PRIVATE ( 1 << 0 ) +#define T1_FONTDIR_AFTER_PRIVATE ( 1 << 1 ) + + + FT_LOCAL( FT_Error ) + T1_Open_Face( T1_Face face ); + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + FT_LOCAL( FT_Error ) + T1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ); + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( T1_Face face, + FT_MM_Var* *master ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( void ) + T1_Done_Blend( T1_Face face ); + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +FT_END_HEADER + +#endif /* __T1LOAD_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1objs.c b/src/freetype2/type1/t1objs.c new file mode 100644 index 0000000..3d08336 --- /dev/null +++ b/src/freetype2/type1/t1objs.c @@ -0,0 +1,566 @@ +/***************************************************************************/ +/* */ +/* t1objs.c */ +/* */ +/* Type 1 objects manager (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_IDS_H + +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_INTERNAL_POSTSCRIPT_AUX_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_t1objs + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /* note that we store the global hints in the size's "internal" root */ + /* field */ + /* */ + /*************************************************************************/ + + + static PSH_Globals_Funcs + T1_Size_Get_Globals_Funcs( T1_Size size ) + { + T1_Face face = (T1_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0 ; + } + + + FT_LOCAL_DEF( void ) + T1_Size_Done( T1_Size size ) + { + if ( size->root.internal ) + { + PSH_Globals_Funcs funcs; + + + funcs = T1_Size_Get_Globals_Funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)size->root.internal ); + + size->root.internal = 0; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Init( T1_Size size ) + { + FT_Error error = 0; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + T1_Face face = (T1_Face)size->root.face; + + + error = funcs->create( size->root.face->memory, + &face->type1.private_dict, &globals ); + if ( !error ) + size->root.internal = (FT_Size_Internal)(void*)globals; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Request( T1_Size size, + FT_Size_Request req ) + { + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + FT_Request_Metrics( size->root.face, req ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->root.internal, + size->root.metrics.x_scale, + size->root.metrics.y_scale, + 0, 0 ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* SLOT FUNCTIONS */ + /* */ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + T1_GlyphSlot_Done( T1_GlyphSlot slot ) + { + slot->root.internal->glyph_hints = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_GlyphSlot_Init( T1_GlyphSlot slot ) + { + T1_Face face; + PSHinter_Service pshinter; + + + face = (T1_Face)slot->root.face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->root.face->driver->root.library, "pshinter" ); + if (module) + { + T1_Hints_Funcs funcs; + + funcs = pshinter->get_t1_funcs( module ); + slot->root.internal->glyph_hints = (void*)funcs; + } + } + return 0; + } + + + /*************************************************************************/ + /* */ + /* FACE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* T1_Face_Done */ + /* */ + /* <Description> */ + /* The face object destructor. */ + /* */ + /* <Input> */ + /* face :: A typeless pointer to the face object to destroy. */ + /* */ + FT_LOCAL_DEF( void ) + T1_Face_Done( T1_Face face ) + { + if ( face ) + { + FT_Memory memory = face->root.memory; + T1_Font type1 = &face->type1; + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + /* release multiple masters information */ + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( face->buildchar ) + { + FT_FREE( face->buildchar ); + + face->buildchar = NULL; + face->len_buildchar = 0; + } + + T1_Done_Blend( face ); + face->blend = 0; +#endif + + /* release font info strings */ + { + PS_FontInfo info = &type1->font_info; + + + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + } + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->subrs ); + FT_FREE( type1->subrs_len ); + + FT_FREE( type1->subrs_block ); + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + +#ifndef T1_CONFIG_OPTION_NO_AFM + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); +#endif + + /* release unicode map, if any */ +#if 0 + FT_FREE( face->unicode_map_rec.maps ); + face->unicode_map_rec.num_maps = 0; + face->unicode_map = NULL; +#endif + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* T1_Face_Init */ + /* */ + /* <Description> */ + /* The face object constructor. */ + /* */ + /* <Input> */ + /* stream :: input stream where to load font data. */ + /* */ + /* face_index :: The index of the font face in the resource. */ + /* */ + /* num_params :: Number of additional generic parameters. Ignored. */ + /* */ + /* params :: Additional generic parameters. Ignored. */ + /* */ + /* <InOut> */ + /* face :: The face record to build. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T1_Face_Init( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + + + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + + face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "pshinter" ); + + /* open the tokenizer; this will also check the font format */ + error = T1_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "T1_Face_Init: invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + + root->num_glyphs = type1->num_glyphs; + root->face_index = face_index; + + root->face_flags = FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES | + FT_FACE_FLAG_HINTER; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( face->blend ) + root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + root->style_name = (char *)"Regular"; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + root->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox.xMin = type1->font_bbox.xMin >> 16; + root->bbox.yMin = type1->font_bbox.yMin >> 16; + root->bbox.xMax = ( type1->font_bbox.xMax + 0xFFFFU ) >> 16; + root->bbox.yMax = ( type1->font_bbox.yMax + 0xFFFFU ) >> 16; + + /* Set units_per_EM if we didn't set it in parse_font_matrix. */ + if ( !root->units_per_EM ) + root->units_per_EM = 1000; + + root->ascender = (FT_Short)( root->bbox.yMax ); + root->descender = (FT_Short)( root->bbox.yMin ); + + root->height = (FT_Short)( ( root->units_per_EM * 12 ) / 10 ); + if ( root->height < root->ascender - root->descender ) + root->height = (FT_Short)( root->ascender - root->descender ); + + /* now compute the maximum advance width */ + root->max_advance_width = + (FT_Short)( root->bbox.xMax ); + { + FT_Pos max_advance; + + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = (FT_Short)max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + } + + { + FT_Face root = &face->root; + + + if ( psnames && psaux ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthetize a Unicode charmap */ + charmap.platform_id = 3; + charmap.encoding_id = 1; + charmap.encoding = FT_ENCODING_UNICODE; + + FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = 7; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + FT_CMap_New( clazz, NULL, &charmap, NULL ); + +#if 0 + /* Select default charmap */ + if (root->num_charmaps) + root->charmap = root->charmaps[0]; +#endif + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* T1_Driver_Init */ + /* */ + /* <Description> */ + /* Initializes a given Type 1 driver object. */ + /* */ + /* <Input> */ + /* driver :: A handle to the target driver object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T1_Driver_Init( T1_Driver driver ) + { + FT_UNUSED( driver ); + + return T1_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* T1_Driver_Done */ + /* */ + /* <Description> */ + /* Finalizes a given Type 1 driver. */ + /* */ + /* <Input> */ + /* driver :: A handle to the target Type 1 driver. */ + /* */ + FT_LOCAL_DEF( void ) + T1_Driver_Done( T1_Driver driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/src/freetype2/type1/t1objs.h b/src/freetype2/type1/t1objs.h new file mode 100644 index 0000000..e5e9029 --- /dev/null +++ b/src/freetype2/type1/t1objs.h @@ -0,0 +1,171 @@ +/***************************************************************************/ +/* */ +/* t1objs.h */ +/* */ +/* Type 1 objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1OBJS_H__ +#define __T1OBJS_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_TYPE1_TYPES_H + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_Driver */ + /* */ + /* <Description> */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct T1_DriverRec_ *T1_Driver; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_Size */ + /* */ + /* <Description> */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct T1_SizeRec_* T1_Size; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_GlyphSlot */ + /* */ + /* <Description> */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_CharMap */ + /* */ + /* <Description> */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* <Note> */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables. */ + /* */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + /*************************************************************************/ + /* */ + /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_SizeRec */ + /* */ + /* <Description> */ + /* Type 1 size record. */ + /* */ + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + + } T1_SizeRec; + + + FT_LOCAL( void ) + T1_Size_Done( T1_Size size ); + + FT_LOCAL( FT_Error ) + T1_Size_Request( T1_Size size, + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + T1_Size_Init( T1_Size size ); + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* T1_GlyphSlotRec */ + /* */ + /* <Description> */ + /* Type 1 glyph slot record. */ + /* */ + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Int max_points; + FT_Int max_contours; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } T1_GlyphSlotRec; + + + FT_LOCAL( FT_Error ) + T1_Face_Init( FT_Stream stream, + T1_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + T1_Face_Done( T1_Face face ); + + FT_LOCAL( FT_Error ) + T1_GlyphSlot_Init( T1_GlyphSlot slot ); + + FT_LOCAL( void ) + T1_GlyphSlot_Done( T1_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + T1_Driver_Init( T1_Driver driver ); + + FT_LOCAL( void ) + T1_Driver_Done( T1_Driver driver ); + + +FT_END_HEADER + +#endif /* __T1OBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1parse.c b/src/freetype2/type1/t1parse.c new file mode 100644 index 0000000..1b252c7 --- /dev/null +++ b/src/freetype2/type1/t1parse.c @@ -0,0 +1,479 @@ +/***************************************************************************/ +/* */ +/* t1parse.c */ +/* */ +/* Type 1 parser (body). */ +/* */ +/* Copyright 1996-2001, 2002, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The Type 1 parser is in charge of the following: */ + /* */ + /* - provide an implementation of a growing sequence of objects called */ + /* a `T1_Table' (used to build various tables needed by the loader). */ + /* */ + /* - opening .pfb and .pfa files to extract their top-level and private */ + /* dictionaries. */ + /* */ + /* - read numbers, arrays & strings from any dictionary. */ + /* */ + /* See `t1load.c' to see how data is loaded from the font file. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_POSTSCRIPT_AUX_H + +#include "t1parse.h" + +#include "t1errors.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_t1parse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + read_pfb_tag( FT_Stream stream, + FT_UShort *atag, + FT_Long *asize ) + { + FT_Error error; + FT_UShort tag; + FT_Long size; + + + *atag = 0; + *asize = 0; + + if ( !FT_READ_USHORT( tag ) ) + { + if ( tag == 0x8001U || tag == 0x8002U ) + { + if ( !FT_READ_LONG_LE( size ) ) + *asize = size; + } + + *atag = tag; + } + + return error; + } + + + static FT_Error + check_type1_format( FT_Stream stream, + const char* header_string, + size_t header_length ) + { + FT_Error error; + FT_UShort tag; + FT_Long size; + + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + + if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) ) + goto Exit; + + if ( !FT_FRAME_ENTER( header_length ) ) + { + error = 0; + + if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 ) + error = T1_Err_Unknown_File_Format; + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_UShort tag; + FT_Long size; + + + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = 0; + parser->private_len = 0; + parser->private_dict = 0; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; + + /* check the header format */ + error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); + if ( error ) + { + if ( error != T1_Err_Unknown_File_Format ) + goto Exit; + + error = check_type1_format( stream, "%!FontType", 10 ); + if ( error ) + { + FT_TRACE2(( "[not a Type1 font]\n" )); + goto Exit; + } + } + + /******************************************************************/ + /* */ + /* Here a short summary of what is going on: */ + /* */ + /* When creating a new Type 1 parser, we try to locate and load */ + /* the base dictionary if this is possible (i.e. for PFB */ + /* files). Otherwise, we load the whole font into memory. */ + /* */ + /* When `loading' the base dictionary, we only setup pointers */ + /* in the case of a memory-based stream. Otherwise, we */ + /* allocate and load the base dictionary in it. */ + /* */ + /* parser->in_pfb is set if we are in a binary (".pfb") font. */ + /* parser->in_memory is set if we have a memory stream. */ + /* */ + + /* try to compute the size of the base dictionary; */ + /* look for a Postscript binary file tag, i.e 0x8001 */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + + if ( tag != 0x8001U ) + { + /* assume that this is a PFA file for now; an error will */ + /* be produced later when more things are checked */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + size = stream->size; + } + else + parser->in_pfb = 1; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory - this is clumsy, but so does the format */ + if ( FT_ALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + T1_Finalize_Parser( T1_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* always free the private dictionary */ + FT_FREE( parser->private_dict ); + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + parser->root.funcs.done( &parser->root ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->root.memory; + FT_Error error = T1_Err_Ok; + FT_Long size; + + + if ( parser->in_pfb ) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory. */ + FT_Long start_pos = FT_STREAM_POS(); + FT_UShort tag; + + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Fail; + + if ( tag != 0x8002U ) + break; + + parser->private_len += size; + + if ( FT_STREAM_SKIP( size ) ) + goto Fail; + } + + /* Check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" )); + FT_ERROR(( " invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + if ( FT_STREAM_SEEK( start_pos ) || + FT_ALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error || tag != 0x8002U ) + { + error = T1_Err_Ok; + break; + } + + if ( FT_STREAM_READ( parser->private_dict + parser->private_len, + size ) ) + goto Fail; + + parser->private_len += size; + } + } + else + { + /* We have already `loaded' the whole PFA font file into memory; */ + /* if this is a memory resource, allocate a new block to hold */ + /* the private dict. Otherwise, simply overwrite into the base */ + /* dictionary block in the heap. */ + + /* first of all, look at the `eexec' keyword */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Byte c; + + + Again: + for (;;) + { + c = cur[0]; + if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */ + /* newline + 4 chars */ + { + if ( cur[1] == 'e' && + cur[2] == 'x' && + cur[3] == 'e' && + cur[4] == 'c' ) + break; + } + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "T1_Get_Private_Dict:" )); + FT_ERROR(( " could not find `eexec' keyword\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + } + + /* check whether `eexec' was real -- it could be in a comment */ + /* or string (as e.g. in u003043t.gsf from ghostscript) */ + + parser->root.cursor = parser->base_dict; + parser->root.limit = cur + 9; + + cur = parser->root.cursor; + limit = parser->root.limit; + + while ( cur < limit ) + { + if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 ) + goto Found; + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + break; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + /* we haven't found the correct `eexec'; go back and continue */ + /* searching */ + + cur = limit; + limit = parser->base_dict + parser->base_len; + goto Again; + + /* now determine where to write the _encrypted_ binary private */ + /* dictionary. We overwrite the base dictionary for disk-based */ + /* resources and allocate a new block otherwise */ + + Found: + parser->root.limit = parser->base_dict + parser->base_len; + + T1_Skip_PS_Token( parser ); + cur = parser->root.cursor; + if ( *cur == '\r' ) + { + cur++; + if ( *cur == '\n' ) + cur++; + } + else if ( *cur == '\n' ) + cur++; + else + { + FT_ERROR(( "T1_Get_Private_Dict:" )); + FT_ERROR(( " `eexec' not properly terminated\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + size = (FT_Long)( parser->base_len - ( cur - parser->base_dict ) ); + + if ( parser->in_memory ) + { + /* note that we allocate one more byte to put a terminating `0' */ + if ( FT_ALLOC( parser->private_dict, size + 1 ) ) + goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = 0; + parser->base_len = 0; + } + + /* now determine whether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format -- decode it accordingly */ + + /* we need to access the next 4 bytes (after the final \r following */ + /* the `eexec' keyword); if they all are hexadecimal digits, then */ + /* we have a case of ASCII storage */ + + if ( ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && + ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) + { + /* ASCII hexadecimal encoding */ + FT_Long len; + + + parser->root.cursor = cur; + (void)psaux->ps_parser_funcs->to_bytes( &parser->root, + parser->private_dict, + parser->private_len, + &len, + 0 ); + parser->private_len = len; + + /* put a safeguard */ + parser->private_dict[len] = '\0'; + } + else + /* binary encoding -- copy the private dict */ + FT_MEM_MOVE( parser->private_dict, cur, size ); + } + + /* we now decrypt the encoded binary private dictionary */ + psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); + + /* replace the four random bytes at the beginning with whitespace */ + parser->private_dict[0] = ' '; + parser->private_dict[1] = ' '; + parser->private_dict[2] = ' '; + parser->private_dict[3] = ' '; + + parser->root.base = parser->private_dict; + parser->root.cursor = parser->private_dict; + parser->root.limit = parser->root.cursor + parser->private_len; + + Fail: + Exit: + return error; + } + + +/* END */ diff --git a/src/freetype2/type1/t1parse.h b/src/freetype2/type1/t1parse.h new file mode 100644 index 0000000..6fa4ca6 --- /dev/null +++ b/src/freetype2/type1/t1parse.h @@ -0,0 +1,135 @@ +/***************************************************************************/ +/* */ +/* t1parse.h */ +/* */ +/* Type 1 parser (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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 __T1PARSE_H__ +#define __T1PARSE_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_ParserRec */ + /* */ + /* <Description> */ + /* A PS_ParserRec is an object used to parse a Type 1 fonts very */ + /* quickly. */ + /* */ + /* <Fields> */ + /* root :: The root parser. */ + /* */ + /* stream :: The current input stream. */ + /* */ + /* base_dict :: A pointer to the top-level dictionary. */ + /* */ + /* base_len :: The length in bytes of the top dictionary. */ + /* */ + /* private_dict :: A pointer to the private dictionary. */ + /* */ + /* private_len :: The length in bytes of the private dictionary. */ + /* */ + /* in_pfb :: A boolean. Indicates that we are handling a PFB */ + /* file. */ + /* */ + /* in_memory :: A boolean. Indicates a memory-based stream. */ + /* */ + /* single_block :: A boolean. Indicates that the private dictionary */ + /* is stored in lieu of the base dictionary. */ + /* */ + typedef struct T1_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_Long base_len; + + FT_Byte* private_dict; + FT_Long private_len; + + FT_Bool in_pfb; + FT_Bool in_memory; + FT_Bool single_block; + + } T1_ParserRec, *T1_Parser; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Done_Table( p ) \ + do \ + { \ + if ( (p)->funcs.done ) \ + (p)->funcs.done( p ); \ + } while ( 0 ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define T1_ToCoordArray( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define T1_ToTokenArray( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) + +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + FT_LOCAL( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ); + + FT_LOCAL( void ) + T1_Finalize_Parser( T1_Parser parser ); + + +FT_END_HEADER + +#endif /* __T1PARSE_H__ */ + + +/* END */ diff --git a/src/freetype2/type1/t1tokens.h b/src/freetype2/type1/t1tokens.h new file mode 100644 index 0000000..788c811 --- /dev/null +++ b/src/freetype2/type1/t1tokens.h @@ -0,0 +1,134 @@ +/***************************************************************************/ +/* */ +/* t1tokens.h */ +/* */ +/* Type 1 tokenizer (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 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. */ +/* */ +/***************************************************************************/ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Notice", notice, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FullName", full_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FamilyName", family_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Weight", weight, + T1_FIELD_DICT_FONTDICT ) + + /* we use pointers to detect modifications made by synthetic fonts */ + T1_FIELD_NUM ( "ItalicAngle", italic_angle, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, + T1_FIELD_DICT_FONTDICT ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, + T1_FIELD_DICT_FONTDICT | T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "lenIV", lenIV, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "LanguageGroup", language_group, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "password", password, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueShift", blue_shift, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED ( "ExpansionFactor", expansion_factor, + T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "PaintType", paint_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "FontType", font_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, T1_FIELD_DICT_FONTDICT ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, T1_FIELD_DICT_FONTDICT ) + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FaceRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FACE + + T1_FIELD_NUM( "NDV", ndv_idx, T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM( "CDV", cdv_idx, T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_BlendRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BLEND + + T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, + T1_MAX_MM_DESIGNS, T1_FIELD_DICT_FONTDICT ) + + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +/* END */ diff --git a/src/freetype2/type1/type1.c b/src/freetype2/type1/type1.c new file mode 100644 index 0000000..ccc12be --- /dev/null +++ b/src/freetype2/type1/type1.c @@ -0,0 +1,33 @@ +/***************************************************************************/ +/* */ +/* type1.c */ +/* */ +/* FreeType Type 1 driver component (body only). */ +/* */ +/* Copyright 1996-2001 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 "t1parse.c" +#include "t1load.c" +#include "t1objs.c" +#include "t1driver.c" +#include "t1gload.c" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.c" +#endif + + +/* END */ diff --git a/src/freetype2/type42/t42drivr.c b/src/freetype2/type42/t42drivr.c new file mode 100644 index 0000000..a6e4cf4 --- /dev/null +++ b/src/freetype2/type42/t42drivr.c @@ -0,0 +1,232 @@ +/***************************************************************************/ +/* */ +/* t42drivr.c */ +/* */ +/* High-level Type 42 driver interface (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2007 by Roberto Alameda. */ +/* */ +/* 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 driver implements Type42 fonts as described in the */ + /* Technical Note #5012 from Adobe, with these limitations: */ + /* */ + /* 1) CID Fonts are not currently supported. */ + /* 2) Incremental fonts making use of the GlyphDirectory keyword */ + /* will be loaded, but the rendering will be using the TrueType */ + /* tables. */ + /* 3) As for Type1 fonts, CDevProc is not supported. */ + /* 4) The Metrics dictionary is not supported. */ + /* 5) AFM metrics are not supported. */ + /* */ + /* In other words, this driver supports Type42 fonts derived from */ + /* TrueType fonts in a non-CID manner, as done by usual conversion */ + /* programs. */ + /* */ + /*************************************************************************/ + + +#include "t42drivr.h" +#include "t42objs.h" +#include "t42error.h" +#include FT_INTERNAL_DEBUG_H + +#include FT_SERVICE_XFREE86_NAME_H +#include FT_SERVICE_GLYPH_DICT_H +#include FT_SERVICE_POSTSCRIPT_NAME_H +#include FT_SERVICE_POSTSCRIPT_INFO_H + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t42 + + + /* + * + * GLYPH DICT SERVICE + * + */ + + static FT_Error + t42_get_glyph_name( T42_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + + return T42_Err_Ok; + } + + + static FT_UInt + t42_get_name_index( T42_Face face, + FT_String* glyph_name ) + { + FT_Int i; + FT_String* gname; + + + for ( i = 0; i < face->type1.num_glyphs; i++ ) + { + gname = face->type1.glyph_names[i]; + + if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)ft_atol( (const char *)face->type1.charstrings[i] ); + } + + return 0; + } + + + static const FT_Service_GlyphDictRec t42_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t42_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)t42_get_name_index + }; + + + /* + * + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + t42_get_ps_font_name( T42_Face face ) + { + return (const char*)face->type1.font_name; + } + + + static const FT_Service_PsFontNameRec t42_service_ps_font_name = + { + (FT_PsName_GetFunc)t42_get_ps_font_name + }; + + + /* + * + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Error + t42_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T42_Face)face)->type1.font_info; + return T42_Err_Ok; + } + + + static FT_Int + t42_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + return 1; + } + + + static FT_Error + t42_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T42_Face)face)->type1.private_dict; + return T42_Err_Ok; + } + + + static const FT_Service_PsInfoRec t42_service_ps_info = + { + (PS_GetFontInfoFunc) t42_ps_get_font_info, + (PS_HasGlyphNamesFunc) t42_ps_has_glyph_names, + (PS_GetFontPrivateFunc)t42_ps_get_font_private + }; + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t42_services[] = + { + { FT_SERVICE_ID_GLYPH_DICT, &t42_service_glyph_dict }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t42_service_ps_font_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t42_service_ps_info }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TYPE_42 }, + { NULL, NULL } + }; + + + static FT_Module_Interface + T42_Get_Interface( FT_Driver driver, + const FT_String* t42_interface ) + { + FT_UNUSED( driver ); + + return ft_service_list_lookup( t42_services, t42_interface ); + } + + + const FT_Driver_ClassRec t42_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_MODULE_DRIVER_HAS_HINTER, +#else + 0, +#endif + + sizeof ( T42_DriverRec ), + + "type42", + 0x10000L, + 0x20000L, + + 0, /* format interface */ + + (FT_Module_Constructor)T42_Driver_Init, + (FT_Module_Destructor) T42_Driver_Done, + (FT_Module_Requester) T42_Get_Interface, + }, + + sizeof ( T42_FaceRec ), + sizeof ( T42_SizeRec ), + sizeof ( T42_GlyphSlotRec ), + + (FT_Face_InitFunc) T42_Face_Init, + (FT_Face_DoneFunc) T42_Face_Done, + (FT_Size_InitFunc) T42_Size_Init, + (FT_Size_DoneFunc) T42_Size_Done, + (FT_Slot_InitFunc) T42_GlyphSlot_Init, + (FT_Slot_DoneFunc) T42_GlyphSlot_Done, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + (FT_Slot_LoadFunc) T42_GlyphSlot_Load, + + (FT_Face_GetKerningFunc) 0, + (FT_Face_AttachFunc) 0, + + (FT_Face_GetAdvancesFunc) 0, + (FT_Size_RequestFunc) T42_Size_Request, + (FT_Size_SelectFunc) T42_Size_Select + }; + + +/* END */ diff --git a/src/freetype2/type42/t42drivr.h b/src/freetype2/type42/t42drivr.h new file mode 100644 index 0000000..98b7410 --- /dev/null +++ b/src/freetype2/type42/t42drivr.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* t42drivr.h */ +/* */ +/* High-level Type 42 driver interface (specification). */ +/* */ +/* Copyright 2002 by Roberto Alameda. */ +/* */ +/* 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 __T42DRIVR_H__ +#define __T42DRIVR_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class; + + +FT_END_HEADER + + +#endif /* __T42DRIVR_H__ */ + + +/* END */ diff --git a/src/freetype2/type42/t42error.h b/src/freetype2/type42/t42error.h new file mode 100644 index 0000000..b230910 --- /dev/null +++ b/src/freetype2/type42/t42error.h @@ -0,0 +1,40 @@ +/***************************************************************************/ +/* */ +/* t42error.h */ +/* */ +/* Type 42 error codes (specification only). */ +/* */ +/* Copyright 2002, 2003 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 Type 42 error enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __T42ERROR_H__ +#define __T42ERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX T42_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type42 + +#include FT_ERRORS_H + +#endif /* __T42ERROR_H__ */ + + +/* END */ diff --git a/src/freetype2/type42/t42objs.c b/src/freetype2/type42/t42objs.c new file mode 100644 index 0000000..db04fde --- /dev/null +++ b/src/freetype2/type42/t42objs.c @@ -0,0 +1,647 @@ +/***************************************************************************/ +/* */ +/* t42objs.c */ +/* */ +/* Type 42 objects manager (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007 by Roberto Alameda. */ +/* */ +/* 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 "t42objs.h" +#include "t42parse.h" +#include "t42error.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_LIST_H + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t42 + + + static FT_Error + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t42_loader_init( &loader, face ); + + parser = &loader.parser; + + if ( FT_ALLOC( face->ttf_data, 12 ) ) + goto Exit; + + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + + error = t42_parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + if ( type1->font_type != 42 ) + { + error = T42_Err_Unknown_File_Format; + goto Exit; + } + + /* now, propagate the charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" )); + error = T42_Err_Invalid_File_Format; + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* as defined in the CharStrings array. */ + /* The index is then stored in type1.encoding.char_index, and */ + /* the name in type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode > max_char ) + max_char = charcode; + } + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t42_loader_done( &loader ); + return error; + } + + + /***************** Driver Functions *************/ + + + FT_LOCAL_DEF( FT_Error ) + T42_Face_Init( FT_Stream stream, + T42_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + FT_Face root = (FT_Face)&face->root; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + + + face->ttf_face = NULL; + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + + /* open the tokenizer, this will also check the font format */ + error = T42_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "T42_Face_Init: invalid face index\n" )); + error = T42_Err_Invalid_Argument; + goto Exit; + } + + /* Now load the font program into the face object */ + + /* Init the face object fields */ + /* Now set up root face fields */ + + root->num_glyphs = type1->num_glyphs; + root->num_charmaps = 0; + root->face_index = face_index; + + root->face_flags = FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* We only set this flag if we have the patented bytecode interpreter. */ + /* There are no known `tricky' Type42 fonts that could be loaded with */ + /* the unpatented interpreter. */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + root->face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + root->style_name = (char *)"Regular"; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + root->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + /* Load the TTF font embedded in the T42 font */ + { + FT_Open_Args args; + + + args.flags = FT_OPEN_MEMORY; + args.memory_base = face->ttf_data; + args.memory_size = face->ttf_size; + + if ( num_params ) + { + args.flags |= FT_OPEN_PARAMS; + args.num_params = num_params; + args.params = params; + } + + error = FT_Open_Face( FT_FACE_LIBRARY( face ), + &args, 0, &face->ttf_face ); + } + + if ( error ) + goto Exit; + + FT_Done_Size( face->ttf_face->size ); + + /* Ignore info in FontInfo dictionary and use the info from the */ + /* loaded TTF font. The PostScript interpreter also ignores it. */ + root->bbox = face->ttf_face->bbox; + root->units_per_EM = face->ttf_face->units_per_EM; + + root->ascender = face->ttf_face->ascender; + root->descender = face->ttf_face->descender; + root->height = face->ttf_face->height; + + root->max_advance_width = face->ttf_face->max_advance_width; + root->max_advance_height = face->ttf_face->max_advance_height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) + root->face_flags |= FT_FACE_FLAG_VERTICAL; + + { + if ( psnames && psaux ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthetize a Unicode charmap */ + charmap.platform_id = 3; + charmap.encoding_id = 1; + charmap.encoding = FT_ENCODING_UNICODE; + + FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = 7; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = 0; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = 1; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = 2; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = 3; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + FT_CMap_New( clazz, NULL, &charmap, NULL ); + +#if 0 + /* Select default charmap */ + if ( root->num_charmaps ) + root->charmap = root->charmaps[0]; +#endif + } + } + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + T42_Face_Done( T42_Face face ) + { + T1_Font type1; + PS_FontInfo info; + FT_Memory memory; + + + if ( face ) + { + type1 = &face->type1; + info = &type1->font_info; + memory = face->root.memory; + + /* delete internal ttf face prior to freeing face->ttf_data */ + if ( face->ttf_face ) + FT_Done_Face( face->ttf_face ); + + /* release font info strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + + FT_FREE( face->ttf_data ); + +#if 0 + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FT_FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* T42_Driver_Init */ + /* */ + /* <Description> */ + /* Initializes a given Type 42 driver object. */ + /* */ + /* <Input> */ + /* driver :: A handle to the target driver object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T42_Driver_Init( T42_Driver driver ) + { + FT_Module ttmodule; + + + ttmodule = FT_Get_Module( FT_MODULE(driver)->library, "truetype" ); + driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; + + return T42_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T42_Driver_Done( T42_Driver driver ) + { + FT_UNUSED( driver ); + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Init( T42_Size size ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + FT_Size ttsize; + FT_Error error = T42_Err_Ok; + + + error = FT_New_Size( t42face->ttf_face, &ttsize ); + size->ttsize = ttsize; + + FT_Activate_Size( ttsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Request( T42_Size size, + FT_Size_Request req ) + { + T42_Face face = (T42_Face)size->root.face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Request_Size( face->ttf_face, req ); + if ( !error ) + ( (FT_Size)size )->metrics = face->ttf_face->size->metrics; + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Select( T42_Size size, + FT_ULong strike_index ) + { + T42_Face face = (T42_Face)size->root.face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Select_Size( face->ttf_face, strike_index ); + if ( !error ) + ( (FT_Size)size )->metrics = face->ttf_face->size->metrics; + + return error; + + } + + + FT_LOCAL_DEF( void ) + T42_Size_Done( T42_Size size ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + FT_ListNode node; + + + node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); + if ( node ) + { + FT_Done_Size( size->ttsize ); + size->ttsize = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Init( T42_GlyphSlot slot ) + { + FT_Face face = slot->root.face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot ttslot; + FT_Error error = T42_Err_Ok; + + + if ( face->glyph == NULL ) + { + /* First glyph slot for this face */ + slot->ttslot = t42face->ttf_face->glyph; + } + else + { + error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); + slot->ttslot = ttslot; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + T42_GlyphSlot_Done( T42_GlyphSlot slot ) + { + FT_Done_GlyphSlot( slot->ttslot ); + } + + + static void + t42_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + FT_ZERO( &slot->bitmap ); + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; + T42_Size t42size = (T42_Size)size; + FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; + + + t42_glyphslot_clear( t42slot->ttslot ); + error = ttclazz->load_glyph( t42slot->ttslot, + t42size->ttsize, + glyph_index, + load_flags | FT_LOAD_NO_BITMAP ); + + if ( !error ) + { + glyph->metrics = t42slot->ttslot->metrics; + + glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; + glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; + + glyph->format = t42slot->ttslot->format; + glyph->outline = t42slot->ttslot->outline; + + glyph->bitmap = t42slot->ttslot->bitmap; + glyph->bitmap_left = t42slot->ttslot->bitmap_left; + glyph->bitmap_top = t42slot->ttslot->bitmap_top; + + glyph->num_subglyphs = t42slot->ttslot->num_subglyphs; + glyph->subglyphs = t42slot->ttslot->subglyphs; + + glyph->control_data = t42slot->ttslot->control_data; + glyph->control_len = t42slot->ttslot->control_len; + } + + return error; + } + + +/* END */ diff --git a/src/freetype2/type42/t42objs.h b/src/freetype2/type42/t42objs.h new file mode 100644 index 0000000..289dedc --- /dev/null +++ b/src/freetype2/type42/t42objs.h @@ -0,0 +1,124 @@ +/***************************************************************************/ +/* */ +/* t42objs.h */ +/* */ +/* Type 42 objects manager (specification). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007 by Roberto Alameda. */ +/* */ +/* 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 __T42OBJS_H__ +#define __T42OBJS_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H +#include FT_INTERNAL_TYPE1_TYPES_H +#include "t42types.h" +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DRIVER_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + + +FT_BEGIN_HEADER + + + /* Type42 size */ + typedef struct T42_SizeRec_ + { + FT_SizeRec root; + FT_Size ttsize; + + } T42_SizeRec, *T42_Size; + + + /* Type42 slot */ + typedef struct T42_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_GlyphSlot ttslot; + + } T42_GlyphSlotRec, *T42_GlyphSlot; + + + /* Type 42 driver */ + typedef struct T42_DriverRec_ + { + FT_DriverRec root; + FT_Driver_Class ttclazz; + void* extension_component; + + } T42_DriverRec, *T42_Driver; + + + /* */ + + + FT_LOCAL( FT_Error ) + T42_Face_Init( FT_Stream stream, + T42_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + FT_LOCAL( void ) + T42_Face_Done( T42_Face face ); + + + FT_LOCAL( FT_Error ) + T42_Size_Init( T42_Size size ); + + + FT_LOCAL( FT_Error ) + T42_Size_Request( T42_Size size, + FT_Size_Request req ); + + + FT_LOCAL( FT_Error ) + T42_Size_Select( T42_Size size, + FT_ULong strike_index ); + + + FT_LOCAL( void ) + T42_Size_Done( T42_Size size ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Init( T42_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + FT_LOCAL( void ) + T42_GlyphSlot_Done( T42_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_Driver_Init( T42_Driver driver ); + + FT_LOCAL( void ) + T42_Driver_Done( T42_Driver driver ); + + /* */ + +FT_END_HEADER + + +#endif /* __T42OBJS_H__ */ + + +/* END */ diff --git a/src/freetype2/type42/t42parse.c b/src/freetype2/type42/t42parse.c new file mode 100644 index 0000000..7148379 --- /dev/null +++ b/src/freetype2/type42/t42parse.c @@ -0,0 +1,1167 @@ +/***************************************************************************/ +/* */ +/* t42parse.c */ +/* */ +/* Type 42 font parser (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007 by Roberto Alameda. */ +/* */ +/* 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 "t42parse.h" +#include "t42error.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_LIST_H +#include FT_INTERNAL_POSTSCRIPT_AUX_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_t42 + + + static void + t42_parse_font_matrix( T42_Face face, + T42_Loader loader ); + static void + t42_parse_encoding( T42_Face face, + T42_Loader loader ); + + static void + t42_parse_charstrings( T42_Face face, + T42_Loader loader ); + + static void + t42_parse_sfnts( T42_Face face, + T42_Loader loader ); + + + /* as Type42 fonts have no Private dict, */ + /* we set the last argument of T1_FIELD_XXX to 0 */ + static const + T1_FieldRec t42_keywords[] = { + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontInfo +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, 0 ) + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX("FontBBox", xMin, 0 ) + + T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) + T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) + T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Done_Table( p ) \ + do \ + { \ + if ( (p)->funcs.done ) \ + (p)->funcs.done( p ); \ + } while ( 0 ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) \ + (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToBytes( p, b, m, n, d ) \ + (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) + +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + /********************* Parsing Functions ******************/ + + FT_LOCAL_DEF( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error = T42_Err_Ok; + FT_Long size; + + + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = 0; + parser->in_memory = 0; + + /*******************************************************************/ + /* */ + /* Here a short summary of what is going on: */ + /* */ + /* When creating a new Type 42 parser, we try to locate and load */ + /* the base dictionary, loading the whole font into memory. */ + /* */ + /* When `loading' the base dictionary, we only set up pointers */ + /* in the case of a memory-based stream. Otherwise, we allocate */ + /* and load the base dictionary in it. */ + /* */ + /* parser->in_memory is set if we have a memory stream. */ + /* */ + + if ( FT_STREAM_SEEK( 0L ) || + FT_FRAME_ENTER( 17 ) ) + goto Exit; + + if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) + { + FT_TRACE2(( "not a Type42 font\n" )); + error = T42_Err_Unknown_File_Format; + } + + FT_FRAME_EXIT(); + + if ( error || FT_STREAM_SEEK( 0 ) ) + goto Exit; + + size = stream->size; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory */ + if ( FT_ALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + t42_parser_done( T42_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + parser->root.funcs.done( &parser->root ); + } + + + static int + t42_is_space( FT_Byte c ) + { + return ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' || c == '\f' || + c == '\0' ); + } + + + static void + t42_parse_font_matrix( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + FT_Vector* offset = &face->type1.font_offset; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + + + (void)T1_ToFixedArray( parser, 6, temp, 3 ); + + temp_scale = FT_ABS( temp[3] ); + + /* Set Units per EM based on FontMatrix values. We set the value to */ + /* 1000 / temp_scale, because temp_scale was already multiplied by */ + /* 1000 (in t1_tofixed, from psobjs.c). */ + + root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, + temp_scale ) >> 16 ); + + /* we need to scale the values by 1.0/temp_scale */ + if ( temp_scale != 0x10000L ) { + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + t42_parse_encoding( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "t42_parse_encoding: out of bounds!\n" )); + parser->root.error = T42_Err_Invalid_File_Format; + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &face->type1.encoding; + FT_UInt count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_UInt)T1_ToInt( parser ); + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_NEW_ARRAY( encode->char_index, count ) || + FT_NEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + { + char* notdef = (char *)".notdef"; + + + T1_Add_Table( char_table, n, notdef, 8 ); + } + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type42 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + t42_is_space( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we have found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + } + + cur = parser->root.cursor; + + if ( *cur == '/' && cur + 2 < limit && n < count ) + { + FT_PtrDist len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + + len = parser->root.cursor - cur; + + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + + n++; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + + face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + + else + { + FT_ERROR(( "t42_parse_encoding: invalid token!\n" )); + parser->root.error = T42_Err_Invalid_File_Format; + } + } + } + + + typedef enum + { + BEFORE_START, + BEFORE_TABLE_DIR, + OTHER_TABLES + + } T42_Load_Status; + + + static void + t42_parse_sfnts( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Error error; + FT_Int num_tables = 0; + FT_ULong count, ttf_size = 0; + + FT_Long n, string_size, old_string_size, real_size; + FT_Byte* string_buf = NULL; + FT_Bool allocated = 0; + + T42_Load_Status status; + + + /* The format is */ + /* */ + /* /sfnts [ <hexstring> <hexstring> ... ] def */ + /* */ + /* or */ + /* */ + /* /sfnts [ */ + /* <num_bin_bytes> RD <binary data> */ + /* <num_bin_bytes> RD <binary data> */ + /* ... */ + /* ] def */ + /* */ + /* with exactly one space after the `RD' token. */ + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) + { + FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + T1_Skip_Spaces( parser ); + status = BEFORE_START; + string_size = 0; + old_string_size = 0; + count = 0; + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + if ( *cur == ']' ) + { + parser->root.cursor++; + goto Exit; + } + + else if ( *cur == '<' ) + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + /* don't include delimiters */ + string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); + if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) + goto Fail; + + allocated = 1; + + parser->root.cursor = cur; + (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); + old_string_size = string_size; + string_size = real_size; + } + + else if ( ft_isdigit( *cur ) ) + { + if ( allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + string_size = T1_ToInt( parser ); + + T1_Skip_PS_Token( parser ); /* `RD' */ + if ( parser->root.error ) + return; + + string_buf = parser->root.cursor + 1; /* one space after `RD' */ + + parser->root.cursor += string_size + 1; + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + } + + if ( !string_buf ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + /* A string can have a trailing zero byte for padding. Ignore it. */ + if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) ) + string_size--; + + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + for ( n = 0; n < string_size; n++ ) + { + switch ( status ) + { + case BEFORE_START: + /* load offset table, 12 bytes */ + if ( count < 12 ) + { + face->ttf_data[count++] = string_buf[n]; + continue; + } + else + { + num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; + status = BEFORE_TABLE_DIR; + ttf_size = 12 + 16 * num_tables; + + if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) + goto Fail; + } + /* fall through */ + + case BEFORE_TABLE_DIR: + /* the offset table is read; read the table directory */ + if ( count < ttf_size ) + { + face->ttf_data[count++] = string_buf[n]; + continue; + } + else + { + int i; + FT_ULong len; + + + for ( i = 0; i < num_tables; i++ ) + { + FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; + + + len = FT_PEEK_ULONG( p ); + + /* Pad to a 4-byte boundary length */ + ttf_size += ( len + 3 ) & ~3; + } + + status = OTHER_TABLES; + face->ttf_size = ttf_size; + + /* there are no more than 256 tables, so no size check here */ + if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, + ttf_size + 1 ) ) + goto Fail; + } + /* fall through */ + + case OTHER_TABLES: + /* all other tables are just copied */ + if ( count >= ttf_size ) + { + FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + face->ttf_data[count++] = string_buf[n]; + } + } + + T1_Skip_Spaces( parser ); + } + + /* if control reaches this point, the format was not valid */ + error = T42_Err_Invalid_File_Format; + + Fail: + parser->root.error = error; + + Exit: + if ( allocated ) + FT_FREE( string_buf ); + } + + + static void + t42_parse_charstrings( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_UInt n; + FT_UInt notdef_index = 0; + FT_Byte notdef_found = 0; + + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + if ( ft_isdigit( *parser->root.cursor ) ) + { + loader->num_glyphs = (FT_UInt)T1_ToInt( parser ); + if ( parser->root.error ) + return; + } + else if ( *parser->root.cursor == '<' ) + { + /* We have `<< ... >>'. Count the number of `/' in the dictionary */ + /* to get its size. */ + FT_UInt count = 0; + + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + + while ( parser->root.cursor < limit ) + { + if ( *parser->root.cursor == '/' ) + count++; + else if ( *parser->root.cursor == '>' ) + { + loader->num_glyphs = count; + parser->root.cursor = cur; /* rewind */ + break; + } + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + } + } + else + { + FT_ERROR(( "t42_parse_charstrings: invalid token!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + /* initialize tables */ + + error = psaux->ps_table_funcs->init( code_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( name_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + + n = 0; + + for (;;) + { + /* The format is simple: */ + /* `/glyphname' + index [+ def] */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* We stop when we find an `end' keyword or '>' */ + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' && + t42_is_space( cur[3] ) ) + break; + if ( *cur == '>' ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + + if ( *cur == '/' ) + { + FT_PtrDist len; + + + if ( cur + 1 >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + cur++; /* skip `/' */ + len = parser->root.cursor - cur; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)(name_table->elements[n]) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + + (void)T1_ToInt( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + len = parser->root.cursor - cur; + + error = T1_Add_Table( code_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + code_table->elements[n][len] = '\0'; + + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + + loader->num_glyphs = n; + + if ( !notdef_found ) + { + FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + + /* if /.notdef does not occupy index 0, do our magic. */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)name_table->elements[0] ) ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + + return; + + Fail: + parser->root.error = error; + } + + + static FT_Error + t42_load_keyword( T42_Face face, + T42_Loader loader, + T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects = 0; + + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now the keyword is either a simple field or a table of fields; */ + /* we are now going to take care of it */ + + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + break; + + default: + dummy_object = &face->type1; + } + + objects = &dummy_object; + + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T42_Parser parser = &loader->parser; + FT_Byte* limit; + FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / + sizeof ( t42_keywords[0] ) ); + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = T42_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `FontDirectory' which causes problems for some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; + + + /* skip the `FontDirectory' keyword */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = cur2 = parser->root.cursor; + + /* look up the `known' keyword */ + while ( cur < limit ) + { + if ( *cur == 'k' && cur + 5 < limit && + ft_strncmp( (char*)cur, "known", 5 ) == 0 ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + if ( cur < limit ) + { + T1_TokenRec token; + + + /* skip the `known' keyword and the token following it */ + T1_Skip_PS_Token( parser ); + T1_ToToken( parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; + } + parser->root.cursor = cur2; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = parser->root.cursor - cur; + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + int i; + + + /* now compare the immediate name to the keyword table */ + + /* loop through all known keywords */ + for ( i = 0; i < n_keywords; i++ ) + { + T1_Field keyword = (T1_Field)&t42_keywords[i]; + FT_Byte *name = (FT_Byte*)keyword->ident; + + + if ( !name ) + continue; + + if ( cur[0] == name[0] && + len == (FT_PtrDist)ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { + /* we found it -- run the parsing callback! */ + parser->root.error = t42_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + } + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + FT_LOCAL_DEF( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ) + { + FT_UNUSED( face ); + + FT_MEM_ZERO( loader, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + } + + + FT_LOCAL_DEF( void ) + t42_loader_done( T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + + /* finalize parser */ + t42_parser_done( parser ); + } + + +/* END */ diff --git a/src/freetype2/type42/t42parse.h b/src/freetype2/type42/t42parse.h new file mode 100644 index 0000000..f77ec4a --- /dev/null +++ b/src/freetype2/type42/t42parse.h @@ -0,0 +1,90 @@ +/***************************************************************************/ +/* */ +/* t42parse.h */ +/* */ +/* Type 42 font parser (specification). */ +/* */ +/* Copyright 2002, 2003 by Roberto Alameda. */ +/* */ +/* 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 __T42PARSE_H__ +#define __T42PARSE_H__ + + +#include "t42objs.h" +#include FT_INTERNAL_POSTSCRIPT_AUX_H + + +FT_BEGIN_HEADER + + typedef struct T42_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_Long base_len; + + FT_Bool in_memory; + + } T42_ParserRec, *T42_Parser; + + + typedef struct T42_Loader_ + { + T42_ParserRec parser; /* parser used to read the stream */ + + FT_UInt num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_UInt num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + } T42_LoaderRec, *T42_Loader; + + + FT_LOCAL( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + t42_parser_done( T42_Parser parser ); + + + FT_LOCAL( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ); + + + FT_LOCAL( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ); + + FT_LOCAL( void ) + t42_loader_done( T42_Loader loader ); + + + /* */ + +FT_END_HEADER + + +#endif /* __T42PARSE_H__ */ + + +/* END */ diff --git a/src/freetype2/type42/t42types.h b/src/freetype2/type42/t42types.h new file mode 100644 index 0000000..6626b04 --- /dev/null +++ b/src/freetype2/type42/t42types.h @@ -0,0 +1,54 @@ +/***************************************************************************/ +/* */ +/* t42types.h */ +/* */ +/* Type 42 font data types (specification only). */ +/* */ +/* Copyright 2002, 2003, 2006 by Roberto Alameda. */ +/* */ +/* 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 __T42TYPES_H__ +#define __T42TYPES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + + +FT_BEGIN_HEADER + + + typedef struct T42_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_Byte* ttf_data; + FT_ULong ttf_size; + FT_Face ttf_face; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_UnicodesRec unicode_map; + + } T42_FaceRec, *T42_Face; + + +FT_END_HEADER + +#endif /* __T1TYPES_H__ */ + + +/* END */ diff --git a/src/freetype2/type42/type42.c b/src/freetype2/type42/type42.c new file mode 100644 index 0000000..d13df56 --- /dev/null +++ b/src/freetype2/type42/type42.c @@ -0,0 +1,25 @@ +/***************************************************************************/ +/* */ +/* type42.c */ +/* */ +/* FreeType Type 42 driver component. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> +#include "t42objs.c" +#include "t42parse.c" +#include "t42drivr.c" + +/* END */ diff --git a/src/freetype2/winfonts/fnterrs.h b/src/freetype2/winfonts/fnterrs.h new file mode 100644 index 0000000..ea80909 --- /dev/null +++ b/src/freetype2/winfonts/fnterrs.h @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* fnterrs.h */ +/* */ +/* Win FNT/FON error codes (specification only). */ +/* */ +/* Copyright 2001 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 Windows FNT/FON error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __FNTERRS_H__ +#define __FNTERRS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX FNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_Winfonts + +#include FT_ERRORS_H + +#endif /* __FNTERRS_H__ */ + + +/* END */ diff --git a/src/freetype2/winfonts/winfnt.c b/src/freetype2/winfonts/winfnt.c new file mode 100644 index 0000000..4aa9744 --- /dev/null +++ b/src/freetype2/winfonts/winfnt.c @@ -0,0 +1,1122 @@ +/***************************************************************************/ +/* */ +/* winfnt.c */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* Copyright 2003 Huw D M Davies for Codeweavers */ +/* Copyright 2007 Dmitry Timoshkov for Codeweavers */ +/* */ +/* 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_WINFONTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_OBJECTS_H + +#include "winfnt.h" +#include "fnterrs.h" +#include FT_SERVICE_WINFNT_H +#include FT_SERVICE_XFREE86_NAME_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_winfnt + + + static const FT_Frame_Field winmz_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinMZ_HeaderRec + + FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 29 * 2 ), + FT_FRAME_ULONG_LE ( lfanew ), + FT_FRAME_END + }; + + static const FT_Frame_Field winne_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinNE_HeaderRec + + FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE ( resource_tab_offset ), + FT_FRAME_USHORT_LE ( rname_tab_offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_HeaderRec + + FT_FRAME_START( 248 ), + FT_FRAME_ULONG_LE ( magic ), /* PE00 */ + FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */ + FT_FRAME_USHORT_LE ( number_of_sections ), + FT_FRAME_SKIP_BYTES( 12 ), + FT_FRAME_USHORT_LE ( size_of_optional_header ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */ + FT_FRAME_SKIP_BYTES( 110 ), + FT_FRAME_ULONG_LE ( rsrc_virtual_address ), + FT_FRAME_ULONG_LE ( rsrc_size ), + FT_FRAME_SKIP_BYTES( 104 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_section_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_SectionRec + + FT_FRAME_START( 40 ), + FT_FRAME_BYTES ( name, 8 ), + FT_FRAME_SKIP_BYTES( 4 ), + FT_FRAME_ULONG_LE ( virtual_address ), + FT_FRAME_ULONG_LE ( size_of_raw_data ), + FT_FRAME_ULONG_LE ( pointer_to_raw_data ), + FT_FRAME_SKIP_BYTES( 16 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE ( characteristics ), + FT_FRAME_ULONG_LE ( time_date_stamp ), + FT_FRAME_USHORT_LE( major_version ), + FT_FRAME_USHORT_LE( minor_version ), + FT_FRAME_USHORT_LE( number_of_named_entries ), + FT_FRAME_USHORT_LE( number_of_id_entries ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirEntryRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( name ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDataEntryRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( offset_to_data ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( code_page ), + FT_FRAME_ULONG_LE( reserved ), + FT_FRAME_END + }; + + static const FT_Frame_Field winfnt_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_WinFNT_HeaderRec + + FT_FRAME_START( 148 ), + FT_FRAME_USHORT_LE( version ), + FT_FRAME_ULONG_LE ( file_size ), + FT_FRAME_BYTES ( copyright, 60 ), + FT_FRAME_USHORT_LE( file_type ), + FT_FRAME_USHORT_LE( nominal_point_size ), + FT_FRAME_USHORT_LE( vertical_resolution ), + FT_FRAME_USHORT_LE( horizontal_resolution ), + FT_FRAME_USHORT_LE( ascent ), + FT_FRAME_USHORT_LE( internal_leading ), + FT_FRAME_USHORT_LE( external_leading ), + FT_FRAME_BYTE ( italic ), + FT_FRAME_BYTE ( underline ), + FT_FRAME_BYTE ( strike_out ), + FT_FRAME_USHORT_LE( weight ), + FT_FRAME_BYTE ( charset ), + FT_FRAME_USHORT_LE( pixel_width ), + FT_FRAME_USHORT_LE( pixel_height ), + FT_FRAME_BYTE ( pitch_and_family ), + FT_FRAME_USHORT_LE( avg_width ), + FT_FRAME_USHORT_LE( max_width ), + FT_FRAME_BYTE ( first_char ), + FT_FRAME_BYTE ( last_char ), + FT_FRAME_BYTE ( default_char ), + FT_FRAME_BYTE ( break_char ), + FT_FRAME_USHORT_LE( bytes_per_row ), + FT_FRAME_ULONG_LE ( device_offset ), + FT_FRAME_ULONG_LE ( face_name_offset ), + FT_FRAME_ULONG_LE ( bits_pointer ), + FT_FRAME_ULONG_LE ( bits_offset ), + FT_FRAME_BYTE ( reserved ), + FT_FRAME_ULONG_LE ( flags ), + FT_FRAME_USHORT_LE( A_space ), + FT_FRAME_USHORT_LE( B_space ), + FT_FRAME_USHORT_LE( C_space ), + FT_FRAME_ULONG_LE ( color_table_offset ), + FT_FRAME_BYTES ( reserved1, 16 ), + FT_FRAME_END + }; + + + static void + fnt_font_done( FNT_Face face ) + { + FT_Memory memory = FT_FACE( face )->memory; + FT_Stream stream = FT_FACE( face )->stream; + FNT_Font font = face->font; + + + if ( !font ) + return; + + if ( font->fnt_frame ) + FT_FRAME_RELEASE( font->fnt_frame ); + FT_FREE( font->family_name ); + + FT_FREE( font ); + face->font = 0; + } + + + static FT_Error + fnt_font_load( FNT_Font font, + FT_Stream stream ) + { + FT_Error error; + FT_WinFNT_Header header = &font->header; + FT_Bool new_format; + FT_UInt size; + + + /* first of all, read the FNT header */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) + goto Exit; + + /* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( "[not a valid FNT file]\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } + + new_format = FT_BOOL( font->header.version == 0x300 ); + size = new_format ? 148 : 118; + + if ( header->file_size < size ) + { + FT_TRACE2(( "[not a valid FNT file]\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } + + /* Version 2 doesn't have these fields */ + if ( header->version == 0x200 ) + { + header->flags = 0; + header->A_space = 0; + header->B_space = 0; + header->C_space = 0; + + header->color_table_offset = 0; + } + + if ( header->file_type & 1 ) + { + FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } + + /* this is a FNT file/table; extract its frame */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + fnt_face_get_dll_font( FNT_Face face, + FT_Int face_index ) + { + FT_Error error; + FT_Stream stream = FT_FACE( face )->stream; + FT_Memory memory = FT_FACE( face )->memory; + WinMZ_HeaderRec mz_header; + + + face->font = 0; + + /* does it begin with an MZ header? */ + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) + goto Exit; + + error = FNT_Err_Unknown_File_Format; + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { + /* yes, now look for an NE header in the file */ + WinNE_HeaderRec ne_header; + + + FT_TRACE2(( "MZ signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) + goto Exit; + + error = FNT_Err_Unknown_File_Format; + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { + /* good, now look into the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + + ne_header.resource_tab_offset; + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + + + FT_TRACE2(( "NE signature found\n" )); + + if ( FT_STREAM_SEEK( res_offset ) || + FT_FRAME_ENTER( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + + size_shift = FT_GET_USHORT_LE(); + + for (;;) + { + FT_UShort type_id, count; + + + type_id = FT_GET_USHORT_LE(); + if ( !type_id ) + break; + + count = FT_GET_USHORT_LE(); + + if ( type_id == 0x8008U ) + { + font_count = count; + font_offset = (FT_ULong)( FT_STREAM_POS() + 4 + + ( stream->cursor - stream->limit ) ); + break; + } + + stream->cursor += 4 + count * 12; + } + + FT_FRAME_EXIT(); + + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "this file doesn't contain any FNT resources!\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + /* loading `winfnt_header_fields' needs at least 118 bytes; */ + /* use this as a rough measure to check the expected font size */ + if ( font_count * 118UL > stream->size ) + { + FT_TRACE2(( "invalid number of faces\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + face->root.num_faces = font_count; + + if ( face_index >= font_count ) + { + error = FNT_Err_Bad_Argument; + goto Exit; + } + + if ( FT_NEW( face->font ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) || + FT_FRAME_ENTER( 12 ) ) + goto Fail; + + face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + + stream->cursor += 8; + + FT_FRAME_EXIT(); + + error = fnt_font_load( face->font, stream ); + } + else if ( ne_header.magic == WINFNT_PE_MAGIC ) + { + WinPE32_HeaderRec pe32_header; + WinPE32_SectionRec pe32_section; + WinPE_RsrcDirRec root_dir, name_dir, lang_dir; + WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; + WinPE_RsrcDataEntryRec data_entry; + + FT_Long root_dir_offset, name_dir_offset, lang_dir_offset; + FT_UShort i, j, k; + + + FT_TRACE2(( "PE signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) + goto Exit; + + FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " + "size_of_optional_header %02x\n" + "magic32 %02x, rsrc_virtual_address %04lx, " + "rsrc_size %04lx\n", + pe32_header.magic, pe32_header.machine, + pe32_header.number_of_sections, + pe32_header.size_of_optional_header, + pe32_header.magic32, pe32_header.rsrc_virtual_address, + pe32_header.rsrc_size )); + + if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || + pe32_header.machine != 0x014c /* i386 */ || + pe32_header.size_of_optional_header != 0xe0 /* FIXME */ || + pe32_header.magic32 != 0x10b ) + { + FT_TRACE2(( "this file has an invalid PE header\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + face->root.num_faces = 0; + + for ( i = 0; i < pe32_header.number_of_sections; i++ ) + { + if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, + &pe32_section ) ) + goto Exit; + + FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", + pe32_section.name, pe32_section.virtual_address, + pe32_section.size_of_raw_data, + pe32_section.pointer_to_raw_data )); + + if ( pe32_header.rsrc_virtual_address == + pe32_section.virtual_address ) + goto Found_rsrc_section; + } + + FT_TRACE2(( "this file doesn't contain any resources\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + + Found_rsrc_section: + FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) + goto Exit; + + root_dir_offset = pe32_section.pointer_to_raw_data; + + for ( i = 0; i < root_dir.number_of_named_entries + + root_dir.number_of_id_entries; i++ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry1 ) ) + goto Exit; + + if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + dir_entry1.offset &= ~0x80000000UL; + + name_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry1.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry1.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) + goto Exit; + + for ( j = 0; j < name_dir.number_of_named_entries + + name_dir.number_of_id_entries; j++ ) + { + if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry2 ) ) + goto Exit; + + if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + dir_entry2.offset &= ~0x80000000UL; + + lang_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry2.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry2.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) + goto Exit; + + for ( k = 0; k < lang_dir.number_of_named_entries + + lang_dir.number_of_id_entries; k++ ) + { + if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry3 ) ) + goto Exit; + + if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( dir_entry1.name == 8 /* RT_FONT */ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, + &data_entry ) ) + goto Exit; + + FT_TRACE2(( "found font #%lu, offset %04lx, " + "size %04lx, cp %lu\n", + dir_entry2.name, + pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address, + data_entry.size, data_entry.code_page )); + + if ( face_index == face->root.num_faces ) + { + if ( FT_NEW( face->font ) ) + goto Exit; + + face->font->offset = pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address; + face->font->fnt_size = data_entry.size; + + error = fnt_font_load( face->font, stream ); + if ( error ) + { + FT_TRACE2(( "font #%lu load error %d\n", + dir_entry2.name, error )); + goto Fail; + } + else + FT_TRACE2(( "font #%lu successfully loaded\n", + dir_entry2.name )); + } + + face->root.num_faces++; + } + } + } + } + } + + if ( !face->root.num_faces ) + { + FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( face_index >= face->root.num_faces ) + { + error = FNT_Err_Bad_Argument; + goto Exit; + } + } + + Fail: + if ( error ) + fnt_font_done( face ); + + Exit: + return error; + } + + + typedef struct FNT_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt32 first; + FT_UInt32 count; + + } FNT_CMapRec, *FNT_CMap; + + + static FT_Error + fnt_cmap_init( FNT_CMap cmap ) + { + FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); + FNT_Font font = face->font; + + + cmap->first = (FT_UInt32) font->header.first_char; + cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); + + return 0; + } + + + static FT_UInt + fnt_cmap_char_index( FNT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UInt gindex = 0; + + + char_code -= cmap->first; + if ( char_code < cmap->count ) + gindex = char_code + 1; /* we artificially increase the glyph index; */ + /* FNT_Load_Glyph reverts to the right one */ + return gindex; + } + + + static FT_UInt + fnt_cmap_char_next( FNT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + if ( char_code <= cmap->first ) + { + result = cmap->first; + gindex = 1; + } + else + { + char_code -= cmap->first; + if ( char_code < cmap->count ) + { + result = cmap->first + char_code; + gindex = char_code + 1; + } + } + + *pchar_code = result; + return gindex; + } + + + static const FT_CMap_ClassRec fnt_cmap_class_rec = + { + sizeof ( FNT_CMapRec ), + + (FT_CMap_InitFunc) fnt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)fnt_cmap_char_index, + (FT_CMap_CharNextFunc) fnt_cmap_char_next + }; + + static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; + + + static void + FNT_Face_Done( FNT_Face face ) + { + if ( face ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + fnt_font_done( face ); + + FT_FREE( face->root.available_sizes ); + face->root.num_fixed_sizes = 0; + } + } + + + static FT_Error + FNT_Face_Init( FT_Stream stream, + FNT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* try to load font from a DLL */ + error = fnt_face_get_dll_font( face, face_index ); + if ( error == FNT_Err_Unknown_File_Format ) + { + /* this didn't work; try to load a single FNT font */ + FNT_Font font; + + + if ( face_index > 0 ) + { + error = FNT_Err_Bad_Argument; + goto Exit; + } + + if ( FT_NEW( face->font ) ) + goto Exit; + + face->root.num_faces = 1; + + font = face->font; + font->offset = 0; + font->fnt_size = stream->size; + + error = fnt_font_load( font, stream ); + } + + if ( error ) + goto Fail; + + /* we now need to fill the root FT_Face fields */ + /* with relevant information */ + { + FT_Face root = FT_FACE( face ); + FNT_Font font = face->font; + FT_PtrDist family_size; + + + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( font->header.avg_width == font->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( font->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( font->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + /* set up the `fixed_sizes' array */ + if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + goto Fail; + + root->num_fixed_sizes = 1; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_UShort x_res, y_res; + + + bsize->width = font->header.avg_width; + bsize->height = (FT_Short)( + font->header.pixel_height + font->header.external_leading ); + bsize->size = font->header.nominal_point_size << 6; + + x_res = font->header.horizontal_resolution; + if ( !x_res ) + x_res = 72; + + y_res = font->header.vertical_resolution; + if ( !y_res ) + y_res = 72; + + bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); + bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); + + /* + * this reads: + * + * the nominal height is larger than the bbox's height + * + * => nominal_point_size contains incorrect value; + * use pixel_height as the nominal height + */ + if ( bsize->y_ppem > font->header.pixel_height << 6 ) + { + FT_TRACE2(( "use pixel_height as the nominal height\n" )); + + bsize->y_ppem = font->header.pixel_height << 6; + bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); + } + + bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); + bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); + } + + { + FT_CharMapRec charmap; + + + charmap.encoding = FT_ENCODING_NONE; + charmap.platform_id = 0; + charmap.encoding_id = 0; + charmap.face = root; + + if ( font->header.charset == FT_WinFNT_ID_MAC ) + { + charmap.encoding = FT_ENCODING_APPLE_ROMAN; + charmap.platform_id = 1; +/* charmap.encoding_id = 0; */ + } + + error = FT_CMap_New( fnt_cmap_class, + NULL, + &charmap, + NULL ); + if ( error ) + goto Fail; + + /* Select default charmap */ + if ( root->num_charmaps ) + root->charmap = root->charmaps[0]; + } + + /* setup remaining flags */ + + /* reserve one slot for the .notdef glyph at index 0 */ + root->num_glyphs = font->header.last_char - + font->header.first_char + 1 + 1; + + if ( font->header.face_name_offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid family name offset!\n" )); + error = FNT_Err_Invalid_File_Format; + goto Fail; + } + family_size = font->header.file_size - font->header.face_name_offset; + /* Some broken fonts don't delimit the face name with a final */ + /* NULL byte -- the frame is erroneously one byte too small. */ + /* We thus allocate one more byte, setting it explicitly to */ + /* zero. */ + if ( FT_ALLOC( font->family_name, family_size + 1 ) ) + goto Fail; + + FT_MEM_COPY( font->family_name, + font->fnt_frame + font->header.face_name_offset, + family_size ); + + font->family_name[family_size] = '\0'; + + if ( FT_REALLOC( font->family_name, + family_size, + ft_strlen( font->family_name ) + 1 ) ) + goto Fail; + + root->family_name = font->family_name; + root->style_name = (char *)"Regular"; + + if ( root->style_flags & FT_STYLE_FLAG_BOLD ) + { + if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Bold Italic"; + else + root->style_name = (char *)"Bold"; + } + else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Italic"; + } + goto Exit; + + Fail: + FNT_Face_Done( face ); + + Exit: + return error; + } + + + static FT_Error + FNT_Size_Select( FT_Size size ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + + + FT_Select_Metrics( size->face, 0 ); + + size->metrics.ascender = header->ascent * 64; + size->metrics.descender = -( header->pixel_height - + header->ascent ) * 64; + size->metrics.max_advance = header->max_width * 64; + + return FNT_Err_Ok; + } + + + static FT_Error + FNT_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FNT_Err_Invalid_Pixel_Size; + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( bsize->y_ppem + 32 ) >> 6 ) + error = FNT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == header->pixel_height ) + error = FNT_Err_Ok; + break; + + default: + error = FNT_Err_Unimplemented_Feature; + break; + } + + if ( error ) + return error; + else + return FNT_Size_Select( size ); + } + + + static FT_Error + FNT_Load_Glyph( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); + FNT_Font font = face->font; + FT_Error error = FNT_Err_Ok; + FT_Byte* p; + FT_Int len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + + FT_UNUSED( load_flags ); + + + if ( !face || !font || + glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) + { + error = FNT_Err_Invalid_Argument; + goto Exit; + } + + if ( glyph_index > 0 ) + glyph_index--; /* revert to real index */ + else + glyph_index = font->header.default_char; /* the .notdef glyph */ + + new_format = FT_BOOL( font->header.version == 0x300 ); + len = new_format ? 6 : 4; + + /* jump to glyph entry */ + p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index; + + bitmap->width = FT_NEXT_SHORT_LE( p ); + + if ( new_format ) + offset = FT_NEXT_ULONG_LE( p ); + else + offset = FT_NEXT_USHORT_LE( p ); + + if ( offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid FNT offset!\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + /* jump to glyph data */ + p = font->fnt_frame + /* font->header.bits_offset */ + offset; + + /* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Int pitch = ( bitmap->width + 7 ) >> 3; + FT_Byte* column; + FT_Byte* write; + + + bitmap->pitch = pitch; + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + if ( offset + pitch * bitmap->rows >= font->header.file_size ) + { + FT_TRACE2(( "invalid bitmap width\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + + /* note: since glyphs are stored in columns and not in rows we */ + /* can't use ft_glyphslot_set_bitmap */ + if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) ) + goto Exit; + + column = (FT_Byte*)bitmap->buffer; + + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + + + for ( write = column; p < limit; p++, write += bitmap->pitch ) + *write = *p; + } + } + + slot->internal->flags = FT_GLYPH_OWN_BITMAP; + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = FT_GLYPH_FORMAT_BITMAP; + + /* now set up metrics */ + slot->metrics.width = bitmap->width << 6; + slot->metrics.height = bitmap->rows << 6; + slot->metrics.horiAdvance = bitmap->width << 6; + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + + ft_synthesize_vertical_metrics( &slot->metrics, + bitmap->rows << 6 ); + + Exit: + return error; + } + + + static FT_Error + winfnt_get_header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ) + { + FNT_Font font = ((FNT_Face)face)->font; + + + *aheader = font->header; + + return 0; + } + + + static const FT_Service_WinFntRec winfnt_service_rec = + { + winfnt_get_header + }; + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec winfnt_services[] = + { + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT }, + { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, + { NULL, NULL } + }; + + + static FT_Module_Interface + winfnt_get_service( FT_Driver driver, + const FT_String* service_id ) + { + FT_UNUSED( driver ); + + return ft_service_list_lookup( winfnt_services, service_id ); + } + + + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec winfnt_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "winfonts", + 0x10000L, + 0x20000L, + + 0, + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) winfnt_get_service + }, + + sizeof( FNT_FaceRec ), + sizeof( FT_SizeRec ), + sizeof( FT_GlyphSlotRec ), + + (FT_Face_InitFunc) FNT_Face_Init, + (FT_Face_DoneFunc) FNT_Face_Done, + (FT_Size_InitFunc) 0, + (FT_Size_DoneFunc) 0, + (FT_Slot_InitFunc) 0, + (FT_Slot_DoneFunc) 0, + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + ft_stub_set_char_sizes, + ft_stub_set_pixel_sizes, +#endif + (FT_Slot_LoadFunc) FNT_Load_Glyph, + + (FT_Face_GetKerningFunc) 0, + (FT_Face_AttachFunc) 0, + (FT_Face_GetAdvancesFunc) 0, + + (FT_Size_RequestFunc) FNT_Size_Request, + (FT_Size_SelectFunc) FNT_Size_Select + }; + + +/* END */ diff --git a/src/freetype2/winfonts/winfnt.h b/src/freetype2/winfonts/winfnt.h new file mode 100644 index 0000000..ca75c95 --- /dev/null +++ b/src/freetype2/winfonts/winfnt.h @@ -0,0 +1,167 @@ +/***************************************************************************/ +/* */ +/* winfnt.h */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* Copyright 2007 Dmitry Timoshkov for Codeweavers */ +/* */ +/* 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 __WINFNT_H__ +#define __WINFNT_H__ + + +#include <ft2build.h> +#include FT_WINFONTS_H +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + typedef struct WinMZ_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort lfanew; + + } WinMZ_HeaderRec; + + + typedef struct WinNE_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + + } WinNE_HeaderRec; + + + typedef struct WinPE32_HeaderRec_ + { + FT_ULong magic; + FT_UShort machine; + FT_UShort number_of_sections; + /* skipped content */ + FT_UShort size_of_optional_header; + /* skipped content */ + FT_UShort magic32; + /* skipped content */ + FT_ULong rsrc_virtual_address; + FT_ULong rsrc_size; + /* skipped content */ + + } WinPE32_HeaderRec; + + + typedef struct WinPE32_SectionRec_ + { + FT_Byte name[8]; + /* skipped content */ + FT_ULong virtual_address; + FT_ULong size_of_raw_data; + FT_ULong pointer_to_raw_data; + /* skipped content */ + + } WinPE32_SectionRec; + + + typedef struct WinPE_RsrcDirRec_ + { + FT_ULong characteristics; + FT_ULong time_date_stamp; + FT_UShort major_version; + FT_UShort minor_version; + FT_UShort number_of_named_entries; + FT_UShort number_of_id_entries; + + } WinPE_RsrcDirRec; + + + typedef struct WinPE_RsrcDirEntryRec_ + { + FT_ULong name; + FT_ULong offset; + + } WinPE_RsrcDirEntryRec; + + + typedef struct WinPE_RsrcDataEntryRec_ + { + FT_ULong offset_to_data; + FT_ULong size; + FT_ULong code_page; + FT_ULong reserved; + + } WinPE_RsrcDataEntryRec; + + + typedef struct WinNameInfoRec_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + + } WinNameInfoRec; + + + typedef struct WinResourceInfoRec_ + { + FT_UShort type_id; + FT_UShort count; + + } WinResourceInfoRec; + + +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E +#define WINFNT_PE_MAGIC 0x4550 + + + typedef struct FNT_FontRec_ + { + FT_ULong offset; + + FT_WinFNT_HeaderRec header; + + FT_Byte* fnt_frame; + FT_ULong fnt_size; + FT_String* family_name; + + } FNT_FontRec, *FNT_Font; + + + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + FNT_Font font; + + FT_CharMap charmap_handle; + FT_CharMapRec charmap; /* a single charmap per face */ + + } FNT_FaceRec, *FNT_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) winfnt_driver_class; + + +FT_END_HEADER + + +#endif /* __WINFNT_H__ */ + + +/* END */ diff --git a/src/gdiplus/cdcontextplus.def b/src/gdiplus/cdcontextplus.def new file mode 100644 index 0000000..92175a6 --- /dev/null +++ b/src/gdiplus/cdcontextplus.def @@ -0,0 +1,9 @@ +EXPORTS + cdInitContextPlus + cdInitGdiPlus + cdwpCreateCanvas + cdwpGdiPlusStartup + cdwpGdiPlusShutdown + cdwpInitTable + cdwpUpdateCanvas + cdwpKillCanvas diff --git a/src/gdiplus/cdgdiplus.def b/src/gdiplus/cdgdiplus.def new file mode 100644 index 0000000..92175a6 --- /dev/null +++ b/src/gdiplus/cdgdiplus.def @@ -0,0 +1,9 @@ +EXPORTS + cdInitContextPlus + cdInitGdiPlus + cdwpCreateCanvas + cdwpGdiPlusStartup + cdwpGdiPlusShutdown + cdwpInitTable + cdwpUpdateCanvas + cdwpKillCanvas diff --git a/src/gdiplus/cdwclpp.cpp b/src/gdiplus/cdwclpp.cpp new file mode 100644 index 0000000..719713f --- /dev/null +++ b/src/gdiplus/cdwclpp.cpp @@ -0,0 +1,206 @@ +/** \file + * \brief Windows GDI+ Clipboard Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdemf.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cdmf_private.h" + + +static void cdkillcanvasCLIPBDMF (cdCtxCanvas* ctxcanvas) +{ + HANDLE Handle, hFile; + char* buffer; + DWORD dwSize, nBytesRead; + char filename[10240]; + cdCanvasMF* mfcanvas = (cdCanvasMF*)ctxcanvas; + + /* guardar antes de remover o canvas */ + strcpy(filename, mfcanvas->filename); + + OpenClipboard(NULL); + EmptyClipboard(); + + cdkillcanvasMF(mfcanvas); /* this will close the file */ + + hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); + dwSize = GetFileSize (hFile, NULL) ; + + Handle = GlobalAlloc(GMEM_MOVEABLE, dwSize+1); + buffer = (char*)GlobalLock(Handle); + ReadFile(hFile, buffer, dwSize, &nBytesRead, NULL); + buffer[dwSize] = 0; + GlobalUnlock(Handle); + + CloseHandle(hFile); + + SetClipboardData(CF_TEXT, Handle); + + CloseClipboard(); +} + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + OpenClipboard(NULL); + EmptyClipboard(); + + if (ctxcanvas->wtype == CDW_EMF) + { + HENHMETAFILE hEmf = ctxcanvas->metafile->GetHENHMETAFILE(); + SetClipboardData(CF_ENHMETAFILE, hEmf); + delete ctxcanvas->metafile; + } + else + { + HBITMAP hBitmap; + ctxcanvas->bitmap->GetHBITMAP(ctxcanvas->bg, &hBitmap); + SetClipboardData(CF_BITMAP, hBitmap); + delete ctxcanvas->bitmap; + } + + CloseClipboard(); + + delete ctxcanvas; +} + +/* +%F cdCreateCanvas para Clipboard +O DC pode ser um WMF ou um BITMAP. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char* strsize = (char*)data; + int w = 0, h = 0, wtype = CDW_EMF; /* default clipboard type */ + double res = 0; /* used only for BMP */ + Metafile* metafile = NULL; + Bitmap* bitmap = NULL; + Graphics* graphics; + + /* Inicializa parametros */ + if (strsize == NULL) + return; + + if (strstr(strsize, "-b") != NULL) + wtype = CDW_BMP; + else if (strstr(strsize, "-m") != NULL) + wtype = -1; /* CD METAFILE */ + + if (wtype != -1) + { + sscanf(strsize,"%dx%d %g",&w, &h, &res); + if (w == 0 || h == 0) + return; + } + + if (wtype == CDW_EMF) + { + HDC ScreenDC = GetDC(NULL); + /* LOGPIXELS can not be used for EMF */ + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + + Rect frameRect(0, 0, (int)(100 * w / canvas->xres), (int)(100 * h / canvas->yres)); + + metafile = new Metafile(ScreenDC, frameRect, MetafileFrameUnitGdi, EmfTypeEmfPlusDual, NULL); + ReleaseDC(NULL, ScreenDC); + + if (!metafile) + return; + + graphics = new Graphics(metafile); + } + else if (wtype == CDW_BMP) + { + if (!res) + { + HDC ScreenDC = GetDC(NULL); + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + ReleaseDC(NULL, ScreenDC); + } + else + { + canvas->xres = res; + canvas->yres = res; + } + + bitmap = new Bitmap(w, h, PixelFormat24bppRGB); + if (!bitmap) + return; + + bitmap->SetResolution((REAL)(canvas->xres*25.4), (REAL)(canvas->xres*25.4)); + + graphics = new Graphics(bitmap); + } + + if (wtype == -1) + { + char filename[1024]; + char tmpPath[512]; + char str[1024]; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + sprintf(str, "%s %s", filename, strsize); + cdcreatecanvasMF(canvas, str); + } + else + { + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, wtype); + + canvas->w = w; + canvas->h = h; + canvas->bpp = 24; + + if (wtype == CDW_BMP) + ctxcanvas->bitmap = bitmap; + else + ctxcanvas->metafile = metafile; + } +} + +static void cdinittable(cdCanvas* canvas) +{ + if (canvas->invert_yaxis == 0) /* a simple way to distinguish MF from WIN */ + { + cdinittableMF(canvas); + canvas->cxKillCanvas = cdkillcanvasCLIPBDMF; + } + else + { + cdwpInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; + } +} + +static cdContext cdClipboardContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_FLUSH | CD_CAP_YAXIS | + CD_CAP_PLAY | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextClipboardPlus(void) +{ + return &cdClipboardContext; +} +} diff --git a/src/gdiplus/cdwdbufp.cpp b/src/gdiplus/cdwdbufp.cpp new file mode 100644 index 0000000..6d968b2 --- /dev/null +++ b/src/gdiplus/cdwdbufp.cpp @@ -0,0 +1,152 @@ +/** \file + * \brief Windows GDI+ Double Buffer + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cddbuf.h" +#include <stdlib.h> +#include <stdio.h> + + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + delete ctxcanvas->bitmap; + + delete ctxcanvas; +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + if (ctxcanvas->dirty || ctxcanvas->bitmap_dbuffer == NULL) + { + ctxcanvas->dirty = 0; + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + ctxcanvas->bitmap_dbuffer = new CachedBitmap(ctxcanvas->bitmap, canvas_dbuffer->ctxcanvas->graphics); + } + + ctxcanvas->graphics->Flush(FlushIntentionSync); + + /* this is done in the canvas_dbuffer context */ + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + canvas_dbuffer->ctxcanvas->graphics->ResetTransform(); + + int x = 0, y = 0; + if (canvas_dbuffer->use_origin) + { + x += canvas_dbuffer->origin.x; + if (canvas_dbuffer->invert_yaxis) + y -= canvas_dbuffer->origin.y; // top down shift + else + y += canvas_dbuffer->origin.y; + } + + int old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + canvas_dbuffer->ctxcanvas->graphics->DrawCachedBitmap(ctxcanvas->bitmap_dbuffer, x, y); + canvas_dbuffer->ctxcanvas->graphics->Flush(FlushIntentionSync); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->canvas->w || + canvas_dbuffer->h != ctxcanvas->canvas->h) + { + delete ctxcanvas->graphics; + delete ctxcanvas->bitmap; + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + ctxcanvas->bitmap_dbuffer = NULL; + + Bitmap* bitmap = new Bitmap(canvas_dbuffer->w, canvas_dbuffer->h, PixelFormat24bppRGB); + bitmap->SetResolution((REAL)(canvas_dbuffer->xres*25.4), (REAL)(canvas_dbuffer->yres*25.4)); + + ctxcanvas->bitmap = bitmap; + ctxcanvas->graphics = new Graphics(bitmap); + + ctxcanvas->canvas->w = canvas_dbuffer->w; + ctxcanvas->canvas->h = canvas_dbuffer->h; + + ctxcanvas->dirty = 1; + + cdwpUpdateCanvas(ctxcanvas); + } + + return CD_OK; +} + +/* +%F cdCreateCanvas para DBuffer. +O DC é um BITMAP em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCanvas* canvas_dbuffer = (cdCanvas*)data; + if (!canvas_dbuffer) + return; + + Bitmap* bitmap = new Bitmap(canvas_dbuffer->w, canvas_dbuffer->h, PixelFormat24bppRGB); + bitmap->SetResolution((REAL)(canvas_dbuffer->xres*25.4), (REAL)(canvas_dbuffer->yres*25.4)); + + Graphics imggraphics(bitmap); + imggraphics.Clear(Color::White); + + Graphics* graphics = new Graphics(bitmap); + + canvas->w = canvas_dbuffer->w; + canvas->h = canvas_dbuffer->h; + canvas->bpp = 24; + + /* Initialize base driver */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_BMP); + + ctxcanvas->bitmap = bitmap; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxFlush = cdflush; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdDBufferContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextDBufferPlus(void) +{ + return &cdDBufferContext; +} +} diff --git a/src/gdiplus/cdwemfp.cpp b/src/gdiplus/cdwemfp.cpp new file mode 100644 index 0000000..38b4200 --- /dev/null +++ b/src/gdiplus/cdwemfp.cpp @@ -0,0 +1,105 @@ +/** \file + * \brief Windows GDI+ EMF Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdemf.h" +#include <stdlib.h> +#include <stdio.h> + + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + delete ctxcanvas->metafile; + delete ctxcanvas; +} + +/* +%F cdCreateCanvas para EMF. +O DC é um EMF em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + char* strdata = (char*)data; + char filename[10240] = ""; + Metafile* metafile; + + /* Inicializa parametros */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + int w = 0, h = 0; + sscanf(strdata,"%dx%d", &w, &h); + if (w == 0 || h == 0) + return; + + { + /* Verifica se o arquivo pode ser aberto para escrita */ + FILE* file = fopen(filename, "wb"); + if (file == NULL) + return; + fclose(file); + } + + { + HDC ScreenDC = GetDC(NULL); + /* LOGPIXELS can not be used for EMF */ + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + + Rect frameRect(0, 0, (int)(100 * w / canvas->xres), (int)(100 * h / canvas->yres)); + + metafile = new Metafile(cdwpString2Unicode(filename, strlen(filename)), + ScreenDC, frameRect, MetafileFrameUnitGdi, EmfTypeEmfPlusDual, NULL); + + ReleaseDC(NULL, ScreenDC); + } + + canvas->w = w; + canvas->h = h; + canvas->bpp = 24; + + Graphics* graphics = new Graphics(metafile); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_EMF); + + /* Inicializacao de variaveis particulares para o EMF */ + ctxcanvas->metafile = metafile; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdEMFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_FLUSH | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES | + CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextEMFPlus(void) +{ + return &cdEMFContext; +} +} + + diff --git a/src/gdiplus/cdwgdiplus.c b/src/gdiplus/cdwgdiplus.c new file mode 100644 index 0000000..a6862bc --- /dev/null +++ b/src/gdiplus/cdwgdiplus.c @@ -0,0 +1,42 @@ +/** \file + * \brief GDI+ Control + * + * See Copyright Notice in cd.h + */ + +#include "cd.h" +#include "cd_private.h" +#include "cdgdiplus.h" +#include <stdlib.h> +#include <memory.h> + +cdContext* cdContextNativeWindowPlus(void); +cdContext* cdContextImagePlus(void); +cdContext* cdContextDBufferPlus(void); +cdContext* cdContextPrinterPlus(void); +cdContext* cdContextEMFPlus(void); +cdContext* cdContextClipboardPlus(void); +void cdwpGdiPlusStartup(int debug); + +void cdInitGdiPlus(void) +{ + cdInitContextPlus(); +} + +void cdInitContextPlus(void) +{ + cdContext* ctx_list[NUM_CONTEXTPLUS]; + memset(ctx_list, 0, sizeof(ctx_list)); + + ctx_list[CD_CTX_NATIVEWINDOW] = cdContextNativeWindowPlus(); + ctx_list[CD_CTX_IMAGE] = cdContextImagePlus(); + ctx_list[CD_CTX_DBUFFER] = cdContextDBufferPlus(); + ctx_list[CD_CTX_PRINTER] = cdContextPrinterPlus(); + ctx_list[CD_CTX_EMF] = cdContextEMFPlus(); + ctx_list[CD_CTX_CLIPBOARD] = cdContextClipboardPlus(); + + cdInitContextPlusList(ctx_list); + + cdwpGdiPlusStartup(0); +} + diff --git a/src/gdiplus/cdwimgp.cpp b/src/gdiplus/cdwimgp.cpp new file mode 100644 index 0000000..697ff40 --- /dev/null +++ b/src/gdiplus/cdwimgp.cpp @@ -0,0 +1,65 @@ +/** \file + * \brief Windows GDI+ Image Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdimage.h" +#include <stdlib.h> +#include <stdio.h> + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + delete ctxcanvas; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + if (data == NULL) + return; + + cdCtxImage* ctximage = ((cdImage*)data)->ctximage; + + /* Inicializa parametros */ + if (ctximage == NULL) + return; + + Graphics* graphics = new Graphics(ctximage->bitmap); + + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->bpp = ctximage->bpp; + + /* Inicializa driver Image */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_BMP); + + ctxcanvas->bitmap = ctximage->bitmap; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextImagePlus(void) +{ + return &cdImageContext; +} +} diff --git a/src/gdiplus/cdwinp.cpp b/src/gdiplus/cdwinp.cpp new file mode 100644 index 0000000..d91ef6c --- /dev/null +++ b/src/gdiplus/cdwinp.cpp @@ -0,0 +1,2337 @@ +/** \file + * \brief Windows GDI+ Base Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdgdiplus.h" +#include "wd.h" +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index); + +void cdwpShowStatus(const char* title, Status status) +{ + char* status_str = ""; + switch(status) + { + case Ok: status_str = "Ok"; break; + case GenericError: status_str = "GenericError"; break; + case InvalidParameter: status_str = "InvalidParameter"; break; + case OutOfMemory: status_str = "OutOfMemory"; break; + case ObjectBusy: status_str = "ObjectBusy"; break; + case InsufficientBuffer: status_str = "InsufficientBuffer"; break; + case NotImplemented: status_str = "NotImplemented"; break; + case Win32Error: status_str = "Win32Error"; break; + case WrongState: status_str = "WrongState"; break; + case Aborted: status_str = "Aborted"; break; + case FileNotFound: status_str = "FileNotFound"; break; + case ValueOverflow: status_str = "ValueOverflow"; break; + case AccessDenied: status_str = "AccessDenied"; break; + case UnknownImageFormat: status_str = "UnknownImageFormat"; break; + case FontFamilyNotFound: status_str = "FontFamilyNotFound"; break; + case FontStyleNotFound: status_str = "FontStyleNotFound"; break; + case NotTrueTypeFont: status_str = "NotTrueTypeFont"; break; + case UnsupportedGdiplusVersion: status_str = "UnsupportedGdiplusVersion"; break; + case GdiplusNotInitialized: status_str = "GdiplusNotInitialized"; break; + case PropertyNotFound: status_str = "PropertyNotFound"; break; + case PropertyNotSupported: status_str = "PropertyNotSupported"; break; + } + + if (status != Ok) + MessageBox(NULL, status_str, title, MB_OK); +} + +/* +%F Libera memoria e handles alocados pelo driver Windows. +*/ +void cdwpKillCanvas(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_poly) delete[] ctxcanvas->clip_poly; + if (ctxcanvas->clip_region) delete ctxcanvas->clip_region; + if (ctxcanvas->new_region) delete ctxcanvas->new_region; + if (ctxcanvas->font) delete ctxcanvas->font; + if (ctxcanvas->wdpoly) delete ctxcanvas->wdpoly; + + delete ctxcanvas->fillBrush; + delete ctxcanvas->lineBrush; + delete ctxcanvas->linePen; + + delete ctxcanvas->graphics; + + /* ctxcanvas e´ liberado em cada driver */ +} + +static int cdwpSetTransform(cdCtxCanvas* ctxcanvas, Matrix &transformMatrix, const double* matrix) +{ + if (matrix) + { + // configure a bottom-up coordinate system + Matrix Matrix1((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(ctxcanvas->canvas->h-1)); + transformMatrix.Multiply(&Matrix1); + // add the global transform + Matrix Matrix2((REAL)matrix[0], (REAL)matrix[1], (REAL)matrix[2], (REAL)matrix[3], (REAL)matrix[4], (REAL)matrix[5]); + transformMatrix.Multiply(&Matrix2); + return 1; + } + else if (ctxcanvas->rotate_angle) + { + /* the rotation must be corrected because of the Y axis orientation */ + transformMatrix.Translate((REAL)ctxcanvas->rotate_center_x, (REAL)_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + transformMatrix.Rotate((REAL)-ctxcanvas->rotate_angle); + transformMatrix.Translate((REAL)-ctxcanvas->rotate_center_x, (REAL)-_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + return 1; + } + + return 0; +} + +static void cdwpUpdateTransform(cdCtxCanvas* ctxcanvas) +{ + Matrix transformMatrix; + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + if (cdwpSetTransform(ctxcanvas, transformMatrix, ctxcanvas->canvas->use_matrix? ctxcanvas->canvas->matrix: NULL)) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +/*********************************************************************/ +/* +%S Cor +*/ +/*********************************************************************/ + +static Color sColor2Windows(long int cd_color) +{ + return Color(cdAlpha(cd_color),cdRed(cd_color),cdGreen(cd_color),cdBlue(cd_color)); +} + +static void sUpdateFillBrush(cdCtxCanvas* ctxcanvas) +{ + // must update the fill brush that is dependent from the Foreground and Background Color. + BrushType type = ctxcanvas->fillBrush->GetType(); + switch(type) + { + case BrushTypeSolidColor: + { + SolidBrush* solidbrush = (SolidBrush*)ctxcanvas->fillBrush; + solidbrush->SetColor(ctxcanvas->fg); + break; + } + case BrushTypeHatchFill: + { + HatchBrush* hatchbrush = (HatchBrush*)ctxcanvas->fillBrush; + HatchStyle hatchStyle = hatchbrush->GetHatchStyle(); + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new HatchBrush(hatchStyle, ctxcanvas->fg, ctxcanvas->bg); + break; + } + case BrushTypeLinearGradient: + { + LinearGradientBrush* gradientbrush = (LinearGradientBrush*)ctxcanvas->fillBrush; + gradientbrush->SetLinearColors(ctxcanvas->fg, ctxcanvas->bg); + break; + } + case BrushTypeTextureFill: + { + // only stipple depends on Foreground and Background Color. + if (ctxcanvas->canvas->interior_style == CD_STIPPLE) + { + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + } + break; + } + } +} + +static long int cdforeground(cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->fg = sColor2Windows(color); + ctxcanvas->linePen->SetColor(ctxcanvas->fg); + ctxcanvas->lineBrush->SetColor(ctxcanvas->fg); + + sUpdateFillBrush(ctxcanvas); + + return color; +} + +static Color sSetAlpha(const Color& c, BYTE alpha) +{ + return Color(alpha, c.GetRed(), c.GetGreen(), c.GetBlue()); +} + +static long int cdbackground(cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->bg = sColor2Windows(color); + + if ((ctxcanvas->canvas->back_opacity == CD_TRANSPARENT) && + (cdAlpha(ctxcanvas->canvas->background) == 255)) + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)0); + + sUpdateFillBrush(ctxcanvas); + + return color; +} + +static int cdbackopacity(cdCtxCanvas* ctxcanvas, int opacity) +{ + switch (opacity) + { + case CD_TRANSPARENT: + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)0); + break; + case CD_OPAQUE: + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)255); + break; + } + + sUpdateFillBrush(ctxcanvas); + + return opacity; +} + +static void cdpalette(cdCtxCanvas* ctxcanvas, int pal_size, const long int *colors, int mode) +{ + (void)mode; + + if (ctxcanvas->wtype == CDW_BMP && + (ctxcanvas->bitmap->GetPixelFormat() == PixelFormat1bppIndexed || + ctxcanvas->bitmap->GetPixelFormat() == PixelFormat4bppIndexed || + ctxcanvas->bitmap->GetPixelFormat() == PixelFormat8bppIndexed)) + { + UINT size = ctxcanvas->bitmap->GetPaletteSize(); + ColorPalette* palette = new ColorPalette [size]; + + palette->Count = pal_size; + palette->Flags = 0; + + for (int c = 0; c < pal_size; c++) + { + palette->Entries[c] = sColor2Windows(colors[c]).GetValue(); + } + + ctxcanvas->bitmap->SetPalette(palette); + delete palette; + } +} + +/*********************************************************************/ +/* +%S Canvas e clipping +*/ +/*********************************************************************/ + +static void sClipRect(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + + Rect rect(ctxcanvas->canvas->clip_rect.xmin, + ctxcanvas->canvas->clip_rect.ymin, + ctxcanvas->canvas->clip_rect.xmax-ctxcanvas->canvas->clip_rect.xmin+1, + ctxcanvas->canvas->clip_rect.ymax-ctxcanvas->canvas->clip_rect.ymin+1); + + ctxcanvas->clip_region = new Region(rect); + + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); +} + +static void sClipPoly(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + + GraphicsPath path; + path.SetFillMode(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddPolygon(ctxcanvas->clip_poly, ctxcanvas->clip_poly_n); + ctxcanvas->clip_region = new Region(&path); + + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); +} + +static int cdclip(cdCtxCanvas* ctxcanvas, int clip_mode) +{ + switch (clip_mode) + { + case CD_CLIPOFF: + ctxcanvas->graphics->ResetClip(); + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + ctxcanvas->clip_region = NULL; + break; + case CD_CLIPAREA: + sClipRect(ctxcanvas); + break; + case CD_CLIPPOLYGON: + sClipPoly(ctxcanvas); + break; + case CD_CLIPREGION: + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + ctxcanvas->clip_region = ctxcanvas->new_region->Clone(); + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); + break; + } + + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.ymax = ymax; + + sClipRect(ctxcanvas); + } +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->new_region) + delete ctxcanvas->new_region; + ctxcanvas->new_region = new Region(); + ctxcanvas->new_region->MakeEmpty(); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return 0; + + if (ctxcanvas->new_region->IsVisible(x, y)) + return 1; + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return; + + ctxcanvas->new_region->Translate(x, y); +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + Rect rect; + + if (!ctxcanvas->new_region) + return; + + ctxcanvas->new_region->GetBounds(&rect, ctxcanvas->graphics); + + *xmin = rect.X; + *xmax = rect.X+rect.Width-1; + *ymin = rect.Y; + *ymax = rect.Y+rect.Height-1; +} + +static void sCombineRegion(cdCtxCanvas* ctxcanvas, Region& region) +{ + switch(ctxcanvas->canvas->combine_mode) + { + case CD_UNION: + ctxcanvas->new_region->Union(®ion); + break; + case CD_INTERSECT: + ctxcanvas->new_region->Intersect(®ion); + break; + case CD_DIFFERENCE: + ctxcanvas->new_region->Exclude(®ion); + break; + case CD_NOTINTERSECT: + ctxcanvas->new_region->Xor(®ion); + break; + } +} + +/******************************************************************/ +/* +%S Primitivas e seus atributos +*/ +/******************************************************************/ + +static int cdlinestyle(cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case (CD_CONTINUOUS): + { + ctxcanvas->linePen->SetDashStyle(DashStyleSolid); + break; + } + case CD_DASHED: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dashed[2] = {18.0f, 6.0f}; + ctxcanvas->linePen->SetDashPattern(dashed, 2); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDash); + break; + } + case CD_DOTTED: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dotted[2] = {3.0f, 3.0f}; + ctxcanvas->linePen->SetDashPattern(dotted, 2); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDot); + break; + } + case CD_DASH_DOT: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dash_dot[6] = {9.0f, 6.0f, 3.0f, 6.0f}; + ctxcanvas->linePen->SetDashPattern(dash_dot, 4); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDashDot); + break; + } + case CD_DASH_DOT_DOT: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dash_dot_dot[6] = {9.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f}; + ctxcanvas->linePen->SetDashPattern(dash_dot_dot, 6); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDashDotDot); + break; + } + case CD_CUSTOM: + { + REAL* dash_style = new REAL [ctxcanvas->canvas->line_dashes_count]; + for (int i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + dash_style[i] = (REAL)ctxcanvas->canvas->line_dashes[i]/(REAL)ctxcanvas->canvas->line_width; + ctxcanvas->linePen->SetDashPattern(dash_style, ctxcanvas->canvas->line_dashes_count); + delete [] dash_style; + break; + } + } + + return style; +} + +static int cdlinecap(cdCtxCanvas* ctxcanvas, int cap) +{ + LineCap cd2win_lcap[] = {LineCapFlat, LineCapSquare, LineCapRound}; + DashCap cd2win_dcap[] = {DashCapFlat, DashCapFlat, DashCapRound}; + + ctxcanvas->linePen->SetLineCap(cd2win_lcap[cap], cd2win_lcap[cap], cd2win_dcap[cap]); + + return cap; +} + +static int cdlinejoin(cdCtxCanvas* ctxcanvas, int join) +{ + LineJoin cd2win_join[] = {LineJoinMiter, LineJoinBevel, LineJoinRound}; + + ctxcanvas->linePen->SetLineJoin(cd2win_join[join]); + + return join; +} + +static int cdlinewidth(cdCtxCanvas* ctxcanvas, int width) +{ + ctxcanvas->linePen->SetWidth((REAL)width); + cdlinestyle(ctxcanvas, ctxcanvas->canvas->line_style); + return width; +} + +static int cdhatch(cdCtxCanvas* ctxcanvas, int hatch_style) +{ + HatchStyle hatchStyle; + + switch (hatch_style) + { + default: // CD_HORIZONTAL: + hatchStyle = HatchStyleHorizontal; + break; + case CD_VERTICAL: + hatchStyle = HatchStyleVertical; + break; + case CD_FDIAGONAL: + hatchStyle = HatchStyleForwardDiagonal; + break; + case CD_BDIAGONAL: + hatchStyle = HatchStyleBackwardDiagonal; + break; + case CD_CROSS: + hatchStyle = HatchStyleCross; + break; + case CD_DIAGCROSS: + hatchStyle = HatchStyleDiagonalCross; + break; + } + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new HatchBrush(hatchStyle, ctxcanvas->fg, ctxcanvas->bg); + + return hatch_style; +} + +static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index) +{ + ULONG* bitmap_data = new ULONG [w*h]; + + for(int j = 0; j < h; j++) + { + int line_offset_index; + int line_offset = j*w; + if (ctxcanvas->canvas->invert_yaxis) + line_offset_index = ((h - 1) - j)*w; // Fix up side down + else + line_offset_index = line_offset; + + for(int i = 0; i < w; i++) + { + if (index[line_offset_index+i] != 0) + bitmap_data[line_offset+i] = ctxcanvas->fg.GetValue(); + else + bitmap_data[line_offset+i] = ctxcanvas->bg.GetValue(); + } + } + + Bitmap StippleImage(w, h, 4*w, PixelFormat32bppARGB, (BYTE*)bitmap_data); + StippleImage.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new TextureBrush(&StippleImage); + + delete bitmap_data; +} + +static void cdpattern(cdCtxCanvas* ctxcanvas, int w, int h, const long int *colors) +{ + int stride = 4*w; + BYTE* bitmap_data = new BYTE [stride*h]; + + for(int j = 0; j < h; j++) + { + int line_offset_colors; + int line_offset = j*stride; + if (ctxcanvas->canvas->invert_yaxis) + line_offset_colors = ((h - 1) - j)*w; // Fix up side down + else + line_offset_colors = j*w; + memcpy(bitmap_data + line_offset, colors + line_offset_colors, stride); + + // Fix alpha values + for(int i = 3; i < stride; i+=4) + bitmap_data[line_offset+i] = ~bitmap_data[line_offset+i]; + } + + Bitmap PatternImage(w, h, stride, PixelFormat32bppARGB, bitmap_data); + PatternImage.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new TextureBrush(&PatternImage); + + delete bitmap_data; +} + +static int cdinteriorstyle(cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case CD_SOLID: + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new SolidBrush(ctxcanvas->fg); + break; + case CD_HATCH: + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + break; + case CD_STIPPLE: + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + break; + case CD_PATTERN: + cdpattern(ctxcanvas, ctxcanvas->canvas->pattern_w, ctxcanvas->canvas->pattern_h, ctxcanvas->canvas->pattern); + break; + } + + return style; +} + +static void cdline(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + ctxcanvas->graphics->DrawLine(ctxcanvas->linePen, x1, y1, x2, y2); + ctxcanvas->dirty = 1; +} + +static void cdrect(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Rect rect(xmin, ymin, xmax-xmin, ymax-ymin); // in this case Size = Max - Min + ctxcanvas->graphics->DrawRectangle(ctxcanvas->linePen, rect); + ctxcanvas->dirty = 1; +} + +static void cdbox(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Rect rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1); + if (ctxcanvas->canvas->new_region) + { + Region region(rect); + sCombineRegion(ctxcanvas, region); + } + else + { + ctxcanvas->graphics->FillRectangle(ctxcanvas->fillBrush, rect); + ctxcanvas->dirty = 1; + } +} + +static void cdwpFixAngles(cdCtxCanvas* ctxcanvas, double *angle1, double *angle2) +{ + if (ctxcanvas->canvas->invert_yaxis) + { + // GDI+ angle are clock-wise by default + *angle1 *= -1; + *angle2 *= -1; + } +} + +static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (angle1 == 0 && angle2 == 360) + ctxcanvas->graphics->DrawEllipse(ctxcanvas->linePen, rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + ctxcanvas->graphics->DrawArc(ctxcanvas->linePen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + ctxcanvas->dirty = 1; +} + +static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path; + if (angle1==0 && angle2==360) + path.AddEllipse(rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddPie(rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + { + // complete the remaining pixels using an Arc + Pen pen(ctxcanvas->fillBrush); + + if (angle1==0 && angle2==360) + { + ctxcanvas->graphics->FillEllipse(ctxcanvas->fillBrush, rect); + ctxcanvas->graphics->DrawEllipse(&pen, rect); + } + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + ctxcanvas->graphics->FillPie(ctxcanvas->fillBrush, rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + ctxcanvas->dirty = 1; + } +} + +static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path; + if (angle1==0 && angle2==360) + path.AddEllipse(rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); + path.CloseFigure(); + } + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + { + if (angle1==0 && angle2==360) + ctxcanvas->graphics->FillEllipse(ctxcanvas->fillBrush, rect); + else + { + GraphicsPath path; + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->graphics->FillPath(ctxcanvas->fillBrush, &path); + } + Pen pen(ctxcanvas->fillBrush); // complete the remaining pixels using an Arc + ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->dirty = 1; + } +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + switch( mode ) + { + case CD_BEZIER: + if (n < 4) return; + ctxcanvas->graphics->DrawBeziers(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_FILLSPLINE: + if (n < 4) return; + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddClosedCurve((Point*)poly, n); + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + ctxcanvas->graphics->FillClosedCurve(ctxcanvas->fillBrush, (Point*)poly, n); + break; + case CD_SPLINE: + if (n < 4) return; + ctxcanvas->graphics->DrawClosedCurve(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_CLOSED_LINES: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + /* continue */ + case CD_OPEN_LINES: + ctxcanvas->graphics->DrawLines(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_FILLGRADIENT: + { + int count = n; + PathGradientBrush* brush = new PathGradientBrush((Point*)poly, n); + brush->SetSurroundColors(ctxcanvas->pathGradient, &count); + brush->SetCenterColor(ctxcanvas->pathGradient[n]); + ctxcanvas->graphics->FillPolygon(brush, (Point*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + } + break; + case CD_FILL: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddPolygon((Point*)poly, n); + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + ctxcanvas->graphics->FillPolygon(ctxcanvas->fillBrush, (Point*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + break; + case CD_CLIP: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + + if (ctxcanvas->clip_poly) + delete[] ctxcanvas->clip_poly; + + ctxcanvas->clip_poly = new Point [n]; + + Point* pnt = (Point*)poly; + int t = n; + int nc = 1; + + ctxcanvas->clip_poly[0] = *pnt; + pnt++; + + for (int i = 1; i < t-1; i++, pnt++) + { + if (!((pnt->X == ctxcanvas->clip_poly[nc-1].X && pnt->X == (pnt + 1)->X) || + (pnt->Y == ctxcanvas->clip_poly[nc-1].Y && pnt->Y == (pnt + 1)->Y))) + { + ctxcanvas->clip_poly[nc] = *pnt; + nc++; + } + } + + ctxcanvas->clip_poly_n = nc; + + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + sClipPoly(ctxcanvas); + + break; + } + + ctxcanvas->dirty = 1; +} + +WCHAR* cdwpString2Unicode(const char* s, int len) +{ + static WCHAR wstr[10240] = L""; + if (len >= 10240) len = 10239; + MultiByteToWideChar(CP_ACP, 0, s, -1, wstr, len+1); + return wstr; +} + +static int cdwpCompensateHeight(int height) +{ + return (int)floor(height/10. + 0.5); /* 10% */ +} + +static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + RectF boundingBox; + int len = strlen(s); + + ctxcanvas->graphics->MeasureString(cdwpString2Unicode(s, len), len, + ctxcanvas->font, PointF(0,0), + &boundingBox); + if (width) + *width = (int)boundingBox.Width; + + if (height) + *height = (int)boundingBox.Height - cdwpCompensateHeight(ctxcanvas->fontinfo.height); +} + +static void sTextBox(cdCtxCanvas* ctxcanvas, WCHAR *ws, int len, int x, int y, int *w, int *h, int *xmin, int *ymin) +{ + int ydir = 1; + if (ctxcanvas->canvas->invert_yaxis) + ydir = -1; + + RectF boundingBox; + ctxcanvas->graphics->MeasureString(ws, len, + ctxcanvas->font, PointF(0,0), + &boundingBox); + *w = (int)boundingBox.Width; + *h = (int)boundingBox.Height - cdwpCompensateHeight(ctxcanvas->fontinfo.height); + + // distance from bottom to baseline + int baseline = ctxcanvas->fontinfo.height - ctxcanvas->fontinfo.ascent; + + // move to bottom-left + cdTextTranslatePoint(ctxcanvas->canvas, x, y, *w, *h, baseline, xmin, ymin); + + // move to top-left + *ymin += ydir * (*h); +} + +static void cdwpCanvasGetTextHeight(cdCanvas* canvas, int x, int y, const char *s, int w, int h, int *hbox) +{ + int xmin, xmax, ymin, ymax; + + // distance from bottom to baseline + int baseline = canvas->ctxcanvas->fontinfo.height - canvas->ctxcanvas->fontinfo.ascent; + + /* move to bottom-left */ + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin); + + xmax = xmin + w-1; + ymax = ymin + h-1; + + if (canvas->text_orientation) + { + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + int rectY[4]; + + cdRotatePointY(canvas, xmin, ymin, x, y, &rectY[0], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymin, x, y, &rectY[1], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymax, x, y, &rectY[2], sin_theta, cos_theta); + cdRotatePointY(canvas, xmin, ymax, x, y, &rectY[3], sin_theta, cos_theta); + + ymin = ymax = rectY[0]; + if (rectY[1] < ymin) ymin = rectY[1]; + if (rectY[2] < ymin) ymin = rectY[2]; + if (rectY[3] < ymin) ymin = rectY[3]; + if (rectY[1] > ymax) ymax = rectY[1]; + if (rectY[2] > ymax) ymax = rectY[2]; + if (rectY[3] > ymax) ymax = rectY[3]; + } + + *hbox = ymax-ymin+1; +} + +static void cdwpTextTransform(cdCtxCanvas* ctxcanvas, const char* s, int *x, int *y, int w, int h, Matrix &transformMatrix) +{ + int hbox; + double* matrix = ctxcanvas->canvas->matrix; + Matrix m1; + + cdwpCanvasGetTextHeight(ctxcanvas->canvas, *x, *y, s, w, h, &hbox); + + // configure a bottom-up coordinate system + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(ctxcanvas->canvas->h-1)); + transformMatrix.Multiply(&m1); + + // add the global transform + m1.SetElements((REAL)matrix[0], (REAL)matrix[1], (REAL)matrix[2], (REAL)matrix[3], (REAL)matrix[4], (REAL)matrix[5]); + transformMatrix.Multiply(&m1); + + // move to (x,y) and remove a vertical offset since text reference point is top-left + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)1, (REAL)*x, (REAL)(*y - (hbox-1))); + transformMatrix.Multiply(&m1); + + // invert the text vertical orientation, relative to itself + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(hbox-1)); + transformMatrix.Multiply(&m1); + + *x = 0; + *y = 0; +} + +static void cdtext(cdCtxCanvas* ctxcanvas, int x, int y, const char *s) +{ + Matrix transformMatrix; + int len = strlen(s), use_transform = 0, w, h; + WCHAR* ws = cdwpString2Unicode(s, len); + + if (ctxcanvas->canvas->text_orientation) + { + transformMatrix.Translate((REAL)x, (REAL)y); + transformMatrix.Rotate((REAL)-ctxcanvas->canvas->text_orientation); + transformMatrix.Translate((REAL)-x, (REAL)-y); + use_transform = 1; + } + + // Move (x,y) to top-left + sTextBox(ctxcanvas, ws, len, x, y, &w, &h, &x, &y); + + if (ctxcanvas->canvas->use_matrix) + { + cdwpTextTransform(ctxcanvas, s, &x, &y, w, h, transformMatrix); + use_transform = 1; + } + else if (cdwpSetTransform(ctxcanvas, transformMatrix, NULL)) + use_transform = 1; + + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + + if (use_transform) + path.Transform(&transformMatrix); + + FontFamily family; + ctxcanvas->font->GetFamily(&family); + path.AddString(ws, len, &family, ctxcanvas->font->GetStyle(), + ctxcanvas->font->GetSize(), + Point(x, y), NULL); + + Region region(&path); + sCombineRegion(ctxcanvas, region); + return; + } + + if (use_transform) + ctxcanvas->graphics->SetTransform(&transformMatrix); + + ctxcanvas->graphics->DrawString(ws, len, + ctxcanvas->font, PointF((REAL)x, (REAL)y), + ctxcanvas->lineBrush); + + if (use_transform) + cdwpUpdateTransform(ctxcanvas); // reset transform + + ctxcanvas->dirty = 1; +} + +static int sDesign2Pixel(int x, REAL size, int height) +{ + return (int)((x * size) / height); +} + +static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + FontFamily* fontFamily; + + if (cdStrEqualNoCase(type_face, "Courier") || cdStrEqualNoCase(type_face, "Monospace")) + fontFamily = new FontFamily(L"Courier New"); + else if (cdStrEqualNoCase(type_face, "Times") || cdStrEqualNoCase(type_face, "Serif")) + fontFamily = new FontFamily(L"Times New Roman"); + else if (cdStrEqualNoCase(type_face, "Helvetica") || cdStrEqualNoCase(type_face, "Sans")) + fontFamily = new FontFamily(L"Arial"); + else if (cdStrEqualNoCase(type_face, "System")) + fontFamily = FontFamily::GenericSansSerif()->Clone(); + else + fontFamily = new FontFamily(cdwpString2Unicode(type_face, strlen(type_face))); + + REAL emSize = (REAL)(cdGetFontSizePixels(ctxcanvas->canvas, size)); + + INT fontStyle = FontStyleRegular; + if (style&CD_BOLD) fontStyle |= FontStyleBold; + if (style&CD_ITALIC) fontStyle |= FontStyleItalic; + if (style&CD_UNDERLINE) fontStyle |= FontStyleUnderline; + if (style&CD_STRIKEOUT) fontStyle |= FontStyleStrikeout; + + if (ctxcanvas->font) delete ctxcanvas->font; + ctxcanvas->font = new Font(fontFamily, emSize, fontStyle, UnitPixel); + + REAL fontSize = ctxcanvas->font->GetSize(); + int emHeight = fontFamily->GetEmHeight(fontStyle); + ctxcanvas->fontinfo.height = sDesign2Pixel(fontFamily->GetLineSpacing(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.ascent = sDesign2Pixel(fontFamily->GetCellAscent(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.descent = sDesign2Pixel(fontFamily->GetCellDescent(fontStyle), fontSize, emHeight); + + delete fontFamily; + + return 1; +} + +static int cdnativefont(cdCtxCanvas* ctxcanvas, const char* nativefont) +{ + int size = 12, bold = 0, italic = 0, underline = 0, strikeout = 0, style = CD_PLAIN; + char type_face[1024]; + + if (nativefont[0] == '-' && nativefont[1] == 'd') + { + COLORREF rgbColors; + LOGFONT lf; + ctxcanvas->font->GetLogFontA(ctxcanvas->graphics, &lf); + + CHOOSEFONT cf; + ZeroMemory(&cf, sizeof(CHOOSEFONT)); + + cf.lStructSize = sizeof(CHOOSEFONT); + cf.hwndOwner = GetForegroundWindow(); + cf.lpLogFont = &lf; + cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT; + rgbColors = cf.rgbColors = ctxcanvas->fg.ToCOLORREF(); + + if (!ChooseFont(&cf)) + return 0; + + if (rgbColors != cf.rgbColors) + cdCanvasSetForeground(ctxcanvas->canvas, cdEncodeColor(GetRValue(cf.rgbColors),GetGValue(cf.rgbColors),GetBValue(cf.rgbColors))); + + bold = lf.lfWeight>FW_NORMAL? 1: 0; + italic = lf.lfItalic; + size = lf.lfHeight; + strcpy(type_face, lf.lfFaceName); + underline = lf.lfUnderline; + strikeout = lf.lfStrikeOut; + + if (bold) style |= CD_BOLD; + if (italic) style |= CD_ITALIC; + if (underline) style |= CD_UNDERLINE; + if (strikeout) style |= CD_STRIKEOUT; + } + else + { + if (!cdParseIupWinFont(nativefont, type_face, &style, &size)) + { + if (!cdParsePangoFont(nativefont, type_face, &style, &size)) + return 0; + } + + if (style&CD_BOLD) + bold = 1; + if (style&CD_ITALIC) + italic = 1; + if (style&CD_UNDERLINE) + underline = 1; + if (style&CD_STRIKEOUT) + strikeout = 1; + } + + REAL emSize = (REAL)(cdGetFontSizePixels(ctxcanvas->canvas, size)); + + INT fontStyle = FontStyleRegular; + if (bold) fontStyle |= FontStyleBold; + if (italic) fontStyle |= FontStyleItalic; + if (underline) fontStyle |= FontStyleUnderline; + if (strikeout) fontStyle |= FontStyleStrikeout; + + const char* new_type_face = type_face; + if (strstr(type_face, "Times") != NULL) + new_type_face = "Times"; + + if (strstr(type_face, "Courier") != NULL) + new_type_face = "Courier"; + + if (strstr(type_face, "Arial") != NULL) + new_type_face = "Helvetica"; + + if (strstr(type_face, "Helv") != NULL) + new_type_face = "Helvetica"; + + FontFamily *fontFamily; + if (strstr(type_face, "System") != NULL) + { + new_type_face = "System"; + fontFamily = FontFamily::GenericSansSerif()->Clone(); + } + else + fontFamily = new FontFamily(cdwpString2Unicode(type_face, strlen(type_face))); + + if (!fontFamily->IsAvailable()) + { + delete fontFamily; + return 0; + } + + Font* font = new Font(fontFamily, emSize, fontStyle, UnitPixel); + if (!font->IsAvailable()) + { + delete fontFamily; + delete font; + return 0; + } + + if (ctxcanvas->font) delete ctxcanvas->font; + ctxcanvas->font = font; + + REAL fontSize = ctxcanvas->font->GetSize(); + int emHeight = fontFamily->GetEmHeight(fontStyle); + ctxcanvas->fontinfo.height = sDesign2Pixel(fontFamily->GetLineSpacing(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.ascent = sDesign2Pixel(fontFamily->GetCellAscent(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.descent = sDesign2Pixel(fontFamily->GetCellDescent(fontStyle), fontSize, emHeight); + + delete fontFamily; + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, new_type_face); + + return 1; +} + +static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *line_height, int *ascent, int *descent) +{ + if (max_width) + { + RectF boundingBox; + ctxcanvas->graphics->MeasureString(L"W", 2, + ctxcanvas->font, PointF(0,0), + &boundingBox); + *max_width = (int)(boundingBox.Width/2); + } + + if (line_height) + *line_height = ctxcanvas->fontinfo.height; + + if (ascent) + *ascent = ctxcanvas->fontinfo.ascent; + + if (descent) + *descent = ctxcanvas->fontinfo.descent; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + Matrix transformMatrix; + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (matrix) + ctxcanvas->canvas->invert_yaxis = 0; + else + ctxcanvas->canvas->invert_yaxis = 1; + + if (cdwpSetTransform(ctxcanvas, transformMatrix, matrix)) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + ctxcanvas->graphics->ResetClip(); + + ctxcanvas->graphics->Clear(sSetAlpha(ctxcanvas->bg, (BYTE)255)); + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + ctxcanvas->dirty = 1; +} + +/******************************************************************/ +/* +%S Funcoes de imagens do cliente +*/ +/******************************************************************/ + +static void sRGB2Bitmap(Bitmap& image, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*3; + line_data[offset_data+0] = blue[offset]; + line_data[offset_data+1] = green[offset]; + line_data[offset_data+2] = red[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void sRGBA2Bitmap(Bitmap& image, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + const unsigned char *alpha, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*4; + line_data[offset_data+0] = blue? blue[offset]: 0; + line_data[offset_data+1] = green? green[offset]: 0; + line_data[offset_data+2] = red? red[offset]: 0; + line_data[offset_data+3] = alpha[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void sAlpha2Bitmap(Bitmap& image, int width, int height, const unsigned char *alpha, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*4; + line_data[offset_data+3] = alpha[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +/* +GDI+ does not natively work with palettized images. + +GDI+ will not try to draw on a palettized image as it would +require color reducing the drawing result. + +GDI+ will work natively with 32bpp image data behind the scenes anyway so +there is no economy in trying to work with 8bpp images. + +Full support for palettized images was on the feature list but it did not +make the cut for version 1 of GDI+. +*/ + +static void sMap2Bitmap(Bitmap& image, int width, int height, const unsigned char *index, + const long int *colors, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int map_index = index[line_offset + i + xmin]; + long color = colors[map_index]; + + int offset_data = i*3; + line_data[offset_data+0] = cdBlue(color); + line_data[offset_data+1] = cdGreen(color); + line_data[offset_data+2] = cdRed(color); + } + } + + image.UnlockBits(&bitmapData); +} + +static void sBitmap2RGB(Bitmap& image, unsigned char *red, unsigned char *green, unsigned char *blue) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeRead, PixelFormat24bppRGB, &bitmapData); + + for(int j = 0; j < rect.Height; j++) + { + int line_offset = ((rect.Height-1) - j)*rect.Width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i; + int offset_data = i*3; + blue[offset] = line_data[offset_data+0]; + green[offset] = line_data[offset_data+1]; + red[offset] = line_data[offset_data+2]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned char *green, unsigned char *blue, + int x, int y, int w, int h) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + int yr = y - (h - 1); /* y starts at the bottom of the image */ + Bitmap image(w, h, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + Graphics* imggraphics = new Graphics(&image); + + if (ctxcanvas->wtype == CDW_BMP) + { + imggraphics->DrawImage(ctxcanvas->bitmap, + Rect(0, 0, w, h), + x, yr, w, h, UnitPixel, + NULL, NULL, NULL); + } + else + { + HDC hdc = ctxcanvas->graphics->GetHDC(); + HDC img_hdc = imggraphics->GetHDC(); + + BitBlt(img_hdc,0,0,w,h,hdc,x,yr,SRCCOPY); + + imggraphics->ReleaseHDC(img_hdc); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + delete imggraphics; + + sBitmap2RGB(image, red, green, blue); + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void sFixImageY(cdCanvas* canvas, int *topdown, int *y, int *h) +{ + if (canvas->invert_yaxis) + { + if (*h < 0) + *topdown = 1; + else + *topdown = 0; + } + else + { + if (*h < 0) + *topdown = 0; + else + *topdown = 1; + } + + if (*h < 0) + *h = -(*h); // y is at top-left corner (UNDOCUMENTED FEATURE) + + if (!(*topdown)) + *y -= ((*h) - 1); // move Y to top-left corner, since it was at the bottom of the image +} + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *index, + const long int *colors, + int x, int y, int w, int h, + int xmin, int xmax, int ymin, int ymax) +{ + int topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sMap2Bitmap(image, width, height, index, colors, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + int x, int y, int w, int h, + int xmin, int xmax, int ymin, int ymax) +{ + int topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sRGB2Bitmap(image, width, height, red, green, blue, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + const unsigned char *alpha, + int x, int y, int w, int h, + int xmin, int xmax, int ymin, int ymax) +{ + int topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat32bppARGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sRGBA2Bitmap(image, width, height, red, green, blue, alpha, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +/********************************************************************/ +/* +%S Funcoes de imagens do servidor +*/ +/********************************************************************/ + +static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int cd_color) +{ + if (!ctxcanvas->graphics->IsVisible(x, y)) + return; + + if (ctxcanvas->wtype == CDW_BMP) + { + ctxcanvas->bitmap->SetPixel(x, y, sColor2Windows(cd_color)); + } + else + { + if (ctxcanvas->canvas->use_matrix) + { + Point p = Point(x, y); + ctxcanvas->graphics->TransformPoints(CoordinateSpacePage, CoordinateSpaceWorld, &p, 1); + x = p.X; + y = p.Y; + } + HDC hdc = ctxcanvas->graphics->GetHDC(); + SetPixelV(hdc, x, y, sColor2Windows(cd_color).ToCOLORREF()); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + ctxcanvas->dirty = 1; +} + +static int sFormat2Bpp(PixelFormat pixelFormat) +{ + switch(pixelFormat) + { + case PixelFormat1bppIndexed: + return 1; + case PixelFormat4bppIndexed: + return 4; + case PixelFormat8bppIndexed: + return 8; + case PixelFormat16bppARGB1555: + case PixelFormat16bppGrayScale: + case PixelFormat16bppRGB555: + case PixelFormat16bppRGB565: + return 16; + case PixelFormat24bppRGB: + return 24; + case PixelFormat32bppARGB: + case PixelFormat32bppPARGB: + case PixelFormat32bppRGB: + return 32; + case PixelFormat48bppRGB: + return 48; + case PixelFormat64bppARGB: + case PixelFormat64bppPARGB: + return 64; + } + + return 0; +} + +static cdCtxImage *cdcreateimage(cdCtxCanvas* ctxcanvas, int width, int height) +{ + cdCtxImage *ctximage = new cdCtxImage; + ctximage->alpha = NULL; + + if (ctxcanvas->img_format) + { + ctximage->bitmap = new Bitmap(width, height, ctxcanvas->img_format==24? PixelFormat24bppRGB: PixelFormat32bppARGB); + if (!ctximage->bitmap) + { + delete ctximage; + return NULL; + } + + if (ctxcanvas->img_format==32 && ctxcanvas->img_alpha) + ctximage->alpha = ctxcanvas->img_alpha; + + ctximage->bitmap->SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + } + else + { + ctximage->bitmap = new Bitmap(width, height, ctxcanvas->graphics); + if (!ctximage->bitmap) + { + delete ctximage; + return NULL; + } + } + + ctximage->w = width; + ctximage->h = height; + + ctximage->bpp = sFormat2Bpp(ctximage->bitmap->GetPixelFormat()); + ctximage->xres = ctximage->bitmap->GetHorizontalResolution() / 25.4; + ctximage->yres = ctximage->bitmap->GetVerticalResolution() / 25.4; + + ctximage->w_mm = ctximage->w / ctximage->xres; + ctximage->h_mm = ctximage->h / ctximage->yres; + + Graphics imggraphics(ctximage->bitmap); + imggraphics.Clear(Color::White); + + return ctximage; +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + int yr = y - (ctximage->h - 1); /* y0 starts at the bottom of the image */ + + if (ctxcanvas->wtype == CDW_BMP) + { + Graphics imggraphics(ctximage->bitmap); + + imggraphics.DrawImage(ctxcanvas->bitmap, + Rect(0, 0, ctximage->w,ctximage->h), + x, yr, ctximage->w, ctximage->h, UnitPixel, + NULL, NULL, NULL); + } + else + { + Graphics imggraphics(ctximage->bitmap); + + HDC hdc = ctxcanvas->graphics->GetHDC(); + HDC img_hdc = imggraphics.GetHDC(); + + BitBlt(img_hdc,0,0,ctximage->w,ctximage->h,hdc,x,yr,SRCCOPY); + + imggraphics.ReleaseHDC(img_hdc); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x0, int y0, int xmin, int xmax, int ymin, int ymax) +{ + int yr = y0 - (ymax-ymin+1)+1; /* y0 starts at the bottom of the image */ + + INT srcx = xmin; + INT srcy = (ctximage->h-1)-ymax; + INT srcwidth = xmax-xmin+1; + INT srcheight = ymax-ymin+1; + Rect destRect(x0, yr, srcwidth, srcheight); + + ImageAttributes imageAttributes; + + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if (ctximage->bpp == 32 && ctximage->alpha) + { + sAlpha2Bitmap(*ctximage->bitmap, ctximage->w, ctximage->h, ctximage->alpha, + 0, ctximage->w-1, 0, ctximage->h-1, 0); + } + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(ctximage->bitmap, pts, 3, + srcx, srcy, srcwidth, srcheight, UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + ctxcanvas->graphics->DrawImage(ctximage->bitmap, destRect, + srcx, srcy, srcwidth, srcheight, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdkillimage(cdCtxImage *ctximage) +{ + delete ctximage->bitmap; + delete ctximage; +} + +static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + { + dy = -dy; + ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); + ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + if (ctxcanvas->wtype == CDW_BMP) + { + Rect rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1); + + Bitmap* bitmap = ctxcanvas->bitmap->Clone(rect, ctxcanvas->bitmap->GetPixelFormat()); + + rect.Offset(dx, dy); + + ctxcanvas->graphics->DrawImage(bitmap, rect, + 0, 0, rect.Width, rect.Height, UnitPixel, + NULL, NULL, NULL); + delete bitmap; + } + else + { + RECT rect; + rect.left = xmin; + rect.right = xmax+1; + rect.top = ymin; + rect.bottom = ymax+1; + + HDC hdc = ctxcanvas->graphics->GetHDC(); + ScrollDC(hdc, dx, dy, &rect, NULL, NULL, NULL); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + ctxcanvas->dirty = 1; + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + ctxcanvas->graphics->Flush(FlushIntentionSync); +} + +/********************************************************************/ +/* +%S Atributos personalizados +*/ +/********************************************************************/ + +static void set_img_format_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_format = 0; + else + { + int bpp = 0; + sscanf(data, "%d", &bpp); + if (bpp == 0) + return; + + if (bpp == 32) + ctxcanvas->img_format = 32; + else + ctxcanvas->img_format = 24; + } +} + +static char* get_img_format_attrib(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->img_format) + return NULL; + + if (ctxcanvas->img_format == 32) + return "32"; + else + return "24"; +} + +static cdAttribute img_format_attrib = +{ + "IMAGEFORMAT", + set_img_format_attrib, + get_img_format_attrib +}; + +static void set_img_alpha_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_alpha = NULL; + else + ctxcanvas->img_alpha = (unsigned char*)data; +} + +static char* get_img_alpha_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->img_alpha; +} + +static cdAttribute img_alpha_attrib = +{ + "IMAGEALPHA", + set_img_alpha_attrib, + get_img_alpha_attrib +}; + +static void set_img_transp_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->use_img_transp = 0; + else + { + int r1, g1, b1, r2, g2, b2; + ctxcanvas->use_img_transp = 1; + sscanf(data, "%d %d %d %d %d %d", &r1, &g1, &b1, &r2, &g2, &b2); + ctxcanvas->img_transp[0] = Color((BYTE)r1, (BYTE)g1, (BYTE)b1); + ctxcanvas->img_transp[1] = Color((BYTE)r2, (BYTE)g2, (BYTE)b2); + } +} + + +static char* get_img_transp_attrib(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->use_img_transp) + return NULL; + + int r1 = ctxcanvas->img_transp[0].GetRed(); + int g1 = ctxcanvas->img_transp[0].GetGreen(); + int b1 = ctxcanvas->img_transp[0].GetBlue(); + int r2 = ctxcanvas->img_transp[1].GetRed(); + int g2 = ctxcanvas->img_transp[1].GetGreen(); + int b2 = ctxcanvas->img_transp[1].GetBlue(); + + static char data[50]; + sprintf(data, "%d %d %d %d %d %d", r1, g1, b1, r2, g2, b2); + return data; +} + +static cdAttribute img_transp_attrib = +{ + "IMAGETRANSP", + set_img_transp_attrib, + get_img_transp_attrib +}; + +static void set_gradientcolor_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + // used by CD_FILLGRADIENT + if (data) + { + int r, g, b, cur_vertex; + sscanf(data, "%d %d %d", &r, &g, &b); + + cur_vertex = ctxcanvas->canvas->poly_n; + if (cur_vertex < 500) + ctxcanvas->pathGradient[cur_vertex] = Color((BYTE)r, (BYTE)g, (BYTE)b); + } +} + +static cdAttribute gradientcolor_attrib = +{ + "GRADIENTCOLOR", + set_gradientcolor_attrib, + NULL +}; + +static void set_linegradient_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + int x1, y1, x2, y2; + sscanf(data, "%d %d %d %d", &x1, &y1, &x2, &y2); + + Point p1 = Point(x1, y1); + Point p2 = Point(x2, y2); + ctxcanvas->gradient[0] = p1; + ctxcanvas->gradient[1] = p2; + if (ctxcanvas->canvas->invert_yaxis) + { + p1.Y = _cdInvertYAxis(ctxcanvas->canvas, p1.Y); + p2.Y = _cdInvertYAxis(ctxcanvas->canvas, p2.Y); + } + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new LinearGradientBrush(p1, p2, ctxcanvas->fg, ctxcanvas->bg); + } +} + +static char* get_linegradient_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + sprintf(data, "%d %d %d %d", ctxcanvas->gradient[0].X, + ctxcanvas->gradient[0].Y, + ctxcanvas->gradient[1].X, + ctxcanvas->gradient[1].Y); + + return data; +} + +static cdAttribute linegradient_attrib = +{ + "LINEGRADIENT", + set_linegradient_attrib, + get_linegradient_attrib +}; + +static void set_linecap_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + LineCap cap = LineCapFlat; + + switch(data[0]) + { + case 'T': + cap = LineCapTriangle; + ctxcanvas->linePen->SetDashCap(DashCapTriangle); + break; + case 'N': + cap = LineCapNoAnchor; + break; + case 'S': + cap = LineCapSquareAnchor; + break; + case 'R': + cap = LineCapRoundAnchor; + break; + case 'D': + cap = LineCapDiamondAnchor; + break; + case 'A': + cap = LineCapArrowAnchor; + break; + default: + return; + } + + ctxcanvas->linePen->SetStartCap(cap); + ctxcanvas->linePen->SetEndCap(cap); + } +} + +static cdAttribute linecap_attrib = +{ + "LINECAP", + set_linecap_attrib, + NULL +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + cdwpUpdateTransform(ctxcanvas); +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_img_points_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + int p[6]; + + if (!data) + { + ctxcanvas->use_img_points = 0; + return; + } + + sscanf(data, "%d %d %d %d %d %d", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]); + + ctxcanvas->img_points[0] = Point(p[0], p[1]); + ctxcanvas->img_points[1] = Point(p[2], p[3]); + ctxcanvas->img_points[2] = Point(p[4], p[5]); + + ctxcanvas->use_img_points = 1; +} + +static char* get_img_points_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->use_img_points) + return NULL; + + sprintf(data, "%d %d %d %d %d %d", ctxcanvas->img_points[0].X, + ctxcanvas->img_points[0].Y, + ctxcanvas->img_points[1].X, + ctxcanvas->img_points[1].Y, + ctxcanvas->img_points[2].X, + ctxcanvas->img_points[2].Y); + + return data; +} + +static cdAttribute img_points_attrib = +{ + "IMAGEPOINTS", + set_img_points_attrib, + get_img_points_attrib +}; + +static BOOL Is_WinXP_or_Later(void) +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx (&osvi); + + BOOL bIsWindowsXPorLater = + (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && + ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && + (osvi.dwMinorVersion >= 1))); + + return bIsWindowsXPorLater; +} + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data || data[0] == '0') + { + ctxcanvas->graphics->SetInterpolationMode(InterpolationModeNearestNeighbor); + ctxcanvas->graphics->SetSmoothingMode(SmoothingModeNone); + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit); + ctxcanvas->antialias = 0; + } + else + { + ctxcanvas->graphics->SetInterpolationMode(InterpolationModeBilinear); + ctxcanvas->graphics->SetSmoothingMode(SmoothingModeAntiAlias); + if (Is_WinXP_or_Later()) + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintClearTypeGridFit); + else + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit); +/* ctxcanvas->graphics->SetPixelOffsetMode(PixelOffsetModeHalf); + Do NOT set PixelOffsetMode because some graphic objects move their position and size. +*/ + ctxcanvas->antialias = 1; + } +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->antialias) + return "1"; + else + return "0"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static void set_window_rgn(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + HRGN hrgn = ctxcanvas->new_region->GetHRGN(ctxcanvas->graphics); + SetWindowRgn(ctxcanvas->hWnd, hrgn, TRUE); + } + else + SetWindowRgn(ctxcanvas->hWnd, NULL, TRUE); +} + +static cdAttribute window_rgn_attrib = +{ + "WINDOWRGN", + set_window_rgn, + NULL +}; + +static char* get_hdc_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->hDC; +} + +static cdAttribute hdc_attrib = +{ + "HDC", + NULL, + get_hdc_attrib +}; + +static char* get_gdiplus_attrib(cdCtxCanvas* ctxcanvas) +{ + return "1"; +} + +static cdAttribute gdiplus_attrib = +{ + "GDI+", + NULL, + get_gdiplus_attrib +}; + +void cdwpUpdateCanvas(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->wtype == CDW_EMF && ctxcanvas->metafile) // first update metafile is NULL. + { + MetafileHeader metaHeader; + ctxcanvas->metafile->GetMetafileHeader(&metaHeader); + ctxcanvas->canvas->xres = metaHeader.GetDpiX() / 25.4; + ctxcanvas->canvas->yres = metaHeader.GetDpiY() / 25.4; + } + else + { + ctxcanvas->canvas->xres = ctxcanvas->graphics->GetDpiX() / 25.4; + ctxcanvas->canvas->yres = ctxcanvas->graphics->GetDpiY() / 25.4; + } + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + ctxcanvas->graphics->SetPageScale(1); + ctxcanvas->graphics->SetPageUnit(UnitPixel); + ctxcanvas->graphics->SetCompositingMode(CompositingModeSourceOver); + ctxcanvas->graphics->SetCompositingQuality(CompositingQualityDefault); + + if (ctxcanvas->antialias) + set_aa_attrib(ctxcanvas, "1"); + else + set_aa_attrib(ctxcanvas, NULL); + + cdwpUpdateTransform(ctxcanvas); +} + +/* +%F Cria o canvas para o driver Windows. +*/ +cdCtxCanvas *cdwpCreateCanvas(cdCanvas* canvas, Graphics* graphics, int wtype) +{ + cdCtxCanvas* ctxcanvas = new cdCtxCanvas; + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + /* update canvas context */ + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->wtype = wtype; + ctxcanvas->graphics = graphics; + + ctxcanvas->linePen = new Pen(Color()); + ctxcanvas->lineBrush = new SolidBrush(Color()); + ctxcanvas->fillBrush = new SolidBrush(Color()); + ctxcanvas->font = NULL; // will be created in the update default attrib + + set_aa_attrib(ctxcanvas, "1"); // default is ANTIALIAS=1 + + ctxcanvas->fg = Color(); // black + ctxcanvas->bg = Color(255, 255, 255); // white + + canvas->invert_yaxis = 1; + + ctxcanvas->clip_poly = NULL; + ctxcanvas->clip_poly_n = 0; + ctxcanvas->clip_region = NULL; + ctxcanvas->new_region = NULL; + + cdRegisterAttribute(canvas, &img_points_attrib); + cdRegisterAttribute(canvas, &img_transp_attrib); + cdRegisterAttribute(canvas, &img_format_attrib); + cdRegisterAttribute(canvas, &img_alpha_attrib); + cdRegisterAttribute(canvas, &aa_attrib); + cdRegisterAttribute(canvas, &gradientcolor_attrib); + cdRegisterAttribute(canvas, &linegradient_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &linecap_attrib); + cdRegisterAttribute(canvas, &hdc_attrib); + cdRegisterAttribute(canvas, &window_rgn_attrib); + cdRegisterAttribute(canvas, &gdiplus_attrib); + + cdwpUpdateCanvas(ctxcanvas); + + return ctxcanvas; +} + +static ULONG_PTR cd_gdiplusToken = NULL; + +static void __stdcall DebugEvent(DebugEventLevel level, char* msg) +{ + MessageBox(NULL, msg, "GDI+ Debug", 0); +} + +void cdwpGdiPlusStartup(int debug) +{ + if (cd_gdiplusToken == NULL) + { + GdiplusStartupInput input; + if (debug) + input.DebugEventCallback = DebugEvent; + + // Initialize GDI+. + GdiplusStartup(&cd_gdiplusToken, &input, NULL); + } +} + +void cdwpGdiPlusShutdown(void) +{ + if (cd_gdiplusToken) + GdiplusShutdown(cd_gdiplusToken); +} + +void cdwpInitTable(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas = canvas->ctxcanvas; + + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxPalette = cdpalette; + canvas->cxTransform = cdtransform; + + if (ctxcanvas->wtype == CDW_WIN || ctxcanvas->wtype == CDW_BMP) + { + canvas->cxClear = cdclear; + + canvas->cxGetImageRGB = cdgetimagergb; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + + canvas->cxScrollArea = cdscrollarea; + } +} diff --git a/src/gdiplus/cdwinp.h b/src/gdiplus/cdwinp.h new file mode 100644 index 0000000..0c4ae55 --- /dev/null +++ b/src/gdiplus/cdwinp.h @@ -0,0 +1,112 @@ +/** \file + * \brief Windows GDI+ Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDWINP_H +#define __CDWINP_H + +#include <windows.h> +#include <gdiplus.h> +using namespace Gdiplus; + +#include "cd.h" +#include "cd_private.h" + + +/* Contexto de cada imagem no servidor */ +struct _cdCtxImage +{ + Bitmap *bitmap; /* bitmap associado */ + int w; /* largura da imagem */ + int h; /* altura da imagem */ + double w_mm, h_mm; /* size in mm */ + double xres, yres; /* resolution in pixels/mm */ + int bpp; + unsigned char* alpha; /* the alpha values must be stored here to be used at putimage */ +}; + +/* Contexto de todos os canvas GDI+ (CanvasContext). */ +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + Graphics *graphics; + + Pen *linePen; + SolidBrush *lineBrush; + Brush *fillBrush; + Color fg, bg; /* foreground, backgound */ + Font *font; + + struct + { + int height; + int ascent; + int descent; + } fontinfo; + + Point *clip_poly; /* coordenadas do pixel no X,Y */ + int clip_poly_n; /* numero de pontos correntes */ + Region *clip_region; + + Region *new_region; + + int max_points; + PointF *wdpoly; // cache buffer for wdpoly + Point *cdpoly; // alias to cache buffer (float=int) + + int antialias; + + Point gradient[2]; + + Color pathGradient[500]; + + int img_format; + unsigned char* img_alpha; + + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + Point img_points[3]; + int use_img_points; + + Color img_transp[2]; + int use_img_transp; + + int wtype; /* Flag indicando qual o tipo de superficie */ + + HWND hWnd; /* CDW_WIN handle */ + HDC hDC; /* GDI Device Context handle */ + int release_dc; + + HANDLE printerHandle; // Used by the printer driver + + Metafile* metafile; /* CDW_EMF handle */ + Bitmap* bitmap; /* CDW_BMP handle */ + + int dirty; // Used by the double buffer driver + CachedBitmap* bitmap_dbuffer; /* not the image_dbuffer, just a cache */ + cdCanvas* canvas_dbuffer; +}; + +enum{CDW_WIN, CDW_BMP, CDW_EMF}; + +cdCtxCanvas *cdwpCreateCanvas(cdCanvas* canvas, Graphics* graphics, int wtype); +void cdwpKillCanvas(cdCtxCanvas* ctxcanvas); + +void cdwpInitTable(cdCanvas* canvas); +void cdwpUpdateCanvas(cdCtxCanvas* canvas); + +WCHAR* cdwpString2Unicode(const char* s, int len); +void cdwpShowStatus(const char* title, Status status); + +extern "C" { +void cdwpGdiPlusStartup(int debug); +void cdwpGdiPlusShutdown(void); +} + +#endif /* ifndef CDWINP_H */ + diff --git a/src/gdiplus/cdwnativep.cpp b/src/gdiplus/cdwnativep.cpp new file mode 100644 index 0000000..fffd044 --- /dev/null +++ b/src/gdiplus/cdwnativep.cpp @@ -0,0 +1,138 @@ +/** \file + * \brief Windows GDI+ Native Window Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdnative.h" +#include <stdlib.h> +#include <stdio.h> + + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->hWnd) + { + RECT rect; + GetClientRect(ctxcanvas->hWnd, &rect); + int w = rect.right - rect.left; + int h = rect.bottom - rect.top; + int bpp = cdGetScreenColorPlanes(); + + if(ctxcanvas->canvas->w != w || + ctxcanvas->canvas->h != h || + ctxcanvas->canvas->bpp != bpp) + { + ctxcanvas->canvas->w = w; + ctxcanvas->canvas->h = h; + ctxcanvas->canvas->bpp = bpp; + + delete ctxcanvas->graphics; + ctxcanvas->graphics = new Graphics(ctxcanvas->hWnd); + + cdwpUpdateCanvas(ctxcanvas); + } + } + + return CD_OK; +} + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + if (ctxcanvas->release_dc) + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + + delete ctxcanvas; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + HWND hWnd = NULL; + HDC hDC = NULL; + Graphics* graphics; + int release_dc = 0; + + if (!data) + { + hDC = GetDC(NULL); + release_dc = 1; + + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + + graphics = new Graphics(hDC); + } + else if (IsWindow((HWND)data)) + { + hWnd = (HWND)data; + release_dc = 0; + + RECT rect; + GetClientRect(hWnd, &rect); + canvas->w = rect.right - rect.left; + canvas->h = rect.bottom - rect.top; + + graphics = new Graphics(hWnd); + } + else /* can be a HDC or a string */ + { + DWORD objtype = GetObjectType((HGDIOBJ)data); + if (objtype == OBJ_DC || objtype == OBJ_MEMDC || + objtype == OBJ_ENHMETADC || objtype == OBJ_METADC) + { + hDC = (HDC)data; + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + } + else + { + hDC = NULL; + canvas->w = 0; + canvas->h = 0; + sscanf((char*)data,"%p %dx%d", &hDC, &canvas->w, &canvas->h); + + if (!hDC || !canvas->w || !canvas->h) + return; + } + + graphics = new Graphics(hDC); + release_dc = 0; + } + + canvas->bpp = cdGetScreenColorPlanes(); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_WIN); + ctxcanvas->hWnd = hWnd; + ctxcanvas->hDC = hDC; + ctxcanvas->release_dc = release_dc; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +static cdContext cdNativeContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextNativeWindowPlus(void) +{ + return &cdNativeContext; +} +} diff --git a/src/gdiplus/cdwprnp.cpp b/src/gdiplus/cdwprnp.cpp new file mode 100644 index 0000000..3d2b9f7 --- /dev/null +++ b/src/gdiplus/cdwprnp.cpp @@ -0,0 +1,158 @@ +/** \file + * \brief Windows GDI+ Printer Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdprint.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +/* +%F cdKillCanvas para Printer. +Termina a pagina e termina o documento, enviando-o para a impressora. +*/ +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + EndPage(ctxcanvas->hDC); + EndDoc(ctxcanvas->hDC); + + ClosePrinter(ctxcanvas->printerHandle); + DeleteDC(ctxcanvas->hDC); + + delete ctxcanvas; +} + +/* +%F cdFlush para Printer. +Termina uma pagina e inicia outra. +*/ +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + delete ctxcanvas->graphics; + EndPage(ctxcanvas->hDC); + + StartPage(ctxcanvas->hDC); + ctxcanvas->graphics = new Graphics(ctxcanvas->hDC, ctxcanvas->printerHandle); + + cdwpUpdateCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *data_str = (char*) data; + char docname[256] = "CD - Canvas Draw Document"; + int dialog = 0; + + /* Inicializa parametros */ + if (data_str == NULL) + return; + + if (data_str[0] != 0) + { + const char *ptr = strstr(data_str, "-d"); + + if (ptr != NULL) + dialog = 1; + + if (data_str[0] != '-') + { + strcpy(docname, data_str); + + if (dialog) + docname[ptr - data_str - 1] = 0; + } + } + + PRINTDLG pd; + ZeroMemory(&pd, sizeof(PRINTDLG)); + pd.lStructSize = sizeof(PRINTDLG); + pd.nCopies = 1; + + if (dialog) + { + pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE | PD_NOPAGENUMS | PD_NOSELECTION; + pd.hwndOwner = GetForegroundWindow(); + } + else + { + pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; + } + + if (!PrintDlg(&pd)) + { + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); + return; + } + + HDC hDC = pd.hDC; + + DEVMODE* devideMode = (DEVMODE*)GlobalLock(pd.hDevMode); + HANDLE printerHandle; + OpenPrinter((char*)devideMode->dmDeviceName, &printerHandle, NULL); + GlobalUnlock(pd.hDevMode); + + { + /* Inicializa documento */ + DOCINFO docInfo; + ZeroMemory(&docInfo, sizeof(docInfo)); + docInfo.cbSize = sizeof(docInfo); + docInfo.lpszDocName = docname; + + StartDoc(hDC, &docInfo); + } + + StartPage(hDC); + + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + canvas->bpp = GetDeviceCaps(hDC, BITSPIXEL); + + Graphics* graphics = new Graphics(hDC, printerHandle); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_EMF); + + ctxcanvas->hDC = hDC; + ctxcanvas->printerHandle = printerHandle; + + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxFlush = cdflush; +} + +static cdContext cdPrinterContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES | + CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextPrinterPlus(void) +{ + return &cdPrinterContext; +} +} + diff --git a/src/intcgm/bparse.c b/src/intcgm/bparse.c new file mode 100644 index 0000000..ad08179 --- /dev/null +++ b/src/intcgm/bparse.c @@ -0,0 +1,1660 @@ +#include <stdio.h> /* FILE, ftell, fseek, fputc, fopen, fclose, fputs, fprintf */ +#include <string.h> /* strlen, strncpy */ +#include <stdlib.h> /* malloc, free */ +#include "cd.h" +#include "cdcgm.h" +#include "list.h" +#include "types.h" +#include "bparse.h" +#include "intcgm.h" +#include "intcgm2.h" +#include "intcgm4.h" +#include "intcgm6.h" + +/********************* +* Delimiter elements * +*********************/ + +int cgmb_noop ( void ) +{ + return 0; +} + +int cgmb_begmtf ( void ) +{ + char *header = NULL; + + if ( intcgm_cgm.len ) + { + if ( cgmb_s ( &header ) ) return 1; + } + + if (cdcgmbegmtfcb) + { + int err; + err = cdcgmbegmtfcb ( intcgm_canvas, &intcgm_view_xmin, &intcgm_view_ymin, &intcgm_view_xmax, &intcgm_view_ymax ); + if ( err==CD_ABORT ) return -1; + } + + return 0; +} + +int cgmb_endmtf ( void ) +{ + return 0; +} + +int cgmb_begpic ( void ) +{ + char *s = NULL; + + if ( intcgm_cgm.first ) + intcgm_cgm.first = 0; + else + cdCanvasFlush(intcgm_canvas); + + if ( intcgm_color_table==NULL ) + { + if ( intcgm_cgm.max_cix < 1 ) intcgm_cgm.max_cix = 1; + + intcgm_color_table = (trgb *) malloc ( sizeof(trgb)*(intcgm_cgm.max_cix+1) ); + + intcgm_color_table[0].red = 255; + intcgm_color_table[0].green = 255; + intcgm_color_table[0].blue = 255; + intcgm_color_table[1].red = 0; + intcgm_color_table[1].green = 0; + intcgm_color_table[1].blue = 0; + } + + cdCanvasClip(intcgm_canvas, CD_CLIPAREA); + + if ( cgmb_s ( &s ) ) return 1; + + if (cdcgmbegpictcb) + { + int err; + err = cdcgmbegpictcb ( intcgm_canvas, s ); + if ( err==CD_ABORT ) return -1; + } + + return 0; +} + +int cgmb_begpib ( void ) +{ + if (cdcgmbegpictbcb) + { + int err; + err = cdcgmbegpictbcb ( intcgm_canvas, 1., 1., intcgm_scale_factor_x, intcgm_scale_factor_y, + intcgm_scale_factor_mm_x*intcgm_cgm.scaling_mode.scale_factor, + intcgm_scale_factor_mm_y*intcgm_cgm.scaling_mode.scale_factor, + intcgm_cgm.drawing_mode, + intcgm_vdc_ext.xmin, intcgm_vdc_ext.ymin, intcgm_vdc_ext.xmax, intcgm_vdc_ext.ymax ); + + if ( err==CD_ABORT ) return -1; + } + + if (cdcgmsizecb) + { + int err, w, h; + double w_mm=0., h_mm=0.; + + w = intcgm_view_xmax-intcgm_view_xmin+1; + h = intcgm_view_ymax-intcgm_view_ymin+1; + + if ( intcgm_cgm.vdc_type==INTEGER ) + { + w = (int) (intcgm_cgm.vdc_ext.second.x - intcgm_cgm.vdc_ext.first.x); + h = (int) (intcgm_cgm.vdc_ext.second.y - intcgm_cgm.vdc_ext.first.y); + if ( intcgm_cgm.scaling_mode.mode==METRIC ) + { + w_mm = w * intcgm_cgm.scaling_mode.scale_factor; + h_mm = h * intcgm_cgm.scaling_mode.scale_factor; + } + } + else + { + if ( intcgm_cgm.scaling_mode.mode==METRIC ) + { + w_mm = (intcgm_cgm.vdc_ext.second.x - intcgm_cgm.vdc_ext.first.x) * intcgm_cgm.scaling_mode.scale_factor; + h_mm = (intcgm_cgm.vdc_ext.second.y - intcgm_cgm.vdc_ext.first.y) * intcgm_cgm.scaling_mode.scale_factor; + } + } + + err = cdcgmsizecb ( intcgm_canvas, w, h, w_mm, h_mm ); + if ( err==CD_ABORT ) return -1; + } + + return 0; +} + +int cgmb_endpic ( void ) +{ + return 0; +} + +/******************************* +* Metafile Descriptor Elements * +*******************************/ + +int cgmb_mtfver ( void ) +{ + long version; + + if ( cgmb_i ( &version ) ) return 1; + + return 0; +} + +int cgmb_mtfdsc ( void ) +{ + char *s = NULL; + + if ( cgmb_s ( &s ) ) return 1; + + return 0; +} + +int cgmb_vdctyp ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.vdc_type) ) ) return 1; + + return 0; +} + +int cgmb_intpre ( void ) +{ + long prec; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( prec==8 ) intcgm_cgm.int_prec.b_prec = 0; + else if ( prec==16 ) intcgm_cgm.int_prec.b_prec = 1; + else if ( prec==24 ) intcgm_cgm.int_prec.b_prec = 2; + else if ( prec==32 ) intcgm_cgm.int_prec.b_prec = 3; + + return 0; +} + +int cgmb_realpr ( void ) +{ + short mode, i1; + long i2, i3; + + if ( cgmb_e ( &i1 ) ) return 1; + if ( cgmb_i ( &i2 ) ) return 1; + if ( cgmb_i ( &i3 ) ) return 1; + + if ( i1 == 0 && i2 == 9 && i3 == 23 ) mode = 0; + else if ( i1 == 0 && i2 == 12 && i3 == 52 ) mode = 1; + else if ( i1 == 1 && i2 == 16 && i3 == 16 ) mode = 2; + else if ( i1 == 1 && i2 == 32 && i3 == 32 ) mode = 3; + + intcgm_cgm.real_prec.b_prec = mode; + + return 0; +} + +int cgmb_indpre ( void ) +{ + long prec; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( prec==8 ) intcgm_cgm.ix_prec.b_prec = 0; + else if ( prec==16 ) intcgm_cgm.ix_prec.b_prec = 1; + else if ( prec==24 ) intcgm_cgm.ix_prec.b_prec = 2; + else if ( prec==32 ) intcgm_cgm.ix_prec.b_prec = 3; + + return 0; +} + +int cgmb_colpre ( void ) +{ + long prec; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( prec==8 ) intcgm_cgm.cd_prec = 0; + else if ( prec==16 ) intcgm_cgm.cd_prec = 1; + else if ( prec==24 ) intcgm_cgm.cd_prec = 2; + else if ( prec==32 ) intcgm_cgm.cd_prec = 3; + + return 0; +} + +int cgmb_colipr ( void ) +{ + long prec; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( prec==8 ) intcgm_cgm.cix_prec = 0; + else if ( prec==16 ) intcgm_cgm.cix_prec = 1; + else if ( prec==24 ) intcgm_cgm.cix_prec = 2; + else if ( prec==32 ) intcgm_cgm.cix_prec = 3; + + return 0; +} + +int cgmb_maxcoi ( void ) +{ + if ( cgmb_ci ( (unsigned long *)&(intcgm_cgm.max_cix) ) ) return 1; + + intcgm_color_table = (trgb *) realloc ( intcgm_color_table, sizeof(trgb)*(intcgm_cgm.max_cix+1) ); + + intcgm_color_table[0].red = 255; + intcgm_color_table[0].green = 255; + intcgm_color_table[0].blue = 255; + intcgm_color_table[1].red = 0; + intcgm_color_table[1].green = 0; + intcgm_color_table[1].blue = 0; + + return 0; +} + +int cgmb_covaex ( void ) +{ + if ( cgmb_rgb ( &(intcgm_cgm.color_ext.black.red), &(intcgm_cgm.color_ext.black.green), &(intcgm_cgm.color_ext.black.blue) ) ) return 1; + if ( cgmb_rgb ( &(intcgm_cgm.color_ext.white.red), &(intcgm_cgm.color_ext.white.green), &(intcgm_cgm.color_ext.white.blue) ) ) return 1; + + return 0; +} + +int cgmb_mtfell ( void ) +{ + long group, element; + long n, i; + + if ( cgmb_i ( &n ) ) return 1; + + for ( i=0; i<n; i++ ) + { + if ( cgmb_ix ( &group ) ) return 1; + if ( cgmb_ix ( &element ) ) return 1; + } + + return 0; +} + +int cgmb_bmtfdf ( void ) +{ + int c, id, len, cont, totbc; + unsigned short b; + int count=0; + int old_cgmlen; + char *buff; + + buff = (char *) malloc ( sizeof(char)*intcgm_cgm.len ); + + memcpy ( buff, intcgm_cgm.buff.dados, intcgm_cgm.len ); + + old_cgmlen = intcgm_cgm.len; + + totbc = 0; + + while ( count<old_cgmlen ) + { + intcgm_cgm.bc = 0; + + b = ((unsigned char)buff[count] << 8) | (unsigned char)buff[count+1]; + count += 2; + + intcgm_cgm.bl += 2; + + len = b & 0x001F; + + id = ( b & 0x0FE0 ) >> 5; + + c = ( b & 0xF000 ) >> 12; + + cont = 0; + + if ( len > 30 ) + { + b = ((unsigned char)buff[count] << 8) | (unsigned char)buff[count+1]; + count += 2; + + intcgm_cgm.bl += 2; + + len = b & 0x7FFF; + cont = ( b & 0x8000 ); + } + + intcgm_cgm.len = len; + + if ( intcgm_cgm.len ) + { + if ( intcgm_cgm.len>intcgm_cgm.buff.size ) + intcgm_cgm.buff.dados = (char *) realloc ( (char *)intcgm_cgm.buff.dados, sizeof(char) * intcgm_cgm.len ); + + memcpy ( intcgm_cgm.buff.dados, &buff[count], intcgm_cgm.len ); + count += intcgm_cgm.len; + + intcgm_cgm.bl += intcgm_cgm.len; + + if ( len & 1 ) + { + count++; + intcgm_cgm.bl += 1; + } + + while ( cont ) + { + unsigned short b; + int old_len = intcgm_cgm.len; + + intcgm_cgm.bl += 2; + + b = ((unsigned char)buff[count] << 8) | (unsigned char)buff[count+1]; + count += 2; + + cont = ( b & 0x8000 ); + + len = b & 0x7fff; + + intcgm_cgm.len += len; + + if ( intcgm_cgm.len>intcgm_cgm.buff.size ) + intcgm_cgm.buff.dados = (char *) realloc ( (char *)intcgm_cgm.buff.dados, sizeof(char) * intcgm_cgm.len ); + + memcpy ( &intcgm_cgm.buff.dados[old_len], &buff[count], len ); + count += len; + + if ( len & 1 ) + { + count++; + + intcgm_cgm.bl += 1; + } + } + } + + if ( cgmb_exec_comand ( c, id ) ) return 1; + totbc += count; + /*count=0;*/ + } + + return 0; +} + +int cgmb_fntlst ( void ) +{ + char *fl = NULL; + + if ( intcgm_text_att.font_list==NULL ) intcgm_text_att.font_list = cgm_NewList(); + + while ( intcgm_cgm.bc < intcgm_cgm.len ) + { + if ( cgmb_s ( &fl ) ) return 1; + + cgm_AppendList ( intcgm_text_att.font_list, fl ); + } + + return 0; +} + +int cgmb_chslst ( void ) +{ + short mode; + char *s = NULL; + + while ( intcgm_cgm.bc < intcgm_cgm.len ) + { + if ( cgmb_e ( &mode ) ) return 1; + if ( cgmb_s ( &s ) ) return 1; + } + + return 0; +} + +int cgmb_chcdac ( void ) +{ + short mode; + + if ( cgmb_e ( &mode ) ) return 1; + + return 0; +} + + +/****************************** +* Picture Descriptor Elements * +******************************/ + +int cgmb_sclmde ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.scaling_mode.mode) ) ) return 1; + if ( intcgm_cgm.real_prec.b_prec==1 ) + { + if ( cgmb_getfl64 ( &(intcgm_cgm.scaling_mode.scale_factor) ) ) return 1; + } + else + { + float f; + if ( cgmb_getfl32 ( (float *) &f ) ) return 1; + if ( f<1e-20 ) f = 1; + intcgm_cgm.scaling_mode.scale_factor = f; + } + + if ( intcgm_cgm.scaling_mode.mode==ABSTRACT ) intcgm_cgm.scaling_mode.scale_factor=1.; + + intcgm_cgm.drawing_mode = ABSTRACT; + + if (cdcgmsclmdecb) + { + int err; + err = cdcgmsclmdecb ( intcgm_canvas, intcgm_cgm.scaling_mode.mode, &intcgm_cgm.drawing_mode, &intcgm_cgm.scaling_mode.scale_factor ); + if ( err==CD_ABORT ) return -1; + } + + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + { + intcgm_clip_xmin = cgm_canvas2vdcx ( intcgm_view_xmin ); + intcgm_clip_xmax = cgm_canvas2vdcx ( intcgm_view_xmax ); + intcgm_clip_ymin = cgm_canvas2vdcy ( intcgm_view_ymin ); + intcgm_clip_ymax = cgm_canvas2vdcy ( intcgm_view_ymax ); + } + else + { + intcgm_clip_xmin = intcgm_vdc_ext.xmin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_xmax = intcgm_vdc_ext.xmax*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymin = intcgm_vdc_ext.ymin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymax = intcgm_vdc_ext.ymax*intcgm_cgm.scaling_mode.scale_factor; + } + + return 0; +} + +int cgmb_clslmd ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.clrsm) ) ) return 1; + + return 0; +} + +int cgmb_lnwdmd ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.lnwsm) ) ) return 1; + + return 0; +} + +int cgmb_mkszmd ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.mkssm) ) ) return 1; + + return 0; +} + +int cgmb_edwdmd ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.edwsm) ) ) return 1; + + return 0; +} + +int cgmb_vdcext ( void ) +{ + if ( cgmb_p ( &(intcgm_cgm.vdc_ext.first.x), &(intcgm_cgm.vdc_ext.first.y) ) ) return 1; + if ( cgmb_p ( &(intcgm_cgm.vdc_ext.second.x), &(intcgm_cgm.vdc_ext.second.y) ) ) return 1; + + if (cdcgmvdcextcb) + { + int err; + err = cdcgmvdcextcb( intcgm_canvas, intcgm_cgm.vdc_type, &(intcgm_cgm.vdc_ext.first.x), &(intcgm_cgm.vdc_ext.first.y), + &(intcgm_cgm.vdc_ext.second.x), &(intcgm_cgm.vdc_ext.second.y) ); + if (err==CD_ABORT) return -1; + } + + cgm_do_vdcext ( intcgm_cgm.vdc_ext.first, intcgm_cgm.vdc_ext.second ); + + return 0; +} + +int cgmb_bckcol ( void ) +{ + if ( cgmb_rgb ( &(intcgm_cgm.back_color.red), &(intcgm_cgm.back_color.green), &(intcgm_cgm.back_color.blue) ) ) return 1; + + cgm_do_bckcol ( intcgm_cgm.back_color ); + + return 0; +} + +/******************* +* Control Elements * +*******************/ + +int cgmb_vdcipr ( void ) +{ + long prec; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( prec==8 ) intcgm_cgm.vdc_int.b_prec = 0; + else if ( prec==16 ) intcgm_cgm.vdc_int.b_prec = 1; + else if ( prec==24 ) intcgm_cgm.vdc_int.b_prec = 2; + else if ( prec==32 ) intcgm_cgm.vdc_int.b_prec = 3; + + return 0; +} + +int cgmb_vdcrpr ( void ) +{ + short i1; + long mode, i2, i3; + + if ( cgmb_e ( &i1 ) ) return 1; + if ( cgmb_i ( &i2 ) ) return 1; + if ( cgmb_i ( &i3 ) ) return 1 ; + + if ( i1 == 0 && i2 == 9 && i3 == 23 ) mode = 0; + else if ( i1 == 0 && i2 == 12 && i3 == 52 ) mode = 1; + else if ( i1 == 1 && i2 == 16 && i3 == 16 ) mode = 2; + else if ( i1 == 1 && i2 == 32 && i3 == 32 ) mode = 3; + + intcgm_cgm.vdc_real.b_prec = mode; + + return 0; +} + +int cgmb_auxcol ( void ) +{ + if ( cgmb_co ( &(intcgm_cgm.aux_color) ) ) return 1; + + return 0; +} + +int cgmb_transp ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.transparency) ) ) return 1; + + cgm_do_transp ( intcgm_cgm.transparency ); + + return 0; +} + +int cgmb_clprec ( void ) +{ + if ( cgmb_p ( &(intcgm_cgm.clip_rect.first.x), &(intcgm_cgm.clip_rect.first.y) ) ) return 1; + if ( cgmb_p ( &(intcgm_cgm.clip_rect.second.x), &(intcgm_cgm.clip_rect.second.y) ) ) return 1; + + cgm_do_clprec ( intcgm_cgm.clip_rect.first, intcgm_cgm.clip_rect.second ); + + return 0; +} + +int cgmb_clpind ( void ) +{ + if ( cgmb_e ( &(intcgm_cgm.clip_ind) ) ) return 1; + + cgm_do_clpind ( intcgm_cgm.clip_ind ); + + return 0; +} + +/******************************* +* Graphical Primitive Elements * +*******************************/ + +static tpoint *_intcgm_point_list ( int *np ) +{ + *np=0; + + while ( intcgm_cgm.bc < intcgm_cgm.len ) + { + if ( cgmb_p ( &(intcgm_point_list[*np].x), &(intcgm_point_list[*np].y) ) ) return NULL; + ++(*np); + if ( *np==intcgm_npoints) + { + intcgm_npoints *= 2; + intcgm_point_list = (tpoint *) realloc ( intcgm_point_list, intcgm_npoints*sizeof(tpoint) ); + } + } + + return intcgm_point_list; +} + +int cgmb_polyln ( void ) +{ + tpoint *pts; + int np; + + pts = _intcgm_point_list ( &np ); + if ( pts==NULL ) return 1; + + cgm_do_polyln ( np, pts ); + + return 0; +} + +int cgmb_djtply ( void ) +{ + tpoint *pts; + int np; + + pts = _intcgm_point_list ( &np ); + if ( pts==NULL ) return 1; + + cgm_do_djtply ( np, pts ); + + return 0; +} + +int cgmb_polymk ( void ) +{ + tpoint *pts; + int np; + + pts = _intcgm_point_list ( &np ); + if ( pts==NULL ) return 1; + + cgm_do_polymk ( np, pts ); + + return 0; +} + +int cgmb_text ( void ) +{ + tpoint pos; + char *s = NULL; + short t; + + if ( cgmb_p ( &pos.x, &pos.y ) ) return 1; + if ( cgmb_e ( &t ) ) return 1; + if ( cgmb_s ( &s ) ) return 1; + + cgm_do_text ( NORM_TEXT, s, pos ); + + free ( s ); + + return 0; +} + +int cgmb_rsttxt ( void ) +{ + double height, width; + tpoint pos; + char *s = NULL; + short t; + + if ( cgmb_vdc ( &width ) ) return 1; + if ( cgmb_vdc ( &height ) ) return 1; + if ( cgmb_p ( &pos.x, &pos.y ) ) return 1; + if ( cgmb_e ( &t ) ) return 1; + if ( cgmb_s ( &s ) ) return 1; + + intcgm_text_att.height = height; + + cgm_do_text ( RESTRICTED_TEXT, s, pos ); + + if ( s!= NULL ) free ( s ); + + return 0; +} + +int cgmb_apdtxt ( void ) +{ + char *s = NULL; + short t; + + if ( cgmb_e ( &t ) ) return 1; + if ( cgmb_s ( &s ) ) return 1; + + if ( s==NULL ) free ( s ); + + return 0; +} + +int cgmb_polygn ( void ) +{ + tpoint *pts; + int np; + static int porra=0; + + porra++; + + pts = _intcgm_point_list ( &np ); + if ( pts==NULL ) return 1; + + cgm_do_polygn ( np, pts ); + + return 0; +} + +static int _intcgm_vertex_list ( tpoint **pts, short **flags, int *np ) +{ + int intcgm_block=500; + + *np=0; + *pts = (tpoint *) malloc ( intcgm_block*sizeof(tpoint) ); + *flags = (short *) malloc ( intcgm_block*sizeof(short) ); + + while ( intcgm_cgm.bc < intcgm_cgm.len ) + { + if ( cgmb_p ( &((*pts)[*np].x), &((*pts)[*np].y) ) ) return 1; + if ( cgmb_e ( &((*flags)[*np]) ) ) return 1; + + ++(*np); + if ( *np==intcgm_block) + { + intcgm_block *= 2; + *pts = (tpoint *) realloc ( *pts, intcgm_block*sizeof(tpoint) ); + *flags = (short *) realloc ( *flags, intcgm_block*sizeof(short) ); + } + } + + return 0; +} + +int cgmb_plgset ( void ) +{ + tpoint *pts; + short *flags; + int np; + + if ( _intcgm_vertex_list ( &pts, &flags, &np ) ) return 1; + + cgm_do_plgset( NO, np, pts, flags ); + + free ( pts ); + free ( flags ); + + return 0; +} + +int cgmb_cellar ( void ) +{ + register int i, j, k; + long prec; + long sx, sy; + short mode; + int b; + unsigned char dummy; + tpoint corner1, corner2, corner3; + tcolor *cell; + + if ( cgmb_p ( &(corner1.x), &(corner1.y) ) ) return 1; + if ( cgmb_p ( &(corner2.x), &(corner2.y) ) ) return 1; + if ( cgmb_p ( &(corner3.x), &(corner3.y) ) ) return 1; + + if ( cgmb_i ( &sx ) ) return 1; + if ( cgmb_i ( &sy ) ) return 1; + + if ( cgmb_i ( &prec ) ) return 1; + + if ( cgmb_e ( &mode ) ) return 1; + + cell = (tcolor *) malloc ( sx*sy*sizeof(tcolor) ); + + if ( mode ) + for ( k=0; k<sy; k++ ) + { + b=intcgm_cgm.bc; + intcgm_cgm.pc=0; + for ( i=0; i<sx; i++ ) + { + if ( cgmb_getpixel ( &(cell[k*sx+i]), prec ) ) return 1; + } + if ( k<(sy-1) && (intcgm_cgm.bc-b)%2 ) cgmb_getc ( &dummy ); + cgm_getfilepos(); + } + else + for ( k=0; k<sy; k++ ) + { + b=intcgm_cgm.bc; + intcgm_cgm.pc=0; + for ( i=0; i<sx; ) + { + long l; + tcolor cor; + if ( cgmb_i ( &l ) ) return 1; + if ( cgmb_getpixel ( &cor, prec ) ) return 1; + for ( j=0; j<l; j++ ) + { + cell[k*sx+i] = cor; + i++; + } + } + if ( k<(sy-1) && (intcgm_cgm.bc-b)%2 ) cgmb_getc ( &dummy ); + cgm_getfilepos(); + } + + if ( intcgm_cgm.clrsm == 0 ) /* indexed */ + { + for ( i=0; i<sx*sy; i++ ) + { + int ind = cell[i].ind; + cell[i].rgb.red = intcgm_color_table[ind].red; + cell[i].rgb.green = intcgm_color_table[ind].green; + cell[i].rgb.blue = intcgm_color_table[ind].blue; + } + } + + cgm_do_cellar ( corner1, corner2, corner3, sx, sy, prec, cell ); + + free ( cell ); + + return 0; +} + +static long sample_type, n_samples; + +static int BuildString ( char *sin, char **sout, int *slen, int *intcgm_block ) +{ + *slen = strlen ( sin ) + strlen(*sout) + 1 + 1; /* + espaco em branco no final +\0 */ + if (*slen > *intcgm_block) + { + *intcgm_block *= 2; + *sout = (char *) realloc(*sout,sizeof(char)*(*intcgm_block)); + if ( *sout==NULL ) return 1; + } + + strcat(*sout,sin); + strcat(*sout," "); + + return 0; +} + +int intcgm_generalized_drawing_primitive_4 ( void ) +{ + long j, i; + tpoint pt[4]; + unsigned char c; + double r; + char *s=NULL, tmp[80]; + int intcgm_block = 500, slen = 0; + int id = -4; + + s = (char *) malloc ( intcgm_block*sizeof(char) ); + + strcpy ( s, "" ); + + for ( j=0; j<4; j++ ) + { + if ( cgmb_p ( &(pt[j].x), &(pt[j].y) ) ) return 1; + } + + if ( cgmb_getc(&c) ) return 1; + if ( cgmb_getc(&c) ) return 1; + + for ( j=0; j<6; j++ ) + { + if ( cgmb_r(&r) ) return 1; + sprintf(tmp,"%g",r); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + } + + if ( cgmb_i(&i) ) return 1; + sprintf(tmp,"%ld",i); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + + if ( cgmb_i(&sample_type) ) return 1; + sprintf(tmp,"%ld",sample_type); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + + if ( cgmb_i(&n_samples) ) return 1; + sprintf(tmp,"%ld",n_samples); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + + for ( j=0; j<2; j++ ) + { + if ( cgmb_r(&r) ) return 1; + sprintf(tmp,"%g",r); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + } + + for ( j=0; j<4; j++ ) + { + if ( cgmb_i(&i) ) return 1; + sprintf(tmp,"%ld",i); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + } + + cgm_do_gdp ( id, pt, s ); + + free(s); + + return 0; +} + +typedef int (*_getdata) (void *); + +int intcgm_generalized_drawing_primitive_5 ( void ) +{ + int (*getdata) (void *); + void *data; + char format[10]; + int i; + char *s, tmp[80]; + int intcgm_block = 500, slen = 0; + long id=-5; + + s = (char *) malloc ( sizeof(char)*intcgm_block ); + + strcpy ( s, "" ); + + switch ( sample_type ) + { + case 0: + getdata = (_getdata) cgmb_geti16; + data = (short *) malloc ( sizeof(short) ); + if ( data==NULL ) return 1; + strcpy ( format, "%d\0" ); + break; + case 1: + getdata = (_getdata) cgmb_geti32; + data = (long *) malloc ( sizeof(long) ); + if ( data==NULL ) return 1; + strcpy ( format, "%d\0" ); + break; + case 2: + getdata = (_getdata) cgmb_getfl32; + data = (float *) malloc ( sizeof(float) ); + if ( data==NULL ) return 1; + strcpy ( format, "%g\0" ); + break; + case 3: + getdata = (_getdata) cgmb_geti8; + data = (signed char *) malloc ( sizeof(signed char) ); + if ( data==NULL ) return 1; + strcpy ( format, "%d\0" ); + break; + case 4: + getdata = (_getdata) cgmb_geti16; + data = (short *) malloc ( sizeof(short) ); + if ( data==NULL ) return 1; + strcpy ( format, "%d\0" ); + break; + case 5: + getdata = (_getdata) cgmb_geti8; + data = (signed char *) malloc ( sizeof(signed char) ); + if ( data==NULL ) return 1; + strcpy ( format, "%d\0" ); + break; + } + + for ( i=0; i<n_samples; i++ ) + { + + getdata(data); + + if (sample_type==0) + sprintf(tmp,format,*(short *)data); + else if (sample_type==1) + sprintf(tmp,format,*(long *)data); + else if (sample_type==2) + sprintf(tmp,format,*(float *)data); + else if (sample_type==3) + sprintf(tmp,format,*(signed char *)data); + else if (sample_type==4) + sprintf(tmp,format,*(short *)data); + else if (sample_type==5) + sprintf(tmp,format,*(signed char *)data); + + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + + if (sample_type==4 || sample_type==5) + { + unsigned long ci; + char endstr='\0'; + + if ( cgmb_ci ( &ci ) ) return 1; + sprintf(tmp,"%ld%c",ci,endstr); + if ( BuildString ( tmp, &s, &slen, &intcgm_block ) ) return 1; + } + } + + if ( intcgm_cgm.bc < intcgm_cgm.len ) + { + int i; + unsigned char c; + + for ( i=0; i<intcgm_cgm.len-intcgm_cgm.bc; i++ ) + { + if ( cgmb_getc(&c) ) return 1; + if ( cgmb_getc(&c) ) return 1; + } + } + + cgm_do_gdp ( id, NULL, s ); + + free(s); + + return 0; +} + +int cgmb_gdp ( void ) +{ + long id, n, i; + double x, y; + char *s = NULL; + + cgmb_i ( &id ); + + if ( id==-4 ) + { + if ( intcgm_generalized_drawing_primitive_4 ( ) ) return 1; + } + else if ( id==-5 ) + { + if ( intcgm_generalized_drawing_primitive_5 ( ) ) return 1; + } + else + { + if ( cgmb_i ( &n ) ) return 1; + for ( i=0; i<n; i++ ) + { + if ( cgmb_p ( &x, &y ) ) return 1; + } + if ( cgmb_s ( &s ) ) return 1; + } + + return 0; +} + +int cgmb_rect ( void ) +{ + tpoint point1; + tpoint point2; + + if ( cgmb_p ( &(point1.x), &(point1.y) ) ) return 1; + if ( cgmb_p ( &(point2.x), &(point2.y) ) ) return 1; + + cgm_do_rect ( point1, point2 ); + + return 0; +} + +int cgmb_circle ( void ) +{ + tpoint center; + double radius; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_vdc ( &radius ) ) return 1; + + cgm_do_circle ( center, radius ); + + return 0; +} + +int cgmb_circ3p ( void ) +{ + tpoint starting; + tpoint intermediate; + tpoint ending; + + if ( cgmb_p ( &(starting.x), &(starting.y) ) ) return 1; + if ( cgmb_p ( &(intermediate.x), &(intermediate.y) ) ) return 1; + if ( cgmb_p ( &(ending.x), &(ending.y) ) ) return 1; + + cgm_do_circ3p ( starting, intermediate, ending ); + + return 0; +} + +int cgmb_cir3pc ( void ) +{ + tpoint starting; + tpoint intermediate; + tpoint ending; + short close_type; + + if ( cgmb_p ( &(starting.x), &(starting.y) ) ) return 1; + if ( cgmb_p ( &(intermediate.x), &(intermediate.y) ) ) return 1; + if ( cgmb_p ( &(ending.x), &(ending.y) ) ) return 1; + + if ( cgmb_e ( &close_type ) ) return 1; + + cgm_do_circ3pc ( starting, intermediate, ending, close_type ); + + return 0; +} + +int cgmb_circnt ( void ) +{ + tpoint center; + tpoint start; + tpoint end; + double radius; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_vdc ( &(start.x) ) ) return 1; + if ( cgmb_vdc ( &(start.y) ) ) return 1; + + if ( cgmb_vdc ( &(end.x) ) ) return 1; + if ( cgmb_vdc ( &(end.y) ) ) return 1; + + if ( cgmb_vdc ( &radius ) ) return 1; + + cgm_do_circcnt ( center, start, end, radius ); + + return 0; +} + +int cgmb_ccntcl ( void ) +{ + tpoint center; + tpoint start; + tpoint end; + double radius; + short close_type; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_vdc ( &(start.x) ) ) return 1; + if ( cgmb_vdc ( &(start.y) ) ) return 1; + + if ( cgmb_vdc ( &(end.x) ) ) return 1; + if ( cgmb_vdc ( &(end.y) ) ) return 1; + + if ( cgmb_vdc ( &radius ) ) return 1; + + if ( cgmb_e ( &close_type ) ) return 1; + + cgm_do_ccntcl ( center, start, end, radius, close_type ); + + return 0; +} + +int cgmb_ellips ( void ) +{ + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmb_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + cgm_do_ellips ( center, first_CDP, second_CDP ); + + return 0; +} + +int cgmb_ellarc ( void ) +{ + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + tpoint start, end; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmb_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + if ( cgmb_vdc ( &(start.x) ) ) return 1; + if ( cgmb_vdc ( &(start.y) ) ) return 1; + + if ( cgmb_vdc ( &(end.x) ) ) return 1; + if ( cgmb_vdc ( &(end.y) ) ) return 1; + + cgm_do_ellarc ( center, first_CDP, second_CDP, start, end ); + + return 0; +} + +int cgmb_ellacl ( void ) +{ + + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + tpoint start, end; + short close_type; + + if ( cgmb_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmb_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmb_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + if ( cgmb_vdc ( &(start.x) ) ) return 1; + if ( cgmb_vdc ( &(start.y) ) ) return 1; + + if ( cgmb_vdc ( &(end.x) ) ) return 1; + if ( cgmb_vdc ( &(end.y) ) ) return 1; + + if ( cgmb_e ( &close_type ) ) return 1; + + cgm_do_ellacl ( center, first_CDP, second_CDP, start, end, close_type ); + + return 0; +} + +/********************* +* Attribute Elements * +*********************/ + +int cgmb_lnbdin( void ) +{ + if ( cgmb_ix ( &(intcgm_line_att.index) ) ) return 1; + + return 0; +} + +int cgmb_lntype ( void ) +{ + if ( cgmb_ix ( &(intcgm_line_att.type) ) ) return 1; + + return 0; +} + +int cgmb_lnwidt ( void ) +{ + if ( intcgm_cgm.lnwsm==0 ) + { + if ( cgmb_vdc ( &(intcgm_line_att.width) ) ) return 1; + } + else + { + if ( cgmb_r ( &(intcgm_line_att.width) ) ) return 1; + } + + return 0; +} + +int cgmb_lncolr( void ) +{ + if ( cgmb_co ( &(intcgm_line_att.color) ) ) return 1; + + return 0; +} + +int cgmb_mkbdin( void ) +{ + if ( cgmb_ix ( &(intcgm_marker_att.index) ) ) return 1; + + return 0; +} + +int cgmb_mktype( void ) +{ + if ( cgmb_ix ( &(intcgm_marker_att.type) ) ) return 1; + + return 0; +} + +int cgmb_mksize( void ) +{ + if ( intcgm_cgm.mkssm == 0 ) + { + if ( cgmb_vdc ( &(intcgm_marker_att.size) ) ) return 1; + } + else + { + if ( cgmb_r ( &(intcgm_marker_att.size) ) ) return 1; + } + + return 0; +} + +int cgmb_mkcolr( void ) +{ + if ( cgmb_co ( &(intcgm_marker_att.color) ) ) return 1; + + return 0; +} + +int cgmb_txbdin( void ) +{ + if ( cgmb_ix ( &(intcgm_text_att.index) ) ) return 1; + + return 0; +} + +int cgmb_txftin ( void ) +{ + char *font; + char *font_array[] = {"SYSTEM", "COURIER", "TIMES", "HELVETICA", NULL}; + char *style_array[] = {"BOLDITALIC", "ITALIC", "BOLD", "PLAIN", NULL}; + int cdstyle[] = {CD_BOLD_ITALIC, CD_ITALIC, CD_BOLD, CD_PLAIN}; + int i; + + if ( cgmb_ix ( &(intcgm_text_att.font_index) ) ) return 1; + + font = (char *) cgm_GetList ( intcgm_text_att.font_list, intcgm_text_att.font_index ); + + if ( font==NULL ) font = (char*)strdup ( "SYSTEM" ); + + intcgm_text_att.font = 0; + for ( i=0; font_array[i]!=NULL; i++ ) + { + if ( strstr( font, font_array[i] ) ) + { + intcgm_text_att.font = i; + break; + } + } + + intcgm_text_att.style = 0; + for ( i=0; style_array[i]!=NULL; i++ ) + { + if ( strstr( font, style_array[i] ) ) + { + intcgm_text_att.style = cdstyle[i]; + break; + } + } + + cgm_setfont ( intcgm_text_att.font, intcgm_text_att.style, intcgm_text_att.height ); + + return 0; +} + +int cgmb_txtprc( void ) +{ + if ( cgmb_e ( &(intcgm_text_att.prec) ) ) return 1; + + return 0; +} + +int cgmb_chrexp ( void ) +{ + if ( cgmb_r ( &(intcgm_text_att.exp_fact) ) ) return 1; + + return 0; +} + +int cgmb_chrspc ( void ) +{ + if ( cgmb_r ( &(intcgm_text_att.char_spacing) ) ) return 1; + + return 0; +} + +int cgmb_txtclr( void ) +{ + if ( cgmb_co ( &(intcgm_text_att.color) ) ) return 1; + + return 0; +} + +int cgmb_chrhgt ( void ) +{ + if ( cgmb_vdc ( &(intcgm_text_att.height) ) ) return 1; + + cgm_do_text_height ( intcgm_text_att.height ); + + return 0; +} + +int cgmb_chrori ( void ) +{ + if ( cgmb_vdc ( &(intcgm_text_att.char_up.x) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_text_att.char_up.y) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_text_att.char_base.x) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_text_att.char_base.y) ) ) return 1; + + return 0; +} + +int cgmb_txtpat ( void ) +{ + if ( cgmb_e ( &(intcgm_text_att.path) ) ) return 1; + + return 0; +} + +int cgmb_txtali ( void ) +{ + if ( cgmb_e ( &(intcgm_text_att.alignment.hor) ) ) return 1; + if ( cgmb_e ( &(intcgm_text_att.alignment.ver) ) ) return 1; + + if ( cgmb_r ( &(intcgm_text_att.alignment.cont_hor) ) ) return 1; + if ( cgmb_r ( &(intcgm_text_att.alignment.cont_ver) ) ) return 1; + + cgm_do_txtalign ( intcgm_text_att.alignment.hor, intcgm_text_att.alignment.ver ); + + return 0; +} + +int cgmb_chseti( void ) +{ + long set; + + if ( cgmb_ix ( &set ) ) return 1; + + return 0; +} + +int cgmb_achsti( void ) +{ + long set; + + if ( cgmb_i ( &set ) ) return 1; + + return 0; +} + +int cgmb_fillin( void ) +{ + if ( cgmb_ix ( &(intcgm_fill_att.index) ) ) return 1; + + return 0; +} + +int cgmb_intsty( void ) +{ + if ( cgmb_e ( &(intcgm_fill_att.int_style) ) ) return 1; + + return 0; +} + +int cgmb_fillco( void ) +{ + if ( cgmb_co ( &(intcgm_fill_att.color) ) ) return 1; + + return 0; +} + +int cgmb_hatind( void ) +{ + if ( cgmb_ix ( &(intcgm_fill_att.hatch_index) ) ) return 1; + if ( intcgm_fill_att.hatch_index==3 ) intcgm_fill_att.hatch_index = 4; + else if ( intcgm_fill_att.hatch_index==4 ) intcgm_fill_att.hatch_index = 3; + + return 0; +} + +int cgmb_patind( void ) +{ + if ( cgmb_ix ( &(intcgm_fill_att.pat_index) ) ) return 1; + + return 0; +} + +int cgmb_edgind( void ) +{ + if ( cgmb_ix ( &(intcgm_edge_att.index) ) ) return 1; + + return 0; +} + +int cgmb_edgtyp( void ) +{ + if ( cgmb_ix ( &(intcgm_edge_att.type) ) ) return 1; + + return 0; +} + +int cgmb_edgwid ( void ) +{ + if ( intcgm_cgm.edwsm==0 ) + { + if ( cgmb_vdc ( &(intcgm_edge_att.width) ) ) return 1; + } + else + { + if ( cgmb_r ( &(intcgm_edge_att.width) ) ) return 1; + } + + return 0; +} + +int cgmb_edgcol ( void ) +{ + if ( cgmb_co ( &(intcgm_edge_att.color) ) ) return 1; + + return 0; +} + + +int cgmb_edgvis ( void ) +{ + if ( cgmb_e ( &(intcgm_edge_att.visibility) ) ) return 1; + + return 0; +} + +int cgmb_fillrf ( void ) +{ + if ( cgmb_p ( &(intcgm_fill_att.ref_pt.x), &(intcgm_fill_att.ref_pt.y) ) ) return 1; + + return 0; +} + +int cgmb_pattab ( void ) +{ + long localp; + int i; + pat_table *pat; + + pat = (pat_table *) malloc ( sizeof(pat_table) ); + + if ( intcgm_fill_att.pat_list==NULL ) intcgm_fill_att.pat_list = cgm_NewList(); + + if ( cgmb_i ( &(pat->index) ) ) return 1; + + if ( cgmb_i ( &(pat->nx) ) ) return 1; + if ( cgmb_i ( &(pat->ny) ) ) return 1; + + if ( cgmb_i ( &(localp) ) ) return 1; + + pat->pattern = (tcolor *) malloc ( pat->nx*pat->ny*sizeof(tcolor) ); + + for ( i=0; i<(pat->nx*pat->ny); i++ ) + { + if ( cgmb_getpixel ( &(pat->pattern[i]), localp ) ) return 1; + } + + cgm_AppendList ( intcgm_fill_att.pat_list, pat ); + + return 0; +} + +int cgmb_patsiz ( void ) +{ + if ( cgmb_vdc ( &(intcgm_fill_att.pat_size.height.x) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_fill_att.pat_size.height.y) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_fill_att.pat_size.width.x) ) ) return 1; + if ( cgmb_vdc ( &(intcgm_fill_att.pat_size.width.y) ) ) return 1; + + return 0; +} + +int cgmb_coltab ( void ) +{ + unsigned long starting_index, i; + int p[] = {8, 16, 24, 32}; + int n = (intcgm_cgm.len-intcgm_cgm.cix_prec)/(3*(p[intcgm_cgm.cd_prec]/8)); + + if ( cgmb_ci ( &(starting_index) ) ) return 1; + + for ( i=starting_index; i<starting_index+n; i++ ) + { + if ( cgmb_rgb ( &(intcgm_color_table[i].red), &(intcgm_color_table[i].green), &(intcgm_color_table[i].blue) ) ) return 1; + } + + if ( intcgm_cgm.bc==(intcgm_cgm.len-1) ) intcgm_cgm.bc++; + + return 0; +} + +int cgmb_asf ( void ) +{ + tasf *pair; + + if ( intcgm_asf_list==NULL ) intcgm_asf_list = cgm_NewList(); + + while( intcgm_cgm.bc < intcgm_cgm.len ) + { + pair = (tasf *) malloc ( sizeof (tasf) ); + + if ( cgmb_e ( &(pair->type) ) ) return 1; + if ( cgmb_e ( &(pair->value) ) ) return 1; + + cgm_AppendList ( intcgm_asf_list, pair ); + } + + return 0; +} + +/***************** +* Escape Element * +*****************/ + +/******************** +* External elements * +********************/ + +int cgmb_escape ( void ) /* escape */ +{ +#if 1 + + { + int i; + unsigned char c; + for ( i=0; i<intcgm_cgm.len; i++ ) cgmb_getc(&c); + } + +#else + + { + long identifier; + char *data_rec; + + if ( cgmb_i ( &(identifier) ) ) return 1; + + if ( cgmb_s ( &data_rec ) ) return 1; + + free(data_rec); + } + +#endif + + return 0; +} + +int cgmb_messag ( void ) +{ + char *text; + short flag; + + if ( cgmb_e ( &flag ) ) return 1; + + if ( cgmb_s ( &text ) ) return 1; + + free(text); + + return 0; +} + +int cgmb_appdta ( void ) +{ + long identifier; + char *data_rec; + + if ( cgmb_i ( &identifier ) ) return 1; + + if ( cgmb_s ( &data_rec ) ) return 1; + + free(data_rec); + + return 0; +} diff --git a/src/intcgm/bparse.h b/src/intcgm/bparse.h new file mode 100644 index 0000000..1b86fee --- /dev/null +++ b/src/intcgm/bparse.h @@ -0,0 +1,117 @@ +#ifndef _BPARSE_H_ +#define _BPARSE_H_ + +typedef int(*_cdcgmsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm); +typedef int(*_cdcgmbegmtfcb)(cdCanvas* canvas, int *xmin, int *ymin, int *xmax, int *ymax); +typedef int(*_cdcgmcountercb)(cdCanvas* canvas, double size); +typedef int(*_cdcgmsclmdecb)(cdCanvas* canvas, short scl_mde, short *drw_mode, double *factor); +typedef int(*_cdcgmvdcextcb)(cdCanvas* canvas, short type, double *xmn, double *ymn, double *xmx, double *ymx); +typedef int(*_cdcgmbegpictcb)(cdCanvas* canvas , char *pict ); +typedef int(*_cdcgmbegpictbcb)(cdCanvas* canvas, double scale_x, double scale_y, + double vdc_x2pix, double vdc_y2pix, + double vdc_x2mm, double vdc_y2mm, int drw_mode, + double xmin, double ymin, double xmax, double ymax); + +extern _cdcgmsizecb cdcgmsizecb; +extern _cdcgmbegmtfcb cdcgmbegmtfcb; +extern _cdcgmcountercb cdcgmcountercb; +extern _cdcgmsclmdecb cdcgmsclmdecb; +extern _cdcgmvdcextcb cdcgmvdcextcb; +extern _cdcgmbegpictcb cdcgmbegpictcb; +extern _cdcgmbegpictbcb cdcgmbegpictbcb; + +int cgmb_noop ( void ); +int cgmb_begmtf ( void ); +int cgmb_endmtf ( void ); +int cgmb_begpic ( void ); +int cgmb_begpib ( void ); +int cgmb_endpic ( void ); +int cgmb_mtfver ( void ); +int cgmb_mtfdsc ( void ); +int cgmb_vdctyp ( void ); +int cgmb_intpre ( void ); +int cgmb_realpr ( void ); +int cgmb_indpre ( void ); +int cgmb_colpre ( void ); +int cgmb_colipr ( void ); +int cgmb_maxcoi ( void ); +int cgmb_covaex ( void ); +int cgmb_mtfell ( void ); +int cgmb_bmtfdf ( void ); +int cgmb_fntlst ( void ); +int cgmb_chslst ( void ); +int cgmb_chcdac ( void ); +int cgmb_sclmde ( void ); +int cgmb_clslmd ( void ); +int cgmb_lnwdmd ( void ); +int cgmb_mkszmd ( void ); +int cgmb_edwdmd ( void ); +int cgmb_vdcext ( void ); +int cgmb_bckcol ( void ); +int cgmb_vdcipr ( void ); +int cgmb_vdcrpr ( void ); +int cgmb_auxcol ( void ); +int cgmb_transp ( void ); +int cgmb_clprec ( void ); +int cgmb_clpind ( void ); +int cgmb_polyln ( void ); +int cgmb_djtply ( void ); +int cgmb_polymk ( void ); +int cgmb_text ( void ); +int cgmb_rsttxt ( void ); +int cgmb_apdtxt ( void ); +int cgmb_polygn ( void ); +int cgmb_plgset ( void ); +int cgmb_cellar ( void ); +int cgm_generalized_drawing_primitive_4 ( void ); +int cgm_generalized_drawing_primitive_5 ( void ); +int cgmb_gdp ( void ); +int cgmb_rect ( void ); +int cgmb_circle ( void ); +int cgmb_circ3p ( void ); +int cgmb_cir3pc ( void ); +int cgmb_circnt ( void ); +int cgmb_ccntcl ( void ); +int cgmb_ellips ( void ); +int cgmb_ellarc ( void ); +int cgmb_ellacl ( void ); +int cgmb_lnbdin ( void ); +int cgmb_lntype ( void ); +int cgmb_lnwidt ( void ); +int cgmb_lncolr ( void ); +int cgmb_mkbdin ( void ); +int cgmb_mktype ( void ); +int cgmb_mksize ( void ); +int cgmb_mkcolr ( void ); +int cgmb_txbdin ( void ); +int cgmb_txftin ( void ); +int cgmb_txtprc ( void ); +int cgmb_chrexp ( void ); +int cgmb_chrspc ( void ); +int cgmb_txtclr ( void ); +int cgmb_chrhgt ( void ); +int cgmb_chrori ( void ); +int cgmb_txtpat ( void ); +int cgmb_txtali ( void ); +int cgmb_chseti ( void ); +int cgmb_achsti ( void ); +int cgmb_fillin ( void ); +int cgmb_intsty ( void ); +int cgmb_fillco ( void ); +int cgmb_hatind ( void ); +int cgmb_patind ( void ); +int cgmb_edgind ( void ); +int cgmb_edgtyp ( void ); +int cgmb_edgwid ( void ); +int cgmb_edgcol ( void ); +int cgmb_edgvis ( void ); +int cgmb_fillrf ( void ); +int cgmb_pattab ( void ); +int cgmb_messag ( void ); +int cgmb_appdta ( void ); +int cgmb_patsiz ( void ); +int cgmb_coltab ( void ); +int cgmb_asf ( void ); +int cgmb_escape ( void ); + +#endif diff --git a/src/intcgm/circle.c b/src/intcgm/circle.c new file mode 100644 index 0000000..4f54fed --- /dev/null +++ b/src/intcgm/circle.c @@ -0,0 +1,100 @@ +#include <stdio.h> +#include <math.h> + +#include <cd.h> + +#include "list.h" +#include "types.h" +#include "intcgm.h" +#include "intcgm6.h" + +#include "circle.h" + +#define DIM 360 + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#define PI180 PI/180. +#define TWOPI 2*PI +#define VARCS TWOPI/32. + +int cgm_poly_circle ( double xc, double yc, double radius, double angi, double angf, int fechado ) +{ + double coseno, seno; + double xs, ys; + + coseno = cos (VARCS); + seno = sin (VARCS); + + xs = radius * cos(angi); + ys = radius * sin(angi); + + cdCanvasBegin(intcgm_canvas, cgm_setintstyle(intcgm_fill_att.int_style) ); + + if ( fechado==CLOSED_PIE ) cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(xc), cgm_vdcy2canvas(yc) ); + + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(xc+xs), cgm_vdcy2canvas(yc+ys) ); + + while ( (angi+VARCS) < angf ) + { + double xe = xs; + xs = xs * coseno - ys * seno; + ys = ys * coseno + xe * seno; + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(xc+xs), cgm_vdcy2canvas(yc+ys) ); + angi += VARCS; + } + + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(xc+radius*cos(angf)), cgm_vdcy2canvas(yc+radius*sin(angf)) ); + + cdCanvasEnd(intcgm_canvas); + + return 0; +} + +int cgm_line_circle ( double xc, double yc, double radius, double angi, double angf, int fechado ) +{ + double coseno, seno; + double xant, yant, firstx, firsty; + double xs, ys; + + /* GERA O DESENHO DO CIRCULO/ARCO */ + + coseno = cos (VARCS); + seno = sin (VARCS); + + xs = radius * cos(angi); + ys = radius * sin(angi); + + if ( fechado==CLOSED_PIE ) + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(xc), cgm_vdcy2canvas(yc), cgm_vdcx2canvas(xc+xs), cgm_vdcy2canvas(yc+ys) ); + + xant = firstx = xc+xs; + yant = firsty = yc+ys; + + while ( (angi+VARCS) < angf ) + { + double xe = xs; + xs = xs * coseno - ys * seno; + ys = ys * coseno + xe * seno; + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(xant), cgm_vdcy2canvas(yant), cgm_vdcx2canvas(xc+xs), cgm_vdcy2canvas(yc+ys) ); + xant = xc+xs; + yant = yc+ys; + angi += VARCS; + } + + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(xant), cgm_vdcy2canvas(yant), + cgm_vdcx2canvas(xc+radius*cos(angf)), cgm_vdcy2canvas(yc+radius*sin(angf)) ); + + xant = xc+radius*cos(angf); + yant = yc+radius*sin(angf); + + if ( fechado==CLOSED_PIE ) + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(xant), cgm_vdcy2canvas(yant), cgm_vdcx2canvas(xc), cgm_vdcy2canvas(yc) ); + else if ( fechado==CLOSED_CHORD ) + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(xant), cgm_vdcy2canvas(yant), cgm_vdcx2canvas(firstx), cgm_vdcy2canvas(firsty) ); + + return 0; +} + diff --git a/src/intcgm/circle.h b/src/intcgm/circle.h new file mode 100644 index 0000000..3209c0f --- /dev/null +++ b/src/intcgm/circle.h @@ -0,0 +1,3 @@ +int cgm_poly_circle ( double xc, double yc, double radius, double angi, double angf, int fechado ); +int cgm_line_circle ( double xc, double yc, double radius, double angi, double angf, int fechado ); + diff --git a/src/intcgm/ellipse.c b/src/intcgm/ellipse.c new file mode 100644 index 0000000..8d6889c --- /dev/null +++ b/src/intcgm/ellipse.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <math.h> + +#include <cd.h> + +#include "list.h" +#include "types.h" +#include "intcgm.h" +#include "intcgm6.h" +#include "ellipse.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#define ANGMIN 0.00001 + +/* Adjust the circle parametrization for the elipsis parametrization */ +double cgm_AdjArc ( double arc, double w, double h ) +{ + double value; + + if ((fabs(w*sin(arc))<1e-99) && (fabs(h*cos(arc))<1e-99)) + value = 0.0; + else + value = atan2(w*sin(arc), h*cos(arc)); + + if ( arc > PI ) value += 2*PI; + if ( arc < -PI ) value -= 2*PI; + + return value; +} + + +/* Desenha um arco de Elipse */ + +void cgm_ElpArc ( double xc, double yc, double w, double h, double r, double a1, + double a2, int n, int tipo ) + +{ + + /* Onde: + + (xc,yc) Centro + (w,h) Largura e altura (diametro na direcao dos eixos principais) + r Inclinacao dos eixos principais com relacao x e y + a1,a2 Angulos incial e final do arco [-360,+360] + Note-se que o sentido e' dado pela diferenca a2-a1, + ou seja, 30 a 330 e' trigonometrico + 30 a -30 e' horario + n Numero de segmentos da poligonal equivalente + (64 parece ser um bom numero) + tipo 0=aberto 1=fechado(torta) 2=fechado(corda) */ + + double da, c, s, sx, sy, ang, xant, yant; + double px, py, tx, ty, txant, tyant, dx, dy; + int i, inicio; + +/* Reduz de diametro a raio */ + + w = w/2; + h = h/2; + +/* Transforma graus em radianos e ajusta a os angulos da parametrizacao */ + + a1 = cgm_AdjArc(a1,w,h); + + a2 = cgm_AdjArc(a2,w,h); + + if ( a2>a1 ) + ang = a2 - a1; + else + ang = 2*PI - ( a1 - a2 ); + +/* Gera os pontos do arco centrado na origem com os eixos em x e y */ + + da = ang/n; + c = cos(da); + s = sin(da); + sx = -w*s/h; + sy = h*s/w; + + if ( tipo==1 || tipo==2 ) + { + long int cor; + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + cdCanvasBegin(intcgm_canvas, cgm_setintstyle(intcgm_fill_att.int_style) ); + } + else + { + long int cor; + int size = (int)floor(intcgm_line_att.width+.5); + cdCanvasLineStyle (intcgm_canvas, intcgm_line_att.type ); + cdCanvasLineWidth (intcgm_canvas, size>0? size: 1 ); + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + } + + dx = (fabs(r)>ANGMIN) ? sin(r) : 0; + dy = (fabs(r)>ANGMIN) ? cos(r) : 1; + + xant = w*cos(a1); + yant = h*sin(a1); + + txant = xc+dy*xant-dx*yant; /* Inclina (se for o caso) e translada */ + tyant = yc+dx*xant+dy*yant; /* Inclina (se for o caso) e translada */ + + if ( tipo==1 ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(xc), cgm_vdcy2canvas(yc) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(txant), cgm_vdcy2canvas(tyant) ); + inicio = 2; + } + else if ( tipo==2 ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(txant), cgm_vdcy2canvas(tyant) ); + inicio = 1; + } + + for ( i=inicio; i<=(n+inicio-1); i++ ) + { + px = c*xant+sx*yant; + py = sy*xant+c*yant; + + tx = xc+dy*px-dx*py; /* Inclina (se for o caso) e translada */ + ty = yc+dx*px+dy*py; /* Inclina (se for o caso) e translada */ + + if ( tipo==0 ) + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(txant), cgm_vdcy2canvas(tyant), cgm_vdcx2canvas(tx), cgm_vdcy2canvas(ty) ); + else + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(tx), cgm_vdcy2canvas(ty) ); + + xant = px; + yant = py; + txant = tx; + tyant = ty; + } + +/* Desenha */ + + if ( tipo==1 || tipo==2 ) cdCanvasEnd(intcgm_canvas); +} diff --git a/src/intcgm/ellipse.h b/src/intcgm/ellipse.h new file mode 100644 index 0000000..80980ff --- /dev/null +++ b/src/intcgm/ellipse.h @@ -0,0 +1,3 @@ +void cgm_ElpArc ( double, double, double, double, double, double, double, int, int ); +double cgm_AdjArc ( double arc, double w, double h ); + diff --git a/src/intcgm/intcgm.h b/src/intcgm/intcgm.h new file mode 100644 index 0000000..c106ee0 --- /dev/null +++ b/src/intcgm/intcgm.h @@ -0,0 +1,84 @@ +typedef int (*CGM_FUNC) (void); + +#ifdef _INTCGM1_C_ + +t_cgm intcgm_cgm; +cdCanvas* intcgm_canvas = NULL; + +tlimit intcgm_vdc_ext; +double intcgm_scale_factor_x; +double intcgm_scale_factor_y; +double intcgm_scale_factor_mm_x; +double intcgm_scale_factor_mm_y; +double intcgm_scale_factor; +int intcgm_view_xmin, intcgm_view_ymin, intcgm_view_xmax, intcgm_view_ymax; +double intcgm_clip_xmin, intcgm_clip_ymin, intcgm_clip_xmax, intcgm_clip_ymax; + +_line_att intcgm_line_att = { 1, LINE_SOLID, 1., {1} }; + +_marker_att intcgm_marker_att = { 3, MARK_ASTERISK, 1., {1} }; + +_text_att intcgm_text_att = { 1, 1, NULL, 0, CD_PLAIN, 8, STRING, 1., 0., {1}, .1, + {0,1}, {1,0}, PATH_RIGHT, {NORMHORIZ,NORMVERT,0.,0.} }; + +_fill_att intcgm_fill_att = { 1, HOLLOW, {1}, 1, 1, {0,0}, NULL, {{0.,0.},{0.,0.}} }; + +_edge_att intcgm_edge_att = { 1, EDGE_SOLID, 1., {1}, OFF }; + +trgb *intcgm_color_table; +int intcgm_block; + +TList *intcgm_asf_list; + +tpoint *intcgm_point_list; +int intcgm_npoints; + +CGM_FUNC intcgm_funcs[] = { NULL, &cgmb_rch, &cgmt_rch }; + +#else + +extern t_cgm intcgm_cgm; +extern cdCanvas* intcgm_canvas; + +extern tlimit intcgm_vdc_ext; +extern double intcgm_scale_factor_x; +extern double intcgm_scale_factor_y; +extern double intcgm_scale_factor_mm_x; +extern double intcgm_scale_factor_mm_y; +extern double intcgm_scale_factor; +extern int intcgm_view_xmin, intcgm_view_ymin, intcgm_view_xmax, intcgm_view_ymax; +extern double intcgm_clip_xmin, intcgm_clip_ymin, intcgm_clip_xmax, intcgm_clip_ymax; + +extern _line_att intcgm_line_att; + +extern _marker_att intcgm_marker_att; + +extern _text_att intcgm_text_att; + +extern _fill_att intcgm_fill_att; + +extern _edge_att intcgm_edge_att; + +extern trgb *intcgm_color_table; +extern int intcgm_block; + +extern TList *intcgm_asf_list; + +extern tpoint *intcgm_point_list; +extern int intcgm_npoints; + +extern CGM_FUNC *intcgm_funcs; + +#endif + +typedef struct _tasf { + short type; + short value; + } tasf; + +typedef struct _pat_table { + long index; + long nx, ny; + tcolor *pattern; + } pat_table; + diff --git a/src/intcgm/intcgm1.c b/src/intcgm/intcgm1.c new file mode 100644 index 0000000..d4b2399 --- /dev/null +++ b/src/intcgm/intcgm1.c @@ -0,0 +1,291 @@ +#define _INTCGM1_C_ + +#include <stdio.h> /* FILE, ftell, fseek, fputc, fopen, fclose, fputs, fprintf */ +#include <stdlib.h> /* malloc, free */ +#include <string.h> /* strlen */ +#include <math.h> /* floor */ + +#ifdef SunOS +#include <unistd.h> /* SEEK_SET, SEEK_END */ +#endif + +#include <float.h> /* FLT_MIN, FLT_MAX */ +#include <limits.h> /* INT_MIN, INT_MAX */ + +#include "cd.h" +#include "cdcgm.h" + +#include "list.h" +#include "types.h" +#include "intcgm2.h" +#include "intcgm.h" +#include "bparse.h" + +static int isitbin ( char *fname ) +{ + unsigned char ch[2]; + int erro, c, id; + unsigned short b; + FILE *f = fopen ( fname, "rb" ); + if (!f) + return 0; + + erro = fread ( ch, 1, 2, f ); + + b = (ch[0] << 8) + ch[1]; + + id = ( b & 0x0FE0 ) >> 5; + + c = ( b & 0xF000 ) >> 12; + + fclose(f); + + if ( c==0 && id==1 ) + return 1; + else + return 0; +} + +static int cgmplay ( char* filename, int xmn, int xmx, int ymn, int ymx ) +{ + intcgm_view_xmin = xmn; + intcgm_view_xmax = xmx; + intcgm_view_ymin = ymn; + intcgm_view_ymax = ymx; + + intcgm_scale_factor_x = 1; + intcgm_scale_factor_y = 1; + intcgm_scale_factor = 1; + + intcgm_block = 500; + intcgm_npoints = 500; + intcgm_cgm.buff.size = 1024; + + intcgm_point_list = (tpoint *) malloc ( sizeof(tpoint)*intcgm_npoints); + intcgm_cgm.buff.dados = (char *) malloc ( sizeof(char) * intcgm_cgm.buff.size ); + + if ( isitbin(filename) ) + { + intcgm_cgm.fp = fopen ( filename, "rb" ); + if (!intcgm_cgm.fp) + { + free(intcgm_point_list); + free(intcgm_cgm.buff.dados); + return CD_ERROR; + } + + fseek ( intcgm_cgm.fp, 0, SEEK_END ); + intcgm_cgm.file_size = ftell ( intcgm_cgm.fp ); + fseek ( intcgm_cgm.fp, 0, SEEK_SET ); + + intcgm_cgm.mode = 1; + intcgm_cgm.cgmf = intcgm_funcs[intcgm_cgm.mode]; + + intcgm_cgm.int_prec.b_prec = 1; + intcgm_cgm.real_prec.b_prec = 2; + intcgm_cgm.ix_prec.b_prec = 1; + intcgm_cgm.cd_prec = 0; + intcgm_cgm.cix_prec = 0; + intcgm_cgm.vdc_int.b_prec = 1; + intcgm_cgm.vdc_real.b_prec = 2; + } + else + { + intcgm_cgm.fp = fopen ( filename, "r" ); + if (!intcgm_cgm.fp) + { + free(intcgm_point_list); + free(intcgm_cgm.buff.dados); + return CD_ERROR; + } + + fseek ( intcgm_cgm.fp, 0, SEEK_END ); + intcgm_cgm.file_size = ftell ( intcgm_cgm.fp ); + fseek ( intcgm_cgm.fp, 0, SEEK_SET ); + + intcgm_cgm.mode = 2; + intcgm_cgm.cgmf = intcgm_funcs[intcgm_cgm.mode]; + + intcgm_cgm.int_prec.t_prec.minint = -32767; + intcgm_cgm.int_prec.t_prec.maxint = 32767; + intcgm_cgm.real_prec.t_prec.minreal = -32767; + intcgm_cgm.real_prec.t_prec.maxreal = 32767; + intcgm_cgm.real_prec.t_prec.digits = 4; + intcgm_cgm.ix_prec.t_prec.minint = 0; + intcgm_cgm.ix_prec.t_prec.maxint = 127; + intcgm_cgm.cd_prec = 127; + intcgm_cgm.vdc_int.t_prec.minint = -32767; + intcgm_cgm.vdc_int.t_prec.maxint = 32767; + intcgm_cgm.vdc_real.t_prec.minreal = 0; + intcgm_cgm.vdc_real.t_prec.maxreal = 1; + intcgm_cgm.vdc_real.t_prec.digits = 4; + } + + intcgm_cgm.first = 1; + intcgm_cgm.len = 0; + intcgm_cgm.vdc_type = INTEGER; + intcgm_cgm.max_cix = 63; + intcgm_cgm.scaling_mode.mode = ABSTRACT; + intcgm_cgm.scaling_mode.scale_factor = 1.; + intcgm_cgm.drawing_mode = ABSTRACT; + intcgm_cgm.clrsm = INDEXED; + intcgm_cgm.lnwsm = SCALED; + intcgm_cgm.mkssm = SCALED; + intcgm_cgm.edwsm = SCALED; + intcgm_cgm.vdc_ext.first.x = 0; + intcgm_cgm.vdc_ext.first.y = 0; + intcgm_cgm.vdc_ext.second.x = 32767; + intcgm_cgm.vdc_ext.second.y = 32767; + intcgm_cgm.back_color.red = 0; + intcgm_cgm.back_color.green = 0; + intcgm_cgm.back_color.blue = 0; + intcgm_cgm.aux_color.rgb.red = 0; + intcgm_cgm.aux_color.rgb.green = 0; + intcgm_cgm.aux_color.rgb.blue = 0; + intcgm_cgm.color_ext.black.red = 0; + intcgm_cgm.color_ext.black.green = 0; + intcgm_cgm.color_ext.black.blue = 0; + intcgm_cgm.color_ext.white.red = 255; + intcgm_cgm.color_ext.white.green = 255; + intcgm_cgm.color_ext.white.blue = 255; + intcgm_cgm.transparency = ON; + intcgm_cgm.clip_rect.first.x = 0; + intcgm_cgm.clip_rect.first.y = 0; + intcgm_cgm.clip_rect.second.x = 32767; + intcgm_cgm.clip_rect.second.y = 32767; + intcgm_cgm.clip_ind = ON; + intcgm_cgm.bc = 0; + intcgm_cgm.bl= 0; + intcgm_cgm.cl = 0; + + intcgm_line_att.index = 1; + intcgm_line_att.type = LINE_SOLID; + intcgm_line_att.width = 1; + intcgm_line_att.color.ind = 1; + + intcgm_marker_att.index = 1; + intcgm_marker_att.type = 1; + intcgm_marker_att.size = 1; + intcgm_marker_att.color.ind = 1; + + intcgm_text_att.index = 1; + intcgm_text_att.font_index = 1; + intcgm_text_att.font_list = NULL; + intcgm_text_att.font = 0; + intcgm_text_att.style = CD_PLAIN; + intcgm_text_att.size = 8; + intcgm_text_att.prec = STRING; + intcgm_text_att.exp_fact = 1; + intcgm_text_att.char_spacing = 0; + intcgm_text_att.color.ind = 1; + intcgm_text_att.height = 1; + intcgm_text_att.char_up.x = 0; + intcgm_text_att.char_up.y = 1; + intcgm_text_att.char_base.x = 1; + intcgm_text_att.char_base.y = 0; + intcgm_text_att.path = PATH_RIGHT; + intcgm_text_att.alignment.hor = NORMHORIZ; + intcgm_text_att.alignment.ver = NORMVERT; + intcgm_text_att.alignment.cont_hor = 0; + intcgm_text_att.alignment.cont_ver = 0; + + intcgm_fill_att.index = 1; + intcgm_fill_att.int_style = HOLLOW; + intcgm_fill_att.color.ind = 1; + intcgm_fill_att.hatch_index = 1; + intcgm_fill_att.pat_index = 1; + intcgm_fill_att.ref_pt.x = 0; + intcgm_fill_att.ref_pt.y = 0; + intcgm_fill_att.pat_list = NULL; + intcgm_fill_att.pat_size.height.x = 0; + intcgm_fill_att.pat_size.height.y = 0; + intcgm_fill_att.pat_size.height.x = 0; + intcgm_fill_att.pat_size.width.y = 0; + + intcgm_edge_att.index = 1; + intcgm_edge_att.type = EDGE_SOLID; + intcgm_edge_att.width = 1; + intcgm_edge_att.color.ind = 1; + intcgm_edge_att.visibility = OFF; + + cdCanvasLineWidth(intcgm_canvas, 1); + + intcgm_color_table = (trgb *) malloc ( sizeof(trgb)*intcgm_cgm.max_cix); + intcgm_color_table[0].red = 255; + intcgm_color_table[0].green = 255; + intcgm_color_table[0].blue = 255; + intcgm_color_table[1].red = 0; + intcgm_color_table[1].green = 0; + intcgm_color_table[1].blue = 0; + + while ( !(*intcgm_cgm.cgmf)() ){}; + + if ( intcgm_point_list!=NULL ) + { + free(intcgm_point_list); + intcgm_point_list = NULL; + } + + if ( intcgm_cgm.buff.dados!=NULL ) + { + free(intcgm_cgm.buff.dados); + intcgm_cgm.buff.dados = NULL; + } + + if ( intcgm_color_table!=NULL ) + { + free(intcgm_color_table); + intcgm_color_table = NULL; + } + + fclose(intcgm_cgm.fp); + + return CD_OK; +} + +_cdcgmsizecb cdcgmsizecb = NULL; +_cdcgmbegmtfcb cdcgmbegmtfcb = NULL; +_cdcgmcountercb cdcgmcountercb = NULL; +_cdcgmsclmdecb cdcgmsclmdecb = NULL; +_cdcgmvdcextcb cdcgmvdcextcb = NULL; +_cdcgmbegpictcb cdcgmbegpictcb = NULL; +_cdcgmbegpictbcb cdcgmbegpictbcb = NULL; + +int cdRegisterCallbackCGM(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdcgmsizecb = (_cdcgmsizecb)func; + return CD_OK; + case CD_CGMBEGMTFCB: + cdcgmbegmtfcb = (_cdcgmbegmtfcb)func; + return CD_OK; + case CD_CGMCOUNTERCB: + cdcgmcountercb = (_cdcgmcountercb)func; + return CD_OK; + case CD_CGMSCLMDECB: + cdcgmsclmdecb = (_cdcgmsclmdecb)func; + return CD_OK; + case CD_CGMVDCEXTCB: + cdcgmvdcextcb = (_cdcgmvdcextcb)func; + return CD_OK; + case CD_CGMBEGPICTCB: + cdcgmbegpictcb = (_cdcgmbegpictcb)func; + return CD_OK; + case CD_CGMBEGPICTBCB: + cdcgmbegpictbcb = (_cdcgmbegpictbcb)func; + return CD_OK; + } + + return CD_ERROR; +} + +int cdplayCGM(cdCanvas* _canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + int ret; + intcgm_canvas = _canvas; + ret = cgmplay((char*)data, xmin, xmax, ymin, ymax); + _canvas = NULL; + return ret; +} diff --git a/src/intcgm/intcgm2.c b/src/intcgm/intcgm2.c new file mode 100644 index 0000000..f16c916 --- /dev/null +++ b/src/intcgm/intcgm2.c @@ -0,0 +1,1653 @@ +#include <stdio.h> /* FILE, ftell, fseek, fputc, fopen, fclose, fputs, fprintf */ +#include <string.h> /* strlen */ +#include <stdlib.h> +#include <ctype.h> +#include <math.h> +#include "cd.h" +#include "cdcgm.h" +#include "list.h" +#include "types.h" +#include "bparse.h" +#include "tparse.h" +#include "intcgm.h" +#include "intcgm6.h" +#include "tparse.h" + +typedef struct { + const char *nome; + int (*func) (void); + } comando; + +/************************************************** +*************************************************** +** ** +** FUNCOES CGM ** +** ** +*************************************************** +**************************************************/ + +/************************************************ +* * +* Dados para nao-binario * +* * +************************************************/ + +/* delimiter elements */ + +comando _cgmt_NULL = { "", NULL }; +comando _cgmt_BEGMF = { "begmf", &cgmt_begmtf }; +comando _cgmt_ENDMF = { "endmf", &cgmt_endmtf }; +comando _cgmt_BEG_PIC = { "begpic", &cgmt_begpic }; +comando _cgmt_BEG_PIC_BODY = { "begpicbody", &cgmt_begpib }; +comando _cgmt_END_PIC = { "endpic", &cgmt_endpic }; + +/* metafile descriptor elements */ + +comando _cgmt_MF_VERSION = { "mfversion", cgmt_mtfver }; +comando _cgmt_MF_DESC = { "mfdesc", cgmt_mtfdsc }; +comando _cgmt_VDC_TYPE = { "vdctype", cgmt_vdctyp }; +comando _cgmt_INTEGER_PREC = { "integerprec", cgmt_intpre }; +comando _cgmt_REAL_PREC = { "realprec", cgmt_realpr }; +comando _cgmt_INDEX_PREC = { "indexprec", cgmt_indpre }; +comando _cgmt_COLR_PREC = { "colrprec", cgmt_colpre }; +comando _cgmt_COLR_INDEX_PREC = { "colrindexprec", cgmt_colipr }; +comando _cgmt_MAX_COLR_INDEX = { "maxcolrindex", cgmt_maxcoi }; +comando _cgmt_COLR_VALUE_EXT = { "colrvalueext", cgmt_covaex }; +comando _cgmt_MF_ELEM_LIST = { "mfelemlist", cgmt_mtfell }; +comando _cgmt_BEG_MF_DEFAULTS = { "begmfdefaults", cgmt_bmtfdf }; +comando _cgmt_END_MF_DEFAULTS = { "endmfdefaults", cgmt_emtfdf }; +comando _cgmt_FONT_LIST = { "fontlist", cgmt_fntlst }; +comando _cgmt_CHAR_SET_LIST = { "charsetlist", cgmt_chslst }; +comando _cgmt_CHAR_CODING = { "charcoding", cgmt_chcdac }; + +/* picture descriptor elements */ + +comando _cgmt_SCALE_MODE = { "scalemode", cgmt_sclmde }; +comando _cgmt_COLR_MODE = { "colrmode", cgmt_clslmd }; +comando _cgmt_LINE_WIDTH_MODE = { "linewidthmode", cgmt_lnwdmd }; +comando _cgmt_MARKER_SIZE_MODE = { "markersizemode", cgmt_mkszmd }; +comando _cgmt_EDGE_WIDTH_MODE = { "edgewidthmode", cgmt_edwdmd }; +comando _cgmt_VDC_EXTENT = { "vdcext", cgmt_vdcext }; +comando _cgmt_BACK_COLR = { "backcolr", cgmt_bckcol }; + +/* control elements */ + +comando _cgmt_VDC_INTEGER_PREC = { "vdcintegerprec", cgmt_vdcipr }; +comando _cgmt_VDC_REAL_PREC = { "vdcrealprec", cgmt_vdcrpr }; +comando _cgmt_AUX_COLR = { "auxcolr", cgmt_auxcol }; +comando _cgmt_TRANSPARENCY = { "transparency", cgmt_transp }; +comando _cgmt_CLIP_RECT = { "cliprect", cgmt_clprec }; +comando _cgmt_CLIP = { "clip", cgmt_clpind }; + +/* primitive elements */ + +comando _cgmt_LINE = { "line", cgmt_polyln }; +comando _cgmt_INCR_LINE = { "incrline", cgmt_incply }; +comando _cgmt_DISJT_LINE = { "disjtline", cgmt_djtply }; +comando _cgmt_INCR_DISJT_LINE = { "incrdisjt_line", cgmt_indjpl }; +comando _cgmt_MARKER = { "marker", cgmt_polymk }; +comando _cgmt_INCR_MARKER = { "incrmarker", cgmt_incplm }; +comando _cgmt_TEXT = { "text", cgmt_text }; +comando _cgmt_RESTR_TEXT = { "restrtext", cgmt_rsttxt }; +comando _cgmt_APND_TEXT = { "apndtext", cgmt_apdtxt }; +comando _cgmt_POLYGON = { "polygon", cgmt_polygn }; +comando _cgmt_INCR_POLYGON = { "incrpolygon", cgmt_incplg }; +comando _cgmt_POLYGON_SET = { "polygonset", cgmt_plgset }; +comando _cgmt_INCR_POLYGON_SET = { "incrpolygonset", cgmt_inpgst }; +comando _cgmt_CELL_ARRAY = { "cellarray", cgmt_cellar }; +comando _cgmt_GDP = { "gdp", cgmt_gdp }; +comando _cgmt_RECT = { "rect", cgmt_rect }; +comando _cgmt_CIRCLE = { "circle", cgmt_circle }; +comando _cgmt_ARC_3_PT = { "arc3pt", cgmt_circ3p }; +comando _cgmt_ARC_3_PT_CLOSE = { "arc3ptclose", cgmt_cir3pc }; +comando _cgmt_ARC_CTR = { "arcctr", cgmt_circnt }; +comando _cgmt_ARC_CTR_CLOSE = { "arcctr_close", cgmt_ccntcl }; +comando _cgmt_ELLIPSE = { "ellipse", cgmt_ellips }; +comando _cgmt_ELLIP_ARC = { "elliparc", cgmt_ellarc }; +comando _cgmt_ELLIP_ARC_CLOSE = { "elliparcclose", cgmt_ellacl }; + +/* attribute elements */ + +comando _cgmt_LINE_INDEX = { "lineindex", cgmt_lnbdin }; +comando _cgmt_LINE_TYPE = { "linetype", cgmt_lntype }; +comando _cgmt_LINE_WIDTH = { "linewidth", cgmt_lnwidt }; +comando _cgmt_LINE_COLR = { "linecolr", cgmt_lncolr }; +comando _cgmt_MARKER_INDEX = { "markerindex", cgmt_mkbdin }; +comando _cgmt_MARKER_TYPE = { "markertype", cgmt_mktype }; +comando _cgmt_MARKER_WIDTH = { "markersize", cgmt_mksize }; +comando _cgmt_MARKER_COLR = { "markercolr", cgmt_mkcolr }; +comando _cgmt_TEXT_INDEX = { "textindex", cgmt_txbdin }; +comando _cgmt_TEXT_FONT_INDEX = { "textfontindex", cgmt_txftin }; +comando _cgmt_TEXT_PREC = { "textprec", cgmt_txtprc }; +comando _cgmt_CHAR_EXPAN = { "charexpan", cgmt_chrexp }; +comando _cgmt_CHAR_SPACE = { "charspace", cgmt_chrspc }; +comando _cgmt_TEXT_COLR = { "textcolr", cgmt_txtclr }; +comando _cgmt_CHAR_HEIGHT = { "charheight", cgmt_chrhgt }; +comando _cgmt_CHAR_ORI = { "charori", cgmt_chrori }; +comando _cgmt_TEXT_PATH = { "textpath", cgmt_txtpat }; +comando _cgmt_TEXT_ALIGN = { "textalign", cgmt_txtali }; +comando _cgmt_CHAR_SET_INDEX = { "charsetindex", cgmt_chseti }; +comando _cgmt_ALT_CHAR_SET = { "altcharsetindex", cgmt_achsti }; +comando _cgmt_FILL_INDEX = { "fillindex", cgmt_fillin }; +comando _cgmt_INT_STYLE = { "intstyle", cgmt_intsty }; +comando _cgmt_FILL_COLR = { "fillcolr", cgmt_fillco }; +comando _cgmt_HATCH_INDEX = { "hatchindex", cgmt_hatind }; +comando _cgmt_PAT_INDEX = { "patindex", cgmt_patind }; +comando _cgmt_EDGE_INDEX = { "edgeindex", cgmt_edgind }; +comando _cgmt_EDGE_TYPE = { "edgetype", cgmt_edgtyp }; +comando _cgmt_EDGE_WIDTH = { "edgewidth", cgmt_edgwid }; +comando _cgmt_EDGE_COLR = { "edgecolr", cgmt_edgcol }; +comando _cgmt_EDGE_VIS = { "edgevis", cgmt_edgvis }; +comando _cgmt_FILL_REF_PT = { "fillrefpt", cgmt_fillrf }; +comando _cgmt_PAT_TABLE = { "pattable", cgmt_pattab }; +comando _cgmt_PAT_SIZE = { "patsize", cgmt_patsiz }; +comando _cgmt_COLR_TABLE = { "colrtable", cgmt_coltab }; +comando _cgmt_ASF = { "asf", cgmt_asf }; + +/* escape elements */ + +comando _cgmt_ESCAPE = { "escape", cgmt_escape }; +comando _cgmt_DOMAIN_RING = { "domainring", NULL }; + +/* external elements */ + +comando _cgmt_MESSAGE = { "message", cgmt_messag }; +comando _cgmt_APPL_DATA = { "appldata", cgmt_appdta }; + +comando *_cgmt_delimiter[] = { + &_cgmt_NULL, + &_cgmt_BEGMF, + &_cgmt_ENDMF, + &_cgmt_BEG_PIC, + &_cgmt_BEG_PIC_BODY, + &_cgmt_END_PIC, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +comando *_cgmt_metafile[] = { + &_cgmt_END_MF_DEFAULTS, + &_cgmt_MF_VERSION, + &_cgmt_MF_DESC, + &_cgmt_VDC_TYPE, + &_cgmt_INTEGER_PREC, + &_cgmt_REAL_PREC, + &_cgmt_INDEX_PREC, + &_cgmt_COLR_PREC, + &_cgmt_COLR_INDEX_PREC, + &_cgmt_MAX_COLR_INDEX, + &_cgmt_COLR_VALUE_EXT, + &_cgmt_MF_ELEM_LIST, + &_cgmt_BEG_MF_DEFAULTS, + &_cgmt_FONT_LIST, + &_cgmt_CHAR_SET_LIST, + &_cgmt_CHAR_CODING, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +comando *_cgmt_picture[] = { + &_cgmt_NULL, + &_cgmt_SCALE_MODE, + &_cgmt_COLR_MODE, + &_cgmt_LINE_WIDTH_MODE, + &_cgmt_MARKER_SIZE_MODE, + &_cgmt_EDGE_WIDTH_MODE, + &_cgmt_VDC_EXTENT, + &_cgmt_BACK_COLR, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + +comando *_cgmt_control[] = { + &_cgmt_NULL, + &_cgmt_VDC_INTEGER_PREC, + &_cgmt_VDC_REAL_PREC, + &_cgmt_AUX_COLR, + &_cgmt_TRANSPARENCY, + &_cgmt_CLIP_RECT, + &_cgmt_CLIP, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL }; + +comando *_cgmt_primitive[] = { + &_cgmt_NULL, + &_cgmt_LINE, + &_cgmt_INCR_LINE, + &_cgmt_DISJT_LINE, + &_cgmt_INCR_DISJT_LINE, + &_cgmt_MARKER, + &_cgmt_INCR_MARKER, + &_cgmt_TEXT, + &_cgmt_RESTR_TEXT, + &_cgmt_APND_TEXT, + &_cgmt_POLYGON, + &_cgmt_INCR_POLYGON, + &_cgmt_POLYGON_SET, + &_cgmt_INCR_POLYGON_SET, + &_cgmt_CELL_ARRAY, + &_cgmt_GDP, + &_cgmt_RECT, + &_cgmt_CIRCLE, + &_cgmt_ARC_3_PT, + &_cgmt_ARC_3_PT_CLOSE, + &_cgmt_ARC_CTR, + &_cgmt_ARC_CTR_CLOSE, + &_cgmt_ELLIPSE, + &_cgmt_ELLIP_ARC, + &_cgmt_ELLIP_ARC_CLOSE, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +comando *_cgmt_attributes[] = { + &_cgmt_NULL, + &_cgmt_LINE_INDEX, + &_cgmt_LINE_TYPE, + &_cgmt_LINE_WIDTH, + &_cgmt_LINE_COLR, + &_cgmt_MARKER_INDEX, + &_cgmt_MARKER_TYPE, + &_cgmt_MARKER_WIDTH, + &_cgmt_MARKER_COLR, + &_cgmt_TEXT_INDEX, + &_cgmt_TEXT_FONT_INDEX, + &_cgmt_TEXT_PREC, + &_cgmt_CHAR_EXPAN, + &_cgmt_CHAR_SPACE, + &_cgmt_TEXT_COLR, + &_cgmt_CHAR_HEIGHT, + &_cgmt_CHAR_ORI, + &_cgmt_TEXT_PATH, + &_cgmt_TEXT_ALIGN, + &_cgmt_CHAR_SET_INDEX, + &_cgmt_ALT_CHAR_SET, + &_cgmt_FILL_INDEX, + &_cgmt_INT_STYLE, + &_cgmt_FILL_COLR, + &_cgmt_HATCH_INDEX, + &_cgmt_PAT_INDEX, + &_cgmt_EDGE_INDEX, + &_cgmt_EDGE_TYPE, + &_cgmt_EDGE_WIDTH, + &_cgmt_EDGE_COLR, + &_cgmt_EDGE_VIS, + &_cgmt_FILL_REF_PT, + &_cgmt_PAT_TABLE, + &_cgmt_PAT_SIZE, + &_cgmt_COLR_TABLE, + &_cgmt_ASF, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + +comando *_cgmt_escape[] = { + &_cgmt_NULL, + &_cgmt_ESCAPE, + &_cgmt_DOMAIN_RING, + NULL}; + +comando *_cgmt_external[] = { + &_cgmt_NULL, + &_cgmt_MESSAGE, + &_cgmt_APPL_DATA, + NULL }; + +comando *_cgmt_segment[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +comando *_cgmt_NULL_NULL[] = { + &_cgmt_NULL, + NULL }; + +comando **_cgmt_comandos[] = { + _cgmt_NULL_NULL, + _cgmt_delimiter, + _cgmt_metafile, + _cgmt_picture, + _cgmt_control, + _cgmt_primitive, + _cgmt_attributes, + _cgmt_escape, + _cgmt_external, + _cgmt_segment, + NULL }; + +/************************************************ +* * +* Dados para binario * +* * +************************************************/ + +/* delimiter elements */ + +CGM_FUNC _cgmb_NULL = NULL; + +CGM_FUNC _cgmb_NOOP = &cgmb_noop; +CGM_FUNC _cgmb_BEGMF = &cgmb_begmtf; +CGM_FUNC _cgmb_ENDMF = &cgmb_endmtf; +CGM_FUNC _cgmb_BEG_PIC = &cgmb_begpic; +CGM_FUNC _cgmb_BEG_PIC_BODY = &cgmb_begpib; +CGM_FUNC _cgmb_END_PIC = &cgmb_endpic; + +/* metafile descriptor elements */ + +CGM_FUNC _cgmb_MF_VERSION = &cgmb_mtfver; +CGM_FUNC _cgmb_MF_DESC = &cgmb_mtfdsc; +CGM_FUNC _cgmb_VDC_TYPE = &cgmb_vdctyp; +CGM_FUNC _cgmb_INTEGER_PREC = &cgmb_intpre; +CGM_FUNC _cgmb_REAL_PREC = &cgmb_realpr; +CGM_FUNC _cgmb_INDEX_PREC = &cgmb_indpre; +CGM_FUNC _cgmb_COLR_PREC = &cgmb_colpre; +CGM_FUNC _cgmb_COLR_INDEX_PREC = &cgmb_colipr; +CGM_FUNC _cgmb_MAX_COLR_INDEX = &cgmb_maxcoi; +CGM_FUNC _cgmb_COLR_VALUE_EXT = &cgmb_covaex; +CGM_FUNC _cgmb_MF_ELEM_LIST = &cgmb_mtfell; +CGM_FUNC _cgmb_MF_DEFAULTS_RPL = &cgmb_bmtfdf; +CGM_FUNC _cgmb_FONT_LIST = &cgmb_fntlst; +CGM_FUNC _cgmb_CHAR_SET_LIST = &cgmb_chslst; +CGM_FUNC _cgmb_CHAR_CODING = &cgmb_chcdac; + +/* picture descriptor elements */ + +CGM_FUNC _cgmb_SCALE_MODE = &cgmb_sclmde; +CGM_FUNC _cgmb_COLR_MODE = &cgmb_clslmd; +CGM_FUNC _cgmb_LINE_WIDTH_MODE = &cgmb_lnwdmd; +CGM_FUNC _cgmb_MARKER_SIZE_MODE = &cgmb_mkszmd; +CGM_FUNC _cgmb_EDGE_WIDTH_MODE = &cgmb_edwdmd; +CGM_FUNC _cgmb_VDC_EXTENT = &cgmb_vdcext; +CGM_FUNC _cgmb_BACK_COLR = &cgmb_bckcol; + +/* control elements */ + +CGM_FUNC _cgmb_VDC_INTEGER_PREC = &cgmb_vdcipr; +CGM_FUNC _cgmb_VDC_REAL_PREC = &cgmb_vdcrpr; +CGM_FUNC _cgmb_AUX_COLR = &cgmb_auxcol; +CGM_FUNC _cgmb_TRANSPARENCY = &cgmb_transp; +CGM_FUNC _cgmb_CLIP_RECT = &cgmb_clprec; +CGM_FUNC _cgmb_CLIP = &cgmb_clpind; + +/* primitive elements */ + +CGM_FUNC _cgmb_LINE = &cgmb_polyln; +CGM_FUNC _cgmb_DISJT_LINE = &cgmb_djtply; +CGM_FUNC _cgmb_MARKER = &cgmb_polymk; +CGM_FUNC _cgmb_TEXT = &cgmb_text; +CGM_FUNC _cgmb_RESTR_TEXT = &cgmb_rsttxt; +CGM_FUNC _cgmb_APND_TEXT = &cgmb_apdtxt; +CGM_FUNC _cgmb_POLYGON = &cgmb_polygn; +CGM_FUNC _cgmb_POLYGON_SET = &cgmb_plgset; +CGM_FUNC _cgmb_CELL_ARRAY = &cgmb_cellar; +CGM_FUNC _cgmb_GDP = &cgmb_gdp; +CGM_FUNC _cgmb_RECT = &cgmb_rect; +CGM_FUNC _cgmb_CIRCLE = &cgmb_circle; +CGM_FUNC _cgmb_ARC_3_PT = &cgmb_circ3p; +CGM_FUNC _cgmb_ARC_3_PT_CLOSE = &cgmb_cir3pc; +CGM_FUNC _cgmb_ARC_CTR = &cgmb_circnt; +CGM_FUNC _cgmb_ARC_CTR_CLOSE = &cgmb_ccntcl; +CGM_FUNC _cgmb_ELLIPSE = &cgmb_ellips; +CGM_FUNC _cgmb_ELLIP_ARC = &cgmb_ellarc; +CGM_FUNC _cgmb_ELLIP_ARC_CLOSE = &cgmb_ellacl; + +/* attribute elements */ + +CGM_FUNC _cgmb_LINE_INDEX = &cgmb_lnbdin; +CGM_FUNC _cgmb_LINE_TYPE = &cgmb_lntype; +CGM_FUNC _cgmb_LINE_WIDTH = &cgmb_lnwidt; +CGM_FUNC _cgmb_LINE_COLR = &cgmb_lncolr; +CGM_FUNC _cgmb_MARKER_INDEX = &cgmb_mkbdin; +CGM_FUNC _cgmb_MARKER_TYPE = &cgmb_mktype; +CGM_FUNC _cgmb_MARKER_WIDTH = &cgmb_mksize; +CGM_FUNC _cgmb_MARKER_COLR = &cgmb_mkcolr; +CGM_FUNC _cgmb_TEXT_INDEX = &cgmb_txbdin; +CGM_FUNC _cgmb_TEXT_FONT_INDEX = &cgmb_txftin; +CGM_FUNC _cgmb_TEXT_PREC = &cgmb_txtprc; +CGM_FUNC _cgmb_CHAR_EXPAN = &cgmb_chrexp; +CGM_FUNC _cgmb_CHAR_SPACE = &cgmb_chrspc; +CGM_FUNC _cgmb_TEXT_COLR = &cgmb_txtclr; +CGM_FUNC _cgmb_CHAR_HEIGHT = &cgmb_chrhgt; +CGM_FUNC _cgmb_CHAR_ORI = &cgmb_chrori; +CGM_FUNC _cgmb_TEXT_PATH = &cgmb_txtpat; +CGM_FUNC _cgmb_TEXT_ALIGN = &cgmb_txtali; +CGM_FUNC _cgmb_CHAR_SET_INDEX = &cgmb_chseti; +CGM_FUNC _cgmb_ALT_CHAR_SET = &cgmb_achsti; +CGM_FUNC _cgmb_FILL_INDEX = &cgmb_fillin; +CGM_FUNC _cgmb_INT_STYLE = &cgmb_intsty; +CGM_FUNC _cgmb_FILL_COLR = &cgmb_fillco; +CGM_FUNC _cgmb_HATCH_INDEX = &cgmb_hatind; +CGM_FUNC _cgmb_PAT_INDEX = &cgmb_patind; +CGM_FUNC _cgmb_EDGE_INDEX = &cgmb_edgind; +CGM_FUNC _cgmb_EDGE_TYPE = &cgmb_edgtyp; +CGM_FUNC _cgmb_EDGE_WIDTH = &cgmb_edgwid; +CGM_FUNC _cgmb_EDGE_COLR = &cgmb_edgcol; +CGM_FUNC _cgmb_EDGE_VIS = &cgmb_edgvis; +CGM_FUNC _cgmb_FILL_REF_PT = &cgmb_fillrf; +CGM_FUNC _cgmb_PAT_TABLE = &cgmb_pattab; +CGM_FUNC _cgmb_PAT_SIZE = &cgmb_patsiz; +CGM_FUNC _cgmb_COLR_TABLE = &cgmb_coltab; +CGM_FUNC _cgmb_ASF = &cgmb_asf; + +/* escape elements */ + +CGM_FUNC _cgmb_ESCAPE = &cgmb_escape; + +/* external elements */ + +CGM_FUNC _cgmb_MESSAGE = &cgmb_messag; +CGM_FUNC _cgmb_APPL_DATA = &cgmb_appdta; + +CGM_FUNC *_cgmb_delimiter[] = { + &_cgmb_NOOP, + &_cgmb_BEGMF, + &_cgmb_ENDMF, + &_cgmb_BEG_PIC, + &_cgmb_BEG_PIC_BODY, + &_cgmb_END_PIC, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_metafile[] = { + &_cgmb_NULL, + &_cgmb_MF_VERSION, + &_cgmb_MF_DESC, + &_cgmb_VDC_TYPE, + &_cgmb_INTEGER_PREC, + &_cgmb_REAL_PREC, + &_cgmb_INDEX_PREC, + &_cgmb_COLR_PREC, + &_cgmb_COLR_INDEX_PREC, + &_cgmb_MAX_COLR_INDEX, + &_cgmb_COLR_VALUE_EXT, + &_cgmb_MF_ELEM_LIST, + &_cgmb_MF_DEFAULTS_RPL, + &_cgmb_FONT_LIST, + &_cgmb_CHAR_SET_LIST, + &_cgmb_CHAR_CODING, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_picture[] = { + &_cgmb_NULL, + &_cgmb_SCALE_MODE, + &_cgmb_COLR_MODE, + &_cgmb_LINE_WIDTH_MODE, + &_cgmb_MARKER_SIZE_MODE, + &_cgmb_EDGE_WIDTH_MODE, + &_cgmb_VDC_EXTENT, + &_cgmb_BACK_COLR, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_control[] = { + &_cgmb_NULL, + &_cgmb_VDC_INTEGER_PREC, + &_cgmb_VDC_REAL_PREC, + &_cgmb_AUX_COLR, + &_cgmb_TRANSPARENCY, + &_cgmb_CLIP_RECT, + &_cgmb_CLIP, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_primitive[] = { + &_cgmb_NULL, + &_cgmb_LINE, + &_cgmb_DISJT_LINE, + &_cgmb_MARKER, + &_cgmb_TEXT, + &_cgmb_RESTR_TEXT, + &_cgmb_APND_TEXT, + &_cgmb_POLYGON, + &_cgmb_POLYGON_SET, + &_cgmb_CELL_ARRAY, + &_cgmb_GDP, + &_cgmb_RECT, + &_cgmb_CIRCLE, + &_cgmb_ARC_3_PT, + &_cgmb_ARC_3_PT_CLOSE, + &_cgmb_ARC_CTR, + &_cgmb_ARC_CTR_CLOSE, + &_cgmb_ELLIPSE, + &_cgmb_ELLIP_ARC, + &_cgmb_ELLIP_ARC_CLOSE, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_attributes[] = { + &_cgmb_NULL, + &_cgmb_LINE_INDEX, + &_cgmb_LINE_TYPE, + &_cgmb_LINE_WIDTH, + &_cgmb_LINE_COLR, + &_cgmb_MARKER_INDEX, + &_cgmb_MARKER_TYPE, + &_cgmb_MARKER_WIDTH, + &_cgmb_MARKER_COLR, + &_cgmb_TEXT_INDEX, + &_cgmb_TEXT_FONT_INDEX, + &_cgmb_TEXT_PREC, + &_cgmb_CHAR_EXPAN, + &_cgmb_CHAR_SPACE, + &_cgmb_TEXT_COLR, + &_cgmb_CHAR_HEIGHT, + &_cgmb_CHAR_ORI, + &_cgmb_TEXT_PATH, + &_cgmb_TEXT_ALIGN, + &_cgmb_CHAR_SET_INDEX, + &_cgmb_ALT_CHAR_SET, + &_cgmb_FILL_INDEX, + &_cgmb_INT_STYLE, + &_cgmb_FILL_COLR, + &_cgmb_HATCH_INDEX, + &_cgmb_PAT_INDEX, + &_cgmb_EDGE_INDEX, + &_cgmb_EDGE_TYPE, + &_cgmb_EDGE_WIDTH, + &_cgmb_EDGE_COLR, + &_cgmb_EDGE_VIS, + &_cgmb_FILL_REF_PT, + &_cgmb_PAT_TABLE, + &_cgmb_PAT_SIZE, + &_cgmb_COLR_TABLE, + &_cgmb_ASF, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + +CGM_FUNC *_cgmb_escape[] = { + &_cgmb_NULL, + &_cgmb_ESCAPE, + NULL}; + +CGM_FUNC *_cgmb_external[] = { + &_cgmb_NULL, + &_cgmb_MESSAGE, + &_cgmb_APPL_DATA, + NULL }; + +CGM_FUNC *_cgmb_segment[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +CGM_FUNC **_cgmb_comandos[] = { + _cgmb_delimiter, + _cgmb_metafile, + _cgmb_picture, + _cgmb_control, + _cgmb_primitive, + _cgmb_attributes, + _cgmb_escape, + _cgmb_external, + _cgmb_segment, + NULL }; + +/************************************************ +* * +* Funcoes para binario * +* * +************************************************/ + +int cgm_getfilepos ( void ) +{ + if (cdcgmcountercb) + return cdcgmcountercb ( intcgm_canvas, (ftell ( intcgm_cgm.fp )*100.)/intcgm_cgm.file_size ); + + return 0; +} + +#define cgmb_getw cgmb_getu16 +#define cgmb_getb(b) cgmb_getc((unsigned char *)(b)) + +static void cgmb_donothing ( void ) +{ + intcgm_cgm.bc=intcgm_cgm.len; +} + +int cgmb_exec_comand ( int classe, int id ) +{ + int err; + + if ( _cgmb_comandos[classe][id]==NULL ) + { + cgmb_donothing(); + return 0; + } + + err = (*_cgmb_comandos[classe][id])(); + + if ( err == -1 ) + return 1; + else if ( err ) + { + cgmb_donothing(); + return 0; + } + + return 0; +} + +int cgmb_getbit ( unsigned char *b ) +{ + static unsigned char b1; + + if ( intcgm_cgm.pc==0 || intcgm_cgm.pc==8 ) + { + b1 = intcgm_cgm.buff.dados[intcgm_cgm.bc]; + intcgm_cgm.bc++; + + if ( intcgm_cgm.bc > intcgm_cgm.len ) + { + return 1; + } + + intcgm_cgm.pc=0; + } + + *b = b1; + + switch ( intcgm_cgm.pc ) + { + case 0: + *b = ( *b | 0x0080 ) >> 7; + break; + case 1: + *b = ( *b | 0x0040 ) >> 6; + break; + case 2: + *b = ( *b | 0x0020 ) >> 5; + break; + case 3: + *b = ( *b | 0x0010 ) >> 4; + break; + case 4: + *b = ( *b | 0x0008 ) >> 3; + break; + case 5: + *b = ( *b | 0x0004 ) >> 2; + break; + case 6: + *b = ( *b | 0x0002 ) >> 1; + break; + case 7: + *b = ( *b | 0x0001 ); + break; + } + + intcgm_cgm.pc++; + + return 0; +} + +int cgmb_get2bit ( unsigned char *b ) +{ + static unsigned char b1; + + if ( intcgm_cgm.pc==0 || intcgm_cgm.pc==8 ) + { + b1 = intcgm_cgm.buff.dados[intcgm_cgm.bc]; + intcgm_cgm.bc++; + + if ( intcgm_cgm.bc > intcgm_cgm.len ) return 1; + + intcgm_cgm.pc=0; + } + + *b = b1; + + switch ( intcgm_cgm.pc ) + { + case 0: + *b = ( *b | 0x00C0 ) >> 6; + break; + case 2: + *b = ( *b | 0x0030 ) >> 4; + break; + case 4: + *b = ( *b | 0x000C ) >> 2; + break; + case 6: + *b = ( *b | 0x0003 ); + break; + } + + intcgm_cgm.pc += 2; + + return 0; +} + + +int cgmb_get4bit ( unsigned char *b ) +{ + static unsigned char b1; + + if ( intcgm_cgm.pc==0 || intcgm_cgm.pc==8 ) + { + b1 = intcgm_cgm.buff.dados[intcgm_cgm.bc]; + intcgm_cgm.bc++; + + if ( intcgm_cgm.bc > intcgm_cgm.len ) return 1; + + intcgm_cgm.pc=0; + } + + *b = b1; + + switch ( intcgm_cgm.pc ) + { + case 0: + *b = ( *b | 0x00F0 ) >> 4; + break; + case 4: + *b = ( *b | 0x000F ); + break; + } + + intcgm_cgm.pc += 4; + + return 0; +} + +int cgmb_getw ( unsigned short * ); + +int cgmb_getc ( unsigned char *b ) +{ + *b = intcgm_cgm.buff.dados[intcgm_cgm.bc]; + intcgm_cgm.bc++; + + if ( intcgm_cgm.bc > intcgm_cgm.len ) return 1; + + return 0; +} + +int cgmb_geti8 ( signed char *b ) +{ + unsigned char b1; + + if ( cgmb_getb ( &b1 ) ) return 1; + + *b = (signed char) b1; + + return 0; +} + +int cgmb_geti16 ( short *b ) +{ + unsigned char b1, b2; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + + *b = ( b1<<8 ) | b2; + + return 0; +} + +int cgmb_geti24 ( long *b ) +{ + unsigned char b1, b2, b3; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + + *b = ( b1<<16 ) | ( b2<<8 ) | b3; + + return 0; +} + +int cgmb_geti32 ( long *b ) +{ + unsigned char b1, b2, b3, b4; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + if ( cgmb_getb ( &b4 ) ) return 1; + + *b = ( b1<<24 ) | ( b2<<16 ) | ( b3<<8 ) | b4; + + return 0; +} + +int cgmb_getu8 ( unsigned char *b ) +{ + if ( cgmb_getb ( b ) ) return 1; + + return 0; +} + +int cgmb_getu16 ( unsigned short *b ) +{ + unsigned char b1, b2; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + + *b = ( b1<<8 ) | b2; + + return 0; +} + +int cgmb_getu24 ( unsigned long *b ) +{ + unsigned char b1, b2, b3; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + + *b = ( b1<<16 ) | ( b2<<8 ) | b3; + + return 0; +} + +int cgmb_getu32 ( unsigned long *b ) +{ + unsigned char b1, b2, b3, b4; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + if ( cgmb_getb ( &b4 ) ) return 1; + + *b = ( b1<<24 ) | ( b2<<16 ) | ( b3<<8 ) | b4; + + return 0; +} + +int cgmb_getfl32 ( float *b ) +{ + unsigned char b1, b2, b3, b4; + union { + float f; + long l; + } r; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + if ( cgmb_getb ( &b4 ) ) return 1; + + r.l = ( b1<<24 ) | ( b2<<16 ) | ( b3<<8 ) | b4; + *b = r.f; + + return 0; +} + +int cgmb_getfl64 ( double *b ) +{ + unsigned char b1, b2, b3, b4, b5, b6, b7, b8; + union { + double d; + long l[2]; + } r; + + if ( cgmb_getb ( &b1 ) ) return 1; + if ( cgmb_getb ( &b2 ) ) return 1; + if ( cgmb_getb ( &b3 ) ) return 1; + if ( cgmb_getb ( &b4 ) ) return 1; + if ( cgmb_getb ( &b5 ) ) return 1; + if ( cgmb_getb ( &b6 ) ) return 1; + if ( cgmb_getb ( &b7 ) ) return 1; + if ( cgmb_getb ( &b8 ) ) return 1; + + r.l[1] = ( b1<<24 ) | ( b2<<16 ) | ( b3<<8 ) | b4; + r.l[0] = ( b5<<24 ) | ( b6<<16 ) | ( b7<<8 ) | b8; + *b = r.d; + + return 0; +} + +int cgmb_getfx32 ( float *b ) +{ + short si; + unsigned short ui; + + if ( cgmb_geti16 ( &si ) ) return 1; + if ( cgmb_getu16 ( &ui ) ) return 1; + + *b = (float) ( si + ( ui / 65536.0 ) ); + + return 0; +} + +int cgmb_getfx64 ( double *b ) +{ + long si, ui; + + if ( cgmb_geti32 ( &si ) ) return 1; + if ( cgmb_geti32 ( &ui ) ) return 1; + + *b = si + ( (unsigned short) ui / ( 65536.0 * 65536.0 ) ); + + return 0; +} + +int cgmb_ter ( void ) +{ + return 0; +} + +int cgmb_rch ( void ) +{ + int c, id, len, cont, i; + unsigned char ch[2], dummy; + unsigned short b; + int erro; + + if ( intcgm_cgm.bc!=intcgm_cgm.len ) + { + return 1; + } + + intcgm_cgm.bc = 0; + + erro = fread ( ch, 1, 2, intcgm_cgm.fp ); + if ( erro<2 ) return 1; + + intcgm_cgm.bl += 2; + + b = (ch[0] << 8) + ch[1]; + + len = b & 0x001F; + + id = ( b & 0x0FE0 ) >> 5; + + c = ( b & 0xF000 ) >> 12; + + cont = 0; + + if ( len > 30 ) + { + erro = fread ( ch, 1, 2, intcgm_cgm.fp ); + if ( erro<2 ) return 1; + + intcgm_cgm.bl += 2; + + b = (ch[0] << 8) + ch[1]; + + len = b & 0x7FFF; + cont = ( b & 0x8000 ); + } + + intcgm_cgm.len = len; + + if ( intcgm_cgm.len ) + { + if ( intcgm_cgm.len>intcgm_cgm.buff.size ) + intcgm_cgm.buff.dados = (char *) realloc ( intcgm_cgm.buff.dados, sizeof(char) * intcgm_cgm.len ); + + erro = fread ( intcgm_cgm.buff.dados, 1, intcgm_cgm.len, intcgm_cgm.fp ); + if ( erro<intcgm_cgm.len ) return 1; + + intcgm_cgm.bl += intcgm_cgm.len; + + if ( len & 1 ) + { + erro = fread ( &dummy, 1, 1, intcgm_cgm.fp ); + if ( erro<1 ) return 1; + + intcgm_cgm.bl += 1; + } + + while ( cont ) + { + unsigned char ch[2]; + unsigned short b; + int old_len = intcgm_cgm.len; + + erro = fread ( ch, 1, 2, intcgm_cgm.fp ); + if ( erro<2 ) return 1; + + intcgm_cgm.bl += 2; + + b = (ch[0] << 8) + ch[1]; + + cont = ( b & 0x8000 ); + + len = b & 0x7fff; + + intcgm_cgm.len += len; + + if ( intcgm_cgm.len>intcgm_cgm.buff.size ) + intcgm_cgm.buff.dados = (char *) realloc ( (char *)intcgm_cgm.buff.dados, sizeof(char) * intcgm_cgm.len ); + + erro = fread ( &intcgm_cgm.buff.dados[old_len], 1, len, intcgm_cgm.fp ); + if ( erro<len ) return 1; + + if ( len & 1 ) + { + erro = fread ( &dummy, 1, 1, intcgm_cgm.fp ); + if ( erro<1 ) return 1; + intcgm_cgm.bl += 1; + } + } + } + + cgm_getfilepos (); + + if ( cgmb_exec_comand ( c, id ) ) return 1; + + for ( i=0; i<intcgm_cgm.len-intcgm_cgm.bc; i++ ) + { + unsigned char dummy; + if ( cgmb_getb ( &dummy ) ) return 1; + } + + return 0; +} + +int cgmb_ci ( unsigned long *ci ) +{ + unsigned char c; + unsigned short i; + + switch ( intcgm_cgm.cix_prec ) + { + case 0: if ( cgmb_getu8 ( &c ) ) return 1; + *ci = (unsigned long) c; + break; + case 1: if ( cgmb_getu16 ( &i ) ) return 1; + *ci = (unsigned long) i; + break; + case 2: if ( cgmb_getu24 ( ci ) ) return 1; + break; + case 3: if ( cgmb_getu32 ( ci ) ) return 1; + break; + } + + return 0; +} + +int cgmb_cd ( unsigned long *cd ) +{ + unsigned char c; + unsigned short i; + + switch ( intcgm_cgm.cd_prec ) + { + case 0: if ( cgmb_getu8 ( &c ) ) return 1; + *cd = (unsigned long) c; + break; + case 1: if ( cgmb_getu16 ( &i ) ) return 1; + *cd = (unsigned long) i; + break; + case 2: if ( cgmb_getu24 ( cd ) ) return 1; + break; + case 3: if ( cgmb_getu32 ( cd ) ) return 1; + break; + } + + return 0; +} + +int cgmb_rgb ( unsigned long *r, unsigned long *g, unsigned long *b ) +{ + if ( cgmb_cd ( r ) ) return 1; + if ( cgmb_cd ( g ) ) return 1; + if ( cgmb_cd ( b ) ) return 1; + + return 0; +} + +int cgmb_ix ( long *ix ) +{ + signed char c; + short i; + + switch ( intcgm_cgm.ix_prec.b_prec ) + { + case 0: if ( cgmb_geti8 ( &c ) ) return 1; + *ix = (long) c; + break; + case 1: if ( cgmb_geti16 ( &i ) ) return 1; + *ix = (long) i; + break; + case 2: if ( cgmb_geti24 ( ix ) ) return 1; + break; + case 3: if ( cgmb_geti32 ( ix ) ) return 1; + break; + } + + return 0; +} + +int cgmb_e ( short *e ) +{ + return cgmb_geti16 ( e ); +} + +int cgmb_i ( long *li ) +{ + signed char c; + short i; + + switch ( intcgm_cgm.int_prec.b_prec ) + { + case 0: if ( cgmb_geti8 ( &c ) ) return 1; + *li = (long) c; + break; + case 1: if ( cgmb_geti16 ( &i ) ) return 1; + *li = (long) i; + break; + case 2: if ( cgmb_geti24 ( li ) ) return 1; + break; + case 3: if ( cgmb_geti32 ( li ) ) return 1; + break; + } + + return 0; +} + +int cgmb_u ( unsigned long *ui ) +{ + unsigned char c; + unsigned short i; + + switch ( intcgm_cgm.int_prec.b_prec ) + { + case 0: if ( cgmb_getu8 ( &c ) ) return 1; + *ui = (unsigned long) c; + break; + case 1: if ( cgmb_getu16 ( &i ) ) return 1; + *ui = (unsigned long) i; + break; + case 2: if ( cgmb_getu24 ( ui ) ) return 1; + break; + case 3: if ( cgmb_getu32 ( ui ) ) return 1; + break; + } + + return 0; +} + +int cgmb_r ( double *d ) +{ + float f; + + switch ( intcgm_cgm.real_prec.b_prec ) + { + case 0: if ( cgmb_getfl32 ( &f ) ) return 1; + *d = (double) f; + break; + case 1: if ( cgmb_getfl64 ( d ) ) return 1; + break; + case 2: if ( cgmb_getfx32 ( &f ) ) return 1; + *d = (double) f; + break; + case 3: if ( cgmb_getfx64 ( d ) ) return 1; + break; + } + + return 0; +} + +int cgmb_s ( char **str ) +{ + register unsigned i; + unsigned char l; + unsigned short l1; + unsigned short cont; + char *s = NULL; + + cont = 1; + + if ( cgmb_getu8 ( &l ) ) return 1; + + l1 = l; + + while ( cont ) + { + if ( l > 254 ) + { + if ( cgmb_getu16 ( &l1 ) ) return 1; + cont = ( l1 & 0x8000); + l1 &= 0x7fff; + } + else + cont = 0; + + s = (char *)realloc ( (unsigned char *)s, (sizeof ( char ) * l1) + 1 ); + + for ( i=0; i<l1; i++ ) + { + unsigned char k; + if ( cgmb_getb ( &k ) ) return 1; + s[i] = (char) k; + } + + } + s[i] = '\0'; + + *str = (char*)strdup ( s ); + + free ( s ); + + return 0; +} + +int cgmb_vdc ( double *vdc ) +{ + signed char c; + short i; + long l; + float f; + + if ( intcgm_cgm.vdc_type == 0 ) + switch ( intcgm_cgm.vdc_int.b_prec ) + { + case 0: if ( cgmb_geti8 ( &c ) ) return 1; + *vdc = (double) c; + break; + case 1: if ( cgmb_geti16 ( &i ) ) return 1; + *vdc = (double) i; + break; + case 2: if ( cgmb_geti24 ( &l ) ) return 1; + *vdc = (double) l; + break; + case 3: if ( cgmb_geti32 ( &l ) ) return 1; + *vdc = (double) l; + break; + } + else + switch ( intcgm_cgm.vdc_real.b_prec ) + { + case 0: if ( cgmb_getfl32 ( &f ) ) return 1; + *vdc = (double) f; + break; + case 1: if ( cgmb_getfl64 ( vdc ) ) return 1; + break; + case 2: if ( cgmb_getfx32 ( &f ) ) return 1; + *vdc = (double) f; + break; + case 3: if ( cgmb_getfx64 ( vdc ) ) return 1; + break; + } + + return 0; +} + +int cgmb_p ( double *x, double *y ) +{ + if ( cgmb_vdc ( x ) ) return 1; + if ( cgmb_vdc ( y ) ) return 1; + + return 0; +} + +int cgmb_co ( void *co ) +{ + if ( intcgm_cgm.clrsm == 0 ) /* indexed */ + { + unsigned long *ci = (unsigned long *) co; + if ( cgmb_ci ( ci ) ) return 1; + } + else + { + unsigned long *rgb = (unsigned long *) co; + if ( cgmb_rgb ( &rgb[0], &rgb[1], &rgb[2] ) ) return 1; + } + + return 0; +} + +int cgmb_pixeli ( unsigned long *ci, int localp ) +{ + unsigned char c; + unsigned short i; + + if ( localp==0 ) + { + if ( intcgm_cgm.cix_prec==0 ) localp = 8; + else if ( intcgm_cgm.cix_prec==1 ) localp = 16; + else if ( intcgm_cgm.cix_prec==2 ) localp = 24; + else if ( intcgm_cgm.cix_prec==3 ) localp = 32; + } + + switch ( localp ) + { + case 1: if ( cgmb_getbit ( &c ) ) return 1; + *ci = (unsigned long) c; + break; + case 2: if ( cgmb_get2bit ( &c ) ) + *ci = (unsigned long) c; + return 1; + break; + case 4: if ( cgmb_get4bit ( &c ) ) + *ci = (unsigned long) c; + return 1; + break; + case 8: if ( cgmb_getu8 ( &c ) ) return 1; + *ci = (unsigned long) c; + break; + case 16: if ( cgmb_getu16 ( &i ) ) return 1; + *ci = (unsigned long) i; + break; + case 24: if ( cgmb_getu24 ( ci ) ) return 1; + break; + case 32: if ( cgmb_getu32 ( ci ) ) return 1; + break; + } + + return 0; +} + +int cgmb_pixeld ( unsigned long *cd, int localp ) +{ + unsigned char c; + unsigned short i; + + if ( localp==0 ) + { + if ( intcgm_cgm.cd_prec==0 ) localp = 8; + else if ( intcgm_cgm.cd_prec==1 ) localp = 16; + else if ( intcgm_cgm.cd_prec==2 ) localp = 24; + else if ( intcgm_cgm.cd_prec==3 ) localp = 32; + } + + switch ( localp ) + { + case 1: if ( cgmb_getbit ( &c ) ) return 1; + *cd = (unsigned long) c; + break; + case 2: if ( cgmb_get2bit ( &c ) ) return 1; + *cd = (unsigned long) c; + break; + case 4: if ( cgmb_get4bit ( &c ) ) + *cd = (unsigned long) c; + return 1; + break; + case 8: if ( cgmb_getu8 ( &c ) ) return 1; + *cd = (unsigned long) c; + break; + case 16: if ( cgmb_getu16 ( &i ) ) return 1; + *cd = (unsigned long) i; + break; + case 24: if ( cgmb_getu24 ( cd ) ) return 1; + break; + case 32: if ( cgmb_getu32 ( cd ) ) return 1; + break; + } + + return 0; +} + +int cgmb_pixelrgb ( unsigned long *r, unsigned long *g, unsigned long *b, int localp ) +{ + if ( cgmb_pixeld ( r, localp ) ) return 1; + if ( cgmb_pixeld ( g, localp ) ) return 1; + if ( cgmb_pixeld ( b, localp ) ) return 1; + + return 0; +} + +int cgmb_getpixel ( void *co, int localp ) +{ + if ( intcgm_cgm.clrsm == 0 ) /* indexed */ + { + unsigned long *ci = (unsigned long *) co; + if ( cgmb_pixeli ( ci, localp ) ) return 1; + } + else + { + unsigned long *rgb = (unsigned long *) co; + if ( cgmb_pixelrgb ( &rgb[0], &rgb[1], &rgb[2], localp ) ) return 1; + } + + return 0; +} + +/************************************************ +* * +* Funcoes para clear text * +* * +************************************************/ + +void strlower ( char *string ) +{ + int i; + for ( i=0; string[i]!='\0'; i++ ) + string[i] = tolower ( string[i] ); +} + +char *cgmt_getsep (void) +{ + static char ch[256]; + + fscanf ( intcgm_cgm.fp, "%[ \r\n\t\v\f,]", ch ); + + return ch; +} + +void cgmt_getcom (void) +{ + char chr[256], c; + + while ( (c = fgetc( intcgm_cgm.fp )) == '%' ) + { + fscanf ( intcgm_cgm.fp, "%[^%]%%", chr ); + + cgmt_getsep(); + } + + ungetc( c, intcgm_cgm.fp ); +} + +char *cgmt_getparentheses (void) +{ + static char ch[256]; + + cgmt_getsep(); + + fscanf ( intcgm_cgm.fp, "%[()]", ch ); + + return ch; +} + +int cgmt_ter ( void ) +{ + char c; + + cgmt_getcom(); + + cgmt_getsep(); + + fscanf ( intcgm_cgm.fp, "%c", &c ); + + if ( c=='/' || c==';' ) return 0; + + ungetc ( c, intcgm_cgm.fp ); + + return 1; +} + +int cgmt_rch ( void ) +{ + char chr[256]; + char *pt; + int i, j; + + cgmt_getsep(); + + cgmt_getcom(); + +/* addcounter();*/ + + fscanf ( intcgm_cgm.fp, "%[^ \r\n\t\v\f,/;%\"()]", chr ); + + pt = strtok(chr,"_$"); + + while ( (pt = strtok ( NULL, "_$" )) ) + strcat ( chr, pt ); + + strlower(chr); + + for ( i=0; _cgmt_comandos[i]!=NULL; i++ ) + { + for ( j=0; _cgmt_comandos[i][j]!=NULL; j++ ) + { + if ( strcmp( chr, _cgmt_comandos[i][j]->nome )==0 ) + { + int r = (*_cgmt_comandos[i][j]->func)(); + cgm_getfilepos (); + return r; + } + } + } + + + return 0; +} + +int cgmt_i ( long *i ) +{ + cgmt_getsep(); + + cgmt_getcom(); + + if ( fscanf( intcgm_cgm.fp, "%ld", i ) ) return 0; + + return 1; +} + +int cgmt_ci ( unsigned long *ci ) +{ + return cgmt_i ( (long*)ci ); +} + +int cgmt_cd ( unsigned long *cd ) +{ + return cgmt_i ( (long *) cd ); +} + +int cgmt_rgb ( unsigned long *r, unsigned long *g, unsigned long *b ) +{ + if ( cgmt_cd ( r ) ) return 1; + + if ( cgmt_cd ( g ) ) return 1; + + if ( cgmt_cd ( b ) ) return 1; + + return 0; +} + +int cgmt_ix ( long *ix ) +{ + return cgmt_i ( (long *) ix ); +} + +int cgmt_e ( short *e, const char **el ) +{ + char chr[256]; + int i; + char *pt; + + cgmt_getsep(); + + cgmt_getcom(); + + fscanf ( intcgm_cgm.fp, "%[^ \r\n\t\v\f,/;%\"\']", chr ); + + strlower(chr); + + pt = strtok(chr,"_$"); + + while ( (pt = strtok ( NULL, "_$" )) ) + strcat ( chr, pt ); + + for ( i=0; el[i]!=NULL; i++ ) + if ( strcmp( chr, el[i] ) == 0 ) + { + *e = i; + return 0; + }; + + return 1; +} + +int cgmt_r ( double *f ) +{ + cgmt_getsep(); + + cgmt_getcom(); + + if ( fscanf( intcgm_cgm.fp, "%lg", f ) ) return 0; + + return 1; +} + +int cgmt_s ( char **str ) +{ + char c, delim; + int intcgm_block = 80; + int i = 0; + + *str = (char *) malloc ( intcgm_block*sizeof(char) ); + + strcpy ( *str, "" ); + + cgmt_getsep(); + + cgmt_getcom(); + + delim = fgetc ( intcgm_cgm.fp ); + + if ( delim != '"' && delim != '\'' ) return 1; + + do + { + if ( (c=fgetc(intcgm_cgm.fp))==delim ) + if ( (c=fgetc(intcgm_cgm.fp))==delim ) + (*str)[i++] = c; + else + { + ungetc(c,intcgm_cgm.fp); + break; + } + else + (*str)[i++] = c; + + if ( (i+1)==intcgm_block ) + { + intcgm_block *= 2; + + *str = (char *) realloc ( *str, intcgm_block*sizeof(char) ); + } + } while ( 1 ); + + (*str)[i] = '\0'; + + /* addcounter();*/ + + return 0; +} + +int cgmt_vdc ( double *vdc ) +{ + long l; + + if ( intcgm_cgm.vdc_type==0 ) + { + if ( cgmt_i ( &l ) ) return 1; + *vdc = (double) l; + return 0; + } + else + return cgmt_r ( vdc ); +} + +int cgmt_p ( double *x, double *y ) +{ + cgmt_getparentheses(); + + if ( cgmt_vdc ( x ) ) return 1; + + if ( cgmt_vdc ( y ) ) return 1; + + cgmt_getparentheses(); + + return 0; +} + +int cgmt_co ( void *co ) +{ + if ( intcgm_cgm.clrsm == 0 ) /* indexed */ + { + unsigned long *ci = (unsigned long*)co; + if ( cgmt_ci ( ci ) ) return 1; + } + else + { + unsigned long *cb = (unsigned long *) co; + if ( cgmt_rgb ( &cb[0], &cb[1], &cb[2] ) ) return 1; + } + + return 0; +} diff --git a/src/intcgm/intcgm2.h b/src/intcgm/intcgm2.h new file mode 100644 index 0000000..d7f5204 --- /dev/null +++ b/src/intcgm/intcgm2.h @@ -0,0 +1,52 @@ + +int cgm_getfilepos ( void ); + +int cgmb_exec_comand ( int, int ); +int cgmb_geti8 ( signed char * ); +int cgmb_geti16 ( short * ); +int cgmb_geti24 ( long * ); +int cgmb_geti32 ( long * ); +int cgmb_getu8 ( unsigned char * ); +int cgmb_getu16 ( unsigned short * ); +int cgmb_getu24 ( unsigned long * ); +int cgmb_getu32 ( unsigned long * ); +int cgmb_getfl32 ( float * ); +int cgmb_getfl64 ( double * ); +int cgmb_getfx32 ( float * ); +int cgmb_getfx64 ( double * ); +int cgmb_ter ( void ); +int cgmb_rch ( void ); +int cgmb_ci ( unsigned long * ); +int cgmb_cd ( unsigned long * ); +int cgmb_rgb ( unsigned long *, unsigned long *, unsigned long * ); +int cgmb_ix ( long * ); +int cgmb_e ( short * ); +int cgmb_i ( long * ); +int cgmb_u ( unsigned long * ); +int cgmb_r ( double * ); +int cgmb_s ( char ** ); +int cgmb_vdc ( double * ); +int cgmb_p ( double *, double * ); +int cgmb_co ( void * ); +int cgmb_getpixel ( void *, int ); +int cgmb_getc ( unsigned char * ); + +char *cgmt_getsep ( void ); +void cgmt_getcom ( void ); +char *cgmt_getparentheses ( void ); +int cgmt_ter ( void ); +int cgmt_rch ( void ); +int cgmt_i ( long * ); +int cgmt_ci ( unsigned long * ); +int cgmt_cd ( unsigned long * ); +int cgmt_rgb ( unsigned long *, unsigned long *, unsigned long * ); +int cgmt_ix ( long * ); +int cgmt_e ( short *, const char ** ); +int cgmt_r ( double * ); +int cgmt_s ( char ** ); +int cgmt_vdc ( double * ); +int cgmt_p ( double *, double * ); +int cgmt_co ( void * ); + + + diff --git a/src/intcgm/intcgm4.c b/src/intcgm/intcgm4.c new file mode 100644 index 0000000..4c8afe0 --- /dev/null +++ b/src/intcgm/intcgm4.c @@ -0,0 +1,1265 @@ +#define _INTCGM4_C_ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include <cd.h> +#include <cdcgm.h> + +#include "list.h" +#include "types.h" +#include "intcgm.h" +#include "intcgm2.h" +#include "intcgm4.h" +#include "intcgm6.h" +#include "ellipse.h" +#include "circle.h" +#include "sism.h" + +#ifndef PI +#define PI 3.1415931 +#endif +#define TWOPI 2*PI + +static double myhypot ( double x, double y ) +{ + return sqrt ( x*x + y*y ); +} + +int cgm_do_vdcext ( tpoint first, tpoint second ) +{ + double width, height; + double tmp; + double razao_vp; + double razao_wn; + int w_pixel, h_pixel; + double w_mm, h_mm; + + if ( first.x > second.x ) + { + tmp = first.x; + first.x = second.x; + second.x = tmp; + } + + if ( first.y > second.y ) + { + tmp = first.y; + first.y = second.y; + second.y = tmp; + } + + width = intcgm_view_xmax-intcgm_view_xmin+1; + height = intcgm_view_ymax-intcgm_view_ymin+1; + + razao_vp = (double) width/ (double) height; + razao_wn = (second.x-first.x) / (second.y-first.y); + + if ( razao_vp > razao_wn ) + { + first.x -= ((second.y-first.y)*razao_vp - (second.x-first.x)) / 2.; + second.x = (second.y-first.y)*razao_vp+first.x; + } + else + { + first.y -= ((second.x-first.x)/razao_vp - (second.y-first.y)) / 2.; + second.y = (second.x-first.x)/razao_vp+first.y; + } + + intcgm_vdc_ext.xmin = first.x; + intcgm_vdc_ext.xmax = second.x; + intcgm_vdc_ext.ymin = first.y; + intcgm_vdc_ext.ymax = second.y; + + intcgm_scale_factor_x = width/(second.x-first.x); + intcgm_scale_factor_y = height/(second.y-first.y); + intcgm_scale_factor = sqrt(width * width + height * height)/sqrt((second.x-first.x)+(second.y-first.y)); + cdCanvasGetSize (intcgm_canvas, &w_pixel, &h_pixel, &w_mm, &h_mm ); + intcgm_scale_factor_mm_x = w_pixel/w_mm; + intcgm_scale_factor_mm_y = h_pixel/h_mm; + + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + { + intcgm_clip_xmin = cgm_canvas2vdcx ( intcgm_view_xmin ); + intcgm_clip_xmax = cgm_canvas2vdcx ( intcgm_view_xmax ); + intcgm_clip_ymin = cgm_canvas2vdcy ( intcgm_view_ymin ); + intcgm_clip_ymax = cgm_canvas2vdcy ( intcgm_view_ymax ); + } + else + { + intcgm_clip_xmin = intcgm_vdc_ext.xmin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_xmax = intcgm_vdc_ext.xmax*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymin = intcgm_vdc_ext.ymin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymax = intcgm_vdc_ext.ymax*intcgm_cgm.scaling_mode.scale_factor; + } + + cdCanvasClipArea (intcgm_canvas, cgm_vdcx2canvas(first.x), cgm_vdcx2canvas(second.x), + cgm_vdcy2canvas(first.y), cgm_vdcy2canvas(second.y) ); + cdCanvasClip(intcgm_canvas, CD_CLIPOFF ); + + return 0; +} + +int cgm_do_bckcol ( trgb rgb ) +{ + long int cor = cdEncodeColor ( (unsigned char) rgb.red, + (unsigned char) rgb.green, + (unsigned char) rgb.blue ); + + cdCanvasSetBackground (intcgm_canvas, cor ); + + return 0; +} + +int cgm_do_transp ( int transparency ) +{ + if ( transparency ) + cdCanvasBackOpacity (intcgm_canvas, CD_TRANSPARENT ); + else + cdCanvasBackOpacity (intcgm_canvas, CD_OPAQUE ); + + return 0; +} + +int cgm_do_clprec ( tpoint first, tpoint second ) +{ + double tmp; + + if ( first.x > second.x ) + { + tmp = first.x; + first.x = second.x; + second.x = tmp; + } + + if ( first.y > second.y ) + { + tmp = first.y; + first.y = second.y; + second.y = tmp; + } + + cdCanvasClipArea (intcgm_canvas, cgm_vdcx2canvas(first.x), cgm_vdcx2canvas(second.x), + cgm_vdcy2canvas(first.y), cgm_vdcy2canvas(second.y) ); + + return 0; +} + +int cgm_do_clpind ( int indicator ) +{ + if ( indicator ) + cdCanvasClip(intcgm_canvas, CD_CLIPAREA ); + else + cdCanvasClip(intcgm_canvas, CD_CLIPOFF ); + + return 0; +} + +int cgm_do_polyln ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasBegin(intcgm_canvas, CD_OPEN_LINES ); + + for ( i=0; i<n_points; i++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + + cdCanvasEnd (intcgm_canvas); + + return 0; +} + +int cgm_do_incply ( int n_points, tpoint *pt ) +{ + int i; + double x, y; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getincpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasBegin(intcgm_canvas, CD_OPEN_LINES ); + + x = pt[0].x; y = pt[0].y; + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[0].x), cgm_vdcy2canvas(pt[0].y) ); + + for ( i=1; i<n_points; i++ ) + { + x += pt[i].x; y += pt[i].x; + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(x), cgm_vdcy2canvas(y) ); + } + + cdCanvasEnd (intcgm_canvas); + + return 0; +} + +int cgm_do_djtply ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + if ( n_points < 2 ) return 1; + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + for ( i=0; i<n_points; i=i+2 ) + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y), + cgm_vdcx2canvas(pt[i+1].x), cgm_vdcy2canvas(pt[i+1].y) ); + + return 0; +} + +int cgm_do_indpl ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getincpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + if ( n_points < 2 ) return 1; + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + pt[1].x = pt[0].x + pt[1].x; pt[1].y = pt[0].y + pt[1].y; + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(pt[0].x), cgm_vdcy2canvas(pt[0].y), + cgm_vdcx2canvas(pt[1].x), cgm_vdcy2canvas(pt[1].y) ); + + for ( i=2; i<n_points; i=i+2 ) + { + pt[i].x += pt[i-1].x; pt[i].y += pt[i-1].y; + pt[i+1].x += pt[i].x; pt[i+1].y += pt[i].y; + cdCanvasLine (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y), + cgm_vdcx2canvas(pt[i+1].x), cgm_vdcy2canvas(pt[i+1].y) ); + } + + return 0; +} + +int cgm_do_polymk ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_setmarktype ( intcgm_marker_att.type ); + cgm_setmarksize ( intcgm_marker_att.size ); + cor = cgm_getcolor ( intcgm_marker_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + for ( i=0; i<n_points; i++ ) + cdCanvasMark (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + + return 0; +} + +int cgm_do_incplm ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getincpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_setmarktype ( intcgm_marker_att.type ); + cgm_setmarksize ( intcgm_marker_att.size ); + cor = cgm_getcolor ( intcgm_marker_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasMark (intcgm_canvas, cgm_vdcx2canvas(pt[0].x), cgm_vdcy2canvas(pt[0].y) ); + + for ( i=1; i<n_points; i++ ) + { + pt[i].x += pt[i-1].x; pt[i].y += pt[i-1].y; + cdCanvasMark (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + } + + return 0; +} + +int cgm_do_text ( int mode, char *string, tpoint pos ) +{ + long int cor; + + cor = cgm_getcolor ( intcgm_text_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setfont ( intcgm_text_att.font, intcgm_text_att.style, intcgm_text_att.height ); + + cdCanvasText (intcgm_canvas, cgm_vdcx2canvas(pos.x), cgm_vdcy2canvas(pos.y), string ); + + return 0; +} + +int cgm_do_txtalign ( int hor, int ver ) +{ + enum { NORMHORIZ, LEFT, CTR, RIGHT }; + enum { NORMVERT, TOP, CAP, HALF, BASE, BOTTOM }; + + switch (hor) + { + case NORMHORIZ: + switch (ver) + { + case NORMVERT: + cdCanvasTextAlignment(intcgm_canvas, CD_CENTER); + break; + case TOP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH); + break; + case CAP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH); + break; + case HALF: + cdCanvasTextAlignment(intcgm_canvas, CD_CENTER); + break; + case BASE: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH); + break; + case BOTTOM: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH); + break; + } + break; + case LEFT: + switch (ver) + { + case NORMVERT: + cdCanvasTextAlignment(intcgm_canvas, CD_WEST); + break; + case TOP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH_WEST); + break; + case CAP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH_WEST); + break; + case HALF: + cdCanvasTextAlignment(intcgm_canvas, CD_WEST); + break; + case BASE: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH_WEST); + break; + case BOTTOM: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH_WEST); + break; + } + break; + case CTR: + switch (ver) + { + case NORMVERT: + cdCanvasTextAlignment(intcgm_canvas, CD_CENTER); + break; + case TOP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH); + break; + case CAP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH); + break; + case HALF: + cdCanvasTextAlignment(intcgm_canvas, CD_CENTER); + break; + case BASE: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH); + break; + case BOTTOM: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH); + break; + } + break; + case RIGHT: + switch (ver) + { + case NORMVERT: + cdCanvasTextAlignment(intcgm_canvas, CD_EAST); + break; + case TOP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH_EAST); + break; + case CAP: + cdCanvasTextAlignment(intcgm_canvas, CD_NORTH_EAST); + break; + case HALF: + cdCanvasTextAlignment(intcgm_canvas, CD_EAST); + break; + case BASE: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH_EAST); + break; + case BOTTOM: + cdCanvasTextAlignment(intcgm_canvas, CD_SOUTH_EAST); + break; + } + break; + } + + return 0; +} + +int cgm_do_polygn ( int n_points, tpoint *pt ) +{ + int i; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_line_att.width ); + + if ( intcgm_fill_att.int_style!=HOLLOW && intcgm_fill_att.int_style!=EMPTY ) + { + cdCanvasBegin(intcgm_canvas, cgm_setintstyle ( intcgm_fill_att.int_style ) ); + + for ( i=0; i<n_points; i++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + + cdCanvasEnd (intcgm_canvas); + } + + if ( intcgm_edge_att.visibility==ON ) + { + cor = cgm_getcolor ( intcgm_edge_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_edge_att.width ); + + cdCanvasBegin(intcgm_canvas, CD_CLOSED_LINES ); + + for ( i=0; i<n_points; i++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + + cdCanvasEnd (intcgm_canvas); + } + + return 0; +} + +int cgm_do_incplg ( int n_points, tpoint *pt ) +{ + int i; + tpoint p; + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getincpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasBegin(intcgm_canvas, cgm_setintstyle ( intcgm_fill_att.int_style ) ); + + p.x = pt[0].x; p.y = pt[0].y; + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[0].x), cgm_vdcy2canvas(pt[0].y) ); + + for ( i=1; i<n_points; i++ ) + { + p.x += pt[i].x; p.y += pt[i].y; + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(p.x), cgm_vdcy2canvas(p.y) ); + } + + cdCanvasEnd (intcgm_canvas); + + return 0; +} + +int cgm_do_plgset( int incremental, int n_points, tpoint *pt, short *flag ) +{ + int i, j; + tpoint closure; + long int cor; + int start; + int vis = intcgm_edge_att.visibility; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cgm_getpolybbox ( pt, n_points, &bb_xmin, &bb_ymin, &bb_xmax, &bb_ymax ); + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + intcgm_edge_att.visibility = OFF; + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + if ( intcgm_fill_att.int_style!=HOLLOW && intcgm_fill_att.int_style!=EMPTY ) + { + cdCanvasBegin(intcgm_canvas, cgm_setintstyle ( intcgm_fill_att.int_style ) ); + start = 1; + for ( i=0; i<n_points; i++ ) + { + if ( start ) + { + closure.x = pt[i].x; + closure.y = pt[i].y; + start = 0; + } + else if ( incremental==YES ) + { + pt[i].x = pt[i].x+pt[i-1].x; + pt[i].y = pt[i].y+pt[i-1].y; + } + + if ( flag[i]==CLOSE_VISIBLE || flag[i]==CLOSE_INVISIBLE ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(closure.x), cgm_vdcy2canvas(closure.y) ); + start=1; + } + else + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[i].x), cgm_vdcy2canvas(pt[i].y) ); + } + cdCanvasEnd (intcgm_canvas); + } + + + intcgm_edge_att.visibility = vis; + + if ( intcgm_edge_att.visibility==ON ) + { + int np; + + cor = cgm_getcolor ( intcgm_edge_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_edge_att.width ); + + np = 0; + start = 0; + for ( i=0; i<n_points; i++ ) + { + if ( incremental==YES ) + { + pt[i].x = pt[i].x+pt[i-1].x; + pt[i].y = pt[i].y+pt[i-1].y; + } + + if ( flag[i]==CLOSE_VISIBLE || (flag[i]==VISIBLE && i==n_points-1) ) + { + cdCanvasBegin(intcgm_canvas, CD_CLOSED_LINES ); + for ( j=0; j<np; j++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[start+j].x), cgm_vdcy2canvas(pt[start+j].y) ); + cdCanvasEnd(intcgm_canvas); + start += np; + np = 0; + } + else if ( flag[i]==INVISIBLE || flag[i]==CLOSE_INVISIBLE ) + { + cdCanvasBegin(intcgm_canvas, CD_OPEN_LINES ); + for ( j=0; j<np; j++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(pt[start+j].x), cgm_vdcy2canvas(pt[start+j].y) ); + cdCanvasEnd(intcgm_canvas); + start += np; + np = 0; + } + else + np++; + } + } + + return 0; +} + +int cgm_do_cellar ( tpoint corner1, tpoint corner2, tpoint corner3, int nx, + int ny, long color_prec, tcolor *cell ) +{ + int cx1, cy1, cx2, cy2, cx3, cy3, tmp, i, j; + unsigned char *r, *g, *b; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = ( corner1.x < corner2.x ) ? corner1.x : corner2.x; + bb_xmax = ( corner1.x > corner2.x ) ? corner1.x : corner2.x; + bb_ymin = ( corner1.y < corner2.y ) ? corner1.y : corner2.y; + bb_ymax = ( corner1.y > corner2.y ) ? corner1.y : corner2.y; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + r = (unsigned char *) malloc ( nx*ny*sizeof(unsigned char) ); + g = (unsigned char *) malloc ( nx*ny*sizeof(unsigned char) ); + b = (unsigned char *) malloc ( nx*ny*sizeof(unsigned char) ); + + cx1 = cgm_vdcx2canvas(corner1.x); + cy1 = cgm_vdcy2canvas(corner1.y); + cx2 = cgm_vdcx2canvas(corner2.x); + cy2 = cgm_vdcy2canvas(corner2.y); + cx3 = cgm_vdcx2canvas(corner3.x); + cy3 = cgm_vdcy2canvas(corner3.y); + +#if 1 + if ( cx1<cx3 && cy1==cy3 && cx2==cx3 && cy2>cy3 ) + { + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[nx*i+j].rgb.red; + g[nx*i+j] = (unsigned char) cell[nx*i+j].rgb.green; + b[nx*i+j] = (unsigned char) cell[nx*i+j].rgb.blue; + } + } + else if ( cx1==cx3 && cy1<cy3 && cx2>cx3 && cy2==cy3 ) + { + tmp = nx; nx = ny; ny = tmp; + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[ny*j+i].rgb.red; + g[nx*i+j] = (unsigned char) cell[ny*j+i].rgb.green; + b[nx*i+j] = (unsigned char) cell[ny*j+i].rgb.blue; + } + } + else if ( cx1<cx3 && cy1==cy3 && cx2==cx3 && cy2<cy3 ) + { + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+j].rgb.red; + g[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+j].rgb.green; + b[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+j].rgb.blue; + } + } + else if ( cx1==cx3 && cy1>cy3 && cx2>cx3 && cy2==cy3 ) + { + tmp = nx; nx = ny; ny = tmp; + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[ny*j+(ny-i-1)].rgb.red; + g[nx*i+j] = (unsigned char) cell[ny*j+(ny-i-1)].rgb.green; + b[nx*i+j] = (unsigned char) cell[ny*j+(ny-i-1)].rgb.blue; + } + } + else if ( cx1>cx3 && cy1==cy3 && cx2==cx3 && cy2>cy3 ) + { + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[nx*i+(nx-j-1)].rgb.red; + g[nx*i+j] = (unsigned char) cell[nx*i+(nx-j-1)].rgb.green; + b[nx*i+j] = (unsigned char) cell[nx*i+(nx-j-1)].rgb.blue; + } + } + else if ( cx1==cx3 && cy1>cy3 && cx2<cx3 && cy2==cy3 ) + { + tmp = nx; nx = ny; ny = tmp; + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+(ny-i-1)].rgb.red; + g[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+(ny-i-1)].rgb.green; + b[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+(ny-i-1)].rgb.blue; + } + } + else if ( cx1>cx3 && cy1==cy3 && cx2==cx3 && cy2<cy3 ) + { + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+(nx-j-1)].rgb.red; + g[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+(nx-j-1)].rgb.green; + b[nx*i+j] = (unsigned char) cell[nx*(ny-i-1)+(nx-j-1)].rgb.blue; + } + } + else if ( cx1==cx3 && cy1<cy3 && cx2<cx3 && cy2==cy3 ) + { + tmp = nx; nx = ny; ny = tmp; + for ( i=0; i<ny; i++ ) + for ( j=0; j<nx; j++ ) + { + r[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+i].rgb.red; + g[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+i].rgb.green; + b[nx*i+j] = (unsigned char) cell[ny*(nx-j-1)+i].rgb.blue; + } + } +#else + for ( i=0; i<nx; i++ ) + for ( j=0; j<ny; j++ ) + { + r[nx*j+i] = (unsigned char) cell[nx*j+i].rgb.red; + g[nx*j+i] = (unsigned char) cell[nx*j+i].rgb.green; + b[nx*j+i] = (unsigned char) cell[nx*j+i].rgb.blue; + } +#endif + +#if 1 + if ( cx1>cx2 ) + { + tmp = cx1; + cx1 = cx2; + cx2 = tmp; + } + + if ( cy1>cy2 ) + { + tmp = cy1; + cy1 = cy2; + cy2 = tmp; + } +#endif + + cdCanvasPutImageRectRGB (intcgm_canvas, nx, ny, r, g, b, cx1, cy1, cx2-cx1+1, cy2-cy1+1,0,0,0,0 ); + + free(r); + free(g); + free(b); + + return 0; +} + +int cgm_do_gdp ( int identifier, tpoint *pt, char *data_rec ) +{ + if ( identifier==-4 ) + cgm_sism4 ( pt, data_rec ); + else if ( identifier==-5 ) + cgm_sism5 ( data_rec ); + + return 0; +} + +int cgm_do_rect ( tpoint point1, tpoint point2 ) +{ + long int cor; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = ( point1.x < point2.x ) ? point1.x : point2.x; + bb_xmax = ( point1.x > point2.x ) ? point1.x : point2.x; + bb_ymin = ( point1.y < point2.y ) ? point1.y : point2.y; + bb_ymax = ( point1.y > point2.y ) ? point1.y : point2.y; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasBegin(intcgm_canvas, cgm_setintstyle ( intcgm_fill_att.int_style ) ); + + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(point1.x), cgm_vdcy2canvas(point1.y) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(point2.x), cgm_vdcy2canvas(point1.y) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(point2.x), cgm_vdcy2canvas(point2.y) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(point1.x), cgm_vdcy2canvas(point2.y) ); + + cdCanvasEnd (intcgm_canvas); + + return 0; +} + +int cgm_do_circle ( tpoint center, double radius ) +{ + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - radius; + bb_xmax = center.x + radius; + bb_ymin = center.y - radius; + bb_ymax = center.y + radius; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin|| + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + if ( intcgm_fill_att.int_style!=EMPTY ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + + if ( intcgm_fill_att.int_style!=EMPTY ) + cgm_poly_circle ( center.x, center.y, radius, 0, TWOPI, CLOSED_CHORD ); + else + cgm_line_circle ( center.x, center.y, radius, 0, TWOPI, CLOSED_CHORD ); + } + + if ( intcgm_edge_att.visibility==ON ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_edge_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinestyle ( intcgm_edge_att.type ); + cgm_setlinewidth ( intcgm_edge_att.width ); + + cgm_line_circle ( center.x, center.y, radius, 0., TWOPI, CLOSED_CHORD ); + } + + return 0; +} + +static double angulo ( double cx, double cy, double px, double py ) +{ + double ang; + if ((fabs(py-cy)<1e-9) && (fabs(px-cx)<1e-9)) + ang = 0.0; + else + ang = atan2 ( py - cy , px - cx ); + + if ( ang<0.) ang = TWOPI - fabs(ang); + + return ang; +} + +static void solve2 ( double m[][2], double *b, double *x ) +{ + double det; + + det = m[0][0]*m[1][1] - m[0][1]*m[1][0]; + + if ( det==0.0 ) return; + + x[0] = ( b[0]*m[1][1] - b[1]*m[1][0] ) / det; + x[1] = ( m[0][0]*b[1] - m[0][1]*b[0] ) / det; +} + +static void getcenter ( double xs, double ys, double xi, double yi, double xe, double ye, + double *xc, double *yc ) +{ + double c[2]; + + double x2, y2, x3, y3, m[2][2], b[2]; + + x2 = xi - xs; + y2 = yi - ys; + x3 = xe - xs; + y3 = ye - ys; + + m[0][0] = 2*x2; + m[1][0] = 2*y2; + m[0][1] = 2*x3; + m[1][1] = 2*y3; + b[0] = x2*x2 + y2*y2; + b[1] = x3*x3 + y3*y3; + + solve2 ( m, b, c ); + + *xc = c[0] + xs; + *yc = c[1] + ys; +} + +int cgm_do_circ3p ( tpoint starting, tpoint intermediate, tpoint ending ) +{ + long int cor; + double xc, yc; + double angi, angm, angf; + double radius; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cor = cgm_getcolor ( intcgm_line_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + + getcenter ( starting.x, starting.y, intermediate.x, intermediate.y, ending.x, ending.y, &xc, &yc ); + + angi = angulo( xc, yc, starting.x, starting.y ); + angm = angulo( xc, yc, intermediate.x, intermediate.y ); + angf = angulo( xc, yc, ending.x, ending.y ); + + if ( angm<angi ) + { + double tmp = angi; + angi = angf; + angf = tmp; + } + + if ( angf<angi ) angf = angf + TWOPI; + + radius = sqrt ( (starting.x-xc)*(starting.x-xc) + (starting.y-yc)*(starting.y-yc) ); + + bb_xmin = xc - radius; + bb_xmax = xc + radius; + bb_ymin = yc - radius; + bb_ymax = yc + radius; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_line_circle ( xc, yc, radius, angi, angf, OPEN ); + + return 0; +} + +int cgm_do_circ3pc ( tpoint starting, tpoint intermediate, tpoint ending, int close_type ) +{ + long int cor; + double xc, yc; + double angi, angm, angf; + double radius; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinestyle ( intcgm_line_att.type ); + cgm_setlinewidth ( intcgm_line_att.width ); + + getcenter ( starting.x, starting.y, intermediate.x, intermediate.y, ending.x, ending.y, &xc, &yc ); + + angi = angulo( xc, yc, starting.x, starting.y ); + angm = angulo( xc, yc, intermediate.x, intermediate.y ); + angf = angulo( xc, yc, ending.x, ending.y ); + + radius = sqrt ( (starting.x-xc)*(starting.x-xc) + (starting.y-yc)*(starting.y-yc) ); + + bb_xmin = xc - radius; + bb_xmax = xc + radius; + bb_ymin = yc - radius; + bb_ymax = yc + radius; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + if ( angm<angi ) + { + double tmp = angi; + angi = angf; + angf = tmp; + } + + if ( angf<angi ) angf = angf + TWOPI; + + if ( intcgm_fill_att.int_style!=EMPTY ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_line_att.width ); + + if ( intcgm_fill_att.int_style!=EMPTY ) + cgm_poly_circle ( xc, yc, radius, angi, angf, (close_type) ? CLOSED_CHORD : CLOSED_PIE ); + else + cgm_line_circle ( xc, yc, radius, angi, angf, (close_type) ? CLOSED_CHORD : CLOSED_PIE ); + } + + if ( intcgm_edge_att.visibility==ON ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_edge_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinestyle ( intcgm_edge_att.type ); + cgm_setlinewidth ( intcgm_edge_att.width ); + + cgm_line_circle ( xc, yc, radius, angi, angf, (close_type) ? CLOSED_CHORD : CLOSED_PIE ); + } + + return 0; +} + +int cgm_do_circcnt ( tpoint center, tpoint start, tpoint end, double radius ) +{ + long int cor; + double angi, angf; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - radius; + bb_xmax = center.x + radius; + bb_ymin = center.y - radius; + bb_ymax = center.y + radius; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_line_att.width ); + + angi = angulo( center.x, center.y, start.x, start.y ); + angf = angulo( center.x, center.y, end.x, end.y ); + + if ( angf<angi ) + { + double tmp = angi; + angi = angf; + angf = tmp; + } + + cgm_line_circle ( center.x, center.y, radius, angi, angf, OPEN ); + + return 0; +} + +int cgm_do_ccntcl ( tpoint center, tpoint start, tpoint end, double radius, int close_type ) +{ + long int cor; + double angi, angf; + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - radius; + bb_xmax = center.x + radius; + bb_ymin = center.y - radius; + bb_ymax = center.y + radius; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_line_att.width ); + + angi = angulo( center.x, center.y, start.x, start.y ); + angf = angulo( center.x, center.y, end.x, end.y ); + + if ( angf<angi ) + { + double tmp = angi; + angi = angf; + angf = tmp; + } + + if ( intcgm_fill_att.int_style!=HOLLOW && intcgm_fill_att.int_style!=EMPTY ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_fill_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_line_att.width ); + + cgm_poly_circle ( center.x, center.y, radius, angi, angf, (close_type) ? CLOSED_CHORD : CLOSED_PIE ); + } + + if ( intcgm_edge_att.visibility==ON ) + { + long int cor; + + cor = cgm_getcolor ( intcgm_edge_att.color ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cgm_setlinewidth ( intcgm_edge_att.width ); + + cgm_line_circle ( center.x, center.y, radius, angi, angf, (close_type) ? CLOSED_CHORD : CLOSED_PIE ); + } + + return 0; +} + +int cgm_do_ellips ( tpoint center, tpoint first_CDP, tpoint second_CDP ) +{ + double w = myhypot ( first_CDP.x-center.x, first_CDP.y-center.y ); + double h = myhypot ( second_CDP.x-center.x, second_CDP.y-center.y ); + double inc = atan2 ( first_CDP.y-center.y, first_CDP.x-center.x ); + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - w; + bb_xmax = center.x + w; + bb_ymin = center.y - h; + bb_ymax = center.y + h; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_ElpArc ( center.x, center.y, w*2., h*2., inc, 0-inc, TWOPI-inc, 64, 2 ); + + return 0; +} + +int cgm_do_ellarc ( tpoint center, tpoint first_CDP, tpoint second_CDP, + tpoint start, tpoint end ) +{ + double w = myhypot ( first_CDP.x-center.x, first_CDP.y-center.y ); + double h = myhypot ( second_CDP.x-center.x, second_CDP.y-center.y ); + double inc = atan2 ( first_CDP.y-center.y, first_CDP.x-center.x ); + double a1 = atan2 ( start.y, start.x ); + double a2 = atan2 ( end.y, end.x ); + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - w; + bb_xmax = center.x + w; + bb_ymin = center.y - h; + bb_ymax = center.y + h; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_ElpArc ( center.x, center.y, w*2., h*2., inc, a1-inc, a2-inc, 64, 0 ); + + return 0; +} + +int cgm_do_ellacl ( tpoint center, tpoint first_CDP, tpoint second_CDP, + tpoint start, tpoint end, int close_type ) +{ + double w = myhypot ( first_CDP.x-center.x, first_CDP.y-center.y ); + double h = myhypot ( second_CDP.x-center.x, second_CDP.y-center.y ); + double inc = atan2 ( first_CDP.y-center.y, first_CDP.x-center.x ); + double a1 = atan2 ( start.y, start.x ); + double a2 = atan2 ( end.y, end.x ); + + double bb_xmin, bb_ymin, bb_xmax, bb_ymax; + + bb_xmin = center.x - w; + bb_xmax = center.x + w; + bb_ymin = center.y - h; + bb_ymax = center.y + h; + +#if 0 + if ( cgm_vdcx2canvas(bb_xmin) > intcgm_view_xmax || cgm_vdcx2canvas(bb_xmax) < intcgm_view_xmin || + cgm_vdcy2canvas(bb_ymin) > intcgm_view_ymax || cgm_vdcy2canvas(bb_ymax) < intcgm_view_ymin ) return 0; +#else + if ( bb_xmin > intcgm_clip_xmax || bb_xmax < intcgm_clip_xmin || + bb_ymin > intcgm_clip_ymax || bb_ymax < intcgm_clip_ymin ) return 0; +#endif + + cgm_ElpArc ( center.x, center.y, w*2., h*2., inc, a1-inc, a2-inc, 64, close_type+1 ); + + return 0; +} + +int cgm_do_text_height ( double height ) +{ + cgm_setfont ( intcgm_text_att.font, intcgm_text_att.style, height ); + + return 0; +} + diff --git a/src/intcgm/intcgm4.h b/src/intcgm/intcgm4.h new file mode 100644 index 0000000..4b12873 --- /dev/null +++ b/src/intcgm/intcgm4.h @@ -0,0 +1,28 @@ +int cgm_do_vdcext ( tpoint, tpoint ); +int cgm_do_bckcol ( trgb ); +int cgm_do_transp ( int ); +int cgm_do_clprec ( tpoint, tpoint ); +int cgm_do_clpind ( int ); +int cgm_do_polyln ( int, tpoint * ); +int cgm_do_incply ( int, tpoint * ); +int cgm_do_djtply ( int, tpoint * ); +int cgm_do_indpl ( int, tpoint * ); +int cgm_do_polymk ( int, tpoint * ); +int cgm_do_incplm ( int, tpoint * ); +int cgm_do_text ( int, char *, tpoint ); +int cgm_do_txtalign ( int hor, int ver ); +int cgm_do_polygn ( int, tpoint * ); +int cgm_do_incplg ( int, tpoint * ); +int cgm_do_plgset( int, int, tpoint *, short * ); +int cgm_do_cellar ( tpoint, tpoint, tpoint, int, int, long, tcolor * ); +int cgm_do_gdp ( int, tpoint *, char * ); +int cgm_do_rect ( tpoint point1, tpoint point2 ); +int cgm_do_circle ( tpoint, double ); +int cgm_do_circ3p ( tpoint, tpoint, tpoint ); +int cgm_do_circ3pc ( tpoint, tpoint, tpoint, int ); +int cgm_do_circcnt ( tpoint, tpoint, tpoint, double ); +int cgm_do_ccntcl ( tpoint, tpoint, tpoint, double, int ); +int cgm_do_ellips ( tpoint, tpoint, tpoint ); +int cgm_do_ellarc ( tpoint, tpoint, tpoint, tpoint, tpoint ); +int cgm_do_ellacl ( tpoint, tpoint, tpoint, tpoint, tpoint, int ); +int cgm_do_text_height ( double ); diff --git a/src/intcgm/intcgm6.c b/src/intcgm/intcgm6.c new file mode 100644 index 0000000..c23afee --- /dev/null +++ b/src/intcgm/intcgm6.c @@ -0,0 +1,253 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include <cd.h> + +#include "list.h" +#include "types.h" +#include "intcgm.h" +#include "intcgm2.h" +#include "intcgm6.h" + +void cgm_setlinestyle ( int type ) +{ + switch ( type ) + { + case LINE_SOLID: + cdCanvasLineStyle (intcgm_canvas, CD_CONTINUOUS ); + break; + case LINE_DASH: + cdCanvasLineStyle (intcgm_canvas, CD_DASHED ); + break; + case LINE_DOT: + cdCanvasLineStyle (intcgm_canvas, CD_DOTTED ); + break; + case LINE_DASH_DOT: + cdCanvasLineStyle (intcgm_canvas, CD_DASH_DOT ); + break; + case LINE_DASH_DOT_DOT: + cdCanvasLineStyle (intcgm_canvas, CD_DASH_DOT_DOT ); + break; + } +} + +void cgm_setlinewidth ( double width ) +{ + int w; + if ( intcgm_cgm.lnwsm == ABSOLUTE ) + w = cgm_delta_vdc2canvas(width); + else + w = (int)floor ( width+0.5 ); + + cdCanvasLineWidth (intcgm_canvas, w>0?w:1 ); +} + +void cgm_setmarktype ( int type ) +{ + switch ( type ) + { + case MARK_DOT: + cdCanvasMarkType (intcgm_canvas, CD_STAR ); + break; + case MARK_PLUS: + cdCanvasMarkType (intcgm_canvas, CD_PLUS ); + break; + case MARK_ASTERISK: + cdCanvasMarkType (intcgm_canvas, CD_X ); + break; + case MARK_CIRCLE: + cdCanvasMarkType (intcgm_canvas, CD_CIRCLE ); + break; + case MARK_CROSS: + cdCanvasMarkType (intcgm_canvas, CD_PLUS ); + break; + } +} + +void cgm_setmarksize ( double size ) +{ + if ( intcgm_cgm.lnwsm == ABSOLUTE ) + cdCanvasMarkSize (intcgm_canvas, cgm_delta_vdc2canvas(size) ); + else + cdCanvasMarkSize (intcgm_canvas, (int)floor ( size*0.5 ) ); +} + +long int *cgm_setpattern ( pat_table pat ) +{ + int i; + long int *cor = (long int *) malloc ( pat.nx*pat.ny*sizeof(long int) ); + + for ( i=0; i<pat.nx*pat.ny ; i++ ) + cor[i] = cgm_getcolor ( pat.pattern[i] ); + + return cor; +} + +int cgm_setintstyle ( int style ) +{ + if ( style==HOLLOW ) + return CD_CLOSED_LINES; + else if ( style==SOLID ) + { + cdCanvasInteriorStyle (intcgm_canvas, CD_SOLID ); + return CD_FILL; + } + else if ( style==PATTERN ) + { + int i; + pat_table *pat; + long int *p; + + for ( i=1; (pat=(pat_table *)cgm_GetList( intcgm_fill_att.pat_list,i ))!=NULL; i++ ) + { + if ( pat->index==intcgm_fill_att.pat_index ) break; + } + + p = (long int *) malloc ( pat->nx*pat->ny*sizeof(long int) ); + + for ( i=0; i<pat->nx*pat->ny; i++ ) + { + if ( intcgm_cgm.clrsm==DIRECT ) + p[i] = cdEncodeColor ((unsigned char)(pat->pattern[i].rgb.red*255./intcgm_cgm.color_ext.white.red), + (unsigned char)(pat->pattern[i].rgb.green*255./intcgm_cgm.color_ext.white.green), + (unsigned char)(pat->pattern[i].rgb.blue*255./intcgm_cgm.color_ext.white.blue) ); + else + p[i] = cdEncodeColor ((unsigned char)(intcgm_color_table[pat->pattern[i].ind].red*255/intcgm_cgm.color_ext.white.red), + (unsigned char)(intcgm_color_table[pat->pattern[i].ind].green*255/intcgm_cgm.color_ext.white.green), + (unsigned char)(intcgm_color_table[pat->pattern[i].ind].blue*255/intcgm_cgm.color_ext.white.blue) ); + } + + cdCanvasPattern(intcgm_canvas, pat->nx, pat->ny, (long *) p ); + + return CD_FILL; + } + else if ( style==HATCH ) + { + cdCanvasHatch (intcgm_canvas, intcgm_fill_att.hatch_index-1 ); + return CD_FILL; + } + else + return CD_CLOSED_LINES; +} + +long int cgm_getcolor ( tcolor cor ) +{ + + if ( intcgm_cgm.clrsm==INDEXED ) + return cdEncodeColor ((unsigned char)(intcgm_color_table[cor.ind].red*255/intcgm_cgm.color_ext.white.red), + (unsigned char)(intcgm_color_table[cor.ind].green*255/intcgm_cgm.color_ext.white.green), + (unsigned char)(intcgm_color_table[cor.ind].blue*255/intcgm_cgm.color_ext.white.blue) ); + else + return cdEncodeColor ((unsigned char)(cor.rgb.red*255/intcgm_cgm.color_ext.white.red), + (unsigned char)(cor.rgb.green*255/intcgm_cgm.color_ext.white.green), + (unsigned char)(cor.rgb.blue*255/intcgm_cgm.color_ext.white.blue) ); +} + +int cgm_vdcx2canvas ( double vdc ) +{ + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + return (int) floor ( intcgm_scale_factor_x*(vdc-intcgm_vdc_ext.xmin)+.5 ) + intcgm_view_xmin; + else + return (int) floor ( intcgm_scale_factor_mm_x*(vdc-intcgm_vdc_ext.xmin)*intcgm_cgm.scaling_mode.scale_factor + + intcgm_vdc_ext.xmin*intcgm_cgm.scaling_mode.scale_factor + .5 ); +} + +int cgm_vdcy2canvas ( double vdc ) +{ + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + return (int) floor ( intcgm_scale_factor_y*(vdc-intcgm_vdc_ext.ymin)+.5 ) + intcgm_view_ymin; + else + return (int) floor ( intcgm_scale_factor_mm_y*(vdc-intcgm_vdc_ext.ymin)*intcgm_cgm.scaling_mode.scale_factor + + intcgm_vdc_ext.ymin*intcgm_cgm.scaling_mode.scale_factor + .5 ); +} + +int cgm_delta_vdc2canvas ( double vdc ) +{ + int delta = (int) cgm_vdcx2canvas(intcgm_vdc_ext.xmin+vdc) - (int) cgm_vdcx2canvas(intcgm_vdc_ext.xmin); + return delta; +} + +double cgm_canvas2vdcx ( int x ) +{ + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + return (double) (x-intcgm_view_xmin)/intcgm_scale_factor_x + intcgm_vdc_ext.xmin; + else + return (double) (x-intcgm_view_xmin)/(intcgm_scale_factor_mm_x*intcgm_cgm.scaling_mode.scale_factor) + intcgm_vdc_ext.xmin; +} + +double cgm_canvas2vdcy ( int y ) +{ + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + return (double) (y-intcgm_view_ymin)/intcgm_scale_factor_y + intcgm_vdc_ext.ymin; + else + return (double) (y-intcgm_view_ymin)/(intcgm_scale_factor_mm_y*intcgm_cgm.scaling_mode.scale_factor) + intcgm_vdc_ext.ymin; +} + +void cgm_getpolybbox ( tpoint *pt, int n_points, double *bb_xmin, double *bb_ymin, + double *bb_xmax, double *bb_ymax ) +{ + int i; + + *bb_xmin = *bb_xmax = pt[0].x; + *bb_ymin = *bb_ymax = pt[0].y; + + for ( i=1; i<n_points; i++) + { + if ( pt[i].x < *bb_xmin ) *bb_xmin = pt[i].x; + else if ( pt[i].x > *bb_xmax ) *bb_xmax = pt[i].x; + if ( pt[i].y < *bb_ymin ) *bb_ymin = pt[i].y; + else if ( pt[i].y > *bb_ymax ) *bb_ymax = pt[i].y; + } +} + +void cgm_getincpolybbox ( tpoint *pt, int n_points, double *bb_xmin, double *bb_ymin, + double *bb_xmax, double *bb_ymax ) +{ + int i; + double px, py; + + px = *bb_xmin = *bb_xmax = pt[0].x; + py = *bb_ymin = *bb_ymax = pt[0].y; + + for ( i=1; i<n_points; i++) + { + px += pt[i].x; py += pt[i].y; + if ( px < *bb_xmin ) *bb_xmin = px; + else if ( px > *bb_xmax ) *bb_xmax = px; + if ( py < *bb_ymin ) *bb_ymin = py; + else if ( py > *bb_ymax ) *bb_ymax = py; + } +} + +int cgm_setfont ( int font, int style, double height ) +{ + int size; + int cy; + char* type_face; + + cy = cgm_delta_vdc2canvas ( height ); + size = (int) floor (((cy/intcgm_scale_factor_mm_y)/0.353)+0.5); + switch (font) + { + case 0: + type_face = "System"; + break; + case 1: + type_face = "Courier"; + break; + case 2: + type_face = "Times"; + break; + case 3: + type_face = "Helvetica"; + break; + default: + return 0; + } + + cdCanvasFont(intcgm_canvas, type_face, style, size ); + + return 0; +} diff --git a/src/intcgm/intcgm6.h b/src/intcgm/intcgm6.h new file mode 100644 index 0000000..fde660e --- /dev/null +++ b/src/intcgm/intcgm6.h @@ -0,0 +1,15 @@ +void cgm_setlinestyle ( int ); +void cgm_setlinewidth ( double ); +void cgm_setmarktype ( int ); +void cgm_setmarksize ( double ); +long int cgm_getcolor ( tcolor ); +long int *cgm_setpattern ( pat_table ); +int cgm_setfont ( int, int, double ); +int cgm_setintstyle ( int ); +int cgm_vdcx2canvas ( double ); +int cgm_vdcy2canvas ( double ); +int cgm_delta_vdc2canvas ( double ); +double cgm_canvas2vdcx ( int ); +double cgm_canvas2vdcy ( int ); +void cgm_getpolybbox ( tpoint *, int, double *n, double *, double *, double * ); +void cgm_getincpolybbox ( tpoint *, int, double *, double *, double *, double * ); diff --git a/src/intcgm/list.c b/src/intcgm/list.c new file mode 100644 index 0000000..6fefbbc --- /dev/null +++ b/src/intcgm/list.c @@ -0,0 +1,117 @@ +/* +* list.c +* Generic List Manager +* TeCGraf +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include "list.h" + +TList *cgm_NewList ( void ) +{ + TList *l = (TList *) malloc ( sizeof (TList) ); + + list_nba(l) = 8; + list_head(l) = (void **)malloc(list_nba(l)*sizeof(void*)); + list_n(l) = 0; + + return l; +} + +TList *cgm_AppendList ( TList *l, void *i ) +{ + if ( l == NULL ) + return NULL; + + if (list_n(l) == list_nba(l)) + { + list_nba(l) += 32; + list_head(l) = (void **)realloc(list_head(l),list_nba(l)*sizeof(void*)); + } + + list_head(l)[list_n(l)]=i; + list_n(l)++; + + return l; +} + +TList *cgm_AddList ( TList *l, int n, void *info ) +{ + int i; + + if ( l == NULL) + return NULL; + + if ( n < 1) + n=1; + + if ( n > list_n(l) ) + return cgm_AppendList( l, info ); + + --n; /* o usuario ve a lista iniciando em 1 e a */ + /* lista e' implementada iniciando em 0 */ + + if (list_n(l) == list_nba(l)) + { + list_nba(l) *= 2; + list_head(l) = (void **)realloc(list_head(l),list_nba(l)*sizeof(void*)); + } + + for (i=list_n(l)-1; i>=n; --i) + list_head(l)[i+1]=list_head(l)[i]; + + list_head(l)[n]=info; + list_n(l)++; + return l; +} + +TList *cgm_DelList ( TList *l, int n ) +{ + int i; + + if ( l == NULL || list_n(l) == 0 || n < 0) + return NULL; + + if ( n < 1) + n=1; + + if ( n > list_n(l)) + n=list_n(l); + + --n; /* o usuario ve a lista iniciando em 1 e a */ + /* lista e' implementada iniciando em 0 */ + list_n(l)--; + + for (i=n; i<list_n(l); ++i) + list_head(l)[i]=list_head(l)[i+1]; + + return l; +} + +void *cgm_GetList ( TList *l, int n ) +{ + if ( l == NULL || n <= 0) + return NULL; + + return n > list_n(l) ? NULL : list_head(l)[n-1]; +} + +int cgm_DelEntry ( TList *l, void *entry ) +{ + int i=1; + + if ( l == NULL || list_n(l) == 0) + return 0; + + for (i=0; i< list_n(l); ++i) + if (list_head(l)[i]==entry) + { + cgm_DelList(l,i+1); /* o usuario ve a lista iniciando em 1 e a */ + /* lista e' implementada iniciando em 0 */ + return i+1; + } + return 0; +} + diff --git a/src/intcgm/list.h b/src/intcgm/list.h new file mode 100644 index 0000000..c661a7c --- /dev/null +++ b/src/intcgm/list.h @@ -0,0 +1,30 @@ + +/* +* list.h +* prototipos das funcoes de manipulacao de lista +* TeCGraf +* 27 Ago 93 +*/ + +#ifndef __LIST_H__ +#define __LIST_H__ + +typedef struct TList_ + { + void **h; /* head */ + int nba; + int n; /* Numero de elementos na lista */ + } TList; + +#define list_head(l) ((l)->h) +#define list_n(l) ((l)->n) +#define list_nba(l) ((l)->nba) + +TList *cgm_NewList ( void ); +TList *cgm_AppendList ( TList *, void * ); +TList *cgm_AddList ( TList *, int, void * ); +TList *cgm_DelList ( TList *, int ); +void *cgm_GetList ( TList *, int ); +int cgm_DelEntry ( TList *, void * ); + +#endif diff --git a/src/intcgm/sism.c b/src/intcgm/sism.c new file mode 100644 index 0000000..9946ac3 --- /dev/null +++ b/src/intcgm/sism.c @@ -0,0 +1,392 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <limits.h> +#include <float.h> + +#include <cd.h> + +#include "list.h" +#include "types.h" +#include "intcgm.h" +#include "intcgm2.h" +#include "intcgm6.h" + +static tpoint trace_start_pos, base_direction, amp_direction, trace_direction; +static double bline_sc_f, amp_sc_f, trc_st_f, VA_bline_offset, pos_clp_lmt, + neg_clp_lmt, pos_bckfil_bnd, neg_bckfil_bnd; +static int trace_dsp_md, samp_type, n_samp, wig_trc_mod, nul_clr_i, n_trace; +static double *sample; +static long *coind; +static int trace=0; + +void cgm_sism4 ( tpoint *pt, char *data_rec ) +{ + sscanf ( data_rec, "%lg %lg %lg %lg %lg %lg %d %d %d %lg %lg %*d %d %d %d", + &bline_sc_f, &_sc_f, &trc_st_f, &VA_bline_offset, &pos_clp_lmt, + &neg_clp_lmt, &trace_dsp_md, &samp_type, &n_samp, &pos_bckfil_bnd, + &neg_bckfil_bnd, &wig_trc_mod, &nul_clr_i, &n_trace ); + + trace_start_pos = pt[0]; + base_direction = pt[1]; + amp_direction = pt[2]; + trace_direction = pt[3]; + trace = 0; +} + +/* adjust the samples to the amplitude direction vector */ +static void dirvet ( double dx ) +{ + int i; + + for ( i=0; i<n_samp; i++ ) + sample[i] *= dx/fabs(dx); +} + +/* adust the x offset from the baseline to maximum amplitude */ +static void ampscf ( double dx ) +{ + double max=1; + int i; + + if ( samp_type == 0 || samp_type == 4 ) max = (double) SHRT_MAX; + else if ( samp_type == 1 ) max = (double) INT_MAX; + else if ( samp_type == 2 ) max = (double) FLT_MAX; + else if ( samp_type == 3 || samp_type == 5 ) max = (double) SCHAR_MAX; + + for ( i=0; i<n_samp; i++ ) + sample[i] = (sample[i]/max) * amp_sc_f * dx; +} + +static double interpl ( int i, double y1, double y2, double x ) +{ + return ( y1*(x-sample[i+1]) + y2*(sample[i]-x) ) / ( sample[i]-sample[i+1] ); +} + +static void vasamp ( int mode, double max, double min, int cordep ) +{ + double factx, facty; + double x[5], y[5]; + double samp1, samp2, mn, mx; + long int cor; + int i,j,n; + + facty = base_direction.y * bline_sc_f; + factx = trace_direction.x * trc_st_f; + + max *= amp_sc_f; + min *= amp_sc_f; + mn = min; + mx = max; + + if ( mode==64 ) + { + double tmp = min; + min = max; + max = tmp; + mn = min * -1.; + mx = max * -1.; + } + + for ( i=0; i<(n_samp-1); i++ ) + { + double y1 = trace_start_pos.y + facty*(i); + double y2 = trace_start_pos.y + facty*(i+1); + double dx = trace_start_pos.x + factx*(trace-1); + + samp1 = sample[i]; + samp2 = sample[i+1]; + + if ( mode==64 ) + { + samp1 *= -1.; + samp2 *= -1.; + } + + n=0; + + if (samp1<mn && samp2>mn && samp2<mx) + { + x[n] = min + dx; + y[n++] = interpl(i,y1,y2,min); + x[n] = sample[i+1] + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if (samp1<mn && samp2>mx) + { + x[n] = min + dx; + y[n++] = interpl(i,y1,y2,min); + x[n] = max + dx; + y[n++] = interpl(i,y1,y2,max); + x[n] = max + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if ( (samp1>mn && samp1<mx) && + (samp2>mn && samp2<mx) ) + { + x[n] = min + dx; + y[n++] = y1; + x[n] = sample[i] + dx; + y[n++] = y1; + x[n] = sample[i+1] + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if ( samp1>mn && samp1<mx && samp2>mx ) + { + x[n] = min + dx; + y[n++] = y1; + x[n] = sample[i] + dx; + y[n++] = y1; + x[n] = max + dx; + y[n++] = interpl(i,y1,y2,max); + x[n] = max + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if ( samp1>mx && samp2>mx ) + { + x[n] = min + dx; + y[n++] = y1; + x[n] = max + dx; + y[n++] = y1; + x[n] = max + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if ( samp1>mx && samp2<mx && samp2>mn ) + { + x[n] = min + dx; + y[n++] = y1; + x[n] = max + dx; + y[n++] = y1; + x[n] = max + dx; + y[n++] = interpl(i,y1,y2,max); + x[n] = sample[i+1] + dx; + y[n++] = y2; + x[n] = min + dx; + y[n++] = y2; + } + + else if ( samp1>mn && samp1<mx && samp2<mn ) + { + x[n] = min + dx; + y[n++] = y1; + x[n] = sample[i] + dx; + y[n++] = y1; + x[n] = min + dx; + y[n++] = interpl(i,y1,y2,min); + } + + if ( n>0 ) + { + if ( cordep ) + { + cor = cdEncodeColor ( (unsigned char)((intcgm_color_table[coind[i]].red*255)/intcgm_cgm.color_ext.white.red), + (unsigned char)((intcgm_color_table[coind[i]].green*255)/intcgm_cgm.color_ext.white.green), + (unsigned char)((intcgm_color_table[coind[i]].blue*255)/intcgm_cgm.color_ext.white.blue) ); + cdCanvasSetForeground (intcgm_canvas, cor ); + } + + cdCanvasBegin(intcgm_canvas, CD_FILL ); + + for ( j=0; j<n; j++ ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(x[j]), cgm_vdcy2canvas(y[j]) ); + + cdCanvasEnd(intcgm_canvas); + } + } +} + +static void bgclfl ( int mode ) +{ + double factx, facty; + double posdx, negdx; + long int cor; + int i; + + facty = base_direction.y * bline_sc_f; + factx = trace_direction.x * trc_st_f; + + posdx = pos_bckfil_bnd * amp_sc_f * amp_direction.x; + negdx = neg_bckfil_bnd * amp_sc_f * amp_direction.x; + + cdCanvasInteriorStyle(intcgm_canvas, CD_SOLID ); + + for ( i=0; i<n_samp; i++ ) + { + int index = ( coind[i] <= intcgm_cgm.max_cix ) ? coind[i] : 1; + + cor = cdEncodeColor ( (unsigned char)((intcgm_color_table[index].red*255)/intcgm_cgm.color_ext.white.red), + (unsigned char)((intcgm_color_table[index].green*255)/intcgm_cgm.color_ext.white.green), + (unsigned char)((intcgm_color_table[index].blue*255)/intcgm_cgm.color_ext.white.blue) ); + cdCanvasSetForeground (intcgm_canvas, cor ); + + cdCanvasBegin(intcgm_canvas, CD_FILL ); + + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posdx + trace_start_pos.x + factx*(trace-1)), + cgm_vdcy2canvas(trace_start_pos.y + facty*(i)) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posdx + trace_start_pos.x + factx*(trace-1)), + cgm_vdcy2canvas(trace_start_pos.y + facty*(i+1)) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negdx + trace_start_pos.x + factx*(trace-1)), + cgm_vdcy2canvas(trace_start_pos.y + facty*(i+1)) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negdx + trace_start_pos.x + factx*(trace-1)), + cgm_vdcy2canvas(trace_start_pos.y + facty*(i)) ); + + cdCanvasEnd(intcgm_canvas); + } +} + +void wiggle ( double posclp, double negclp ) +{ + int i; + double facty = base_direction.y * bline_sc_f; + double factx = trace_direction.x * trc_st_f; + double dx = trace_start_pos.x + factx*(trace-1); + + posclp *= amp_sc_f; + negclp *= amp_sc_f; + + cdCanvasBegin(intcgm_canvas, CD_OPEN_LINES ); + + for ( i=0; i<n_samp; i++ ) + { + double y1 = trace_start_pos.y + facty*(i); + double y2 = trace_start_pos.y + facty*(i+1); + + if ( sample[i]>negclp && sample[i]<posclp && + sample[i+1]>negclp && sample[i+1]<posclp ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(sample[i] + dx), cgm_vdcy2canvas(y1) ); + else if ( sample[i]<negclp && sample[i+1]>negclp && sample[i+1]<posclp ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,negclp)) ); + else if ( sample[i]<negclp && sample[i+1]>posclp ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,negclp)) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,posclp)) ); + } + else if ( sample[i]>negclp && sample[i]<posclp && sample[i+1]>posclp ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(sample[i] + dx), cgm_vdcy2canvas(y1) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,posclp)) ); + } + else if ( sample[i]>posclp && sample[i+1]<posclp && sample[i+1]>negclp ) + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,posclp)) ); + else if ( sample[i]>posclp && sample[i+1]<negclp ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(posclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,posclp)) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,negclp)) ); + } + else if ( sample[i]>negclp && sample[i]<posclp && sample[i+1]<negclp ) + { + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(sample[i] + dx), cgm_vdcy2canvas(y1) ); + cdCanvasVertex (intcgm_canvas, cgm_vdcx2canvas(negclp + dx), cgm_vdcy2canvas(interpl(i,y1,y2,negclp)) ); + } + } + + cdCanvasEnd(intcgm_canvas); +} + +void cgm_sism5 ( char *data_rec ) +{ + int i, mode, trace_mode; + double pos_clp, neg_clp; + + sample = (double *) malloc ( n_samp*sizeof(double) ); + + if ( trace_dsp_md > 7 ) + coind = (long *) malloc ( n_samp*sizeof(long) ); + + for ( i=0; i<n_samp; i++ ) + if ( trace_dsp_md < 8 ) + sample[i] = strtod ( data_rec, &data_rec ); + else + { + sample[i] = (double) strtol ( data_rec, &data_rec, 10 ); + coind[i] = strtol ( data_rec, &data_rec, 10 ); + } + + trace += 1; + + dirvet ( amp_direction.x ); + + ampscf ( amp_direction.x ); + + trace_mode = trace_dsp_md; + + do + { + + if ( trace_mode >= 64 ) + mode = 64; + else if ( trace_mode >= 32 ) + mode = 32; + else if ( trace_mode >= 16 ) + mode = 16; + else if ( trace_mode >= 8 ) + mode = 8; + else if ( trace_mode >= 4 ) + mode = 4; + else if ( trace_mode >= 2 ) + mode = 2; + else if ( trace_mode == 1 ) + mode = 1; + + switch ( mode ) + { + case 64: + neg_clp = neg_clp_lmt; + pos_clp = ( pos_clp_lmt < 0 ) ? pos_clp_lmt : 0; + vasamp ( mode, pos_clp, neg_clp, 1 ); + trace_mode -= 64; + break; + case 32: + neg_clp = ( neg_clp_lmt > 0 ) ? neg_clp_lmt : 0; + pos_clp = pos_clp_lmt; + vasamp ( mode, pos_clp, neg_clp, 1 ); + trace_mode -= 32; + break; + case 16: + bgclfl( mode ); + trace_mode -= 16; + break; + case 8: + bgclfl( mode ); + trace_mode -= 8; + break; + case 4: + neg_clp = ( neg_clp_lmt > 0 ) ? neg_clp_lmt : 0; + pos_clp = pos_clp_lmt; + vasamp ( mode, pos_clp, neg_clp, 0 ); + trace_mode -= 4; + break; + case 2: + neg_clp = ( neg_clp_lmt > 0 ) ? neg_clp_lmt : 0; + pos_clp = pos_clp_lmt; + vasamp ( mode, pos_clp, neg_clp, 0 ); + trace_mode -= 2; + break; + case 1: + wiggle ( pos_clp_lmt, neg_clp_lmt ); + trace_mode -= 1; + break; + } + } while ( trace_mode != 0 ); + + free(sample); + + if ( trace_dsp_md > 7 ) + free(coind); +} diff --git a/src/intcgm/sism.h b/src/intcgm/sism.h new file mode 100644 index 0000000..f2f08f0 --- /dev/null +++ b/src/intcgm/sism.h @@ -0,0 +1,3 @@ +void cgm_sism4 ( tpoint *, char * ); +void cgm_sism5 ( char * ); + diff --git a/src/intcgm/tparse.c b/src/intcgm/tparse.c new file mode 100644 index 0000000..0402ce6 --- /dev/null +++ b/src/intcgm/tparse.c @@ -0,0 +1,1370 @@ +#define _INTCGM2_C_ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <cd.h> +#include <cdcgm.h> + +#include "list.h" +#include "types.h" +#include "bparse.h" +#include "intcgm.h" +#include "intcgm2.h" +#include "intcgm4.h" +#include "intcgm6.h" + +int cgmt_begmtf ( void ) /* begin metafile */ +{ + char *str=NULL; + + if ( cgmt_s ( &str ) ) return 1; + + if (cdcgmbegmtfcb) + { + int err; + err = cdcgmbegmtfcb ( intcgm_canvas, &intcgm_view_xmin, &intcgm_view_ymin, &intcgm_view_xmax, &intcgm_view_ymax ); + if ( err==CD_ABORT ) return -1; + } + + free(str); + + return cgmt_ter(); +} + +int cgmt_endmtf ( void ) /* end metafile */ +{ + cgmt_ter(); + return 1; +} + +int cgmt_begpic ( void ) /* begin picture */ +{ + char *string=NULL; + + if ( intcgm_cgm.first ) + intcgm_cgm.first = 0; + else + cdCanvasFlush(intcgm_canvas); + + cdCanvasClip(intcgm_canvas, CD_CLIPAREA); + + if ( cgmt_s ( &string ) ) return 1; + + if (cdcgmbegpictcb) + { + int err; + err = cdcgmbegpictcb ( intcgm_canvas, string ); + if ( err==CD_ABORT ) return -1; + } + + free(string); + + return cgmt_ter(); +} + +int cgmt_begpib ( void ) /* begin picture body */ +{ + if (cdcgmbegpictbcb) + { + int err; + err = cdcgmbegpictbcb ( intcgm_canvas, 1., 1., intcgm_scale_factor_x, intcgm_scale_factor_y, + intcgm_scale_factor_mm_x*intcgm_cgm.scaling_mode.scale_factor, + intcgm_scale_factor_mm_y*intcgm_cgm.scaling_mode.scale_factor, + intcgm_cgm.drawing_mode, + intcgm_vdc_ext.xmin, intcgm_vdc_ext.ymin, intcgm_vdc_ext.xmax, intcgm_vdc_ext.ymax ); + if ( err==CD_ABORT ) return -1; + } + + + if (cdcgmsizecb) + { + int err, w, h; + double w_mm=0., h_mm=0.; + + w = intcgm_view_xmax-intcgm_view_xmin+1; + h = intcgm_view_ymax-intcgm_view_ymin+1; + + if ( intcgm_cgm.vdc_type==INTEGER ) + { + w = (int) (intcgm_cgm.vdc_ext.second.x - intcgm_cgm.vdc_ext.first.x); + h = (int) (intcgm_cgm.vdc_ext.second.y - intcgm_cgm.vdc_ext.first.y); + if ( intcgm_cgm.scaling_mode.mode==METRIC ) + { + w_mm = w * intcgm_cgm.scaling_mode.scale_factor; + h_mm = h * intcgm_cgm.scaling_mode.scale_factor; + } + } + else + { + if ( intcgm_cgm.scaling_mode.mode==METRIC ) + { + w_mm = (intcgm_cgm.vdc_ext.second.x - intcgm_cgm.vdc_ext.first.x) * intcgm_cgm.scaling_mode.scale_factor; + h_mm = (intcgm_cgm.vdc_ext.second.y - intcgm_cgm.vdc_ext.first.y) * intcgm_cgm.scaling_mode.scale_factor; + } + } + + err = cdcgmsizecb ( intcgm_canvas, w, h, w_mm, h_mm ); + if ( err==CD_ABORT ) return -1; + } + + return cgmt_ter(); +} + +int cgmt_endpic ( void ) /* end picture */ +{ + return cgmt_ter(); +} + +int cgmt_mtfver ( void ) /* metafile version */ +{ + long version; + + if ( cgmt_i ( &version ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mtfdsc ( void ) /* metafile description */ +{ + char *string=NULL; + + if ( cgmt_s ( &string ) ) return 1; + + free(string); + + return cgmt_ter(); +} + +int cgmt_vdctyp ( void ) /* vdc type */ +{ + const char *options[] = { "integer", "real", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.vdc_type), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_intpre ( void ) /* integer precision */ +{ + if ( cgmt_i ( &(intcgm_cgm.int_prec.t_prec.minint) ) ) return 1; + if ( cgmt_i ( &(intcgm_cgm.int_prec.t_prec.maxint) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_realpr ( void ) /* real precision */ +{ + if ( cgmt_r ( &(intcgm_cgm.real_prec.t_prec.minreal) ) ) return 1; + if ( cgmt_r ( &(intcgm_cgm.real_prec.t_prec.maxreal) ) ) return 1; + if ( cgmt_i ( &(intcgm_cgm.real_prec.t_prec.digits) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_indpre ( void ) /* index precision */ +{ + if ( cgmt_i ( &(intcgm_cgm.ix_prec.t_prec.minint) ) ) return 1; + if ( cgmt_i ( &(intcgm_cgm.ix_prec.t_prec.maxint) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_colpre ( void ) /* colour precision */ +{ + if ( cgmt_i ( &(intcgm_cgm.cd_prec) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_colipr ( void ) /* colour index precision */ +{ + if ( cgmt_i ( &(intcgm_cgm.cix_prec) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_maxcoi ( void ) /* maximum colour index */ +{ + if ( cgmt_i ( &(intcgm_cgm.max_cix) ) ) return 1; + + intcgm_color_table = (trgb *) realloc ( intcgm_color_table, sizeof(trgb)*(intcgm_cgm.max_cix+1) ); + + intcgm_color_table[0].red = 255; + intcgm_color_table[0].green = 255; + intcgm_color_table[0].blue = 255; + intcgm_color_table[1].red = 0; + intcgm_color_table[1].green = 0; + intcgm_color_table[1].blue = 0; + + return cgmt_ter(); +} + +int cgmt_covaex ( void ) /* colour value extent */ +{ + if ( cgmt_rgb ( &(intcgm_cgm.color_ext.black.red), &(intcgm_cgm.color_ext.black.green), &(intcgm_cgm.color_ext.black.blue) ) ) return 1; + + if ( cgmt_rgb ( &(intcgm_cgm.color_ext.white.red), &(intcgm_cgm.color_ext.white.green), &(intcgm_cgm.color_ext.white.blue) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mtfell ( void ) /* metafile element list */ +{ + char *elist=NULL; + + if ( cgmt_s ( &elist ) ) return 1; + + free(elist); + + return cgmt_ter(); +} + +int cgmt_bmtfdf (void ) /* begin metafile defaults */ +{ + return cgmt_ter(); +} + +int cgmt_emtfdf ( void ) /* end metafile defaults */ +{ + return cgmt_ter(); +} + +int cgmt_fntlst ( void ) /* font list */ +{ + char *font=NULL; + + if ( intcgm_text_att.font_list==NULL ) intcgm_text_att.font_list = cgm_NewList(); + + while ( cgmt_ter() ) + { + if ( cgmt_s ( &font ) ) return 1; + cgm_AppendList ( intcgm_text_att.font_list, font ); + } + + return 0; +} + +int cgmt_chslst ( void ) /* character set list */ +{ + const char *options[] = { "std94", "std96", "std94multibyte", "std96multibyte", + "completecode", NULL }; + char *tail; + short code; + + do + { + if ( cgmt_e ( &(code), options ) ) return 1; + + if ( cgmt_s ( &tail ) ) return 1; + + free ( tail ); + + } while ( cgmt_ter() ); + + return 0; +} + +int cgmt_chcdac ( void ) /* character coding announcer */ +{ + const char *options[] = { "basic7bit", "basic8bit", "extd7bit", "extd8bit", NULL }; + short code; + + if ( cgmt_e ( &(code), options ) ) return 1; + + return cgmt_ter (); +} + +int cgmt_sclmde ( void ) /* scaling mode */ +{ + const char *options[] = { "abstract", "metric", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.scaling_mode.mode), options ) ) return 1; + + if ( cgmt_r ( &(intcgm_cgm.scaling_mode.scale_factor) ) ) return 1; + + if ( intcgm_cgm.scaling_mode.mode==ABSTRACT ) intcgm_cgm.scaling_mode.scale_factor=1.; + + intcgm_cgm.drawing_mode = ABSTRACT; + + if (cdcgmsclmdecb) + { + int err; + err = cdcgmsclmdecb ( intcgm_canvas, intcgm_cgm.scaling_mode.mode, &intcgm_cgm.drawing_mode, &intcgm_cgm.scaling_mode.scale_factor ); + if ( err==CD_ABORT ) return -1; + } + + if ( intcgm_cgm.drawing_mode==ABSTRACT ) + { + intcgm_clip_xmin = cgm_canvas2vdcx ( intcgm_view_xmin ); + intcgm_clip_xmax = cgm_canvas2vdcx ( intcgm_view_xmax ); + intcgm_clip_ymin = cgm_canvas2vdcy ( intcgm_view_ymin ); + intcgm_clip_ymax = cgm_canvas2vdcy ( intcgm_view_ymax ); + } + else + { + intcgm_clip_xmin = intcgm_vdc_ext.xmin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_xmax = intcgm_vdc_ext.xmax*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymin = intcgm_vdc_ext.ymin*intcgm_cgm.scaling_mode.scale_factor; + intcgm_clip_ymax = intcgm_vdc_ext.ymax*intcgm_cgm.scaling_mode.scale_factor; + } + + return cgmt_ter(); +} + +int cgmt_clslmd ( void ) /* colour selection mode */ +{ + const char *options[] = { "indexed", "direct", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.clrsm), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_lnwdmd ( void ) /* line width specification mode */ +{ + const char *options[] = { "abstract", "scaled", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.lnwsm), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mkszmd ( void ) /* marker size specification mode */ +{ + const char *options[] = { "abstract", "scaled", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.mkssm), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_edwdmd ( void ) /* edge width specification mode */ +{ + const char *options[] = { "abstract", "scaled", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.edwsm), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_vdcext ( void ) /* vdc extent */ +{ + if ( cgmt_p ( &(intcgm_cgm.vdc_ext.first.x), &(intcgm_cgm.vdc_ext.first.y) ) ) return 1; + + if ( cgmt_p ( &(intcgm_cgm.vdc_ext.second.x), &(intcgm_cgm.vdc_ext.second.y) ) ) return 1; + + if (cdcgmvdcextcb) + { + int err; + err = cdcgmvdcextcb( intcgm_canvas, intcgm_cgm.vdc_type, &(intcgm_cgm.vdc_ext.first.x), &(intcgm_cgm.vdc_ext.first.y), + &(intcgm_cgm.vdc_ext.second.x), &(intcgm_cgm.vdc_ext.second.y) ); + if (err==CD_ABORT) return -1; + } + + cgm_do_vdcext ( intcgm_cgm.vdc_ext.first, intcgm_cgm.vdc_ext.second ); + + return cgmt_ter(); +} + +int cgmt_bckcol ( void ) /* backgound colour */ +{ + if ( cgmt_rgb ( &(intcgm_cgm.back_color.red), &(intcgm_cgm.back_color.green), &(intcgm_cgm.back_color.blue) ) ) return 1; + + cgm_do_bckcol ( intcgm_cgm.back_color ); + + return cgmt_ter(); +} + +int cgmt_vdcipr ( void ) /* vdc integer precision */ +{ + if ( cgmt_i ( &(intcgm_cgm.vdc_int.t_prec.minint) ) ) return 1; + if ( cgmt_i ( &(intcgm_cgm.vdc_int.t_prec.maxint) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_vdcrpr ( void ) /* vdc real precision */ +{ + if ( cgmt_r ( &(intcgm_cgm.vdc_real.t_prec.minreal) ) ) return 1; + if ( cgmt_r ( &(intcgm_cgm.vdc_real.t_prec.maxreal) ) ) return 1; + if ( cgmt_i ( &(intcgm_cgm.vdc_real.t_prec.digits) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_auxcol ( void ) /* auxiliary colour */ +{ + if ( cgmt_co ( &(intcgm_cgm.aux_color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_transp ( void ) /* transparency */ +{ + const char *options[] = { "on", "off", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.transparency), options ) ) return 1; + + cgm_do_transp ( intcgm_cgm.transparency ); + + return cgmt_ter(); +} + +int cgmt_clprec ( void ) /* clip rectangle */ +{ + if ( cgmt_p ( &(intcgm_cgm.clip_rect.first.x), &(intcgm_cgm.clip_rect.first.y) ) ) return 1; + + if ( cgmt_p ( &(intcgm_cgm.clip_rect.second.x), &(intcgm_cgm.clip_rect.second.y) ) ) return 1; + + cgm_do_clprec ( intcgm_cgm.clip_rect.first, intcgm_cgm.clip_rect.second ); + + return cgmt_ter(); +} + +int cgmt_clpind ( void ) /* clip indicator */ +{ + const char *options[] = { "on", "off", NULL }; + + if ( cgmt_e ( &(intcgm_cgm.clip_ind), options ) ) return 1; + + cgm_do_clpind ( intcgm_cgm.clip_ind ); + + return cgmt_ter(); +} + +static tpoint *get_points ( int *np ) +{ + *np=0; + + do + { + if ( cgmt_p ( &(intcgm_point_list[*np].x), &(intcgm_point_list[*np].y) ) ) return NULL; + ++(*np); + if ( *np==intcgm_npoints) + { + intcgm_npoints *= 2; + intcgm_point_list = (tpoint *) realloc ( intcgm_point_list, intcgm_npoints*sizeof(tpoint) ); + } + } while ( cgmt_ter() ); + + return intcgm_point_list; +} + +int cgmt_polyln ( void ) /* polyline */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_polyln ( np, pt ); + + return 0; +} + +int cgmt_incply ( void ) /* incremental polyline */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_incply ( np, pt ); + + return 0; +} + +int cgmt_djtply ( void ) /* disjoint polyline */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_djtply ( np, pt ); + + return 0; +} + +int cgmt_indjpl ( void ) /* incremental disjoint polyline */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_indpl ( np, pt ); + + return 0; +} + +int cgmt_polymk ( void ) /* polymarker */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_polymk ( np, pt ); + + return 0; +} + +int cgmt_incplm ( void ) /* incremental polymarker */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_incplm ( np, pt ); + + return 0; +} + +int cgmt_text ( void ) /* text */ +{ + tpoint pos; + const char *options[] = { "final", "notfinal", NULL }; + short flag; + char *string; + + if ( cgmt_p ( &(pos.x), &(pos.y) ) ) return 1; + + if ( cgmt_e ( &flag, options ) ) return 1; + + if ( cgmt_s ( &string ) ) return 1; + + cgm_do_text ( NORM_TEXT, string, pos ); + + free ( string ); + + return cgmt_ter(); +} + +int cgmt_rsttxt ( void ) /* restricted text */ +{ + double width, height; + tpoint pos; + const char *options[] = { "final", "notfinal", NULL }; + short flag; + char *string; + + if ( cgmt_vdc ( &width ) ) return 1; + + if ( cgmt_vdc ( &height ) ) return 1; + + if ( cgmt_p ( &(pos.x), &(pos.y) ) ) return 1; + + if ( cgmt_e ( &flag, options ) ) return 1; + + if ( cgmt_s ( &string ) ) return 1; + + intcgm_text_att.height = height; + + cgm_do_text ( RESTRICTED_TEXT, string, pos ); + + if ( string!= NULL ) free ( string ); + + return cgmt_ter(); +} + +int cgmt_apdtxt ( void ) /* append text */ +{ + const char *options[] = { "final", "notfinal", NULL }; + short flag; + char *string; + + if ( cgmt_e ( &flag, options ) ) return 1; + + if ( cgmt_s ( &string ) ) return 1; + + free ( string ); + + return cgmt_ter(); +} + +int cgmt_polygn ( void ) /* polygon */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_polygn ( np, pt ); + + return 0; +} + +int cgmt_incplg ( void ) /* incremental polygon */ +{ + tpoint *pt; + int np; + + pt = get_points( &np ); + if ( pt == NULL ) return 1; + + cgm_do_incplg ( np, pt ); + + return 0; +} + +static int get_point_set ( tpoint **pts, short **flags, int *np ) +{ + int intcgm_block=500; + const char *options[] = { "invis", "vis", "closeinvis", "closevis", NULL }; + + *np=0; + *pts = (tpoint *) malloc ( intcgm_block*sizeof(tpoint) ); + *flags = (short *) malloc ( intcgm_block*sizeof(short) ); + + do + { + if ( cgmt_p ( &((*pts)[*np].x), &((*pts)[*np].y) ) ) return 1; + + if ( cgmt_e ( &((*flags)[*np]), options ) ) return 1; + + ++(*np); + if ( *np==intcgm_block) + { + intcgm_block *= 2; + *pts = (tpoint *) realloc ( *pts, intcgm_block*sizeof(tpoint) ); + *flags = (short *) realloc ( *flags, intcgm_block*sizeof(short) ); + } + } while ( cgmt_ter() ); + + return 0; +} + +int cgmt_plgset ( void ) /* polygon set */ +{ + tpoint *pt; + short *flag; + int np; + + if ( get_point_set ( &pt, &flag, &np ) ) return 1; + + cgm_do_plgset( NO, np, pt, flag ); + + free ( pt ); + free ( flag ); + + return 0; +} + +int cgmt_inpgst ( void ) /* incremental polygon set */ +{ + tpoint *pt; + short *flag; + int np; + + if ( get_point_set ( &pt, &flag, &np ) ) return 1; + + cgm_do_plgset( YES, np, pt, flag ); + + free ( pt ); + free ( flag ); + + return 0; +} + +int cgmt_cellar ( void ) /* cell array */ +{ + tpoint corner1; + tpoint corner2; + tpoint corner3; + long nx, ny; + long local_color_prec; + tcolor *cell; + int i,k; + + if ( cgmt_p ( &(corner1.x), &(corner1.y) ) ) return 1; + if ( cgmt_p ( &(corner2.x), &(corner2.y) ) ) return 1; + if ( cgmt_p ( &(corner3.x), &(corner3.y) ) ) return 1; + + if ( cgmt_i ( &nx ) ) return 1; + if ( cgmt_i ( &ny ) ) return 1; + + if ( cgmt_i ( &(local_color_prec) ) ) return 1; + + cell = (tcolor *) malloc ( nx*ny*sizeof(tcolor) ); + + cgmt_getparentheses(); + + for ( k=0; k<ny; k++ ) + { + for ( i=0; i<nx; i++ ) + { + if ( cgmt_co ( &(cell[k*nx+i]) ) ) return 1; + } + cgm_getfilepos(); + } + + cgmt_getparentheses(); + + cgm_do_cellar ( corner1, corner2, corner3, nx, ny, local_color_prec, cell ); + + free(cell); + + return cgmt_ter(); +} + +int cgmt_gdp ( void ) /* generalized drawing picture */ +{ + long identifier; + tpoint *pt = NULL; + int intcgm_block = 500; + int np = 0; + char *data_rec; + + pt = (tpoint *) malloc ( intcgm_block*sizeof(tpoint) ); + + if ( cgmt_i ( &identifier ) ) return 1; + + while ( strstr(cgmt_getsep(),",")==NULL ) + { + if ( cgmt_p ( &(pt[np].x), &(pt[np].y) ) ) + { + if ( pt!=NULL ) free(pt); + return 1; + } + ++np; + + if ( np==intcgm_block ) + { + intcgm_block *= 2; + pt = (tpoint *) realloc ( pt, intcgm_block*sizeof(tpoint) ); + } + } + + if ( cgmt_s ( &data_rec ) ) return 1; + + cgm_do_gdp ( identifier, pt, data_rec ); + + free ( data_rec ); + free ( pt ); + + return cgmt_ter(); +} + +int cgmt_rect ( void ) /* rectangle */ +{ + tpoint point1; + tpoint point2; + + if ( cgmt_p ( &(point1.x), &(point1.y) ) ) return 1; + if ( cgmt_p ( &(point2.x), &(point2.y) ) ) return 1; + + cgm_do_rect ( point1, point2 ); + + return cgmt_ter(); +} + +int cgmt_circle ( void ) /* circle */ +{ + tpoint center; + double radius; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_vdc ( &radius ) ) return 1; + + cgm_do_circle ( center, radius ); + + return cgmt_ter(); +} + +int cgmt_circ3p ( void ) /* circular arc 3 point */ +{ + tpoint starting; + tpoint intermediate; + tpoint ending; + + if ( cgmt_p ( &(starting.x), &(starting.y) ) ) return 1; + if ( cgmt_p ( &(intermediate.x), &(intermediate.y) ) ) return 1; + if ( cgmt_p ( &(ending.x), &(ending.y) ) ) return 1; + + cgm_do_circ3p ( starting, intermediate, ending ); + + return cgmt_ter(); +} + +int cgmt_cir3pc ( void ) /* circular arc 3 point close */ +{ + tpoint starting; + tpoint intermediate; + tpoint ending; + const char *options[] = { "pie", "chord", NULL }; + short close_type; + + if ( cgmt_p ( &(starting.x), &(starting.y) ) ) return 1; + if ( cgmt_p ( &(intermediate.x), &(intermediate.y) ) ) return 1; + if ( cgmt_p ( &(ending.x), &(ending.y) ) ) return 1; + + if ( cgmt_e ( &close_type, options ) ) return 1; + + cgm_do_circ3pc ( starting, intermediate, ending, close_type ); + + return cgmt_ter(); +} + +int cgmt_circnt ( void ) /* circular arc centre */ +{ + tpoint center; + tpoint start; + tpoint end; + double radius; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_vdc ( &(start.x) ) ) return 1; + if ( cgmt_vdc ( &(start.y) ) ) return 1; + + if ( cgmt_vdc ( &(end.x) ) ) return 1; + if ( cgmt_vdc ( &(end.y) ) ) return 1; + + if ( cgmt_vdc ( &radius ) ) return 1; + + cgm_do_circcnt ( center, start, end, radius ); + + return cgmt_ter(); +} + +int cgmt_ccntcl ( void ) /* circular arc centre close */ +{ + tpoint center; + tpoint start; + tpoint end; + double radius; + const char *options[] = { "pie", "chord", NULL }; + short close_type; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_vdc ( &(start.x) ) ) return 1; + if ( cgmt_vdc ( &(start.y) ) ) return 1; + + if ( cgmt_vdc ( &(end.x) ) ) return 1; + if ( cgmt_vdc ( &(end.y) ) ) return 1; + + if ( cgmt_vdc ( &radius ) ) return 1; + + if ( cgmt_e ( &close_type, options ) ) return 1; + + cgm_do_ccntcl ( center, start, end, radius, close_type ); + + return cgmt_ter(); +} + +int cgmt_ellips ( void ) /* ellipse */ +{ + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmt_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + cgm_do_ellips ( center, first_CDP, second_CDP ); + + return cgmt_ter(); +} + +int cgmt_ellarc ( void ) /* elliptical arc */ +{ + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + tpoint start, end; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmt_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + if ( cgmt_vdc ( &(start.x) ) ) return 1; + if ( cgmt_vdc ( &(start.y) ) ) return 1; + + if ( cgmt_vdc ( &(end.x) ) ) return 1; + if ( cgmt_vdc ( &(end.y) ) ) return 1; + + cgm_do_ellarc ( center, first_CDP, second_CDP, start, end ); + + return cgmt_ter(); +} + +int cgmt_ellacl ( void ) /* elliptical arc close */ +{ + tpoint center; + tpoint first_CDP; + tpoint second_CDP; + tpoint start, end; + const char *options[] = { "pie", "chord", NULL }; + short close_type; + + if ( cgmt_p ( &(center.x), &(center.y) ) ) return 1; + + if ( cgmt_p ( &(first_CDP.x), &(first_CDP.y) ) ) return 1; + if ( cgmt_p ( &(second_CDP.x), &(second_CDP.y) ) ) return 1; + + if ( cgmt_vdc ( &(start.x) ) ) return 1; + if ( cgmt_vdc ( &(start.y) ) ) return 1; + + if ( cgmt_vdc ( &(end.x) ) ) return 1; + if ( cgmt_vdc ( &(end.y) ) ) return 1; + + if ( cgmt_e ( &close_type, options ) ) return 1; + + cgm_do_ellacl ( center, first_CDP, second_CDP, start, end, close_type ); + + return cgmt_ter(); +} + +int cgmt_lnbdin ( void ) /* line bundle index */ +{ + if ( cgmt_i ( &(intcgm_line_att.index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_lntype ( void ) /* line type */ +{ + if ( cgmt_i ( &(intcgm_line_att.type) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_lnwidt ( void ) /* line width */ +{ + if ( intcgm_cgm.lnwsm==0 ) + { + if ( cgmt_vdc ( &(intcgm_line_att.width) ) ) return 1; + } + else + { + + if ( cgmt_r ( &(intcgm_line_att.width) ) ) return 1; + } + + return cgmt_ter(); +} + +int cgmt_lncolr ( void ) /* line colour */ +{ + if ( cgmt_co ( &(intcgm_line_att.color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mkbdin ( void ) /* marker bundle index */ +{ + if ( cgmt_i ( &(intcgm_marker_att.index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mktype ( void ) /* marker type */ +{ + if ( cgmt_i ( &(intcgm_marker_att.type) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_mksize ( void ) /* marker size */ +{ + if ( intcgm_cgm.mkssm == 0 ) + { + if ( cgmt_vdc ( &(intcgm_marker_att.size) ) ) return 1; + } + else + { + if ( cgmt_r ( &(intcgm_marker_att.size) ) ) return 1; + } + + return cgmt_ter(); +} + +int cgmt_mkcolr ( void ) /* marker colour */ +{ + if ( cgmt_co ( &(intcgm_marker_att.color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_txbdin ( void ) /* text bundle index */ +{ + if ( cgmt_i ( &(intcgm_text_att.index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_txftin ( void ) /* text font index */ +{ + char *font; + char *font_array[] = {"SYSTEM", "COURIER", "TIMES", "HELVETICA", NULL}; + char *style_array[] = {"BOLDITALIC", "ITALIC", "BOLD", "PLAIN", NULL}; + int cdstyle[] = {CD_BOLD_ITALIC, CD_ITALIC, CD_BOLD, CD_PLAIN}; + int i; + + if ( cgmt_i ( &(intcgm_text_att.font_index) ) ) return 1; + + font = (char *) cgm_GetList ( intcgm_text_att.font_list, intcgm_text_att.font_index ); + + if ( font==NULL ) font = (char*)strdup ( "SYSTEM" ); + + intcgm_text_att.font = 0; + for ( i=0; font_array[i]!=NULL; i++ ) + { + if ( strstr( font, font_array[i] ) ) + { + intcgm_text_att.font = i; + break; + } + } + + intcgm_text_att.style = 0; + for ( i=0; style_array[i]!=NULL; i++ ) + { + if ( strstr( font, style_array[i] ) ) + { + intcgm_text_att.style = cdstyle[i]; + break; + } + } + + cgm_setfont ( intcgm_text_att.font, intcgm_text_att.style, intcgm_text_att.height ); + + return cgmt_ter(); +} + +int cgmt_txtprc ( void ) /* text precision */ +{ + const char *options[] = { "string", "char", "stroke", NULL }; + + if ( cgmt_e ( &(intcgm_text_att.prec), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_chrexp ( void ) /* char expansion factor */ +{ + if ( cgmt_r ( &(intcgm_text_att.exp_fact) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_chrspc ( void ) /* char spacing */ +{ + if ( cgmt_r ( &(intcgm_text_att.char_spacing) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_txtclr ( void ) /* text colour */ +{ + if ( cgmt_co ( &(intcgm_text_att.color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_chrhgt ( void ) /* char height */ +{ + if ( cgmt_vdc ( &(intcgm_text_att.height) ) ) return 1; + + cgm_do_text_height ( intcgm_text_att.height ); + + return cgmt_ter(); +} + +int cgmt_chrori ( void ) /* char orientation */ +{ + if ( cgmt_vdc ( &(intcgm_text_att.char_up.x) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_text_att.char_up.y) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_text_att.char_base.x) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_text_att.char_base.y) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_txtpat ( void ) /* text path */ +{ + const char *options[] = { "right", "left", "up", "down", NULL }; + + if ( cgmt_e ( &(intcgm_text_att.path), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_txtali ( void ) /* text alignment */ +{ + const char *hor[] = { "normhoriz", "left", "ctr", "right", "conthoriz", NULL }; + const char *ver[] = { "normvert", "top", "cap", "half", "base", "bottom", + "contvert", NULL }; + + if ( cgmt_e ( &(intcgm_text_att.alignment.hor), hor ) ) return 1; + if ( cgmt_e ( &(intcgm_text_att.alignment.ver), ver ) ) return 1; + + if ( cgmt_r ( &(intcgm_text_att.alignment.cont_hor) ) ) return 1; + if ( cgmt_r ( &(intcgm_text_att.alignment.cont_ver) ) ) return 1; + + cgm_do_txtalign ( intcgm_text_att.alignment.hor, intcgm_text_att.alignment.ver ); + + return cgmt_ter(); +} + +int cgmt_chseti ( void ) /* character set index */ +{ + long set; + + if ( cgmt_i ( &set ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_achsti ( void ) /* alternate character set index */ +{ + long set; + + if ( cgmt_i ( &set ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_fillin ( void ) /* fill bundle index */ +{ + if ( cgmt_i ( &(intcgm_fill_att.index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_intsty ( void ) /* interior style */ +{ + const char *options[] = { "hollow", "solid", "pat", "hatch", "empty", NULL }; + + if ( cgmt_e ( &(intcgm_fill_att.int_style), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_fillco ( void ) /* fill colour */ +{ + if ( cgmt_co ( &(intcgm_fill_att.color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_hatind ( void ) /* hatch index */ +{ + if ( cgmt_i ( &(intcgm_fill_att.hatch_index) ) ) return 1; + if ( intcgm_fill_att.hatch_index==3 ) intcgm_fill_att.hatch_index = 4; + else if ( intcgm_fill_att.hatch_index==4 ) intcgm_fill_att.hatch_index = 3; + + return cgmt_ter(); +} + +int cgmt_patind ( void ) /* pattern index */ +{ + if ( cgmt_i ( &(intcgm_fill_att.pat_index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_edgind ( void ) /* edge bundle index */ +{ + if ( cgmt_i ( &(intcgm_edge_att.index) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_edgtyp( void ) /* edge type */ +{ + if ( cgmt_i ( &(intcgm_edge_att.type) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_edgwid ( void ) /* edge width */ +{ + if ( intcgm_cgm.edwsm==0 ) + { + if ( cgmt_vdc ( &(intcgm_edge_att.width) ) ) return 1; + } + else + { + if ( cgmt_r ( &(intcgm_edge_att.width) ) ) return 1; + } + + return cgmt_ter(); +} + +int cgmt_edgcol ( void ) /* edge colour */ +{ + if ( cgmt_co ( &(intcgm_edge_att.color) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_edgvis ( void ) /* edge visibility */ +{ + const char *options[] = { "off", "on", NULL }; + + if ( cgmt_e ( &(intcgm_edge_att.visibility), options ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_fillrf ( void ) /* fill reference point */ +{ + if ( cgmt_p ( &(intcgm_fill_att.ref_pt.x), &(intcgm_fill_att.ref_pt.y) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_pattab ( void ) /* pattern table */ +{ + long local_color_prec; + int i; + pat_table *pat, *p; + + pat = (pat_table *) malloc ( sizeof(pat_table) ); + + if ( intcgm_fill_att.pat_list==NULL ) intcgm_fill_att.pat_list = cgm_NewList(); + + if ( cgmt_i ( &(pat->index) ) ) return 1; + + if ( cgmt_i ( &(pat->nx) ) ) return 1; + if ( cgmt_i ( &(pat->ny) ) ) return 1; + + if ( cgmt_i ( &(local_color_prec) ) ) return 1; + + pat->pattern = (tcolor *) malloc ( pat->nx*pat->ny*sizeof(tcolor) ); + + cgmt_getparentheses(); + + for ( i=0; i<(pat->nx*pat->ny); i++ ) + if ( cgmt_co ( &(pat->pattern[i]) ) ) return 1; + + cgmt_getparentheses(); + + for ( i=0; (p=(pat_table *)cgm_GetList(intcgm_fill_att.pat_list,i))!=NULL; i++ ) + { + if ( p->index==pat->index ) + { + free(p->pattern); + cgm_DelList(intcgm_fill_att.pat_list,i); + break; + } + } + + cgm_AppendList ( intcgm_fill_att.pat_list, pat ); + + return cgmt_ter(); +} + +int cgmt_patsiz ( void ) /* pattern size */ +{ + if ( cgmt_vdc ( &(intcgm_fill_att.pat_size.height.x) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_fill_att.pat_size.height.y) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_fill_att.pat_size.width.x) ) ) return 1; + if ( cgmt_vdc ( &(intcgm_fill_att.pat_size.width.y) ) ) return 1; + + return cgmt_ter(); +} + +int cgmt_coltab ( void ) /* colour table */ +{ + long starting_index; + + if ( cgmt_i ( &(starting_index) ) ) return 1; + + while ( cgmt_ter() ) + { + if ( cgmt_rgb ( &(intcgm_color_table[starting_index].red), &(intcgm_color_table[starting_index].green), + &(intcgm_color_table[starting_index].blue) ) ) return 1; + starting_index++; + } + + return 0; +} + +int cgmt_asf ( void ) /* asfs */ +{ + const char *asf_value[] = { "bundled", "indiv", NULL }; + const char *asf_type[] = { "linetype" , "linewidth" , "linecolr" , + "markertype" , "markersize", "markercolr", + "textfontindex", "textprec" , "charexp" , + "charspace" , "textcolr" , "intstyle" , + "fillcolr" , "hatchindex", "patindex" , + "edgetype" , "edgewidth" , "edgecolr" , + "all" , "allline" , "allmarker" , + "alltext" , "allfill" , "alledge", NULL }; + tasf *pair; + + if ( intcgm_asf_list==NULL ) intcgm_asf_list = cgm_NewList(); + + while( cgmt_ter() ) + { + pair = (tasf *) malloc ( sizeof (tasf) ); + + if ( cgmt_e ( &(pair->type), asf_type ) ) return 1; + if ( cgmt_e ( &(pair->value), asf_value ) ) return 1; + + cgm_AppendList ( intcgm_asf_list, pair ); + } + + return 0; +} + +int cgmt_escape ( void ) /* escape */ +{ + long identifier; + char *data_rec; + + if ( cgmt_i ( &(identifier) ) ) return 1; + + if ( cgmt_s ( &data_rec ) ) return 1; + + free(data_rec); + + return cgmt_ter(); +} + +int cgmt_messag ( void ) /* message */ +{ + const char *options[] = { "noaction", "action", NULL }; + char *text; + short flag; + + if ( cgmt_e ( &flag, options ) ) return 1; + + if ( cgmt_s ( &text ) ) return 1; + + free(text); + + return cgmt_ter(); +} + +int cgmt_appdta ( void ) /* application data */ +{ + long identifier; + char *data_rec; + + if ( cgmt_i ( &identifier ) ) return 1; + + if ( cgmt_s ( &data_rec ) ) return 1; + + free(data_rec); + + return cgmt_ter(); +} diff --git a/src/intcgm/tparse.h b/src/intcgm/tparse.h new file mode 100644 index 0000000..c1292bc --- /dev/null +++ b/src/intcgm/tparse.h @@ -0,0 +1,101 @@ +#ifndef _TPARSE_H_ +#define _TPARSE_H_ + +int cgmt_begmtf ( void ); +int cgmt_endmtf ( void ); +int cgmt_begpic ( void ); +int cgmt_begpib ( void ); +int cgmt_endpic ( void ); +int cgmt_mtfver ( void ); +int cgmt_mtfdsc ( void ); +int cgmt_vdctyp ( void ); +int cgmt_intpre ( void ); +int cgmt_realpr ( void ); +int cgmt_indpre ( void ); +int cgmt_colpre ( void ); +int cgmt_colipr ( void ); +int cgmt_maxcoi ( void ); +int cgmt_covaex ( void ); +int cgmt_mtfell ( void ); +int cgmt_bmtfdf (void ); +int cgmt_emtfdf ( void ); +int cgmt_fntlst ( void ); +int cgmt_chslst ( void ); +int cgmt_chcdac ( void ); +int cgmt_sclmde ( void ); +int cgmt_clslmd ( void ); +int cgmt_lnwdmd ( void ); +int cgmt_mkszmd ( void ); +int cgmt_edwdmd ( void ); +int cgmt_vdcext ( void ); +int cgmt_bckcol ( void ); +int cgmt_vdcipr ( void ); +int cgmt_vdcrpr ( void ); +int cgmt_auxcol ( void ); +int cgmt_transp ( void ); +int cgmt_clprec ( void ); +int cgmt_clpind ( void ); +int cgmt_polyln ( void ); +int cgmt_incply ( void ); +int cgmt_djtply ( void ); +int cgmt_indjpl ( void ); +int cgmt_polymk ( void ); +int cgmt_incplm ( void ); +int cgmt_text ( void ); +int cgmt_rsttxt ( void ); +int cgmt_apdtxt ( void ); +int cgmt_polygn ( void ); +int cgmt_incplg ( void ); +int cgmt_plgset ( void ); +int cgmt_inpgst ( void ); +int cgmt_cellar ( void ); +int cgmt_gdp ( void ); +int cgmt_rect ( void ); +int cgmt_circle ( void ); +int cgmt_circ3p ( void ); +int cgmt_cir3pc ( void ); +int cgmt_circnt ( void ); +int cgmt_ccntcl ( void ); +int cgmt_ellips ( void ); +int cgmt_ellarc ( void ); +int cgmt_ellacl ( void ); +int cgmt_lnbdin ( void ); +int cgmt_lntype ( void ); +int cgmt_lnwidt ( void ); +int cgmt_lncolr ( void ); +int cgmt_mkbdin ( void ); +int cgmt_mktype ( void ); +int cgmt_mksize ( void ); +int cgmt_mkcolr ( void ); +int cgmt_txbdin ( void ); +int cgmt_txftin ( void ); +int cgmt_txtprc ( void ); +int cgmt_chrexp ( void ); +int cgmt_chrspc ( void ); +int cgmt_txtclr ( void ); +int cgmt_chrhgt ( void ); +int cgmt_chrori ( void ); +int cgmt_txtpat ( void ); +int cgmt_txtali ( void ); +int cgmt_chseti ( void ); +int cgmt_achsti ( void ); +int cgmt_fillin ( void ); +int cgmt_intsty ( void ); +int cgmt_fillco ( void ); +int cgmt_hatind ( void ); +int cgmt_patind ( void ); +int cgmt_edgind ( void ); +int cgmt_edgtyp( void ); +int cgmt_edgwid ( void ); +int cgmt_edgcol ( void ); +int cgmt_edgvis ( void ); +int cgmt_fillrf ( void ); +int cgmt_pattab ( void ); +int cgmt_patsiz ( void ); +int cgmt_coltab ( void ); +int cgmt_asf ( void ); +int cgmt_escape ( void ); +int cgmt_messag ( void ); +int cgmt_appdta ( void ); + +#endif diff --git a/src/intcgm/types.h b/src/intcgm/types.h new file mode 100644 index 0000000..6d6f65c --- /dev/null +++ b/src/intcgm/types.h @@ -0,0 +1,225 @@ +#ifndef _CGM_TYPES_H_ +#define _CGM_TYPES_H_ + +typedef struct { + double xmin; + double xmax; + double ymin; + double ymax; + } tlimit; + +typedef struct { + unsigned long red; + unsigned long green; + unsigned long blue; + } trgb; + +typedef union { + int ind; + trgb rgb; + } tcolor; + +typedef struct { + double x; + double y; + } tpoint; + +typedef struct { + char *dados; + int size; + } tdados; + +typedef struct { + FILE *fp; + + int (*cgmf)(void); + + int file_size; + + int first; + + int mode; /* character, binary, clear text */ + + int len; + + tdados buff; + + short vdc_type; + + union { + long b_prec; /* 8, 16, 24, 32 */ + struct { long minint; long maxint; } t_prec ; + } int_prec; + union { + long b_prec; /* float*32, float*64, fixed*32, fixed*64 */ + struct { double minreal; double maxreal; long digits; } t_prec; + } real_prec; + union { + long b_prec; /* 8, 16, 24, 32 */ + struct { long minint; long maxint; } t_prec; + } ix_prec; + long cd_prec; + long cix_prec; + struct { + trgb black; + trgb white; + } color_ext; + long max_cix; + + struct { + short mode; + double scale_factor; + } scaling_mode; + + short drawing_mode; + + short clrsm; + short lnwsm; + short mkssm; + short edwsm; + + union { + long b_prec; /* 8, 16, 24, 32 */ + struct { long minint; long maxint; } t_prec; + } vdc_int; + union { + long b_prec; /* float*32, float*64, fixed*32, fixed*64 */ + struct { double minreal; double maxreal; long digits; } t_prec; + } vdc_real; + + struct { + tpoint first; + tpoint second; + } vdc_ext; + + trgb back_color; + + tcolor aux_color; + + short transparency; + + struct { + tpoint first; + tpoint second; + } clip_rect; + + short clip_ind; + + int bc; /* byte count */ + int pc; /* pixel count */ + + long bl; /* bytes lidos */ + + int cl; /* coluna para alinhamento */ + + } t_cgm; + +typedef struct { + long index; + long type; + double width; + tcolor color; + } _line_att; + +typedef struct { + long index; + long type; + double size; + tcolor color; + } _marker_att; + +typedef struct { + long index; + long font_index; + TList *font_list; + int font; + int style; + int size; + short prec; + double exp_fact; + double char_spacing; + tcolor color; + double height; + tpoint char_up; + tpoint char_base; + short path; + struct { short hor; + short ver; + double cont_hor; + double cont_ver; + } alignment; + } _text_att; + +typedef struct { + long index; + short int_style; + tcolor color; + long hatch_index; + long pat_index; + tpoint ref_pt; + TList *pat_list; + struct { + tpoint height; + tpoint width; + } pat_size; + } _fill_att; + +typedef struct { + long index; + long type; + double width; + tcolor color; + short visibility; + } _edge_att; + +enum { OFF, ON }; + +enum { YES, NO }; + +enum { INTEGER, REAL }; + +enum { STRING, CHAR, STROKE }; + +enum { ABSOLUTE, SCALED }; + +enum { ABSTRACT, METRIC }; + +enum { INDEXED, DIRECT }; + +enum { MARK_DOT=1, MARK_PLUS=2, MARK_ASTERISK=3, MARK_CIRCLE=4, MARK_CROSS=5 }; + +enum { LINE_SOLID=1, LINE_DASH=2, LINE_DOT=3, LINE_DASH_DOT=4, + LINE_DASH_DOT_DOT=5 }; + +enum { EDGE_SOLID=1, EDGE_DASH=2, EDGE_DOT=3, EDGE_DASH_DOT=4, + EDGE_DASH_DOT_DOT=5 }; + +enum { HOLLOW, SOLID, PATTERN, HATCH, EMPTY }; + +enum { HORIZONTAL=1, VERTICAL=2, POSITIVE_SLOPE=3, NEGATIVE_SLOPE=4, + HV_CROSS=5, SLOPE_CROSS=6 }; + +enum { PATH_RIGHT, PATH_LEFT, PATH_UP, PATH_DOWN }; + +enum { NORMHORIZ, LEFT, CTR, RIGHT, CONTHORIZ }; + +enum { NORMVERT, TOP, CAP, HALF, BASE, BOTTOM, CONTVERT }; + +enum { LINE_TYPE, LINE_WIDTH, LINE_COLOUR, MARKER_TYPE, MARKER_SIZE, + MARKER_COLOUR, TEXT_FONT_INDEX, TEXT_PRECISION, + CHARACTER_EXPANSION_FACTOR, CHARACTER_SPACING, TEXT_COLOUR, + INTERIOR_STYLE, FILL_COLOUR, HATCH_INDEX, PATTERN_INDEX, EDGE_TYPE, + EDGE_WIDTH, EDGE_COLOUR, ALL, ALL_LINE, ALL_MARKER, ALL_TEXT, ALL_FILL, + ALL_EDGE }; + +enum { INDIVIDUAL, BUNDLED }; + +enum { INVISIBLE, VISIBLE, CLOSE_INVISIBLE, CLOSE_VISIBLE }; + +enum { PIE, CHORD }; + +enum { OPEN, CLOSED_PIE, CLOSED_CHORD }; + +enum { NORM_TEXT, RESTRICTED_TEXT }; + +#endif diff --git a/src/lua3/cdlua.c b/src/lua3/cdlua.c new file mode 100644 index 0000000..ea5ac44 --- /dev/null +++ b/src/lua3/cdlua.c @@ -0,0 +1,4366 @@ +/***************************************************************************\ +* CDLUA.C, for LUA 3.1 * +* Diego Fernandes Nehab, Antonio Escano Scuri * +* 01/99 * +* Implements all that TOLUA couldn't handle. * +\***************************************************************************/ + +/***************************************************************************\ +* Included definitions. * +\***************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +/***************************************************************************\ +* CD Definitions. * +\***************************************************************************/ +#include "cd.h" +#include "wd.h" + +#include "cdirgb.h" /* cdRedImage, cdGreenImage, cdBlueImage */ + +/* error checking when there is no active canvas */ +#include "cdvoid.h" + +/***************************************************************************\ +* LUA Definitions. * +\***************************************************************************/ +#include <lua.h> +#include <lauxlib.h> + +/***************************************************************************\ +* CDLUA Definitions. * +\***************************************************************************/ +#include "cdlua.h" +#include "cdlua3_private.h" + +/***************************************************************************\ +* Globals. * +\***************************************************************************/ +static int color_tag; +static int stipple_tag; +static int pattern_tag; +static int image_tag; +static int bitmap_tag; +static int imagergb_tag; +static int imagergba_tag; +static int palette_tag; +static int imagemap_tag; +static int channel_tag; +static int canvas_tag; +static int state_tag; + +static channel_t channel_info; +static cdCanvas *void_canvas; +static cdContextLUA* cdlua_drivers[50]; +static int cdlua_numdrivers = 0; +static lua_Object cdlua_namespace; + +int luaL_cd_open(void); /* from toluacd.c */ +int luaL_wd_open(void); /* from toluawd.c */ +void cdlua_initdrivers(void); /* to cdluactx.c */ + + +/***************************************************************************\ +* Creation and destruction of types LUA can't handle. * +\***************************************************************************/ + +void cdlua_setnamespace(char* name, char* new_name) +{ + lua_Object obj = lua_getglobal(name); + lua_pushobject(cdlua_namespace); + lua_pushstring(new_name); + lua_pushobject(obj); + lua_settable(); +} + +void cdlua_register(char* name, lua_CFunction func) +{ + lua_register(name, func); + + if (name[0] == 'w') + { + char new_name[100]; + new_name[0] = 'w'; + strcpy(new_name+1, name+2); + cdlua_setnamespace(name, new_name); /* wdXXX */ + } + else + cdlua_setnamespace(name, name+2); /* cdXXX */ +} + +void cdlua_pushnumber(double num, char* name) +{ + lua_pushnumber(num); lua_setglobal(name); + cdlua_setnamespace(name, name+3); /* CD_XXXX */ +} + +static void cdlua_pushcolor(long color, char* name) +{ + lua_pushusertag((void*)color, color_tag); lua_setglobal(name); + cdlua_setnamespace(name, name+3); /* CD_XXXX */ +} + +void cdlua_addcontext(cdContextLUA* luactx) +{ + int i; + luactx->id = cdlua_numdrivers; + cdlua_drivers[cdlua_numdrivers] = luactx; + + cdlua_pushnumber(cdlua_numdrivers, luactx->name); + + /* skip CD_SIZECB, register other callbacks */ + for (i=1; i<luactx->cb_n; i++) + { + cdlua_pushnumber(i, luactx->cb_list[i].name); + } + + cdlua_numdrivers++; +} + +/***************************************************************************\ +* Creates a CD canvas as a canvas_tag usertag lua_Object. * +* If the creation fails, the function returns a nil lua_Object. * +\***************************************************************************/ +static void cdlua_createcanvas(void) +{ + lua_Object driver; + + long int driver_i; + canvas_t *canvas_p; + void *data_p; + + /* if there is not enough memory */ + canvas_p = (canvas_t *) malloc(sizeof(canvas_t)); + if (!canvas_p) { + lua_pushnil(); + return; + } + + /* get driver parameter */ + driver = lua_getparam(1); + if (!lua_isnumber(driver)) + lua_error("cdCreateCanvas: invalid driver parameter!"); + driver_i = (long int) lua_getnumber(driver); + + if (driver_i >= cdlua_numdrivers) + lua_error("cdCreateCanvas: unknown driver!"); + + data_p = cdlua_drivers[driver_i]->checkdata(2); + canvas_p->cd_canvas = cdCreateCanvas(cdlua_drivers[driver_i]->ctx(), data_p); + + /* if creation failed, return nil so that the user can compare */ + /* the result with nil and know that it failed */ + if (!canvas_p->cd_canvas) { + free(canvas_p); + lua_pushnil(); + } + /* else, return a canvas_t structure */ + else + lua_pushusertag((void *) canvas_p, canvas_tag); +} + +static lua_Object wdlua_hardcopy_func_lua = 0; + +static void wdlua_hardcopy_func(void) +{ + lua_callfunction(wdlua_hardcopy_func_lua); +} + +static void wdlua_hardcopy(void) +{ + lua_Object driver; + lua_Object canvas; + + long int driver_i; + canvas_t *canvas_p; + void *data_p; + + /* get driver parameter */ + driver = lua_getparam(1); + if (!lua_isnumber(driver)) + lua_error("wdHardcopy: invalid driver parameter!"); + driver_i = (long int) lua_getnumber(driver); + + canvas = lua_getparam(3); + + if (canvas == LUA_NOOBJECT) + lua_error("wdHardcopy: canvas parameter missing!"); + + /* if the creation failed, canvas can be nil, in which case we */ + /* issue an error */ + if (lua_isnil(canvas)) + lua_error("wdHardcopy: attempt to get a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("wdHardcopy: invalid canvas parameter!"); + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("wdHardcopy: attempt to get a killed canvas!"); + + wdlua_hardcopy_func_lua = lua_getparam(4); + + if (!lua_isfunction(wdlua_hardcopy_func_lua)) + lua_error("wdHardcopy: invalid draw function!"); + + if (lua_getparam(5) != LUA_NOOBJECT) + lua_error("wdHardcopy: too many parameters!"); + + if (driver_i >= cdlua_numdrivers) + lua_error("wdHardcopy: unknown driver!"); + + data_p = cdlua_drivers[driver_i]->checkdata(2); + wdHardcopy(cdlua_drivers[driver_i]->ctx(), data_p, canvas_p->cd_canvas, wdlua_hardcopy_func); +} + +static void cdlua_getcontext(void) +{ + lua_Object canvas; + canvas_t *canvas_p; + cdContext* ctx; + int driver_i = -1, i; + + canvas = lua_getparam(1); + + if (canvas == LUA_NOOBJECT) + lua_error("cdGetContext: canvas parameter missing!"); + + /* if the creation failed, canvas can be nil, in which case we */ + /* issue an error */ + if (lua_isnil(canvas)) + lua_error("cdGetContext: attempt to get a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdGetContext: invalid canvas parameter!"); + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdGetContext: attempt to get a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdGetContext: too many parameters!"); + + ctx = cdGetContext(canvas_p->cd_canvas); + + for (i=0; i < cdlua_numdrivers; i++) + { + if (ctx == cdlua_drivers[i]->ctx()) + { + driver_i = i; + break; + } + } + + if (i == cdlua_numdrivers) + lua_error("cdGetContext: unknown driver!"); + + lua_pushnumber(driver_i); +} + +static void cdlua_contextcaps(void) +{ + lua_Object driver; + long int driver_i; + unsigned long caps; + + /* get driver parameter */ + driver = lua_getparam(1); + if (!lua_isnumber(driver)) + lua_error("cdCreateCanvas: invalid driver parameter!"); + driver_i = (long int) lua_getnumber(driver); + + if (driver_i >= cdlua_numdrivers) + lua_error("cdContextCaps: unknown driver!"); + + caps = cdContextCaps(cdlua_drivers[driver_i]->ctx()); + + lua_pushnumber(caps); +} + +/***************************************************************************\ +* Activates a cd canvas. * +\***************************************************************************/ +static void cdlua_activate(void) +{ + lua_Object canvas; + canvas_t *canvas_p; + + canvas = lua_getparam(1); + + if (canvas == LUA_NOOBJECT) + lua_error("cdActivate: canvas parameter missing!"); + + /* if canvas is nil, activate a void canvas */ + if (lua_isnil(canvas)) { + lua_pushnumber(cdActivate(void_canvas)); + return; + } + + if (lua_tag(canvas) != canvas_tag) { + cdActivate(void_canvas); + lua_error("cdActivate: invalid canvas parameter!"); + } + + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) { + cdActivate(void_canvas); + lua_error("cdActivate: attempt to activate a killed canvas!"); + } + + if (lua_getparam(2) != LUA_NOOBJECT) { + cdActivate(void_canvas); + lua_error("cdActivate: too many parameters!"); + } + + lua_pushnumber(cdActivate(canvas_p->cd_canvas)); +} + +/***************************************************************************\ +* Returns the active canvas. * +\***************************************************************************/ +static void cdlua_activecanvas(void) +{ + canvas_t *canvas_p; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdActiveCanvas: too many parameters!"); + + canvas_p = (canvas_t *) malloc(sizeof(canvas_t)); + if (!canvas_p) { + lua_pushnil(); + return; + } + + canvas_p->cd_canvas = cdActiveCanvas(); + + /* if the active canvas is NULL, return nil so that the user can compare */ + /* the result with nil */ + if (!canvas_p->cd_canvas) { + free(canvas_p); + lua_pushnil(); + } + else + lua_pushusertag((void *) canvas_p, canvas_tag); +} + +cdCanvas* cdlua_checkcanvas(int pos) +{ + lua_Object canvas; + canvas_t *canvas_p; + + canvas = lua_getparam(pos); + + if (canvas == LUA_NOOBJECT) + lua_error("cdlua_getcanvas: canvas parameter missing!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdlua_getcanvas: invalid canvas parameter!"); + + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdlua_getcanvas: attempt to get a killed canvas!"); + + return canvas_p->cd_canvas; +} + +cdCanvas* cdlua_getcanvas(void) +{ + return cdlua_checkcanvas(1); +} + +void cdlua_pushcanvas(cdCanvas* canvas) +{ + canvas_t *canvas_p = (canvas_t *) malloc(sizeof(canvas_t)); + canvas_p->cd_canvas = canvas; + lua_pushusertag((void *)canvas_p, canvas_tag); +} + +static void cdlua_savestate(void) +{ + state_t *state_p; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdSaveState: too many parameters!"); + + state_p = (state_t *) malloc(sizeof(state_t)); + if (!state_p) { + lua_pushnil(); + return; + } + + state_p->state = cdSaveState(); + + /* if the active canvas is NULL, return nil so that the user can compare */ + /* the result with nil */ + if (!state_p->state) { + free(state_p); + lua_pushnil(); + } + else + lua_pushusertag((void *) state_p, state_tag); +} + +static void cdlua_restorestate(void) +{ + lua_Object state; + state_t *state_p; + + state = lua_getparam(1); + if (state == LUA_NOOBJECT) + lua_error("cdRestoreState: state parameter missing!"); + if (lua_isnil(state)) + lua_error("cdRestoreState: attempt to restore a NIL state!"); + + if (lua_tag(state) != state_tag) + lua_error("cdRestoreState: invalid canvas parameter!"); + + state_p = (state_t *) lua_getuserdata(state); + if (!state_p->state) + lua_error("cdRestoreState: attempt to restore a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdRestoreState: too many parameters!"); + + cdRestoreState(state_p->state); +} + +static void cdlua_releasestate(void) +{ + lua_Object state; + state_t *state_p; + + state = lua_getparam(1); + if (state == LUA_NOOBJECT) + lua_error("cdReleaseState: state parameter missing!"); + if (lua_isnil(state)) + lua_error("cdReleaseState: attempt to release a NIL state!"); + + if (lua_tag(state) != state_tag) + lua_error("cdReleaseState: invalid canvas parameter!"); + + state_p = (state_t *) lua_getuserdata(state); + if (!state_p->state) + lua_error("cdReleaseState: attempt to release a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdReleaseState: too many parameters!"); + + cdReleaseState(state_p->state); + state_p->state = NULL; +} + +static void cdlua_LineStyleDashes(void) +{ + lua_Object dashes, count, value; + int *dashes_int, dashes_count, i; + + dashes = lua_getparam(1); + if (dashes == LUA_NOOBJECT) + lua_error("cdLineStyleDashes: dashes parameter missing!"); + if (lua_isnil(dashes)) + lua_error("cdLineStyleDashes: dashes parameter is nil!"); + if (!lua_istable(dashes)) + lua_error("cdLineStyleDashes: invalid dashes parameter!"); + + count = lua_getparam(2); + if (count == LUA_NOOBJECT) + lua_error("cdLineStyleDashes: count parameter missing!"); + if (lua_isnil(count)) + lua_error("cdLineStyleDashes: count parameter is nil!"); + if (!lua_isnumber(dashes)) + lua_error("cdLineStyleDashes: invalid count parameter!"); + + dashes_count = (int)lua_getnumber(count); + dashes_int = malloc(dashes_count*sizeof(int)); + + for (i=0; i < dashes_count; i++) + { + lua_pushobject(dashes); + lua_pushnumber(i+1); + value = lua_gettable(); + + if (!lua_isnumber(value)) + lua_error("cdLineStyleDashes: invalid dash!"); + + dashes_int[i] = (int)lua_getnumber(value); + } + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdLineStyleDashes: too many parameters!"); + + cdLineStyleDashes(dashes_int, dashes_count); + free(dashes_int); +} + +/***************************************************************************\ +* Frees a previously alocated canvas. * +\***************************************************************************/ +static void cdlua_killcanvas(void) +{ + lua_Object canvas; + canvas_t *canvas_p; + cdCanvas *current_canvas; + + canvas = lua_getparam(1); + + if (canvas == LUA_NOOBJECT) + lua_error("cdKillCanvas: canvas parameter missing!"); + + /* if the creation failed, canvas can be nil, in which case we */ + /* issue an error */ + if (lua_isnil(canvas)) + lua_error("cdKillCanvas: attempt to kill a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdKillCanvas: invalid canvas parameter!"); + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdKillCanvas: attempt to kill a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillCanvas: too many parameters!"); + + /* find out about the currently active canvas */ + current_canvas = cdActiveCanvas(); + + /* this should never happen, unless the user did it on purpouse! */ + if (canvas_p->cd_canvas == void_canvas) + lua_error("cdKillCanvas: trying to kill the void canvas???"); + + /* if the user killed the currently active canvas, activate void canvas */ + if (canvas_p->cd_canvas == current_canvas) { + cdActivate(void_canvas); + } + + cdKillCanvas(canvas_p->cd_canvas); + canvas_p->cd_canvas = NULL; +} + +/***************************************************************************\ +* Creates a color as a color_tag usertag lua_Object. The color value is * +* placed in the (void *) value. Not beautiful, but works best. * +\***************************************************************************/ +static void cdlua_encodecolor(void) +{ + lua_Object red, green, blue; + float red_f, green_f, blue_f; + unsigned char red_i, green_i, blue_i; + long int color_i; + + red = lua_getparam(1); + green = lua_getparam(2); + blue = lua_getparam(3); + if (!(lua_isnumber(red) && lua_isnumber(green) && lua_isnumber(blue))) + lua_error("cdEncodeColor: invalid color component parameter!"); + red_f = (float) lua_getnumber(red); + green_f = (float) lua_getnumber(green); + blue_f = (float) lua_getnumber(blue); + if (red_f < 0 || red_f > 255 || green_f < 0 || + green_f > 255 || blue_f < 0 || blue_f > 255) + lua_error("cdEncodeColor: color components values should be in range [0, 255]!"); + red_i = (unsigned char) (red_f); + green_i = (unsigned char) (green_f); + blue_i = (unsigned char) (blue_f); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdEncodeColor: too many parameters!"); + + color_i = cdEncodeColor(red_i, green_i, blue_i); + lua_pushusertag((void *) color_i, color_tag); +} + +static void cdlua_encodealpha(void) +{ + lua_Object color, alpha; + float alpha_f; + unsigned char alpha_i; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdEncodeAlpha: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + alpha = lua_getparam(2); + if (!lua_isnumber(alpha)) + lua_error("cdEncodeAlpha: invalid alpha parameter!"); + alpha_f = (float) lua_getnumber(alpha); + if (alpha_f < 0 || alpha_f > 255) + lua_error("cdEncodeAlpha: alpha components values should be in range [0, 255]!"); + alpha_i = (unsigned char) (alpha_f); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdEncodeAlpha: too many parameters!"); + + color_i = cdEncodeAlpha(color_i, alpha_i); + lua_pushusertag((void *) color_i, color_tag); +} + +/***************************************************************************\ +* Decodes a color previously created. * +\***************************************************************************/ +static void cdlua_decodecolor(void) +{ + lua_Object color; + long int color_i; + unsigned char red_i, green_i, blue_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdDecodeColor: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdDecodeColor: too many parameters!"); + + cdDecodeColor(color_i, &red_i, &green_i, &blue_i); + lua_pushnumber(red_i); + lua_pushnumber(green_i); + lua_pushnumber(blue_i); +} + +static void cdlua_decodealpha(void) +{ + lua_Object color; + long int color_i; + unsigned char alpha_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdDecodeAlpha: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdDecodeAlpha: too many parameters!"); + + alpha_i = cdDecodeAlpha(color_i); + lua_pushnumber(alpha_i); +} + +static void cdlua_alpha(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdRed: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdAlpha: too many parameters!"); + + lua_pushnumber(cdAlpha(color_i)); +} + +static void cdlua_red(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdRed: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdRed: too many parameters!"); + + lua_pushnumber(cdRed(color_i)); +} + +static void cdlua_blue(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdBlue: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdBlue: too many parameters!"); + + lua_pushnumber(cdBlue(color_i)); +} + +static void cdlua_green(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdGreen: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdGreen: too many parameters!"); + + lua_pushnumber(cdGreen(color_i)); +} + +static void cdlua_reserved(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdReserved: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdReserved: too many parameters!"); + + lua_pushnumber(cdReserved(color_i)); +} + +/***************************************************************************\ +* Creates a stipple as a stipple_tag usertag lua_Object. * +\***************************************************************************/ +static void cdlua_createstipple(void) +{ + lua_Object width, height; + long int width_i, height_i; + stipple_t *stipple_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateStipple: invalid dimension parameters!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateStipple: stipple dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreateStipple: too many parameters!"); + + stipple_p = (stipple_t *) malloc(sizeof(stipple_t)); + if (!stipple_p) { + lua_pushnil(); + return; + } + + stipple_p->size = width_i*height_i; + stipple_p->height = height_i; + stipple_p->width = width_i; + stipple_p->value = (unsigned char *) malloc(stipple_p->size); + if (!stipple_p->value) { + free(stipple_p); + lua_pushnil(); + return; + } + + memset(stipple_p->value, '\0', stipple_p->size); + lua_pushusertag((void *) stipple_p, stipple_tag); +} + +static void cdlua_getstipple(void) +{ + int width, height; + unsigned char * stipple; + stipple_t *stipple_p; + + stipple = cdGetStipple(&width, &height); + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdGetStipple: too many parameters!"); + + stipple_p = (stipple_t *) malloc(sizeof(stipple_t)); + if (!stipple_p) { + lua_pushnil(); + return; + } + + stipple_p->size = width*height; + stipple_p->height = height; + stipple_p->width = width; + stipple_p->value = (unsigned char *) malloc(stipple_p->size); + if (!stipple_p->value) { + free(stipple_p); + lua_pushnil(); + return; + } + + memcpy(stipple_p->value, stipple, stipple_p->size); + lua_pushusertag((void *) stipple_p, stipple_tag); +} + +/***************************************************************************\ +* Frees a previously allocated stipple. We don't free stipple_p to prevent * +* a problem if the user called killstipple twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killstipple(void) +{ + lua_Object stipple; + stipple_t *stipple_p; + + stipple = lua_getparam(1); + if (stipple == LUA_NOOBJECT) + lua_error("cdKillStipple: stipple parameter missing!"); + if (lua_isnil(stipple)) + lua_error("cdKillStipple: attempt to kill a NIL stipple!"); + if (lua_tag(stipple) != stipple_tag) + lua_error("cdKillStipple: invalid stipple parameter!"); + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p->value) + lua_error("cdKillStipple: attempt to kill a killed stipple!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillStipple: too many parameters!"); + + free(stipple_p->value); + stipple_p->value = NULL; +} + +/***************************************************************************\ +* Creates a pattern as a pattern_tag usertag lua_Object. A pattern can be * +* considered and treated as a color table. * +\***************************************************************************/ +static void cdlua_createpattern(void) +{ + lua_Object width, height; + long int width_i, height_i; + pattern_t *pattern_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreatePattern: invalid dimension parameters!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreatePattern: pattern dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreatePattern: too many parameters!"); + + pattern_p = (pattern_t *) malloc(sizeof(pattern_t)); + if (!pattern_p) { + lua_pushnil(); + return; + } + + pattern_p->size = width_i*height_i; + pattern_p->width = width_i; + pattern_p->height = height_i; + pattern_p->color = (long int *) malloc(pattern_p->size * sizeof(long int)); + if (!pattern_p->color) { + free(pattern_p); + lua_pushnil(); + return; + } + + memset(pattern_p->color, 255, pattern_p->size * sizeof(long int)); + lua_pushusertag((void *) pattern_p, pattern_tag); +} + +static void cdlua_getpattern(void) +{ + int width, height; + long int * pattern; + pattern_t *pattern_p; + + pattern = cdGetPattern(&width, &height); + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdGetPattern: too many parameters!"); + + pattern_p = (pattern_t *) malloc(sizeof(pattern_t)); + if (!pattern_p) { + lua_pushnil(); + return; + } + + pattern_p->size = width*height; + pattern_p->height = height; + pattern_p->width = width; + pattern_p->color = (long int *) malloc(pattern_p->size * sizeof(long int)); + if (!pattern_p->color) { + free(pattern_p); + lua_pushnil(); + return; + } + + memcpy(pattern_p->color, pattern, pattern_p->size * sizeof(long int)); + lua_pushusertag((void *) pattern_p, pattern_tag); +} + +/***************************************************************************\ +* Frees a previously allocated pattern. We don't free pattern_p to prevent * +* a problem if the user called killpattern twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killpattern(void) +{ + lua_Object pattern; + pattern_t *pattern_p; + + pattern = lua_getparam(1); + + if (pattern == LUA_NOOBJECT) + lua_error("cdKillPattern: pattern parameter missing!"); + if (lua_isnil(pattern)) + lua_error("cdKillPattern: attempt to kill a NIL pattern!"); + if (lua_tag(pattern) != pattern_tag) + lua_error("cdKillPattern: invalid pattern parameter!"); + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p->color) + lua_error("cdKillPattern: attempt to kill a killed pattern!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillPattern: too many parameters!"); + + free(pattern_p->color); + pattern_p->color = NULL; +} + +/***************************************************************************\ +* Creates a palette as a palette_tag usertag lua_Object. A palette can be * +* considered and treated as a color table. * +\***************************************************************************/ +static void cdlua_createpalette(void) +{ + lua_Object size; + long int size_i; + palette_t *palette_p; + + size = lua_getparam(1); + if (!(lua_isnumber(size))) + lua_error("cdCreatePalette: invalid size parameter!"); + size_i = (long int) lua_getnumber(size); + if (size_i < 1) + lua_error("cdCreatePalette: palette size should be a positive integer!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdCreatePalette: too many parameters!"); + + palette_p = (palette_t *) malloc(sizeof(palette_t)); + if (!palette_p) { + lua_pushnil(); + return; + } + + palette_p->size = size_i; + palette_p->color = (long int *) malloc(palette_p->size * sizeof(long int)); + if (!palette_p->color) { + free(palette_p); + lua_pushnil(); + return; + } + + memset(palette_p->color, 255, palette_p->size * sizeof(long int)); + lua_pushusertag((void *) palette_p, palette_tag); +} + +/***************************************************************************\ +* Frees a previously allocated palette. We don't free palette_p to prevent * +* a problem if the user called killpalette twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killpalette(void) +{ + lua_Object palette; + palette_t *palette_p; + + palette = lua_getparam(1); + if (palette == LUA_NOOBJECT) + lua_error("cdKillPalette: palette parameter missing!"); + if (lua_isnil(palette)) + lua_error("cdKillPalette: attempt to kill a NIL palette!"); + if (lua_tag(palette) != palette_tag) + lua_error("cdKillPalette: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("cdKillPalette: attempt to kill a killed palette!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillPalette: too many parameters!"); + + free(palette_p->color); + palette_p->color = NULL; +} + +/***************************************************************************\ +* Image Extended Functions. * +\***************************************************************************/ + +static void cdlua_createbitmap(void) +{ + lua_Object width; + lua_Object height; + lua_Object type; + + long int width_i; + long int height_i; + int type_i; + bitmap_t *image_p; + + width = lua_getparam(1); + height = lua_getparam(2); + type = lua_getparam(3); + if (!(lua_isnumber(type) && lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateBitmap: invalid parameters!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + type_i = (long int) lua_getnumber(type); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateBitmap: imagemap dimensions should be positive integers!"); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdCreateBitmap: too many parameters!"); + + image_p = (bitmap_t *) malloc(sizeof(bitmap_t)); + if (!image_p) { + lua_pushnil(); + return; + } + + image_p->image = cdCreateBitmap(width_i, height_i, type_i); + if (!image_p->image) { + free(image_p); + lua_pushnil(); + } + else + lua_pushusertag((void *) image_p, bitmap_tag); +} + +static void cdlua_killbitmap(void) +{ + lua_Object image; + bitmap_t *image_p; + + image = lua_getparam(1); + if (image == LUA_NOOBJECT) + lua_error("cdKillBitmap: image parameter missing!"); + if (lua_isnil(image)) + lua_error("cdKillBitmap: attempt to kill a NIL image!"); + if (lua_tag(image) != bitmap_tag) + lua_error("cdKillBitmap: invalid image parameter!"); + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p->image) + lua_error("cdKillBitmap: attempt to kill a killed image"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillBitmap: too many parameters!"); + + cdKillBitmap(image_p->image); + image_p->image = NULL; +} + +static void cdlua_getbitmap(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + + bitmap_t *image_p; + int x_i; + int y_i; + + image = lua_getparam(1); + if (image == LUA_NOOBJECT) + lua_error("cdGetBitmap: image parameter missing!"); + if (lua_isnil(image)) + lua_error("cdGetBitmap: attempt to get NIL image"); + if (lua_tag(image) != bitmap_tag) + lua_error("cdGetBitmap: invalid image parameter!"); + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p->image) + lua_error("cdGetBitmap: attempt to get a killed image"); + + x = lua_getparam(2); + y = lua_getparam(3); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("cdGetBitmap: invalid (x, y) parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdGetBitmap: too many parameters!"); + + cdGetBitmap(image_p->image, x_i, y_i); +} + +static void cdlua_putbitmap(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + + bitmap_t *image_p; + int x_i; + int y_i; + int w_i; + int h_i; + + image = lua_getparam(1); + if (image == LUA_NOOBJECT) + lua_error("cdPutBitmap: image parameter missing!"); + if (lua_isnil(image)) + lua_error("cdPutBitmap: attempt to put a NIL image!"); + if (lua_tag(image) != bitmap_tag) + lua_error("cdPutBitmap: invalid image parameter!"); + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p->image) + lua_error("cdPutBitmap: attempt to put a killed image!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h))) + lua_error("cdPutBitmap: invalid (x, y) parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + if (w_i < 0 || h_i < 0) + lua_error("cdPutBitmap: target region dimensions should be positive integers!"); + + if (lua_getparam(6) != LUA_NOOBJECT) + lua_error("cdPutBitmap: too many parameters!"); + + cdPutBitmap(image_p->image, x_i, y_i, w_i, h_i); +} + +static void wdlua_putbitmap(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + + bitmap_t *image_p; + double x_i; + double y_i; + double w_i; + double h_i; + + image = lua_getparam(1); + if (image == LUA_NOOBJECT) + lua_error("wdPutBitmap: image parameter missing!"); + if (lua_isnil(image)) + lua_error("wdPutBitmap: attempt to put a NIL image!"); + if (lua_tag(image) != bitmap_tag) + lua_error("wdPutBitmap: invalid image parameter!"); + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p->image) + lua_error("wdPutBitmap: attempt to put a killed image!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h))) + lua_error("wdPutBitmap: invalid (x, y) parameter!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + w_i = (double) lua_getnumber(w); + h_i = (double) lua_getnumber(h); + if (w_i < 0 || h_i < 0) + lua_error("wdPutBitmap: target region dimensions should be positive integers!"); + + if (lua_getparam(6) != LUA_NOOBJECT) + lua_error("wdPutBitmap: too many parameters!"); + + wdPutBitmap(image_p->image, x_i, y_i, w_i, h_i); +} + +static void cdlua_bitmapsetrect(void) +{ + lua_Object image; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + bitmap_t *image_p; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + image = lua_getparam(1); + if (image == LUA_NOOBJECT) + lua_error("cdBitmapSetRect: image parameter missing!"); + if (lua_isnil(image)) + lua_error("cdBitmapSetRect: attempt to get a NIL image!"); + if (lua_tag(image) != bitmap_tag) + lua_error("cdBitmapSetRect: invalid image parameter!"); + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p->image) + lua_error("cdBitmapSetRect: attempt to get a killed image!"); + + xmin = lua_getparam(2); + xmax = lua_getparam(3); + ymin = lua_getparam(4); + ymax = lua_getparam(5); + if (!(lua_isnumber(xmin) && lua_isnumber(xmax) && + lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("cdBitmapSetRect: invalid parameter!"); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + + if (lua_getparam(6) != LUA_NOOBJECT) + lua_error("cdBitmapSetRect: too many parameters!"); + + cdBitmapSetRect(image_p->image, xmin_i, xmax_i, ymin_i, ymax_i); +} + +static void cdlua_rgb2mapex(void) +{ + lua_Object imagemap; + lua_Object imagergb; + + bitmap_t *imagemap_p; + bitmap_t *imagergb_p; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdBitmapRGB2Map: attempt to put a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdBitmapRGB2Map: invalid imagergb parameter!"); + imagergb_p = (bitmap_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->image)) + lua_error("cdBitmapRGB2Map: attempt to put a killed imagergb!"); + + imagemap = lua_getparam(2); + if (lua_isnil(imagemap)) + lua_error("cdBitmapRGB2Map: attempt to put a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("cdBitmapRGB2Map: imagemap invalid parameter!"); + imagemap_p = (bitmap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->image) + lua_error("cdBitmapRGB2Map: attempt to put a killed imagemap!"); + + if (imagergb_p->image->type != CD_RGB || imagemap_p->image->type <= 0) + lua_error("cdBitmapRGB2Map: invalid image type!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdBitmapRGB2Map: too many parameters!"); + + cdBitmapRGB2Map(imagergb_p->image, imagemap_p->image); +} + +/***************************************************************************\ +* Creates a buffer for a RGB image. * +\***************************************************************************/ +static void cdlua_createimagergb(void) +{ + lua_Object width, height; + long int width_i, height_i; + imagergb_t *imagergb_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateImageRGB: invalid imagergb parameter!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateImageRGB: image dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreateImageRGB: too many parameters!"); + + imagergb_p = (imagergb_t *) malloc(sizeof(imagergb_t)); + if (!imagergb_p) { + lua_pushnil(); + return; + } + + imagergb_p->width = width_i; + imagergb_p->height = height_i; + imagergb_p->size = width_i*height_i; + imagergb_p->red = (unsigned char *) malloc(imagergb_p->size); + imagergb_p->green = (unsigned char *) malloc(imagergb_p->size); + imagergb_p->blue = (unsigned char *) malloc(imagergb_p->size); + + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) { + if (imagergb_p->red) free(imagergb_p->red); + if (imagergb_p->green) free(imagergb_p->green); + if (imagergb_p->blue) free(imagergb_p->blue); + free(imagergb_p); + lua_pushnil(); + return; + } + + memset(imagergb_p->red, 255, imagergb_p->size); + memset(imagergb_p->green, 255, imagergb_p->size); + memset(imagergb_p->blue, 255, imagergb_p->size); + + lua_pushusertag((void *) imagergb_p, imagergb_tag); +} + +static void cdlua_imagergb(void) +{ + lua_Object canvas; + canvas_t *canvas_p; + cdCanvas *current_canvas; + int w, h, type = CD_RGB; + + canvas = lua_getparam(1); + + /* if the creation failed, canvas can be nil, in which case we */ + /* issue an error */ + if (lua_isnil(canvas)) + lua_error("cdImageRGB: attempt to get a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdImageRGB: invalid canvas parameter!"); + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdImageRGB: attempt to get a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdImageRGB: too many parameters!"); + + if (cdAlphaImage(canvas_p->cd_canvas)) + type = CD_RGBA; + + current_canvas = cdActiveCanvas(); + cdActivate(canvas_p->cd_canvas); + cdGetCanvasSize(&w, &h, NULL, NULL); + cdActivate(current_canvas); + + if (type == CD_RGBA) + { + imagergba_t *imagergba_p = (imagergba_t *) malloc(sizeof(imagergba_t)); + if (!imagergba_p) { + lua_pushnil(); + return; + } + + imagergba_p->width = w; + imagergba_p->height = h; + imagergba_p->size = w*h; + imagergba_p->red = cdRedImage(canvas_p->cd_canvas); + imagergba_p->green = cdGreenImage(canvas_p->cd_canvas); + imagergba_p->blue = cdBlueImage(canvas_p->cd_canvas); + imagergba_p->blue = cdAlphaImage(canvas_p->cd_canvas); + + lua_pushusertag((void *) imagergba_p, imagergba_tag); + } + else + { + imagergb_t * imagergb_p = (imagergb_t *) malloc(sizeof(imagergb_t)); + if (!imagergb_p) { + lua_pushnil(); + return; + } + + imagergb_p->width = w; + imagergb_p->height = h; + imagergb_p->size = w*h; + imagergb_p->red = cdRedImage(canvas_p->cd_canvas); + imagergb_p->green = cdGreenImage(canvas_p->cd_canvas); + imagergb_p->blue = cdBlueImage(canvas_p->cd_canvas); + + lua_pushusertag((void *) imagergb_p, imagergb_tag); + } +} + +static void cdlua_imagergbbitmap(void) +{ + lua_Object canvas; + canvas_t *canvas_p; + cdCanvas *current_canvas; + bitmap_t *image_p; + int w, h, type = CD_RGB; + + canvas = lua_getparam(1); + + /* if the creation failed, canvas can be nil, in which case we */ + /* issue an error */ + if (lua_isnil(canvas)) + lua_error("cdImageRGBBitmap: attempt to get a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdImageRGBBitmap: invalid canvas parameter!"); + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdImageRGBBitmap: attempt to get a killed canvas!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdImageRGBBitmap: too many parameters!"); + + if (cdAlphaImage(canvas_p->cd_canvas)) + type = CD_RGBA; + + current_canvas = cdActiveCanvas(); + cdActivate(canvas_p->cd_canvas); + cdGetCanvasSize(&w, &h, NULL, NULL); + cdActivate(current_canvas); + + image_p = (bitmap_t *) malloc(sizeof(bitmap_t)); + if (!image_p) { + lua_pushnil(); + return; + } + + image_p->image = cdInitBitmap(w, h, type, + cdRedImage(canvas_p->cd_canvas), + cdGreenImage(canvas_p->cd_canvas), + cdBlueImage(canvas_p->cd_canvas), + cdAlphaImage(canvas_p->cd_canvas)); + + lua_pushusertag((void *)image_p, bitmap_tag); +} + +/***************************************************************************\ +* Frees a previously allocated imagergb. We don't free imagergb_p to avoid * +* problems if the user called killimagergb twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killimagergb(void) +{ + lua_Object imagergb; + imagergb_t *imagergb_p; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdKillImageRGB: attempt to kill a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdKillImageRGB: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdKillImageRGB: attempt to kill a killed imagergb!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillImageRGB: too many parameters!"); + + free(imagergb_p->red); + free(imagergb_p->green); + free(imagergb_p->blue); + imagergb_p->red = NULL; + imagergb_p->green = NULL; + imagergb_p->blue = NULL; +} + +/***************************************************************************\ +* Creates a buffer for a RGBA image. * +\***************************************************************************/ +static void cdlua_createimagergba(void) +{ + lua_Object width, height; + long int width_i, height_i; + imagergba_t *imagergba_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateImageRGBA: invalid imagergba parameter!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateImageRGBA: image dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreateImageRGBA: too many parameters!"); + + imagergba_p = (imagergba_t *) malloc(sizeof(imagergba_t)); + if (!imagergba_p) { + lua_pushnil(); + return; + } + + imagergba_p->width = width_i; + imagergba_p->height = height_i; + imagergba_p->size = width_i*height_i; + imagergba_p->red = (unsigned char *) malloc(imagergba_p->size); + imagergba_p->green = (unsigned char *) malloc(imagergba_p->size); + imagergba_p->blue = (unsigned char *) malloc(imagergba_p->size); + imagergba_p->alpha = (unsigned char *) malloc(imagergba_p->size); + + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue && imagergba_p->alpha)) { + if (imagergba_p->red) free(imagergba_p->red); + if (imagergba_p->green) free(imagergba_p->green); + if (imagergba_p->blue) free(imagergba_p->blue); + if (imagergba_p->alpha) free(imagergba_p->alpha); + free(imagergba_p); + lua_pushnil(); + return; + } + + memset(imagergba_p->red, 255, imagergba_p->size); + memset(imagergba_p->green, 255, imagergba_p->size); + memset(imagergba_p->blue, 255, imagergba_p->size); + memset(imagergba_p->alpha, 255, imagergba_p->size); + + lua_pushusertag((void *) imagergba_p, imagergba_tag); +} + +/***************************************************************************\ +* Frees a previously allocated imagergba. Don't free imagergba_p to avoid * +* problems if the user called killimagergba twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killimagergba(void) +{ + lua_Object imagergba; + imagergba_t *imagergba_p; + + imagergba = lua_getparam(1); + if (lua_isnil(imagergba)) + lua_error("cdKillImageRGBA: attempt to kill a NIL imagergba!"); + if (lua_tag(imagergba) != imagergba_tag) + lua_error("cdKillImageRGBA: invalid imagergba parameter!"); + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue && imagergba_p->alpha)) + lua_error("cdKillImageRGBA: attempt to kill a killed imagergba!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillImageRGBA: too many parameters!"); + + free(imagergba_p->red); + free(imagergba_p->green); + free(imagergba_p->blue); + free(imagergba_p->alpha); + imagergba_p->red = NULL; + imagergba_p->green = NULL; + imagergba_p->blue = NULL; + imagergba_p->alpha = NULL; +} + +/***************************************************************************\ +* Creates a imagemap as a imagemap_tag usertag lua_Object. * +\***************************************************************************/ +static void cdlua_createimagemap(void) +{ + lua_Object width; + lua_Object height; + + long int width_i; + long int height_i; + imagemap_t *imagemap_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateImageMap: invalid imagemap parameter!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateImageMap: imagemap dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreateImageMap: too many parameters!"); + + imagemap_p = (imagemap_t *) malloc(sizeof(imagemap_t)); + if (!imagemap_p) { + lua_pushnil(); + return; + } + + imagemap_p->size = width_i*height_i; + imagemap_p->width = width_i; + imagemap_p->height = height_i; + imagemap_p->index = (unsigned char *) malloc(imagemap_p->size); + if (!imagemap_p->index) { + free(imagemap_p); + lua_pushnil(); + return; + } + + memset(imagemap_p->index, 0, imagemap_p->size); + lua_pushusertag((void *) imagemap_p, imagemap_tag); +} + +/***************************************************************************\ +* Frees a previously allocated imagemap. We don't free imagemap_p to avoid * +* problems if the user called killimagemap twice with the same object. The * +* structure will be freed by a userdata "gc" fallback in LUA 3.0. * +\***************************************************************************/ +static void cdlua_killimagemap(void) +{ + lua_Object imagemap; + imagemap_t *imagemap_p; + + imagemap = lua_getparam(1); + if (lua_isnil(imagemap)) + lua_error("cdKillImageMap: attempt to kill a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("cdKillImageMap: invalid imagemap parameter!"); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->index) + lua_error("cdKillImageMap: attempt to kill a killed imagemap!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillImageMap: too many parameters!"); + + free(imagemap_p->index); + imagemap_p->index = NULL; +} + +/***************************************************************************\ +* Creates an image as a image_tag usertag lua_Object. * +\***************************************************************************/ +static void cdlua_createimage(void) +{ + lua_Object width; + lua_Object height; + + long int width_i; + long int height_i; + image_t *image_p; + + width = lua_getparam(1); + height = lua_getparam(2); + if (!(lua_isnumber(width) && lua_isnumber(height))) + lua_error("cdCreateImage: invalid dimension parameters!"); + width_i = (long int) lua_getnumber(width); + height_i = (long int) lua_getnumber(height); + if (width_i < 1 || height_i < 1) + lua_error("cdCreateImage: imagemap dimensions should be positive integers!"); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdCreateImage: too many parameters!"); + + image_p = (image_t *) malloc(sizeof(image_t)); + if (!image_p) { + lua_pushnil(); + return; + } + + image_p->cd_image = cdCreateImage(width_i, height_i); + if (!image_p->cd_image) { + free(image_p); + lua_pushnil(); + } + else + lua_pushusertag((void *) image_p, image_tag); +} + +/***************************************************************************\ +* Frees a previously allocated image. * +\***************************************************************************/ +static void cdlua_killimage(void) +{ + lua_Object image; + image_t *image_p; + + image = lua_getparam(1); + if (lua_isnil(image)) + lua_error("cdKillImage: attempt to kill a NIL image!"); + if (lua_tag(image) != image_tag) + lua_error("cdKillImage: invalid image parameter!"); + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("cdKillImage: attempt to kill a killed image"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdKillImage: too many parameters!"); + + cdKillImage(image_p->cd_image); + image_p->cd_image = NULL; +} + +/***************************************************************************\ +* Fallback definitions. * +\***************************************************************************/ +/***************************************************************************\ +* stipple "settable" fallback. * +\***************************************************************************/ +static void stipplesettable_fb(void) +{ + lua_Object stipple, index, value; + + stipple_t *stipple_p; + long int index_i; + unsigned char value_i; + + stipple = lua_getparam(1); + index = lua_getparam(2); + value = lua_getparam(3); + + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p) { + lua_error("stipple_tag \"settable\": invalid stipple_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("stipple_tag \"settable\": index should be a number!"); + } + + if (!lua_isnumber(value)) { + lua_error("stipple_tag \"settable\": value should be a number!"); + } + + value_i = (unsigned char) lua_getnumber(value); + if ((value_i != 0 && value_i != 1)) + lua_error("stipple_tag \"settable\": value should belong to {0, 1}!"); + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= stipple_p->size) + lua_error("stipple_tag \"settable\": index is out of bounds!"); + + stipple_p->value[index_i] = value_i; +} + +/***************************************************************************\ +* imagemap "settable" fallback. * +\***************************************************************************/ +static void imagemapsettable_fb(void) +{ + lua_Object imagemap, index, value; + + imagemap_t *imagemap_p; + long int index_i; + long int value_i; + + imagemap = lua_getparam(1); + index = lua_getparam(2); + value = lua_getparam(3); + + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p) { + lua_error("imagemap_tag \"settable\": invalid imagemap_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("imagemap_tag \"settable\": index should be a number!"); + } + + if (!lua_isnumber(value)) { + lua_error("imagemap_tag \"settable\": value should be a number!"); + } + + value_i = (long int) lua_getnumber(value); + if ((value_i < 0 || value_i > 255)) + lua_error("imagemap_tag \"settable\": value should be in range [0, 255]!"); + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= imagemap_p->size) + lua_error("imagemap_tag \"settable\": index is out of bounds!"); + + imagemap_p->index[index_i] = (unsigned char) value_i; +} + +/***************************************************************************\ +* pattern "settable" fallback. * +\***************************************************************************/ +static void patternsettable_fb(void) +{ + lua_Object pattern, index, color; + + pattern_t *pattern_p; + long int index_i; + long int color_i; + + pattern = lua_getparam(1); + index = lua_getparam(2); + color = lua_getparam(3); + + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p) { + lua_error("pattern_tag \"settable\": invalid pattern_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("pattern_tag \"settable\": index should be a number!"); + } + + if (lua_tag(color) != color_tag) + lua_error("pattern_tag \"settable\": value should be of type color_tag!"); + + color_i = (long int) lua_getuserdata(color); + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= pattern_p->size) + lua_error("pattern_tag \"settable\": index is out of bounds!"); + + pattern_p->color[index_i] = color_i; +} + +/***************************************************************************\ +* palette "settable" fallback. * +\***************************************************************************/ +static void palettesettable_fb(void) +{ + lua_Object palette, index, color; + + palette_t *palette_p; + long int index_i; + long int color_i; + + palette = lua_getparam(1); + index = lua_getparam(2); + color = lua_getparam(3); + + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p) { + lua_error("palette_tag \"settable\": invalid palette_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("palette_tag \"settable\": index should be a number!"); + } + + if (lua_tag(color) != color_tag) + lua_error("palette_tag \"settable\": value should be of type color_tag!"); + + color_i = (long int) lua_getuserdata(color); + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= palette_p->size) + lua_error("palette_tag \"settable\": index is out of bounds!"); + + palette_p->color[index_i] = color_i; +} + +/***************************************************************************\ +* channel "settable" fallback. This fallback is called when a LUA line like * +* "imagergb.r[y*w + x] = c" is executed. The imagergb "gettable" fallback * +* fills and returns a channel structure with info about the buffer. This * +* structure is consulted and the value is assigned where it should. * +\***************************************************************************/ +static void channelsettable_fb(void) +{ + lua_Object channel, index, value; + + channel_t *channel_p; + long int index_i; + long int value_i; + + channel = lua_getparam(1); + index = lua_getparam(2); + value = lua_getparam(3); + + channel_p = (channel_t *) lua_getuserdata(channel); + if (!channel_p) { + lua_error("channel_tag \"settable\": invalid channel_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("channel_tag \"settable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || (channel_p->size > 0 && index_i >= channel_p->size) || + (channel_p->size == -1 && index_i >= 256)) { + lua_error("channel_tag \"settable\": index is out of bounds!"); + } + + if (channel_p->size > 0) + { + if (!lua_isnumber(value)) { + lua_error("channel_tag \"settable\": value should be a number!"); + } + + value_i = (long int) lua_getnumber(value); + if ((value_i < 0 || value_i > 255)) { + lua_error("channel_tag \"settable\": value should be in range [0, 255]!"); + } + + channel_p->value[index_i] = (unsigned char) value_i; + } + else + { + if (lua_tag(value) != color_tag) + lua_error("channel_tag \"settable\": value should be of type color_tag!"); + + value_i = (long int) lua_getuserdata(value); + + ((long int*)channel_p->value)[index_i] = value_i; + } +} + +/***************************************************************************\ +* stipple "gettable" fallback. * +\***************************************************************************/ +static void stipplegettable_fb(void) +{ + lua_Object stipple, index; + + stipple_t *stipple_p; + long int index_i; + + stipple = lua_getparam(1); + index = lua_getparam(2); + + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p) + lua_error("stipple_tag \"gettable\": invalid stipple_tag object!"); + + if (!lua_isnumber(index)) { + lua_error("stipple_tag \"gettable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= stipple_p->size) + lua_error("stipple_tag \"gettable\": index is out of bounds!"); + + lua_pushnumber(stipple_p->value[index_i]); +} + +/***************************************************************************\ +* imagemap "gettable" fallback. * +\***************************************************************************/ +static void imagemapgettable_fb(void) +{ + lua_Object imagemap, index; + + imagemap_t *imagemap_p; + long int index_i; + + imagemap = lua_getparam(1); + index = lua_getparam(2); + + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p) + lua_error("imagemap_tag \"gettable\": invalid imagemap_tag object!"); + + if (!lua_isnumber(index)) { + lua_error("imagemap_tag \"gettable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= imagemap_p->size) + lua_error("imagemap_tag \"gettable\": index is out of bounds!"); + + lua_pushnumber(imagemap_p->index[index_i]); +} + +/***************************************************************************\ +* pattern "gettable" fallback. * +\***************************************************************************/ +static void patterngettable_fb(void) +{ + lua_Object pattern, index; + + pattern_t *pattern_p; + long int index_i; + + pattern = lua_getparam(1); + index = lua_getparam(2); + + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p) + lua_error("pattern_tag \"gettable\": invalid pattern_tag object!"); + + if (!lua_isnumber(index)) { + lua_error("pattern_tag \"gettable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= pattern_p->size) + lua_error("pattern_tag \"gettable\": index is out of bounds!"); + + lua_pushusertag((void *) pattern_p->color[index_i], color_tag); +} + +/***************************************************************************\ +* palette "gettable" fallback. * +\***************************************************************************/ +static void palettegettable_fb(void) +{ + lua_Object palette, index; + + palette_t *palette_p; + long int index_i; + + palette = lua_getparam(1); + index = lua_getparam(2); + + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p) + lua_error("palette_tag \"gettable\": invalid palette_tag object!"); + + if (!lua_isnumber(index)) { + lua_error("palette_tag \"gettable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + if (index_i < 0 || index_i >= palette_p->size) + lua_error("palette_tag \"gettable\": index is out of bounds!"); + + lua_pushusertag((void *) palette_p->color[index_i], color_tag); +} + +/***************************************************************************\ +* channel "gettable" fallback. This fallback is called when a LUA line like * +* "c = imagergb.r[y*w + x]" is executed. The imagergb "gettable" fallback * +* fills and returns a channel structure with info about the buffer. This * +* structure is consulted and the appropriate value is returned. * +\***************************************************************************/ +static void channelgettable_fb(void) +{ + lua_Object channel, index; + + channel_t *channel_p; + long int index_i; + + channel = lua_getparam(1); + index = lua_getparam(2); + + channel_p = (channel_t *) lua_getuserdata(channel); + if (!channel_p) { + lua_error("channel_tag \"gettable\": invalid channel_tag object!"); + } + + if (!lua_isnumber(index)) { + lua_error("channel_tag \"gettable\": index should be a number!"); + } + + index_i = (long int) lua_getnumber(index); + + if (index_i < 0 || (channel_p->size > 0 && index_i >= channel_p->size) || + (channel_p->size == -1 && index_i >= 256)) { + lua_error("channel_tag \"gettable\": index is out of bounds!"); + } + + if (channel_p->size == -1) + lua_pushusertag((void *) ((long int*)channel_p->value)[index_i], color_tag); + else + lua_pushnumber(channel_p->value[index_i]); +} + +/***************************************************************************\ +* imagergb "gettable" fallback. This fallback is called when a LUA line * +* like "c = imagergb.r[y*w + x]" or "imagergb.r[y*w + x] = c" is executed. * +* The channel_info global is filled and its address is returned with a * +* channel_tag usertag lua_Object. The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static void imagergbgettable_fb(void) +{ + lua_Object imagergb, index; + + char *index_s; + imagergb_t *imagergb_p; + + imagergb = lua_getparam(1); + index = lua_getparam(2); + + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!imagergb_p) + lua_error("imagergb_tag \"gettable\": invalid imagergb_tag object!"); + + if (!lua_isstring(index)) { + lua_error("imagergb_tag \"gettable\": index should be a channel name!"); + } + index_s = (char *) lua_getstring(index); + + channel_info.size = imagergb_p->size; + + if (*index_s == 'r' || *index_s == 'R') { + channel_info.value = imagergb_p->red; + } + else if (*index_s == 'g' || *index_s == 'G') { + channel_info.value = imagergb_p->green; + } + else if (*index_s == 'b' || *index_s == 'B') { + channel_info.value = imagergb_p->blue; + } + else { + lua_error("imagergb_tag \"gettable\": index is an invalid channel name!"); + } + + lua_pushusertag((void *) &channel_info, channel_tag); +} + +/***************************************************************************\ +* imagergba "gettable" fallback. This fallback is called when a LUA line * +* like "c = imagergba.r[y*w + x]" or "imagergba.r[y*w + x] = c" is executed.* +* The channel_info global is filled and its address is returned with a * +* channel_tag usertag lua_Object. The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static void imagergbagettable_fb(void) +{ + lua_Object imagergba, index; + + char *index_s; + imagergba_t *imagergba_p; + + imagergba = lua_getparam(1); + index = lua_getparam(2); + + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!imagergba_p) + lua_error("imagergba_tag \"gettable\": invalid imagergba_tag object!"); + + if (!lua_isstring(index)) { + lua_error("imagergba_tag \"gettable\": index should be a channel name!"); + } + index_s = (char *) lua_getstring(index); + + channel_info.size = imagergba_p->size; + + if (*index_s == 'r' || *index_s == 'R') { + channel_info.value = imagergba_p->red; + } + else if (*index_s == 'g' || *index_s == 'G') { + channel_info.value = imagergba_p->green; + } + else if (*index_s == 'b' || *index_s == 'B') { + channel_info.value = imagergba_p->blue; + } + else if (*index_s == 'a' || *index_s == 'A') { + channel_info.value = imagergba_p->alpha; + } + else { + lua_error("imagergba_tag \"gettable\": index is an invalid channel name!"); + } + + lua_pushusertag((void *) &channel_info, channel_tag); +} + +/***************************************************************************\ +* bitmap "gettable" fallback. This fallback is called when a LUA line * +* like "c = bitmap.r[y*w + x]" or "bitmap.r[y*w + x] = c" is executed.* +* The channel_info global is filled and its address is returned with a * +* channel_tag usertag lua_Object. The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static void bitmapgettable_fb(void) +{ + lua_Object image, index; + + char *index_s; + bitmap_t *image_p; + + image = lua_getparam(1); + index = lua_getparam(2); + + image_p = (bitmap_t *) lua_getuserdata(image); + if (!image_p) + lua_error("bitmap_tag \"gettable\": invalid bitmap_tag object!"); + + if (!lua_isstring(index)) { + lua_error("bitmap_tag \"gettable\": index should be a channel name!"); + } + index_s = (char *) lua_getstring(index); + + channel_info.size = image_p->image->w * image_p->image->h; + + if (*index_s == 'r' || *index_s == 'R') { + channel_info.value = cdBitmapGetData(image_p->image, CD_IRED); + } + else if (*index_s == 'g' || *index_s == 'G') { + channel_info.value = cdBitmapGetData(image_p->image, CD_IGREEN); + } + else if (*index_s == 'b' || *index_s == 'B') { + channel_info.value = cdBitmapGetData(image_p->image, CD_IBLUE); + } + else if (*index_s == 'a' || *index_s == 'A') { + channel_info.value = cdBitmapGetData(image_p->image, CD_IALPHA); + } + else if (*index_s == 'i' || *index_s == 'I') { + channel_info.value = cdBitmapGetData(image_p->image, CD_INDEX); + } + else if (*index_s == 'c' || *index_s == 'C') { + channel_info.value = cdBitmapGetData(image_p->image, CD_COLORS); + channel_info.size = -1; + } + else { + lua_error("imagergba_tag \"gettable\": index is an invalid channel name!"); + } + + lua_pushusertag((void *) &channel_info, channel_tag); +} + +static void stategc_fb(void) +{ + lua_Object state; + + state_t *state_p; + + state = lua_getparam(1); + state_p = (state_t *) lua_getuserdata(state); + if (!state_p) + lua_error("state_tag \"gc\": invalid state_tag object!"); + + if (state_p->state) cdReleaseState(state_p->state); + + /* free the state_t structure */ + free(state_p); +} + +/***************************************************************************\ +* stipple "gc" fallback. * +\***************************************************************************/ +static void stipplegc_fb(void) +{ + lua_Object stipple; + + stipple_t *stipple_p; + + stipple = lua_getparam(1); + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p) + lua_error("stipple_tag \"gc\": invalid stipple_tag object!"); + + /* if the stipple has not been killed, kill it */ + if (stipple_p->value) free(stipple_p->value); + + /* free the stipple_t structure */ + free(stipple_p); +} + +/***************************************************************************\ +* pattern "gc" fallback. * +\***************************************************************************/ +static void patterngc_fb(void) +{ + lua_Object pattern; + + pattern_t *pattern_p; + + pattern = lua_getparam(1); + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p) + lua_error("pattern_tag \"gc\": invalid pattern_tag object!"); + + /* if the pattern has not been killed, kill it */ + if (pattern_p->color) free(pattern_p->color); + + /* free the pattern_t structure */ + free(pattern_p); +} + +/***************************************************************************\ +* palette "gc" fallback. * +\***************************************************************************/ +static void palettegc_fb(void) +{ + lua_Object palette; + + palette_t *palette_p; + + palette = lua_getparam(1); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p) + lua_error("palette_tag \"gc\": invalid palette_tag object!"); + + /* if the palette has not been killed, kill it */ + if (palette_p->color) free(palette_p->color); + + /* free the palette_t structure */ + free(palette_p); +} + +/***************************************************************************\ +* imagergb "gc" fallback. * +\***************************************************************************/ +static void imagergbgc_fb(void) +{ + lua_Object imagergb; + + imagergb_t *imagergb_p; + + imagergb = lua_getparam(1); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!imagergb_p) + lua_error("imagergb_tag \"gc\": invalid imagergb_tag object!"); + + /* if the imagergb has not been killed, kill it */ + if (imagergb_p->red) free(imagergb_p->red); + if (imagergb_p->green) free(imagergb_p->green); + if (imagergb_p->blue) free(imagergb_p->blue); + + /* free the imagergb_t structure */ + free(imagergb_p); +} + +/***************************************************************************\ +* imagergba "gc" fallback. * +\***************************************************************************/ +static void imagergbagc_fb(void) +{ + lua_Object imagergba; + + imagergba_t *imagergba_p; + + imagergba = lua_getparam(1); + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!imagergba_p) + lua_error("imagergba_tag \"gc\": invalid imagergba_tag object!"); + + /* if the imagergba has not been killed, kill it */ + if (imagergba_p->red) free(imagergba_p->red); + if (imagergba_p->green) free(imagergba_p->green); + if (imagergba_p->blue) free(imagergba_p->blue); + if (imagergba_p->alpha) free(imagergba_p->alpha); + + /* free the imagergba_t structure */ + free(imagergba_p); +} + +/***************************************************************************\ +* imagemap "gc" fallback. * +\***************************************************************************/ +static void imagemapgc_fb(void) +{ + lua_Object imagemap; + + imagemap_t *imagemap_p; + + imagemap = lua_getparam(1); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p) + lua_error("imagemap_tag \"gc\": invalid imagemap_tag object!"); + + /* if the imagemap has not been killed, kill it */ + if (imagemap_p->index) free(imagemap_p->index); + + /* free the imagemap_t structure */ + free(imagemap_p); +} + +/***************************************************************************\ +* bitmap "gc" fallback. * +\***************************************************************************/ +static void bitmapgc_fb(void) +{ + lua_Object bitmap; + + bitmap_t *bitmap_p; + + bitmap = lua_getparam(1); + bitmap_p = (bitmap_t *) lua_getuserdata(bitmap); + if (!bitmap_p) + lua_error("bitmap_tag \"gc\": invalid bitmap_tag object!"); + + /* if the bitmap has not been killed, kill it */ + if (bitmap_p->image) cdKillBitmap(bitmap_p->image); + + /* free the bitmap_t structure */ + free(bitmap_p); +} + +/***************************************************************************\ +* cdPixel. * +\***************************************************************************/ +static void cdlua_pixel (void) +{ + lua_Object x; + lua_Object y; + lua_Object color; + + int x_i; + int y_i; + long int color_i; + + x = lua_getparam(1); + y = lua_getparam(2); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("cdPixel: pixel coordinates should be integers!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + + color = lua_getparam(3); + if (lua_tag(color) != color_tag) + lua_error("cdPixel: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdPixel: too many parameters!"); + + cdPixel(x_i, y_i, color_i); +} + +static void wdlua_pixel (void) +{ + lua_Object x; + lua_Object y; + lua_Object color; + + double x_i; + double y_i; + long int color_i; + + x = lua_getparam(1); + y = lua_getparam(2); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("wdPixel: pixel coordinates should be numbers!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + + color = lua_getparam(3); + if (lua_tag(color) != color_tag) + lua_error("cdPixel: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdPixel: too many parameters!"); + + wdPixel(x_i, y_i, color_i); +} + +/***************************************************************************\ +* cdGetCanvasSize. * +\***************************************************************************/ +static void cdlua_getcanvassize(void) +{ + int width; + int height; + double mm_width; + double mm_height; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdGetCanvasSize: too many parameters!"); + + cdGetCanvasSize(&width, &height, &mm_width, &mm_height); + lua_pushnumber(width); + lua_pushnumber(height); + lua_pushnumber(mm_width); + lua_pushnumber(mm_height); +} + +/***************************************************************************\ +* Register callback functions. * +\***************************************************************************/ +static void cdlua_registercallback(void) +{ + lua_Object driver, cb, func; + int driver_i, cb_i, func_lock; + cdContextLUA* luactx; + cdCallbackLUA* cdCB; + + driver = lua_getparam(1); + if (!lua_isnumber(driver)) + lua_error("cdRegisterCallback: invalid driver parameter!"); + driver_i = (int) lua_getnumber(driver); + + cb = lua_getparam(2); + if (!lua_isnumber(cb)) + lua_error("cdRegisterCallback: invalid cb parameter!"); + cb_i = (int) lua_getnumber(cb); + + func = lua_getparam(3); + if (lua_isnil(func)) + func_lock = -1; + else if (!lua_isfunction(func)) + { + lua_error("cdRegisterCallback: invalid func parameter!"); + return; + } + else { + lua_pushobject(func); + func_lock = lua_ref(1); + } + + if (driver_i >= cdlua_numdrivers) + lua_error("cdRegisterCallback: invalid driver parameter!"); + + luactx = cdlua_drivers[driver_i]; + + if (cb_i >= luactx->cb_n) + lua_error("cdRegisterCallback: invalid cb parameter!"); + + cdCB = &luactx->cb_list[cb_i]; + + if (cdCB->lock != -1) { + lua_unref(cdCB->lock); + cdCB->lock = func_lock; + if (func_lock == -1) { + cdRegisterCallback(luactx->ctx(), cb_i, NULL); + } + } + else { + if (func_lock != -1) { + cdRegisterCallback(luactx->ctx(), cb_i, (cdCallback)cdCB->func); + cdCB->lock = func_lock; + } + } +} + +/***************************************************************************\ +* cdPlay. * +\***************************************************************************/ +static void cdlua_play(void) +{ + lua_Object driver; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + lua_Object data; + + int driver_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + char *data_s; + + driver = lua_getparam(1); + if (!lua_isnumber(driver)) + lua_error("cdPlay: invalid driver parameter!"); + driver_i = (long int) lua_getnumber(driver); + + xmin = lua_getparam(2); + xmax = lua_getparam(3); + ymin = lua_getparam(4); + ymax = lua_getparam(5); + if (!(lua_isnumber(xmin) && lua_isnumber(xmax) && + lua_isnumber(ymin) && lua_isnumber(ymin))) + lua_error("cdPlay: invalid viewport!"); + xmin_i = (long int) lua_getnumber(xmin); + xmax_i = (long int) lua_getnumber(xmax); + ymin_i = (long int) lua_getnumber(ymin); + ymax_i = (long int) lua_getnumber(ymax); + + data = lua_getparam(6); + if (!lua_isstring(data)) + lua_error("cdPlay: data should be of type string!"); + data_s = lua_getstring(data); + + if (driver_i >= cdlua_numdrivers) + lua_error("cdPlay: unknown driver!"); + + if (lua_getparam(7) != LUA_NOOBJECT) + lua_error("cdPlay: too many parameters!"); + + cdPlay(cdlua_drivers[driver_i]->ctx(), xmin_i, xmax_i, ymin_i, ymax_i, data_s); +} + +/***************************************************************************\ +* cdUpdateYAxis. * +\***************************************************************************/ + +static void cdlua_updateyaxis(void) +{ + lua_Object y; + + int y_i; + + y = lua_getparam(1); + if (!lua_isnumber(y)) + lua_error("cdUpdateYAxis: invalid (y) parameter!"); + y_i = (int) lua_getnumber(y); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdUpdateYAxis: too many parameters!"); + + cdUpdateYAxis(&y_i); + lua_pushnumber(y_i); +} + +/***************************************************************************\ +* cdGetClipArea. * +\***************************************************************************/ +static void cdlua_getcliparea(void) +{ + int xmin; + int xmax; + int ymin; + int ymax; + int status; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdGetClipArea: too many parameters!"); + + status = cdGetClipArea(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); + lua_pushnumber(status); +} + +static void cdlua_RegionBox(void) +{ + int xmin; + int xmax; + int ymin; + int ymax; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdRegionBox: too many parameters!"); + + cdRegionBox(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +static void cdlua_getclippoly(void) +{ + int n, i; + int *pts; + lua_Object points; + + pts = cdGetClipPoly(&n); + lua_pushnumber(n); + + points = lua_createtable(); + + for (i=0; i < 2*n; i++) + { + lua_pushobject(points); + lua_pushnumber(i+1); + lua_pushnumber(pts[i]); + lua_settable(); + } +} + +static void wdlua_getclippoly(void) +{ + int n, i; + double *pts; + lua_Object points; + + pts = wdGetClipPoly(&n); + lua_pushnumber(n); + + points = lua_createtable(); + + for (i=0; i < 2*n; i++) + { + lua_pushobject(points); + lua_pushnumber(i+1); + lua_pushnumber(pts[i]); + lua_settable(); + } +} + +/***************************************************************************\ +* cdMM2Pixel. * +\***************************************************************************/ +static void cdlua_mm2pixel(void) +{ + lua_Object mm_dx; + lua_Object mm_dy; + + double mm_dx_d; + double mm_dy_d; + int dx; + int dy; + + mm_dx = lua_getparam(1); + mm_dy = lua_getparam(2); + if (!(lua_isnumber(mm_dx) && lua_isnumber(mm_dy))) + lua_error("cdMM2Pixel: invalid (mm_dx, mm_dy) parameter!"); + mm_dx_d = (double) lua_getnumber(mm_dx); + mm_dy_d = (double) lua_getnumber(mm_dy); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdMM2Pixel: too many parameters!"); + + cdMM2Pixel(mm_dx, mm_dy, &dx, &dy); + lua_pushnumber(dx); + lua_pushnumber(dy); +} + +/***************************************************************************\ +* cdPixel2MM. * +\***************************************************************************/ +static void cdlua_pixel2mm(void) +{ + lua_Object dx; + lua_Object dy; + int dx_i; + int dy_i; + + double mm_dx; + double mm_dy; + + dx = lua_getparam(1); + dy = lua_getparam(2); + if (!(lua_isnumber(dx) && lua_isnumber(dy))) + lua_error("cdPixel2MM: invalid (dx, dy) parameter!"); + dx_i = (int) lua_getnumber(dx); + dy_i = (int) lua_getnumber(dy); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdPixel2MM: too many parameters!"); + + cdPixel2MM(dx_i, dy_i, &mm_dx, &mm_dy); + lua_pushnumber(mm_dx); + lua_pushnumber(mm_dy); +} + +/***************************************************************************\ +* cdStipple. * +\***************************************************************************/ +static void cdlua_stipple(void) +{ + lua_Object stipple; + stipple_t *stipple_p; + + stipple = lua_getparam(1); + if (lua_isnil(stipple)) + lua_error("cdStipple: attempt to set a NIL stipple!"); + if (lua_tag(stipple) != stipple_tag) + lua_error("cdStipple: invalid stipple parameter!"); + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p->value) + lua_error("cdStipple: attempt to set a killed stipple!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdStipple: too many parameters!"); + + cdStipple(stipple_p->width, stipple_p->height, stipple_p->value); +} + +static void wdlua_stipple(void) +{ + lua_Object stipple; + stipple_t *stipple_p; + double w_mm; + double h_mm; + + stipple = lua_getparam(1); + if (lua_isnil(stipple)) + lua_error("wdStipple: attempt to set a NIL stipple!"); + if (lua_tag(stipple) != stipple_tag) + lua_error("wdStipple: invalid stipple parameter!"); + stipple_p = (stipple_t *) lua_getuserdata(stipple); + if (!stipple_p->value) + lua_error("wdStipple: attempt to set a killed stipple!"); + + w_mm = (double)luaL_check_number(2); + h_mm = (double)luaL_check_number(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdStipple: too many parameters!"); + + wdStipple(stipple_p->width, stipple_p->height, stipple_p->value, w_mm, h_mm); +} + +/***************************************************************************\ +* cdPattern. * +\***************************************************************************/ +static void cdlua_pattern(void) +{ + lua_Object pattern; + pattern_t *pattern_p; + + pattern = lua_getparam(1); + if (lua_isnil(pattern)) + lua_error("cdPattern: attempt to set a NIL pattern!"); + if (lua_tag(pattern) != pattern_tag) + lua_error("cdPattern: invalid pattern parameter!"); + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p->color) + lua_error("cdPattern: attempt to set a killed pattern!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdPattern: too many parameters!"); + + cdPattern(pattern_p->width, pattern_p->height, pattern_p->color); +} + +static void wdlua_pattern(void) +{ + lua_Object pattern; + pattern_t *pattern_p; + double w_mm; + double h_mm; + + pattern = lua_getparam(1); + if (lua_isnil(pattern)) + lua_error("wdPattern: attempt to set a NIL pattern!"); + if (lua_tag(pattern) != pattern_tag) + lua_error("wdPattern: invalid pattern parameter!"); + pattern_p = (pattern_t *) lua_getuserdata(pattern); + if (!pattern_p->color) + lua_error("wdPattern: attempt to set a killed pattern!"); + + w_mm = (double)luaL_check_number(2); + h_mm = (double)luaL_check_number(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdPattern: too many parameters!"); + + wdPattern(pattern_p->width, pattern_p->height, pattern_p->color, w_mm, h_mm); +} + +/***************************************************************************\ +* cdFontDim. * +\***************************************************************************/ +static void cdlua_fontdim(void) +{ + int max_width; + int height; + int ascent; + int descent; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdFontDim: too many parameters!"); + + cdFontDim(&max_width, &height, &ascent, &descent); + lua_pushnumber(max_width); + lua_pushnumber(height); + lua_pushnumber(ascent); + lua_pushnumber(descent); +} + +/***************************************************************************\ +* cdTextSize. * +\***************************************************************************/ +static void cdlua_textsize(void) +{ + lua_Object text; + char* text_s; + + int width; + int height; + + text = lua_getparam(1); + if (!lua_isstring(text)) + lua_error("cdTextSize: text should be of type string!"); + text_s = (char*) lua_getstring(text); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdTextSize: too many parameters!"); + + cdTextSize(text_s, &width, &height); + lua_pushnumber(width); + lua_pushnumber(height); +} + +static void cdlua_textbox(void) +{ + int xmin; + int xmax; + int ymin; + int ymax; + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdTextBox: too many parameters!"); + + cdTextBox(x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +static void wdlua_textbox(void) +{ + double xmin; + double xmax; + double ymin; + double ymax; + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdTextBox: too many parameters!"); + + wdTextBox(x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +static void cdlua_textbounds(void) +{ + int rect[8]; + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdTextBox: too many parameters!"); + + cdTextBounds(x, y, s, rect); + lua_pushnumber(rect[0]); + lua_pushnumber(rect[1]); + lua_pushnumber(rect[2]); + lua_pushnumber(rect[3]); + lua_pushnumber(rect[4]); + lua_pushnumber(rect[5]); + lua_pushnumber(rect[6]); + lua_pushnumber(rect[7]); +} + +static void wdlua_textbounds(void) +{ + double rect[8]; + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdTextBox: too many parameters!"); + + wdTextBounds(x, y, s, rect); + lua_pushnumber(rect[0]); + lua_pushnumber(rect[1]); + lua_pushnumber(rect[2]); + lua_pushnumber(rect[3]); + lua_pushnumber(rect[4]); + lua_pushnumber(rect[5]); + lua_pushnumber(rect[6]); + lua_pushnumber(rect[7]); +} + +static void cdlua_getfont(void) +{ + int type_face, style, size; + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdGetFont: too many parameters!"); + + cdGetFont(&type_face, &style, &size); + lua_pushnumber(type_face); + lua_pushnumber(style); + lua_pushnumber(size); +} + +static void wdlua_getfont(void) +{ + int type_face, style; + double size; + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("wdGetFont: too many parameters!"); + + wdGetFont(&type_face, &style, &size); + lua_pushnumber(type_face); + lua_pushnumber(style); + lua_pushnumber(size); +} + +/***************************************************************************\ +* cdPalette. * +\***************************************************************************/ +static void cdlua_palette(void) +{ + lua_Object palette; + lua_Object mode; + palette_t *palette_p; + int mode_i; + + palette = lua_getparam(1); + if (lua_isnil(palette)) + lua_error("cdPalette: attempt to set a NIL palette!"); + if (lua_tag(palette) != palette_tag) + lua_error("cdPalette: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("cdPalette: attempt to set a killed palette!"); + + mode = lua_getparam(2); + if (!lua_isnumber(mode)) + lua_error("cdPalette: invalid mode parameter!"); + mode_i = (int) lua_getnumber(mode); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("cdPalette: too many parameters!"); + + cdPalette(palette_p->size, palette_p->color, mode_i); +} + +/***************************************************************************\ +* cdBackground. * +\***************************************************************************/ +static void cdlua_background(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdBackground: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdBackground: too many parameters!"); + + color_i = cdBackground(color_i); + lua_pushusertag((void*) color_i, color_tag); +} + +/***************************************************************************\ +* cdForeground. * +\***************************************************************************/ +static void cdlua_foreground(void) +{ + lua_Object color; + long int color_i; + + color = lua_getparam(1); + if (lua_tag(color) != color_tag) + lua_error("cdForeground: invalid color parameter!"); + color_i = (long int) lua_getuserdata(color); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdForeground: too many parameters!"); + + color_i = cdForeground(color_i); + lua_pushusertag((void*) color_i, color_tag); +} + +/***************************************************************************\ +* cdGetImageRGB. * +\***************************************************************************/ +static void cdlua_getimagergb(void) +{ + lua_Object imagergb; + lua_Object x; + lua_Object y; + + imagergb_t *imagergb_p; + int x_i; + int y_i; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdGetImageRGB: attempt to get a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdGetImageRGB: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdGetImageRGB: attempt to get a killed imagergb!"); + + x = lua_getparam(2); + y = lua_getparam(3); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("cdGetImageRGB: invalid (x, y) parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdGetImageRGB: too many parameters!"); + + cdGetImageRGB(imagergb_p->red, imagergb_p->green, imagergb_p->blue, + x_i, y_i, imagergb_p->width, imagergb_p->height); +} +/***************************************************************************\ +* cdPutImageRGB. * +\***************************************************************************/ + +static void cdlua_rgb2map(void) +{ + lua_Object imagemap; + lua_Object palette; + lua_Object imagergb; + + imagemap_t *imagemap_p; + palette_t *palette_p; + imagergb_t *imagergb_p; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdRGB2Map: attempt to put a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdRGB2Map: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdRGB2Map: attempt to put a killed imagergb!"); + + imagemap = lua_getparam(2); + if (lua_isnil(imagemap)) + lua_error("cdRGB2Map: attempt to put a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("cdRGB2Map: imagemap invalid parameter!"); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->index) + lua_error("cdRGB2Map: attempt to put a killed imagemap!"); + + palette = lua_getparam(3); + if (lua_isnil(palette)) + lua_error("cdRGB2Map: NIL pallete!"); + if (lua_tag(palette) != palette_tag) + lua_error("cdRGB2Map: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("cdRGB2Map: killed pallete!"); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdRGB2Map: too many parameters!"); + + cdRGB2Map(imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue, + imagemap_p->index, palette_p->size, palette_p->color); +} + +static void cdlua_putimagergb(void) +{ + lua_Object imagergb; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + + imagergb_t *imagergb_p; + int x_i; + int y_i; + int w_i; + int h_i; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdPutImageRGB: attempt to put a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdPutImageRGB: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdPutImageRGB: attempt to put a killed imagergb!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h))) + lua_error("cdPutImageRGB: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageRGB: target region dimensions should be positive integers!"); + + if (lua_getparam(6) != LUA_NOOBJECT) + lua_error("cdPutImageRGB: too many parameters!"); + + cdPutImageRGB(imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x_i, y_i, w_i, h_i); +} + +static void cdlua_putimagerectrgb(void) +{ + lua_Object imagergb; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagergb_t *imagergb_p; + int x_i; + int y_i; + int w_i; + int h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("cdPutImageRectRGB: attempt to put a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("cdPutImageRectRGB: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdPutImageRectRGB: attempt to put a killed imagergb!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + xmin = lua_getparam(6); + xmax = lua_getparam(7); + ymin = lua_getparam(8); + ymax = lua_getparam(9); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("cdPutImageRectRGB: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageRectRGB: target region dimensions should be positive integers!"); + + if (lua_getparam(10) != LUA_NOOBJECT) + lua_error("cdPutImageRectRGB: too many parameters!"); + + cdPutImageRectRGB(imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +static void wdlua_putimagerectrgb(void) +{ + lua_Object imagergb; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagergb_t *imagergb_p; + double x_i; + double y_i; + double w_i; + double h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagergb = lua_getparam(1); + if (lua_isnil(imagergb)) + lua_error("wdPutImageRectRGB: attempt to put a NIL imagergb!"); + if (lua_tag(imagergb) != imagergb_tag) + lua_error("wdPutImageRectRGB: invalid imagergb parameter!"); + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("wdPutImageRectRGB: attempt to put a killed imagergb!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + xmin = lua_getparam(6); + xmax = lua_getparam(7); + ymin = lua_getparam(8); + ymax = lua_getparam(9); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("wdPutImageRectRGB: invalid parameter!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + w_i = (double) lua_getnumber(w); + h_i = (double) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("wdPutImageRectRGB: target region dimensions should be positive integers!"); + + if (lua_getparam(10) != LUA_NOOBJECT) + lua_error("wdPutImageRectRGB: too many parameters!"); + + wdPutImageRectRGB(imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +/***************************************************************************\ +* cdPutImageRGBA. * +\***************************************************************************/ +static void cdlua_putimagergba(void) +{ + lua_Object imagergba; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + + imagergba_t *imagergba_p; + int x_i; + int y_i; + int w_i; + int h_i; + + imagergba = lua_getparam(1); + if (lua_isnil(imagergba)) + lua_error("cdPutImageRGBA: attempt to put a NIL imagergba!"); + if (lua_tag(imagergba) != imagergba_tag) + lua_error("cdPutImageRGBA: invalid imagergba parameter!"); + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue && imagergba_p->alpha)) + lua_error("cdPutImageRGBA: attempt to put a killed imagergba!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h))) + lua_error("cdPutImageRGBA: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageRGBA: target region dimensions should be positive integers!"); + + if (lua_getparam(6) != LUA_NOOBJECT) + lua_error("cdPutImageRGBA: too many parameters!"); + + cdPutImageRGBA(imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x_i, y_i, w_i, h_i); +} + +static void cdlua_putimagerectrgba(void) +{ + lua_Object imagergba; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagergba_t *imagergba_p; + int x_i; + int y_i; + int w_i; + int h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagergba = lua_getparam(1); + if (lua_isnil(imagergba)) + lua_error("cdPutImageRectRGBA: attempt to put a NIL imagergba!"); + if (lua_tag(imagergba) != imagergba_tag) + lua_error("cdPutImageRectRGBA: invalid imagergba parameter!"); + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue && imagergba_p->alpha)) + lua_error("cdPutImageRectRGBA: attempt to put a killed imagergba!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + xmin = lua_getparam(6); + xmax = lua_getparam(7); + ymin = lua_getparam(8); + ymax = lua_getparam(9); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("cdPutImageRectRGBA: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageRectRGBA: target region dimensions should be positive integers!"); + + if (lua_getparam(10) != LUA_NOOBJECT) + lua_error("cdPutImageRectRGBA: too many parameters!"); + + cdPutImageRectRGBA(imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +static void wdlua_putimagerectrgba(void) +{ + lua_Object imagergba; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagergba_t *imagergba_p; + double x_i; + double y_i; + double w_i; + double h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagergba = lua_getparam(1); + if (lua_isnil(imagergba)) + lua_error("wdPutImageRectRGBA: attempt to put a NIL imagergba!"); + if (lua_tag(imagergba) != imagergba_tag) + lua_error("wdPutImageRectRGBA: invalid imagergba parameter!"); + imagergba_p = (imagergba_t *) lua_getuserdata(imagergba); + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue && imagergba_p->alpha)) + lua_error("wdPutImageRectRGBA: attempt to put a killed imagergba!"); + + x = lua_getparam(2); + y = lua_getparam(3); + w = lua_getparam(4); + h = lua_getparam(5); + xmin = lua_getparam(6); + xmax = lua_getparam(7); + ymin = lua_getparam(8); + ymax = lua_getparam(9); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("wdPutImageRectRGBA: invalid parameter!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + w_i = (double) lua_getnumber(w); + h_i = (double) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("wdPutImageRectRGBA: target region dimensions should be positive integers!"); + + if (lua_getparam(10) != LUA_NOOBJECT) + lua_error("wdPutImageRectRGBA: too many parameters!"); + + wdPutImageRectRGBA(imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +/***************************************************************************\ +* cdPutImageMap. * +\***************************************************************************/ +static void cdlua_putimagemap(void) +{ + lua_Object imagemap; + lua_Object palette; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + + imagemap_t *imagemap_p; + palette_t *palette_p; + int x_i; + int y_i; + int w_i; + int h_i; + + imagemap = lua_getparam(1); + if (lua_isnil(imagemap)) + lua_error("cdPutImageMap: attempt to put a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("cdPutImageMap: imagemap invalid parameter!"); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->index) + lua_error("cdPutImageMap: attempt to put a killed imagemap!"); + + palette = lua_getparam(2); + if (lua_isnil(palette)) + lua_error("cdPutImageMap: NIL pallete!"); + if (lua_tag(palette) != palette_tag) + lua_error("cdPutImageMap: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("cdPutImageMap: killed pallete!"); + + x = lua_getparam(3); + y = lua_getparam(4); + w = lua_getparam(5); + h = lua_getparam(6); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h))) + lua_error("cdPutImageMap: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageMap: target region dimensions should be positive integers!"); + + if (lua_getparam(7) != LUA_NOOBJECT) + lua_error("cdPutImageMap: too many parameters!"); + + cdPutImageMap(imagemap_p->width, imagemap_p->height, imagemap_p->index, + palette_p->color, x_i, y_i, w_i, h_i); +} + +static void cdlua_putimagerectmap(void) +{ + lua_Object imagemap; + lua_Object palette; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagemap_t *imagemap_p; + palette_t *palette_p; + int x_i; + int y_i; + int w_i; + int h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagemap = lua_getparam(1); + if (lua_isnil(imagemap)) + lua_error("cdPutImageMap: attempt to put a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("cdPutImageMap: imagemap invalid parameter!"); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->index) + lua_error("cdPutImageMap: attempt to put a killed imagemap!"); + + palette = lua_getparam(2); + if (lua_isnil(palette)) + lua_error("cdPutImageRectMap: NIL pallete!"); + if (lua_tag(palette) != palette_tag) + lua_error("cdPutImageRectMap: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("cdPutImageRectMap: killed pallete!"); + + x = lua_getparam(3); + y = lua_getparam(4); + w = lua_getparam(5); + h = lua_getparam(6); + xmin = lua_getparam(7); + xmax = lua_getparam(8); + ymin = lua_getparam(9); + ymax = lua_getparam(10); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("cdPutImageRectMap: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + w_i = (int) lua_getnumber(w); + h_i = (int) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("cdPutImageRectMap: target region dimensions should be positive integers!"); + + if (lua_getparam(11) != LUA_NOOBJECT) + lua_error("cdPutImageRectMap: too many parameters!"); + + cdPutImageRectMap(imagemap_p->width, imagemap_p->height, imagemap_p->index, + palette_p->color, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +static void wdlua_putimagerectmap(void) +{ + lua_Object imagemap; + lua_Object palette; + lua_Object x; + lua_Object y; + lua_Object w; + lua_Object h; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + imagemap_t *imagemap_p; + palette_t *palette_p; + double x_i; + double y_i; + double w_i; + double h_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + imagemap = lua_getparam(1); + if (lua_isnil(imagemap)) + lua_error("wdPutImageMap: attempt to put a NIL imagemap!"); + if (lua_tag(imagemap) != imagemap_tag) + lua_error("wdPutImageMap: imagemap invalid parameter!"); + imagemap_p = (imagemap_t *) lua_getuserdata(imagemap); + if (!imagemap_p->index) + lua_error("wdPutImageMap: attempt to put a killed imagemap!"); + + palette = lua_getparam(2); + if (lua_isnil(palette)) + lua_error("wdPutImageRectMap: NIL pallete!"); + if (lua_tag(palette) != palette_tag) + lua_error("wdPutImageRectMap: invalid palette parameter!"); + palette_p = (palette_t *) lua_getuserdata(palette); + if (!palette_p->color) + lua_error("wdPutImageRectMap: killed pallete!"); + + x = lua_getparam(3); + y = lua_getparam(4); + w = lua_getparam(5); + h = lua_getparam(6); + xmin = lua_getparam(7); + xmax = lua_getparam(8); + ymin = lua_getparam(9); + ymax = lua_getparam(10); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(w) && lua_isnumber(h) && + lua_isnumber(xmin) && lua_isnumber(xmax) && lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("wdPutImageRectMap: invalid parameter!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + w_i = (double) lua_getnumber(w); + h_i = (double) lua_getnumber(h); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + if (w_i < 0 || h_i < 0) + lua_error("wdPutImageRectMap: target region dimensions should be positive integers!"); + + if (lua_getparam(11) != LUA_NOOBJECT) + lua_error("wdPutImageRectMap: too many parameters!"); + + wdPutImageRectMap(imagemap_p->width, imagemap_p->height, imagemap_p->index, + palette_p->color, x_i, y_i, w_i, h_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +/***************************************************************************\ +* cdGetImage. * +\***************************************************************************/ +static void cdlua_getimage(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + + image_t *image_p; + int x_i; + int y_i; + + image = lua_getparam(1); + if (lua_isnil(image)) + lua_error("cdGetImage: attempt to get NIL image"); + if (lua_tag(image) != image_tag) + lua_error("cdGetImage: invalid image parameter!"); + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("cdGetImage: attempt to get a killed image"); + + x = lua_getparam(2); + y = lua_getparam(3); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("cdGetImage: invalid (x, y) parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdGetImage: too many parameters!"); + cdGetImage(image_p->cd_image, x_i, y_i); +} + +/***************************************************************************\ +* cdPutImage. * +\***************************************************************************/ +static void cdlua_putimage(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + + image_t *image_p; + int x_i; + int y_i; + + image = lua_getparam(1); + if (lua_isnil(image)) + lua_error("cdPutImage: attempt to put a NIL image!"); + if (lua_tag(image) != image_tag) + lua_error("cdPutImage: invalid image parameter!"); + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("cdPutImage: attempt to put a killed image!"); + + x = lua_getparam(2); + y = lua_getparam(3); + if (!(lua_isnumber(x) && lua_isnumber(y))) + lua_error("cdPutImage: invalid (x, y) parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdPutImage: too many parameters!"); + + cdPutImage(image_p->cd_image, x_i, y_i); +} + +/***************************************************************************\ +* cdPutImageRect. * +\***************************************************************************/ +static void cdlua_putimagerect(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + image_t *image_p; + int x_i; + int y_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + image = lua_getparam(1); + if (lua_isnil(image)) + lua_error("cdPutImageRect: attempt to put a NIL image!"); + if (lua_tag(image) != image_tag) + lua_error("cdPutImageRect: invalid image parameter!"); + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("cdPutImageRect: attempt to put a killed image!"); + + x = lua_getparam(2); + y = lua_getparam(3); + xmin = lua_getparam(4); + xmax = lua_getparam(5); + ymin = lua_getparam(6); + ymax = lua_getparam(7); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(xmin) && lua_isnumber(xmax) && + lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("cdPutImageRect: invalid parameter!"); + x_i = (int) lua_getnumber(x); + y_i = (int) lua_getnumber(y); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + + if (lua_getparam(8) != LUA_NOOBJECT) + lua_error("cdPutImageRect: too many parameters!"); + + cdPutImageRect(image_p->cd_image, x_i, y_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +static void wdlua_putimagerect(void) +{ + lua_Object image; + lua_Object x; + lua_Object y; + lua_Object xmin; + lua_Object xmax; + lua_Object ymin; + lua_Object ymax; + + image_t *image_p; + double x_i; + double y_i; + int xmin_i; + int xmax_i; + int ymin_i; + int ymax_i; + + image = lua_getparam(1); + if (lua_isnil(image)) + lua_error("wdPutImageRect: attempt to put a NIL image!"); + if (lua_tag(image) != image_tag) + lua_error("wdPutImageRect: invalid image parameter!"); + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("wdPutImageRect: attempt to put a killed image!"); + + x = lua_getparam(2); + y = lua_getparam(3); + xmin = lua_getparam(4); + xmax = lua_getparam(5); + ymin = lua_getparam(6); + ymax = lua_getparam(7); + if (!(lua_isnumber(x) && lua_isnumber(y) && lua_isnumber(xmin) && lua_isnumber(xmax) && + lua_isnumber(ymin) && lua_isnumber(ymax))) + lua_error("wdPutImageRect: invalid parameter!"); + x_i = (double) lua_getnumber(x); + y_i = (double) lua_getnumber(y); + xmin_i = (int) lua_getnumber(xmin); + xmax_i = (int) lua_getnumber(xmax); + ymin_i = (int) lua_getnumber(ymin); + ymax_i = (int) lua_getnumber(ymax); + + if (lua_getparam(8) != LUA_NOOBJECT) + lua_error("wdPutImageRect: too many parameters!"); + + wdPutImageRect(image_p->cd_image, x_i, y_i, xmin_i, xmax_i, ymin_i, ymax_i); +} + +/***************************************************************************\ +* cdVersion. * +\***************************************************************************/ + +static void cdlua_version(void) +{ + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdVersion: too many parameters!"); + + lua_pushstring(cdVersion()); +} + +/***************************************************************************\ +* wdGetViewport. * +\***************************************************************************/ +static void wdlua_getviewport(void) +{ + int xmin; + int xmax; + int ymin; + int ymax; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("wdGetViewport: too many parameters!"); + + wdGetViewport(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +/***************************************************************************\ +* wdGetWindow. * +\***************************************************************************/ +static void wdlua_getwindow(void) +{ + double xmin; + double xmax; + double ymin; + double ymax; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("wdGetWindow: too many parameters!"); + + wdGetWindow(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +/***************************************************************************\ +* wdGetClipArea. * +\***************************************************************************/ +static void wdlua_getcliparea(void) +{ + double xmin; + double xmax; + double ymin; + double ymax; + int status; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("wdGetClipArea: too many parameters!"); + + status = wdGetClipArea(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); + lua_pushnumber(status); +} + +static void wdlua_RegionBox(void) +{ + double xmin; + double xmax; + double ymin; + double ymax; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("wdRegionBox: too many parameters!"); + + wdRegionBox(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(xmin); + lua_pushnumber(xmax); + lua_pushnumber(ymin); + lua_pushnumber(ymax); +} + +/***************************************************************************\ +* wdFontDim. * +\***************************************************************************/ +static void wdlua_fontdim(void) +{ + double max_width; + double height; + double ascent; + double descent; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("wdFontDim: too many parameters!"); + + wdFontDim(&max_width, &height, &ascent, &descent); + lua_pushnumber(max_width); + lua_pushnumber(height); + lua_pushnumber(ascent); + lua_pushnumber(descent); +} + +/***************************************************************************\ +* wdTextSize. * +\***************************************************************************/ +static void wdlua_textsize(void) +{ + lua_Object text; + char* text_s; + + double width; + double height; + + text = lua_getparam(1); + if (!lua_isstring(text)) + lua_error("wdTextSize: invalid text parameter!"); + text_s = (char*) lua_getstring(text); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("wdTextSize: too many parameters!"); + + wdTextSize(text_s, &width, &height); + lua_pushnumber(width); + lua_pushnumber(height); +} + +/***************************************************************************\ +* wdGetVectorTextSize. * +\***************************************************************************/ +static void wdlua_getvectortextsize(void) +{ + lua_Object text; + char* text_s; + + double width; + double height; + + text = lua_getparam(1); + if (!lua_isstring(text)) + lua_error("wdGetVectorTextSize: invalid text parameter!"); + text_s = (char*) lua_getstring(text); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("wdGetVectorTextSize: too many parameters!"); + + wdGetVectorTextSize(text_s, &width, &height); + lua_pushnumber(width); + lua_pushnumber(height); +} + +static void cdlua_vectortexttransform(void) +{ + lua_Object old_table, table, value; + double matrix[6], *old_matrix; + int i; + + table = lua_getparam(1); + if (!lua_istable(table)) + lua_error("cdVectorTextTransform: invalid table parameter!"); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdVectorTextTransform: too many parameters!"); + + for (i=0; i < 6; i++) + { + lua_pushobject(table); + lua_pushnumber(i+1); + value = lua_gettable(); + + if (!lua_isnumber(value)) + lua_error("cdVectorTextTransform: invalid value!"); + + matrix[i] = lua_getnumber(value); + } + + old_matrix = cdVectorTextTransform(matrix); + + old_table = lua_createtable(); + + for (i=0; i < 6; i++) + { + lua_pushobject(old_table); + lua_pushnumber(i+1); + lua_pushnumber(old_matrix[i]); + lua_settable(); + } +} + +static void cdlua_vectortextbounds(void) +{ + char* s = (char*)luaL_check_string(1); + int x = (int)luaL_check_number(2); + int y = (int)luaL_check_number(3); + int rect[8], i; + lua_Object lua_rect; + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("cdGetVectorTextBounds: too many parameters!"); + + cdGetVectorTextBounds(s, x, y, rect); + + lua_rect = lua_createtable(); + + for (i=0; i < 8; i++) + { + lua_pushobject(lua_rect); + lua_pushnumber(i+1); + lua_pushnumber(rect[i]); + lua_settable(); + } +} + +static void wdlua_vectortextbounds(void) +{ + char* s = (char*)luaL_check_string(1); + double x = luaL_check_number(2); + double y = luaL_check_number(3); + double rect[8]; + int i; + lua_Object lua_rect; + + if (lua_getparam(4) != LUA_NOOBJECT) + lua_error("wdGetVectorTextBounds: too many parameters!"); + + wdGetVectorTextBounds(s, x, y, rect); + + lua_rect = lua_createtable(); + + for (i=0; i < 8; i++) + { + lua_pushobject(lua_rect); + lua_pushnumber(i+1); + lua_pushnumber(rect[i]); + lua_settable(); + } +} + +static void cdlua_getvectortextsize(void) +{ + lua_Object text; + char* text_s; + + int width; + int height; + + text = lua_getparam(1); + if (!lua_isstring(text)) + lua_error("cdGetVectorTextSize: invalid text parameter!"); + text_s = (char*) lua_getstring(text); + + if (lua_getparam(2) != LUA_NOOBJECT) + lua_error("cdGetTextSize: too many parameters!"); + + cdGetVectorTextSize(text_s, &width, &height); + lua_pushnumber(width); + lua_pushnumber(height); +} +/***************************************************************************\ +* wdWorld2Canvas. * +\***************************************************************************/ +static void wdlua_world2canvas(void) +{ + lua_Object xw; + lua_Object yw; + double xw_d; + double yw_d; + + int xv_i; + int yv_i; + + xw = lua_getparam(1); + yw = lua_getparam(2); + if (!(lua_isnumber(xw) && lua_isnumber(yw))) + lua_error("wdWorld2Canvas: invalid (xw, yw) parameter!"); + xw_d = (double) lua_getnumber(xw); + yw_d = (double) lua_getnumber(yw); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("wdWorld2Canvas: too many parameters!"); + + wdWorld2Canvas(xw_d, yw_d, &xv_i, &yv_i); + lua_pushnumber(xv_i); + lua_pushnumber(yv_i); +} + +/***************************************************************************\ +* wdCanvas2World. * +\***************************************************************************/ +static void wdlua_canvas2world(void) +{ + lua_Object xv; + lua_Object yv; + int xv_i; + int yv_i; + + double xw_d; + double yw_d; + + xv = lua_getparam(1); + yv = lua_getparam(2); + if (!(lua_isnumber(xv) && lua_isnumber(yv))) + lua_error("wdCanvas2World: invalid (xc, yc) parameter!"); + xv_i = (int) lua_getnumber(xv); + yv_i = (int) lua_getnumber(yv); + + if (lua_getparam(3) != LUA_NOOBJECT) + lua_error("wdCanvas2World: too many parameters!"); + + wdCanvas2World(xv_i, yv_i, &xw_d, &yw_d); + lua_pushnumber(xw_d); + lua_pushnumber(yw_d); +} + +/***************************************************************************\ +* Initializes CDLua. * +\***************************************************************************/ +static void cdlua_pushstring(char* str, char* name) +{ + lua_pushstring(str); lua_setglobal(name); + cdlua_setnamespace(name, name+2); /* CD_XXXX = _XXXX */ +} + +static void setinfo(void) +{ + cdlua_pushstring(CD_COPYRIGHT, "CD_COPYRIGHT"); + cdlua_pushstring("A 2D Graphics Library", "CD_DESCRIPTION"); + cdlua_pushstring("CD - Canvas Draw", "CD_NAME"); + cdlua_pushstring("CD "CD_VERSION, "CD_VERSION"); +} + +void cdlua_open(void) +{ + char version[50]; + lua_Object imlua_tag; + + cdlua_namespace = lua_createtable(); + lua_pushobject(cdlua_namespace); lua_setglobal ("cd"); + + sprintf(version, "CDLua %s", cdVersion()); + lua_pushstring(version); lua_setglobal ("CDLUA_VERSION"); + setinfo(); + + /* check if IM has been initialized */ + imlua_tag = lua_getglobal("IMLUA_INSTALLED"); + + /* get IM defined tags, let IM handle with the user tag objects */ + if ((imlua_tag != LUA_NOOBJECT) && (!lua_isnil(imlua_tag))) + { + imlua_tag = lua_getglobal("IMLUA_COLOR_TAG"); + color_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_IMAGERGB_TAG"); + imagergb_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_IMAGERGBA_TAG"); + imagergba_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_PALETTE_TAG"); + palette_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_IMAGEMAP_TAG"); + imagemap_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_CHANNEL_TAG"); + channel_tag = (int) lua_getnumber(imlua_tag); + imlua_tag = lua_getglobal("IMLUA_BITMAP_TAG"); + bitmap_tag = (int) lua_getnumber(imlua_tag); + } + else /* define CD own tags and fallbacks */ + { + /* create user tags */ + color_tag = lua_newtag(); + bitmap_tag = lua_newtag(); + imagergb_tag = lua_newtag(); + imagergba_tag = lua_newtag(); + imagemap_tag = lua_newtag(); + palette_tag = lua_newtag(); + channel_tag = lua_newtag(); + + /* hook "settable" and "gettable" tag methods */ + lua_pushcfunction(palettesettable_fb); lua_settagmethod(palette_tag, "settable"); + lua_pushcfunction(imagemapsettable_fb); lua_settagmethod(imagemap_tag, "settable"); + lua_pushcfunction(channelsettable_fb); lua_settagmethod(channel_tag, "settable"); + + lua_pushcfunction(palettegettable_fb); lua_settagmethod(palette_tag, "gettable"); + lua_pushcfunction(imagemapgettable_fb); lua_settagmethod(imagemap_tag, "gettable"); + lua_pushcfunction(channelgettable_fb); lua_settagmethod(channel_tag, "gettable"); + lua_pushcfunction(imagergbgettable_fb); lua_settagmethod(imagergb_tag, "gettable"); + lua_pushcfunction(imagergbagettable_fb); lua_settagmethod(imagergba_tag, "gettable"); + lua_pushcfunction(bitmapgettable_fb); lua_settagmethod(bitmap_tag, "gettable"); + + lua_pushcfunction(palettegc_fb); lua_settagmethod(palette_tag, "gc"); + lua_pushcfunction(imagemapgc_fb); lua_settagmethod(imagemap_tag, "gc"); + lua_pushcfunction(imagergbgc_fb); lua_settagmethod(imagergb_tag, "gc"); + lua_pushcfunction(imagergbagc_fb); lua_settagmethod(imagergba_tag, "gc"); + lua_pushcfunction(bitmapgc_fb); lua_settagmethod(bitmap_tag, "gc"); + } + + /* these are not handled by IM */ + stipple_tag = lua_newtag(); + pattern_tag = lua_newtag(); + image_tag = lua_newtag(); + canvas_tag = lua_newtag(); + state_tag = lua_newtag(); + + /* hook "settable" and "gettable" tag methods */ + lua_pushcfunction(stipplesettable_fb); lua_settagmethod(stipple_tag, "settable"); + lua_pushcfunction(patternsettable_fb); lua_settagmethod(pattern_tag, "settable"); + lua_pushcfunction(stipplegettable_fb); lua_settagmethod(stipple_tag, "gettable"); + lua_pushcfunction(patterngettable_fb); lua_settagmethod(pattern_tag, "gettable"); + + lua_pushcfunction(stipplegc_fb); lua_settagmethod(stipple_tag, "gc"); + lua_pushcfunction(patterngc_fb); lua_settagmethod(pattern_tag, "gc"); + lua_pushcfunction(stategc_fb); lua_settagmethod(state_tag, "gc"); + + /* register used tags in global context for other libraries use */ + lua_pushnumber(1.0f); lua_setglobal("CDLUA_INSTALLED"); + + lua_pushnumber(color_tag); lua_setglobal(COLOR_TAG); + lua_pushnumber(stipple_tag); lua_setglobal(STIPPLE_TAG); + lua_pushnumber(pattern_tag); lua_setglobal(PATTERN_TAG); + lua_pushnumber(image_tag); lua_setglobal(IMAGE_TAG); + lua_pushnumber(bitmap_tag); lua_setglobal(BITMAP_TAG); + lua_pushnumber(imagergb_tag); lua_setglobal(IMAGERGB_TAG); + lua_pushnumber(imagergba_tag); lua_setglobal(IMAGERGBA_TAG); + lua_pushnumber(imagemap_tag); lua_setglobal(IMAGEMAP_TAG); + lua_pushnumber(palette_tag); lua_setglobal(PALETTE_TAG); + lua_pushnumber(channel_tag); lua_setglobal(CHANNEL_TAG); + lua_pushnumber(canvas_tag); lua_setglobal(CANVAS_TAG); + lua_pushnumber(state_tag); lua_setglobal(STATE_TAG); + + /* registered cd functions */ + cdlua_register("cdSaveState", cdlua_savestate); + cdlua_register("cdRestoreState", cdlua_restorestate); + cdlua_register("cdReleaseState", cdlua_releasestate); + cdlua_register("cdCreateCanvas", cdlua_createcanvas); + cdlua_register("cdContextCaps", cdlua_contextcaps); + cdlua_register("cdGetContext", cdlua_getcontext); + cdlua_register("cdActivate", cdlua_activate); + cdlua_register("cdActiveCanvas", cdlua_activecanvas); + cdlua_register("cdKillCanvas", cdlua_killcanvas); + cdlua_register("cdCreateStipple", cdlua_createstipple); + cdlua_register("cdGetStipple", cdlua_getstipple); + cdlua_register("cdKillStipple", cdlua_killstipple); + cdlua_register("cdCreatePattern", cdlua_createpattern); + cdlua_register("cdGetPattern", cdlua_getpattern); + cdlua_register("cdKillPattern", cdlua_killpattern); + cdlua_register("cdCreatePalette", cdlua_createpalette); + cdlua_register("cdKillPalette", cdlua_killpalette); + cdlua_register("cdCreateImage", cdlua_createimage); + cdlua_register("cdKillImage", cdlua_killimage); + cdlua_register("cdImageRGB", cdlua_imagergb); + cdlua_register("cdImageRGBBitmap", cdlua_imagergbbitmap); + cdlua_register("cdCreateImageRGB", cdlua_createimagergb); + cdlua_register("cdKillImageRGB", cdlua_killimagergb); + cdlua_register("cdCreateImageRGBA", cdlua_createimagergba); + cdlua_register("cdKillImageRGBA", cdlua_killimagergba); + cdlua_register("cdCreateImageMap", cdlua_createimagemap); + cdlua_register("cdKillImageMap", cdlua_killimagemap); + + cdlua_register("cdRegisterCallback", cdlua_registercallback); + cdlua_register("cdEncodeColor", cdlua_encodecolor); + cdlua_register("cdDecodeColor", cdlua_decodecolor); + cdlua_register("cdEncodeAlpha", cdlua_encodealpha); + cdlua_register("cdDecodeAlpha", cdlua_decodealpha); + cdlua_register("cdReserved", cdlua_reserved); + cdlua_register("cdBlue", cdlua_blue); + cdlua_register("cdGreen", cdlua_green); + cdlua_register("cdRed", cdlua_red); + cdlua_register("cdAlpha", cdlua_alpha); + cdlua_register("cdForeground", cdlua_foreground); + cdlua_register("cdBackground", cdlua_background); + cdlua_register("cdUpdateYAxis", cdlua_updateyaxis); + cdlua_register("cdFontDim", cdlua_fontdim); + cdlua_register("cdGetCanvasSize", cdlua_getcanvassize); + cdlua_register("cdGetClipPoly", cdlua_getclippoly); + cdlua_register("cdGetClipArea", cdlua_getcliparea); + cdlua_register("cdRegionBox", cdlua_RegionBox); + cdlua_register("cdGetImage", cdlua_getimage); + cdlua_register("cdGetImageRGB", cdlua_getimagergb); + cdlua_register("cdMM2Pixel", cdlua_mm2pixel); + cdlua_register("cdPalette", cdlua_palette); + cdlua_register("cdPattern", cdlua_pattern); + cdlua_register("cdPixel", cdlua_pixel); + cdlua_register("cdPixel2MM", cdlua_pixel2mm); + cdlua_register("cdPlay", cdlua_play); + cdlua_register("cdPutImage", cdlua_putimage); + cdlua_register("cdRGB2Map", cdlua_rgb2map); + cdlua_register("cdPutImageRGB", cdlua_putimagergb); + cdlua_register("cdPutImageRectRGB", cdlua_putimagerectrgb); + cdlua_register("cdPutImageRGBA", cdlua_putimagergba); + cdlua_register("cdPutImageRectRGBA", cdlua_putimagerectrgba); + cdlua_register("cdPutImageMap", cdlua_putimagemap); + cdlua_register("cdPutImageRectMap", cdlua_putimagerectmap); + cdlua_register("cdPutImageRect", cdlua_putimagerect); + cdlua_register("cdStipple", cdlua_stipple); + cdlua_register("cdTextSize", cdlua_textsize); + cdlua_register("cdTextBox", cdlua_textbox); + cdlua_register("cdTextBounds", cdlua_textbounds); + cdlua_register("cdGetFont", cdlua_getfont); + cdlua_register("cdVersion", cdlua_version); + cdlua_register("cdGetVectorTextSize", cdlua_getvectortextsize); + cdlua_register("cdVectorTextTransform", cdlua_vectortexttransform); + cdlua_register("cdVectorTextBounds", cdlua_vectortextbounds); + cdlua_register("cdCreateBitmap", cdlua_createbitmap); + cdlua_register("cdKillBitmap", cdlua_killbitmap); + cdlua_register("cdBitmapSetRect", cdlua_bitmapsetrect); + cdlua_register("cdPutBitmap", cdlua_putbitmap); + cdlua_register("cdGetBitmap", cdlua_getbitmap); + cdlua_register("cdBitmapRGB2Map", cdlua_rgb2mapex); + cdlua_register("cdLineStyleDashes", cdlua_LineStyleDashes); + + /* registered wd functions */ + cdlua_register("wdHardcopy", wdlua_hardcopy); + cdlua_register("wdPutBitmap", wdlua_putbitmap); + cdlua_register("wdGetWindow", wdlua_getwindow); + cdlua_register("wdGetViewport", wdlua_getviewport); + cdlua_register("wdWorld2Canvas", wdlua_world2canvas); + cdlua_register("wdCanvas2World", wdlua_canvas2world); + cdlua_register("wdGetClipArea", wdlua_getcliparea); + cdlua_register("wdRegionBox", wdlua_RegionBox); + cdlua_register("wdMM2Pixel", cdlua_mm2pixel); + cdlua_register("wdPixel2MM", cdlua_pixel2mm); + cdlua_register("wdFontDim", wdlua_fontdim); + cdlua_register("wdGetFont", wdlua_getfont); + cdlua_register("wdTextSize", wdlua_textsize); + cdlua_register("wdGetVectorTextSize", wdlua_getvectortextsize); + cdlua_register("wdVectorTextBounds", wdlua_vectortextbounds); + cdlua_register("wdPixel", wdlua_pixel); + cdlua_register("wdTextBox", wdlua_textbox); + cdlua_register("wdTextBounds", wdlua_textbounds); + cdlua_register("wdPutImageRectRGB", wdlua_putimagerectrgb); + cdlua_register("wdPutImageRectRGBA", wdlua_putimagerectrgba); + cdlua_register("wdPutImageRectMap", wdlua_putimagerectmap); + cdlua_register("wdPutImageRect", wdlua_putimagerect); + cdlua_register("wdStipple", wdlua_stipple); + cdlua_register("wdPattern", wdlua_pattern); + cdlua_register("wdGetClipPoly", wdlua_getclippoly); + + cdlua_initdrivers(); + + /* color constants */ + cdlua_pushcolor(CD_RED, "CD_RED"); + cdlua_pushcolor(CD_DARK_RED, "CD_DARK_RED"); + cdlua_pushcolor(CD_GREEN, "CD_GREEN"); + cdlua_pushcolor(CD_DARK_GREEN, "CD_DARK_GREEN"); + cdlua_pushcolor(CD_BLUE, "CD_BLUE"); + cdlua_pushcolor(CD_DARK_BLUE, "CD_DARK_BLUE"); + cdlua_pushcolor(CD_YELLOW, "CD_YELLOW"); + cdlua_pushcolor(CD_DARK_YELLOW, "CD_DARK_YELLOW"); + cdlua_pushcolor(CD_MAGENTA, "CD_MAGENTA"); + cdlua_pushcolor(CD_DARK_MAGENTA, "CD_DARK_MAGENTA"); + cdlua_pushcolor(CD_CYAN, "CD_CYAN"); + cdlua_pushcolor(CD_DARK_CYAN, "CD_DARK_CYAN"); + cdlua_pushcolor(CD_WHITE, "CD_WHITE"); + cdlua_pushcolor(CD_BLACK, "CD_BLACK"); + cdlua_pushcolor(CD_DARK_GRAY, "CD_DARK_GRAY"); + cdlua_pushcolor(CD_GRAY, "CD_GRAY"); + + /* cdplay constants */ + cdlua_pushnumber(CD_SIZECB, "CD_SIZECB"); + + /* create void canvas used when there is no active canvas to avoid protection faults */ + void_canvas = cdCreateCanvas(CD_VOID, NULL); + cdActivate(void_canvas); + + /* initialize toLua implementation */ + luaL_cd_open(); + luaL_wd_open(); +} + +void cdlua_close(void) +{ + cdKillCanvas(void_canvas); +} diff --git a/src/lua3/cdlua.def b/src/lua3/cdlua.def new file mode 100644 index 0000000..68b0ee4 --- /dev/null +++ b/src/lua3/cdlua.def @@ -0,0 +1,7 @@ +EXPORTS + cdlua_open + cdlua_close + cdlua_getcanvas + cdlua_addcontext + cdlua_checkcanvas + cdlua_pushcanvas \ No newline at end of file diff --git a/src/lua3/cdluactx.c b/src/lua3/cdluactx.c new file mode 100644 index 0000000..fc09313 --- /dev/null +++ b/src/lua3/cdluactx.c @@ -0,0 +1,950 @@ +/***************************************************************************\ +* CDLUA.C, for LUA 3.1 * +* Diego Fernandes Nehab, Antonio Escano Scuri * +* 01/99 * +\***************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "cd.h" +#include "wd.h" + +#include "cdimage.h" +#include "cdirgb.h" +#include "cddxf.h" +#include "cddgn.h" +#include "cdcgm.h" +#include "cdwmf.h" +#include "cdemf.h" +#include "cdnative.h" +#include "cdprint.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdps.h" +#include "cddbuf.h" +#include "cdgdiplus.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdlua3_private.h" + + +/***************************************************************************\ +* CD_CGM. * +\***************************************************************************/ +static void *cdcgm_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_CGM: data should be of type string!"); + + return lua_getstring(data); +} + +static int cgm_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); +static int cgm_countercb(cdCanvas *canvas, double percent); +static int cgm_sclmdecb(cdCanvas *canvas, short scl_mde, short *draw_mode_i, double *factor_f); +static int cgm_vdcextcb(cdCanvas *canvas, short type, void *xmn, void *ymn, void *xmx, void *ymx); +static int cgm_begpictcb(cdCanvas *canvas, char *pict); +static int cgm_begpictbcb(cdCanvas *canvas); +static int cgm_begmtfcb(cdCanvas *canvas, int *xmn, int *ymn, int *xmx, int *ymx); + +static cdCallbackLUA cdluacgmcb[7] = { +{ + -1, + "CD_SIZECB", + (cdCallback)cgm_sizecb +}, +{ + -1, + "CD_CGMCOUNTERCB", + (cdCallback)cgm_countercb +}, +{ + -1, + "CD_CGMSCLMDECB", + (cdCallback)cgm_sclmdecb +}, +{ + -1, + "CD_CGMVDCEXTCB", + (cdCallback)cgm_vdcextcb +}, +{ + -1, + "CD_CGMBEGPICTCB", + (cdCallback)cgm_begpictcb +}, +{ + -1, + "CD_CGMBEGPICTBCB", + (cdCallback)cgm_begpictbcb +}, +{ + -1, + "CD_CGMBEGMTFCB", + (cdCallback)cgm_begmtfcb +} +}; + +static cdContextLUA cdluacgmctx = +{ + 0, + "CD_CGM", + cdContextCGM, + cdcgm_checkdata, + cdluacgmcb, + 7 +}; + +/***************************************************************************\ +* CGM CD_COUNTERCB. * +\***************************************************************************/ +static int cgm_countercb(cdCanvas *canvas, double percent) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMCOUNTERCB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( percent); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMCOUNTERCB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_BEGPICTCB. * +\***************************************************************************/ +static int cgm_begpictcb(cdCanvas *canvas, char *pict) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMBEGPICTCB].lock); + + cdlua_pushcanvas(canvas); + lua_pushstring(pict); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMBEGPICTCB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +static int cgm_begmtfcb(cdCanvas *canvas, int *xmn, int *ymn, int *xmx, int *ymx) +{ + lua_Object func, result, xmn_l, ymn_l, xmx_l, ymx_l; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMBEGMTFCB].lock); + + cdlua_pushcanvas(canvas); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMBEGMTFCB: invalid return value!"); + result_i = (int) lua_getnumber(result); + if (result_i == 1) { + lua_endblock(); + return 1; + } + + xmn_l = lua_getresult(2); + if (!lua_isnumber(xmn_l)) + lua_error("cdPlay: CD_CGMBEGMTFCB: invalid xmn return value!"); + *xmn = (int) lua_getnumber(xmn_l); + + ymn_l = lua_getresult(3); + if (!lua_isnumber(ymn_l)) + lua_error("cdPlay: CD_CGMBEGMTFCB: invalid ymn return value!"); + *ymn = (int) lua_getnumber(ymn_l); + + xmx_l = lua_getresult(4); + if (!lua_isnumber(xmx_l)) + lua_error("cdPlay: CD_CGMBEGMTFCB: invalid xmx return value!"); + *xmx = (int) lua_getnumber(xmx_l); + + ymx_l = lua_getresult(5); + if (!lua_isnumber(ymx_l)) + lua_error("cdPlay: CD_CGMBEGMTFCB: invalid ymx return value!"); + *ymx = (int) lua_getnumber(ymx_l); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_BEGPICTBCB. * +\***************************************************************************/ +static int cgm_begpictbcb(cdCanvas *canvas) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMBEGPICTBCB].lock); + + cdlua_pushcanvas(canvas); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMBEGPICTBCB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_SIZECB. * +\***************************************************************************/ +static int cgm_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_SIZECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( w); + lua_pushnumber( h); + lua_pushnumber( mm_w); + lua_pushnumber( mm_h); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_SIZECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_SCLMDE. * +\***************************************************************************/ +static int cgm_sclmdecb(cdCanvas *canvas, short scl_mde, short *draw_mode_i, double *factor_f) +{ + lua_Object func, result, draw_mode, factor; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMSCLMDECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( scl_mde); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMSCLMDECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + if (result_i == 1) { + lua_endblock(); + return 1; + } + + draw_mode = lua_getresult(2); + if (!lua_isnumber(draw_mode)) + lua_error("cdPlay: CD_CGMSCLMDECB: invalid draw_mode return value!"); + *draw_mode_i = (short) lua_getnumber(draw_mode); + + factor = lua_getresult(3); + if (!lua_isnumber(factor)) + lua_error("cdPlay: CD_CGMSCLMDECB: invalid factor return value!"); + *factor_f = (double) lua_getnumber(factor); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_VDCEXTCB. * +\***************************************************************************/ +static int cgm_vdcextcb(cdCanvas *canvas, short type, void *xmn, void *ymn, void *xmx, void *ymx) +{ + lua_Object func, result, xmn_l, ymn_l, xmx_l, ymx_l; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluacgmcb[CD_CGMVDCEXTCB].lock); + + cdlua_pushcanvas(canvas); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_CGMVDCEXTCB: invalid return value!"); + result_i = (int) lua_getnumber(result); + if (result_i == 1) { + lua_endblock(); + return 1; + } + + xmn_l = lua_getresult(2); + if (!lua_isnumber(xmn_l)) + lua_error("cdPlay: CD_CGMVDCEXTCB: invalid xmn return value!"); + if (type == 1) *((float *) xmn) = (float) lua_getnumber(xmn_l); + else *((int *) xmn) = (int) lua_getnumber(xmn_l); + + ymn_l = lua_getresult(3); + if (!lua_isnumber(ymn_l)) + lua_error("cdPlay: CD_CGMVDCEXTCB: invalid ymn return value!"); + if (type == 1) *((float *) ymn) = (float) lua_getnumber(ymn_l); + else *((int *) ymn) = (int) lua_getnumber(ymn_l); + + xmx_l = lua_getresult(4); + if (!lua_isnumber(xmx_l)) + lua_error("cdPlay: CD_CGMVDCEXTCB: invalid xmx return value!"); + if (type == 1) *((float *) xmx) = (float) lua_getnumber(xmx_l); + else *((int *) xmx) = (int) lua_getnumber(xmx_l); + + ymx_l = lua_getresult(5); + if (!lua_isnumber(ymx_l)) + lua_error("cdPlay: CD_CGMVDCEXTCB: invalid ymx return value!"); + if (type == 1) *((float *) ymx) = (float) lua_getnumber(ymx_l); + else *((int *) ymx) = (int) lua_getnumber(ymx_l); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CD_DBUFFER. * +\***************************************************************************/ +static void *cddbuf_checkdata(int param) +{ + canvas_t *canvas_p; + lua_Object canvas; + int canvas_tag = (int)lua_getnumber(lua_getglobal(CANVAS_TAG)); + + canvas = lua_getparam(param); + if (lua_isnil(canvas)) + lua_error("cdCreateCanvas CD_DBUFFER: data is a NIL canvas!"); + + if (lua_tag(canvas) != canvas_tag) + lua_error("cdCreateCanvas CD_DBUFFER: data should be of type canvas_tag!"); + + canvas_p = (canvas_t *) lua_getuserdata(canvas); + if (!canvas_p->cd_canvas) + lua_error("cdCreateCanvas CD_DBUFFER: data is a killed canvas!"); + + return canvas_p->cd_canvas; +} + +static cdContextLUA cdluadbufctx = +{ + 0, + "CD_DBUFFER", + cdContextDBuffer, + cddbuf_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_IMAGE. * +\***************************************************************************/ +static void *cdimage_checkdata(int param) +{ + int image_tag; + image_t *image_p; + lua_Object image = lua_getparam(param); + if (lua_isnil(image)) + lua_error("cdCreateCanvas CD_IMAGE: data is a NIL image!"); + + image_tag = (int)lua_getnumber(lua_getglobal(IMAGE_TAG)); + if (lua_tag(image) != image_tag) + lua_error("cdCreateCanvas CD_IMAGE: data should be of type image_tag!"); + + image_p = (image_t *) lua_getuserdata(image); + if (!image_p->cd_image) + lua_error("cdCreateCanvas CD_IMAGE: data is a killed image!"); + + return image_p->cd_image; +} + +static cdContextLUA cdluaimagectx = +{ + 0, + "CD_IMAGE", + cdContextImage, + cdimage_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_IMAGERGB. * +\***************************************************************************/ +static void *cdimagergb_checkdata(int param) +{ + lua_Object imagergb; + static char data_s[50]; + + imagergb = lua_getparam(param); + if (lua_isnil(imagergb)) + lua_error("cdCreateCanvas CD_IMAGERGB: data is a NIL imagergb!"); + + if (lua_isstring(imagergb)) + { + char* str = lua_getstring(imagergb); + strcpy(data_s, str); + } + else + { + lua_Object res; + int bitmap_tag = (int)lua_getnumber(lua_getglobal(BITMAP_TAG)); + + if (lua_tag(imagergb) == bitmap_tag) + { + bitmap_t *imagergb_p; + + imagergb_p = (bitmap_t *) lua_getuserdata(imagergb); + if (!imagergb_p->image) + lua_error("cdCreateCanvas CD_IMAGERGB: data is a killed imagergb!"); + + if (imagergb_p->image->type != CD_RGB && imagergb_p->image->type != CD_RGBA) + lua_error("cdCreateCanvas CD_IMAGERGB: bitmap should be of type rgb or rgba!"); + + res = lua_getparam(param+1); + if (res == LUA_NOOBJECT || lua_isnil(res)) + { + if (imagergb_p->image->type == CD_RGBA) + sprintf(data_s, "%dx%d %p %p %p %p -a", imagergb_p->image->w, imagergb_p->image->h, + cdBitmapGetData(imagergb_p->image, CD_IRED), + cdBitmapGetData(imagergb_p->image, CD_IGREEN), + cdBitmapGetData(imagergb_p->image, CD_IBLUE), + cdBitmapGetData(imagergb_p->image, CD_IALPHA)); + else + sprintf(data_s, "%dx%d %p %p %p", imagergb_p->image->w, imagergb_p->image->h, + cdBitmapGetData(imagergb_p->image, CD_IRED), + cdBitmapGetData(imagergb_p->image, CD_IGREEN), + cdBitmapGetData(imagergb_p->image, CD_IBLUE)); + } + else + { + double res_f = lua_getnumber(res); + if (imagergb_p->image->type == CD_RGBA) + sprintf(data_s, "%dx%d %p %p %p %p -r%g -a", imagergb_p->image->w, imagergb_p->image->h, + cdBitmapGetData(imagergb_p->image, CD_IRED), + cdBitmapGetData(imagergb_p->image, CD_IGREEN), + cdBitmapGetData(imagergb_p->image, CD_IBLUE), + cdBitmapGetData(imagergb_p->image, CD_IALPHA), + res_f); + else + sprintf(data_s, "%dx%d %p %p %p -r%g", imagergb_p->image->w, imagergb_p->image->h, + cdBitmapGetData(imagergb_p->image, CD_IRED), + cdBitmapGetData(imagergb_p->image, CD_IGREEN), + cdBitmapGetData(imagergb_p->image, CD_IBLUE), + res_f); + } + } + else + { + imagergb_t *imagergb_p; + int imagergb_tag = (int)lua_getnumber(lua_getglobal(IMAGERGB_TAG)); + + if (lua_tag(imagergb) != imagergb_tag) + { + imagergba_t *imagergba_p; + int imagergba_tag = (int)lua_getnumber(lua_getglobal(IMAGERGBA_TAG)); + if (lua_tag(imagergb) != imagergba_tag) + lua_error("cdCreateCanvas CD_IMAGERGB: data should be of type imagergb_tag or imagergba_tag!"); + + imagergba_p = (imagergba_t *) lua_getuserdata(imagergb); + if (!(imagergba_p->red && imagergba_p->green && imagergba_p->blue)) + lua_error("cdCreateCanvas CD_IMAGERGB: data is a killed imagergba!"); + + res = lua_getparam(param+1); + if (res == LUA_NOOBJECT || lua_isnil(res)) + { + sprintf(data_s, "%dx%d %p %p %p", imagergba_p->width, imagergba_p->height, + imagergba_p->red, imagergba_p->green, imagergba_p->blue); + } + else + { + double res_f = lua_getnumber(res); + sprintf(data_s, "%dx%d %p %p %p -r%g", imagergba_p->width, imagergba_p->height, + imagergba_p->red, imagergba_p->green, imagergba_p->blue, res_f); + } + + return data_s; + } + + imagergb_p = (imagergb_t *) lua_getuserdata(imagergb); + if (!(imagergb_p->red && imagergb_p->green && imagergb_p->blue)) + lua_error("cdCreateCanvas CD_IMAGERGB: data is a killed imagergb!"); + + res = lua_getparam(param+1); + if (res == LUA_NOOBJECT || lua_isnil(res)) + { + sprintf(data_s, "%dx%d %p %p %p", imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue); + } + else + { + double res_f = lua_getnumber(res); + sprintf(data_s, "%dx%d %p %p %p -r%g", imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue, res_f); + } + } + } + + return data_s; +} + +static cdContextLUA cdluaimagergbctx = +{ + 0, + "CD_IMAGERGB", + cdContextImageRGB, + cdimagergb_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_DXF. * +\***************************************************************************/ +static void *cddxf_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_DXF: data should be of type string!"); + + return lua_getstring(data); +} + +static cdContextLUA cdluadxfctx = +{ + 0, + "CD_DXF", + cdContextDXF, + cddxf_checkdata +}; + +/***************************************************************************\ +* CD_DGN. * +\***************************************************************************/ +static void *cddgn_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_DGN: data should be of type string!"); + + return lua_getstring(data); +} + +static cdContextLUA cdluadgnctx = +{ + 0, + "CD_DGN", + cdContextDGN, + cddgn_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_WMF. * +\***************************************************************************/ +static void *cdwmf_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_WMF: data should be of type string!"); + + return lua_getstring(data); +} + +static int wmf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdCallbackLUA cdluawmfcb[1] = +{{ + -1, + "CD_SIZECB", + (cdCallback)wmf_sizecb +}}; + +static cdContextLUA cdluawmfctx = +{ + 0, + "CD_WMF", + cdContextWMF, + cdwmf_checkdata, + cdluawmfcb, + 1 +}; + +/***************************************************************************\ +* WMF CD_SIZECB. * +\***************************************************************************/ +static int wmf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluawmfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( w); + lua_pushnumber( h); + lua_pushnumber( mm_w); + lua_pushnumber( mm_h); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_SIZECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CD_EMF. * +\***************************************************************************/ +static void *cdemf_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_EMF: data should be of type string!"); + + return lua_getstring(data); +} + +static int emf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdCallbackLUA cdluaemfcb[1] = +{{ + -1, + "CD_SIZECB", + (cdCallback)emf_sizecb +}}; + +static cdContextLUA cdluaemfctx = +{ + 0, + "CD_EMF", + cdContextEMF, + cdemf_checkdata, + cdluaemfcb, + 1 +}; + +/***************************************************************************\ +* EMF CD_SIZECB. * +\***************************************************************************/ +static int emf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluaemfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( w); + lua_pushnumber( h); + lua_pushnumber( mm_w); + lua_pushnumber( mm_h); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_SIZECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CD_METAFILE. * +\***************************************************************************/ +static void *cdmetafile_checkdata(int param) +{ + lua_Object data; + + data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_METAFILE: data should be of type string!"); + + return lua_getstring(data); +} + +static int metafile_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdCallbackLUA cdluamfcb[1] = +{{ + -1, + "CD_SIZECB", + (cdCallback)metafile_sizecb +}}; + +static cdContextLUA cdluamfctx = +{ + 0, + "CD_METAFILE", + cdContextMetafile, + cdmetafile_checkdata, + cdluamfcb, + 1 +}; + +/***************************************************************************\ +* METAFILE CD_SIZECB. * +\***************************************************************************/ +static int metafile_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluamfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( w); + lua_pushnumber( h); + lua_pushnumber( mm_w); + lua_pushnumber( mm_h); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_SIZECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CD_PS. * +\***************************************************************************/ +static void *cdps_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_PS: data should be of type string!"); + + return lua_getstring(data); +} + +static cdContextLUA cdluapsctx = +{ + 0, + "CD_PS", + cdContextPS, + cdps_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_PRINTER. * +\***************************************************************************/ +static void *cdprinter_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_PRINTER: data should be of type string!"); + + return lua_getstring(data); +} + +static cdContextLUA cdluaprinterctx = +{ + 0, + "CD_PRINTER", + cdContextPrinter, + cdprinter_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_CLIPBOARD. * +\***************************************************************************/ +static void *cdclipboard_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_CLIPBOARD: data should be of type string!"); + + return lua_getstring(data); +} + +static int clipboard_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdCallbackLUA cdluaclipboardcb[1] = +{{ + -1, + "CD_SIZECB", + (cdCallback)clipboard_sizecb +}}; + +static cdContextLUA cdluaclipboardctx = +{ + 0, + "CD_CLIPBOARD", + cdContextClipboard, + cdclipboard_checkdata, + cdluaclipboardcb, + 1 +}; + +/***************************************************************************\ +* CLIPBOARD CD_SIZECB. * +\***************************************************************************/ +static int clipboard_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + lua_Object func, result; + int result_i; + + lua_beginblock(); + func = lua_getref(cdluaclipboardcb[CD_SIZECB].lock); + + cdlua_pushcanvas(canvas); + lua_pushnumber( w); + lua_pushnumber( h); + lua_pushnumber( mm_w); + lua_pushnumber( mm_h); + lua_callfunction(func); + + result = lua_getresult(1); + if (!lua_isnumber(result)) + lua_error("cdPlay: CD_SIZECB: invalid return value!"); + result_i = (int) lua_getnumber(result); + + lua_endblock(); + + return result_i; +} + +/***************************************************************************\ +* CD_NATIVEWINDOW. * +\***************************************************************************/ +static void *cdnativewindow_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + +#ifdef WIN32 + if (!lua_isuserdata(data)) + lua_error("cdCreateCanvas CD_NATIVEWINDOW: data should be of type userdata!"); + + return lua_getuserdata(data); +#else + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_NATIVEWINDOW: data should be of type string!"); + + return lua_getstring(data); +#endif +} + +static cdContextLUA cdluanativewindowctx = +{ + 0, + "CD_NATIVEWINDOW", + cdContextNativeWindow, + cdnativewindow_checkdata, + NULL, + 0 +}; + +static void cdlua_getscreensize(void) +{ + int width; + int height; + double mm_width; + double mm_height; + + if (lua_getparam(1) != LUA_NOOBJECT) + lua_error("cdGetScreenSize: too many parameters!"); + + cdGetScreenSize(&width, &height, &mm_width, &mm_height); + lua_pushnumber( width); + lua_pushnumber( height); + lua_pushnumber( mm_width); + lua_pushnumber( mm_height); +} + +static void cdlua_getscreencolorplanes(void) +{ + int L_result = cdGetScreenColorPlanes(); + lua_pushnumber(L_result); +} + +static void cdlua_usecontextplus(void) +{ + int use = (int)luaL_check_number(1); + int L_result = cdUseContextPlus(use); + lua_pushnumber(L_result); +} + +/*******************************************************************************/ + +void cdlua_initdrivers(void) +{ + cdlua_register("cdGetScreenColorPlanes",cdlua_getscreencolorplanes); + cdlua_register("cdGetScreenSize",cdlua_getscreensize); + + cdlua_register("cdUseContextPlus",cdlua_usecontextplus); + + /* from GDI+ addicional polygon modes */ + cdlua_pushnumber(CD_SPLINE, "CD_SPLINE"); + cdlua_pushnumber(CD_FILLSPLINE, "CD_FILLSPLINE"); + cdlua_pushnumber(CD_FILLGRADIENT, "CD_FILLGRADIENT"); + + cdlua_addcontext(&cdluaimagectx); + cdlua_addcontext(&cdluaimagergbctx); + cdlua_addcontext(&cdluadxfctx); + cdlua_addcontext(&cdluadgnctx); + cdlua_addcontext(&cdluacgmctx); + cdlua_addcontext(&cdluamfctx); + cdlua_addcontext(&cdluapsctx); + cdlua_addcontext(&cdluaclipboardctx); + cdlua_addcontext(&cdluanativewindowctx); + cdlua_addcontext(&cdluaprinterctx); + cdlua_addcontext(&cdluawmfctx); + cdlua_addcontext(&cdluaemfctx); + cdlua_addcontext(&cdluadbufctx); +} + diff --git a/src/lua3/cdluapdf.c b/src/lua3/cdluapdf.c new file mode 100644 index 0000000..1260b91 --- /dev/null +++ b/src/lua3/cdluapdf.c @@ -0,0 +1,43 @@ +/** \file + * \brief PDF Canvas Lua 3 Binding + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" +#include "cdpdf.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdluapdf.h" +#include "cdlua3_private.h" + +static void *cdpdf_checkdata(int param) +{ + lua_Object data = lua_getparam(param); + if (!lua_isstring(data)) + lua_error("cdCreateCanvas CD_PDF: data should be of type string!"); + + return lua_getstring(data); +} + +static cdContextLUA cdluapdfctx = +{ + 0, + "CD_PDF", + cdContextPDF, + cdpdf_checkdata, + NULL, + 0 +}; + +void cdluapdf_open(void) +{ + cdlua_addcontext(&cdluapdfctx); +} + diff --git a/src/lua3/cdluapdf.def b/src/lua3/cdluapdf.def new file mode 100644 index 0000000..62a983f --- /dev/null +++ b/src/lua3/cdluapdf.def @@ -0,0 +1,2 @@ +EXPORTS + cdluapdf_open \ No newline at end of file diff --git a/src/lua3/cdvoid.c b/src/lua3/cdvoid.c new file mode 100644 index 0000000..3c78738 --- /dev/null +++ b/src/lua3/cdvoid.c @@ -0,0 +1,126 @@ +/** \file + * \brief CD Void driver for error checking while there is no active canvas + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#ifndef CD_NO_OLD_INTERFACE +#define CD_NO_OLD_INTERFACE +#endif + +#include "cd.h" +#include "cd_private.h" +#include <lua.h> +#include <lauxlib.h> +#include "cdlua3_private.h" + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; +}; + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas*) malloc(sizeof(cdCtxCanvas)); + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + (void)data; +} + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + free(ctxcanvas); +} + +/***************************************************************************\ +* Echos an error if called. * +\***************************************************************************/ +static void cdvoid_error(void) +{ + lua_error("cdlua: there is no active canvas!"); +} + +/***************************************************************************\ +* Dummy. * +\***************************************************************************/ +static int cdvoid_dummy(void) +{ + return CD_OK; +} + +/***************************************************************************\ +* Driver function table. * +\***************************************************************************/ + +void cdinittable(cdCanvas* canvas) +{ + /* attribute functions can not be set, because of default attributes */ + + canvas->cxClip = (int (*)(cdCtxCanvas*, int))cdvoid_error; + canvas->cxClipArea = (void (*)(cdCtxCanvas*, int, int, int, int))cdvoid_error; + canvas->cxNewRegion = (void (*)(cdCtxCanvas*))cdvoid_error; + canvas->cxIsPointInRegion = (int (*)(cdCtxCanvas*, int, int))cdvoid_error; + canvas->cxOffsetRegion = (void (*)(cdCtxCanvas*, int, int))cdvoid_error; + canvas->cxGetRegionBox = (void (*)(cdCtxCanvas*, int *, int *, int *, int *))cdvoid_error; + canvas->cxFlush = (void ( *)(cdCtxCanvas*))cdvoid_error; + canvas->cxClear = (void ( *)(cdCtxCanvas*))cdvoid_error; + canvas->cxPixel = (void ( *)(cdCtxCanvas*, int ,int ,long ))cdvoid_error; + canvas->cxLine = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxPoly = (void ( *)(cdCtxCanvas*, int ,struct _cdPoint *,int ))cdvoid_error; + canvas->cxRect = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxBox = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxArc = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxSector = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxChord = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxText = (void (*)(cdCtxCanvas*, int ,int ,const char *))cdvoid_error; + canvas->cxGetFontDim = (void (*)(cdCtxCanvas*, int *,int *,int *,int *))cdvoid_error; + canvas->cxGetTextSize = (void (*)(cdCtxCanvas*, const char *,int *,int *))cdvoid_error; + canvas->cxPutImageRectRGB = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const unsigned char *,const unsigned char *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxPutImageRectRGBA = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxPutImageRectMap = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const long *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxScrollArea = (void (*)(cdCtxCanvas*, int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxFLine = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFPoly = (void (*)(cdCtxCanvas*, int , cdfPoint*,int ))cdvoid_error; + canvas->cxFRect = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFBox = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFArc = (void (*)(cdCtxCanvas*, double ,double ,double ,double ,double ,double ))cdvoid_error; + canvas->cxFSector = (void (*)(cdCtxCanvas*, double ,double ,double ,double ,double ,double ))cdvoid_error; + canvas->cxFText = (void (*)(cdCtxCanvas*, double ,double ,const char *))cdvoid_error; + canvas->cxStipple = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *))cdvoid_error; + canvas->cxPattern = (void (*)(cdCtxCanvas*, int ,int , const long *))cdvoid_error; + canvas->cxNativeFont = (int (*)(cdCtxCanvas*, const char*))cdvoid_error; + canvas->cxPalette = (void (*)(cdCtxCanvas*, int ,const long *,int ))cdvoid_error; + canvas->cxGetImageRGB = (void (*)(cdCtxCanvas*, unsigned char *,unsigned char *,unsigned char *,int ,int ,int ,int ))cdvoid_error; + canvas->cxCreateImage = (cdCtxImage* (*)(cdCtxCanvas*, int ,int ))cdvoid_error; + canvas->cxGetImage = (void (*)(cdCtxCanvas*, cdCtxImage*, int ,int ))cdvoid_error; + canvas->cxPutImageRect = (void (*)(cdCtxCanvas*, cdCtxImage*,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxKillImage = (void (*)(cdCtxImage*))cdvoid_error; + canvas->cxFClipArea = (void (*)(cdCtxCanvas*, double,double,double,double))cdvoid_error; + + /* must not be the error callback */ + canvas->cxActivate = (int (*)(cdCtxCanvas*))cdvoid_dummy; + canvas->cxDeactivate = (void (*)(cdCtxCanvas*))cdvoid_dummy; + canvas->cxFont = (int (*)(cdCtxCanvas*, const char *, int, int))cdvoid_dummy; + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdVoidContext = +{ + 0, + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextVoid(void) +{ + return &cdVoidContext; +} + diff --git a/src/lua3/cdvoid.h b/src/lua3/cdvoid.h new file mode 100644 index 0000000..040f604 --- /dev/null +++ b/src/lua3/cdvoid.h @@ -0,0 +1,17 @@ +#ifndef _CD_VOID_ +#define _CD_VOID_ + +#ifdef __cplusplus +extern "C" { +#endif + +cdContext* cdContextVoid(void); + +#define CD_VOID cdContextVoid() + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _CD_VOID_ */ + diff --git a/src/lua3/toluacd.c b/src/lua3/toluacd.c new file mode 100644 index 0000000..5f29875 --- /dev/null +++ b/src/lua3/toluacd.c @@ -0,0 +1,585 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <lua.h> +#include <lauxlib.h> + +#include "cd.h" +#include "cdps.h" + +#include "cdlua.h" +#include "cdlua3_private.h" + + +static void L_cdFlush(void) +{ + cdFlush(); +} + +static void L_cdClear(void) +{ + cdClear(); +} + +static void L_cdSimulate(void) +{ + int mode = (int)luaL_check_number(1); + int L_result = cdSimulate(mode); + lua_pushnumber(L_result); +} + +static void L_cdOrigin(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + cdOrigin(x,y); +} + +static void L_cdClip(void) +{ + int mode = (int)luaL_check_number(1); + int L_result = cdClip(mode); + lua_pushnumber(L_result); +} + +static void L_cdClipArea(void) +{ + int xmin = (int)luaL_check_number(1); + int xmax = (int)luaL_check_number(2); + int ymin = (int)luaL_check_number(3); + int ymax = (int)luaL_check_number(4); + cdClipArea(xmin,xmax,ymin,ymax); +} + +static void L_cdLine(void) +{ + int x1 = (int)luaL_check_number(1); + int y1 = (int)luaL_check_number(2); + int x2 = (int)luaL_check_number(3); + int y2 = (int)luaL_check_number(4); + cdLine(x1,y1,x2,y2); +} + +static void L_cdBox(void) +{ + int xmin = (int)luaL_check_number(1); + int xmax = (int)luaL_check_number(2); + int ymin = (int)luaL_check_number(3); + int ymax = (int)luaL_check_number(4); + cdBox(xmin,xmax,ymin,ymax); +} + +static void L_cdRect(void) +{ + int xmin = (int)luaL_check_number(1); + int xmax = (int)luaL_check_number(2); + int ymin = (int)luaL_check_number(3); + int ymax = (int)luaL_check_number(4); + cdRect(xmin,xmax,ymin,ymax); +} + +static void L_cdArc(void) +{ + int xc = (int)luaL_check_number(1); + int yc = (int)luaL_check_number(2); + int w = (int)luaL_check_number(3); + int h = (int)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + cdArc(xc,yc,w,h,angle1,angle2); +} + +static void L_cdSector(void) +{ + int xc = (int)luaL_check_number(1); + int yc = (int)luaL_check_number(2); + int w = (int)luaL_check_number(3); + int h = (int)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + cdSector(xc,yc,w,h,angle1,angle2); +} + +static void L_cdChord(void) +{ + int xc = (int)luaL_check_number(1); + int yc = (int)luaL_check_number(2); + int w = (int)luaL_check_number(3); + int h = (int)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + cdChord(xc,yc,w,h,angle1,angle2); +} + +static void L_cdText(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + cdText(x,y,s); +} + +static void L_cdBegin(void) +{ + int mode = (int)luaL_check_number(1); + cdBegin(mode); +} + +static void L_cdVertex(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + cdVertex(x,y); +} + +static void L_cdEnd(void) +{ + cdEnd(); +} + +static void L_cdMark(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + cdMark(x,y); +} + +static void L_cdOffsetRegion(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + cdOffsetRegion(x,y); +} + +static void L_cdPointInRegion(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + int L_result = cdPointInRegion(x,y); + lua_pushnumber((int)L_result); +} + +static void L_cdBackOpacity(void) +{ + int opacity = (int)luaL_check_number(1); + int L_result = cdBackOpacity(opacity); + lua_pushnumber(L_result); +} + +static void L_cdWriteMode(void) +{ + int mode = (int)luaL_check_number(1); + int L_result = cdWriteMode(mode); + lua_pushnumber(L_result); +} + +static void L_cdLineStyle(void) +{ + int style = (int)luaL_check_number(1); + int L_result = cdLineStyle(style); + lua_pushnumber(L_result); +} + +static void L_cdLineWidth(void) +{ + int width = (int)luaL_check_number(1); + int L_result = cdLineWidth(width); + lua_pushnumber(L_result); +} + +static void L_cdRegionCombineMode(void) +{ + int v = (int)luaL_check_number(1); + int L_result = cdRegionCombineMode(v); + lua_pushnumber(L_result); +} + +static void L_cdLineJoin(void) +{ + int v = (int)luaL_check_number(1); + int L_result = cdLineJoin(v); + lua_pushnumber(L_result); +} + +static void L_cdLineCap(void) +{ + int v = (int)luaL_check_number(1); + int L_result = cdLineCap(v); + lua_pushnumber(L_result); +} + +static void L_cdFillMode(void) +{ + int v = (int)luaL_check_number(1); + int L_result = cdFillMode(v); + lua_pushnumber(L_result); +} + +static void L_cdInteriorStyle(void) +{ + int style = (int)luaL_check_number(1); + int L_result = cdInteriorStyle(style); + lua_pushnumber(L_result); +} + +static void L_cdHatch(void) +{ + int style = (int)luaL_check_number(1); + int L_result = cdHatch(style); + lua_pushnumber(L_result); +} + +static void L_cdFont(void) +{ + int type_face = (int)luaL_check_number(1); + int style = (int)luaL_check_number(2); + int size = (int)luaL_check_number(3); + cdFont(type_face,style,size); +} + +static void L_cdNativeFont(void) +{ + char* font = (char*)luaL_check_string(1); + lua_pushstring(cdNativeFont(font)); +} + +static int cdlua_isuserdata(char* name) +{ + if (strcmp(name, "HDC")==0) return 1; + if (strcmp(name, "GC")==0) return 1; + return 0; +} + +static void L_cdSetAttribute(void) +{ + char* name = (char*)luaL_check_string(1); + lua_Object p2 = lua_getparam(2); + + if (p2 == LUA_NOOBJECT) + lua_error("cdSetAttribute: value parameter missing!"); + + /* if p2 is nil */ + if (lua_isnil(p2)) + { + cdSetAttribute(name, NULL); + } + else + { + char* data; + if (cdlua_isuserdata(name)) + data = (char*) lua_getuserdata(p2); + else + data = (char*)luaL_check_string(2); + cdSetAttribute(name, data); + } +} + +static void L_cdGetAttribute(void) +{ + char* name = (char*)luaL_check_string(1); + char* data = cdGetAttribute(name); + if (data) + { + if (cdlua_isuserdata(name)) + lua_pushuserdata(data); + else + lua_pushstring(data); + } + else + lua_pushnil(); +} + +static void L_cdTextAlignment(void) +{ + int alignment = (int)luaL_check_number(1); + int L_result = cdTextAlignment(alignment); + lua_pushnumber(L_result); +} + +static void L_cdTextOrientation(void) +{ + double angle = luaL_check_number(1); + double L_result = cdTextOrientation(angle); + lua_pushnumber(L_result); +} + +static void L_cdMarkType(void) +{ + int type = (int)luaL_check_number(1); + int L_result = cdMarkType(type); + lua_pushnumber(L_result); +} + +static void L_cdMarkSize(void) +{ + int size = (int)luaL_check_number(1); + int L_result = cdMarkSize(size); + lua_pushnumber(L_result); +} + +static void L_cdGetColorPlanes(void) +{ + int L_result = cdGetColorPlanes(); + lua_pushnumber(L_result); +} + +static void L_cdScrollArea(void) +{ + int xmin = (int)luaL_check_number(1); + int xmax = (int)luaL_check_number(2); + int ymin = (int)luaL_check_number(3); + int ymax = (int)luaL_check_number(4); + int dx = (int)luaL_check_number(5); + int dy = (int)luaL_check_number(6); + cdScrollArea(xmin,xmax,ymin,ymax,dx,dy); +} + +static void L_cdVectorFont(void) +{ + char* file = (char*)luaL_check_string(1); + char* L_result = cdVectorFont(file); + lua_pushstring(L_result); +} + +static void L_cdVectorTextDirection(void) +{ + int x1 = (int)luaL_check_number(1); + int y1 = (int)luaL_check_number(2); + int x2 = (int)luaL_check_number(3); + int y2 = (int)luaL_check_number(4); + cdVectorTextDirection(x1,y1,x2,y2); +} + +static void L_cdVectorTextSize(void) +{ + int size_x = (int)luaL_check_number(1); + int size_y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + cdVectorTextSize(size_x,size_y,s); +} + +static void L_cdVectorCharSize(void) +{ + int size = (int)luaL_check_number(1); + int L_result = cdVectorCharSize(size); + lua_pushnumber(L_result); +} + +static void L_cdVectorText(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + cdVectorText(x,y,s); +} + +static void L_cdMultiLineVectorText(void) +{ + int x = (int)luaL_check_number(1); + int y = (int)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + cdMultiLineVectorText(x,y,s); +} + + +/* ---------------------------------------- public interface */ +int luaL_cd_open(void) +{ + cdlua_pushnumber(CD_CAP_NONE, "CD_CAP_NONE"); + cdlua_pushnumber(CD_CAP_FLUSH, "CD_CAP_FLUSH"); + cdlua_pushnumber(CD_CAP_CLEAR, "CD_CAP_CLEAR"); + cdlua_pushnumber(CD_CAP_PLAY, "CD_CAP_PLAY"); + cdlua_pushnumber(CD_CAP_YAXIS, "CD_CAP_YAXIS"); + cdlua_pushnumber(CD_CAP_CLIPAREA, "CD_CAP_CLIPAREA"); + cdlua_pushnumber(CD_CAP_CLIPPOLY, "CD_CAP_CLIPPOLY"); + cdlua_pushnumber(CD_CAP_RECT, "CD_CAP_RECT"); + cdlua_pushnumber(CD_CAP_IMAGERGB, "CD_CAP_IMAGERGB"); + cdlua_pushnumber(CD_CAP_IMAGERGBA, "CD_CAP_IMAGERGBA"); + cdlua_pushnumber(CD_CAP_IMAGEMAP, "CD_CAP_IMAGEMAP"); + cdlua_pushnumber(CD_CAP_GETIMAGERGB, "CD_CAP_GETIMAGERGB"); + cdlua_pushnumber(CD_CAP_IMAGESRV, "CD_CAP_IMAGESRV"); + cdlua_pushnumber(CD_CAP_BACKGROUND, "CD_CAP_BACKGROUND"); + cdlua_pushnumber(CD_CAP_BACKOPACITY, "CD_CAP_BACKOPACITY"); + cdlua_pushnumber(CD_CAP_WRITEMODE, "CD_CAP_WRITEMODE"); + cdlua_pushnumber(CD_CAP_LINESTYLE, "CD_CAP_LINESTYLE"); + cdlua_pushnumber(CD_CAP_LINEWITH, "CD_CAP_LINEWITH"); + cdlua_pushnumber(CD_CAP_FPRIMTIVES, "CD_CAP_FPRIMTIVES"); + cdlua_pushnumber(CD_CAP_HATCH, "CD_CAP_HATCH"); + cdlua_pushnumber(CD_CAP_STIPPLE, "CD_CAP_STIPPLE"); + cdlua_pushnumber(CD_CAP_PATTERN, "CD_CAP_PATTERN"); + cdlua_pushnumber(CD_CAP_FONT, "CD_CAP_FONT"); + cdlua_pushnumber(CD_CAP_FONTDIM, "CD_CAP_FONTDIM"); + cdlua_pushnumber(CD_CAP_TEXTSIZE, "CD_CAP_TEXTSIZE"); + cdlua_pushnumber(CD_CAP_TEXTORIENTATION, "CD_CAP_TEXTORIENTATION"); + cdlua_pushnumber(CD_CAP_PALETTE, "CD_CAP_PALETTE"); + cdlua_pushnumber(CD_CAP_ALL, "CD_CAP_ALL"); + cdlua_pushnumber(CD_CAP_LINECAP, "CD_CAP_LINECAP"); + cdlua_pushnumber(CD_CAP_LINEJOIN, "CD_CAP_LINEJOIN"); + cdlua_pushnumber(CD_CAP_REGION, "CD_CAP_REGION"); + cdlua_pushnumber(CD_CAP_CHORD, "CD_CAP_CHORD"); + cdlua_pushnumber(CD_SIM_FILLS, "CD_SIM_FILLS"); + cdlua_pushnumber(CD_SIM_LINES, "CD_SIM_LINES"); + cdlua_pushnumber(CD_SIM_ALL, "CD_SIM_ALL"); + cdlua_pushnumber(CD_SIM_POLYGON, "CD_SIM_POLYGON"); + cdlua_pushnumber(CD_SIM_SECTOR, "CD_SIM_SECTOR"); + cdlua_pushnumber(CD_SIM_POLYLINE, "CD_SIM_POLYLINE"); + cdlua_pushnumber(CD_SIM_BOX, "CD_SIM_BOX"); + cdlua_pushnumber(CD_SIM_ARC, "CD_SIM_ARC"); + cdlua_pushnumber(CD_SIM_RECT, "CD_SIM_RECT"); + cdlua_pushnumber(CD_SIM_LINE, "CD_SIM_LINE"); + cdlua_pushnumber(CD_SIM_NONE, "CD_SIM_NONE"); + cdlua_pushnumber(CD_SIM_CHORD, "CD_SIM_CHORD"); + cdlua_pushnumber(CD_QUERY, "CD_QUERY"); + cdlua_pushnumber(CD_ERROR, "CD_ERROR"); + cdlua_pushnumber(CD_OK, "CD_OK"); + cdlua_pushnumber(CD_CLIPOFF, "CD_CLIPOFF"); + cdlua_pushnumber(CD_CLIPAREA, "CD_CLIPAREA"); + cdlua_pushnumber(CD_CLIPPOLYGON, "CD_CLIPPOLYGON"); + cdlua_pushnumber(CD_CLIPREGION, "CD_CLIPREGION"); + cdlua_pushnumber(CD_FILL, "CD_FILL"); + cdlua_pushnumber(CD_OPEN_LINES, "CD_OPEN_LINES"); + cdlua_pushnumber(CD_CLOSED_LINES, "CD_CLOSED_LINES"); + cdlua_pushnumber(CD_CLIP, "CD_CLIP"); + cdlua_pushnumber(CD_BEZIER, "CD_BEZIER"); + cdlua_pushnumber(CD_OPAQUE, "CD_OPAQUE"); + cdlua_pushnumber(CD_TRANSPARENT, "CD_TRANSPARENT"); + cdlua_pushnumber(CD_REPLACE, "CD_REPLACE"); + cdlua_pushnumber(CD_XOR, "CD_XOR"); + cdlua_pushnumber(CD_NOT_XOR, "CD_NOT_XOR"); + cdlua_pushnumber(CD_POLITE, "CD_POLITE"); + cdlua_pushnumber(CD_FORCE, "CD_FORCE"); + cdlua_pushnumber(CD_CONTINUOUS, "CD_CONTINUOUS"); + cdlua_pushnumber(CD_DASHED, "CD_DASHED"); + cdlua_pushnumber(CD_DOTTED, "CD_DOTTED"); + cdlua_pushnumber(CD_DASH_DOT, "CD_DASH_DOT"); + cdlua_pushnumber(CD_DASH_DOT_DOT, "CD_DASH_DOT_DOT"); + cdlua_pushnumber(CD_PLUS, "CD_PLUS"); + cdlua_pushnumber(CD_STAR, "CD_STAR"); + cdlua_pushnumber(CD_CIRCLE, "CD_CIRCLE"); + cdlua_pushnumber(CD_X, "CD_X"); + cdlua_pushnumber(CD_BOX, "CD_BOX"); + cdlua_pushnumber(CD_DIAMOND, "CD_DIAMOND"); + cdlua_pushnumber(CD_HOLLOW_CIRCLE, "CD_HOLLOW_CIRCLE"); + cdlua_pushnumber(CD_HOLLOW_BOX, "CD_HOLLOW_BOX"); + cdlua_pushnumber(CD_HOLLOW_DIAMOND, "CD_HOLLOW_DIAMOND"); + cdlua_pushnumber(CD_HORIZONTAL, "CD_HORIZONTAL"); + cdlua_pushnumber(CD_VERTICAL, "CD_VERTICAL"); + cdlua_pushnumber(CD_FDIAGONAL, "CD_FDIAGONAL"); + cdlua_pushnumber(CD_BDIAGONAL, "CD_BDIAGONAL"); + cdlua_pushnumber(CD_CROSS, "CD_CROSS"); + cdlua_pushnumber(CD_DIAGCROSS, "CD_DIAGCROSS"); + cdlua_pushnumber(CD_SOLID, "CD_SOLID"); + cdlua_pushnumber(CD_HATCH, "CD_HATCH"); + cdlua_pushnumber(CD_STIPPLE, "CD_STIPPLE"); + cdlua_pushnumber(CD_PATTERN, "CD_PATTERN"); + cdlua_pushnumber(CD_HOLLOW, "CD_HOLLOW"); + cdlua_pushnumber(CD_NORTH, "CD_NORTH"); + cdlua_pushnumber(CD_SOUTH, "CD_SOUTH"); + cdlua_pushnumber(CD_EAST, "CD_EAST"); + cdlua_pushnumber(CD_WEST, "CD_WEST"); + cdlua_pushnumber(CD_NORTH_EAST, "CD_NORTH_EAST"); + cdlua_pushnumber(CD_NORTH_WEST, "CD_NORTH_WEST"); + cdlua_pushnumber(CD_SOUTH_EAST, "CD_SOUTH_EAST"); + cdlua_pushnumber(CD_SOUTH_WEST, "CD_SOUTH_WEST"); + cdlua_pushnumber(CD_CENTER, "CD_CENTER"); + cdlua_pushnumber(CD_BASE_LEFT, "CD_BASE_LEFT"); + cdlua_pushnumber(CD_BASE_CENTER, "CD_BASE_CENTER"); + cdlua_pushnumber(CD_BASE_RIGHT, "CD_BASE_RIGHT"); + cdlua_pushnumber(CD_SYSTEM, "CD_SYSTEM"); + cdlua_pushnumber(CD_COURIER, "CD_COURIER"); + cdlua_pushnumber(CD_TIMES_ROMAN, "CD_TIMES_ROMAN"); + cdlua_pushnumber(CD_HELVETICA, "CD_HELVETICA"); + cdlua_pushnumber(CD_PLAIN, "CD_PLAIN"); + cdlua_pushnumber(CD_BOLD, "CD_BOLD"); + cdlua_pushnumber(CD_ITALIC, "CD_ITALIC"); + cdlua_pushnumber(CD_BOLD_ITALIC, "CD_BOLD_ITALIC"); + cdlua_pushnumber(CD_SMALL, "CD_SMALL"); + cdlua_pushnumber(CD_STANDARD, "CD_STANDARD"); + cdlua_pushnumber(CD_LARGE, "CD_LARGE"); + cdlua_pushnumber(CD_MM2PT, "CD_MM2PT"); + cdlua_pushnumber(CD_RAD2DEG, "CD_RAD2DEG"); + cdlua_pushnumber(CD_DEG2RAD, "CD_DEG2RAD"); + cdlua_pushnumber(CD_RGBA, "CD_RGBA"); + cdlua_pushnumber(CD_RGB, "CD_RGB"); + cdlua_pushnumber(CD_MAP, "CD_MAP"); + cdlua_pushnumber(CD_IRED, "CD_IRED"); + cdlua_pushnumber(CD_IGREEN, "CD_IGREEN"); + cdlua_pushnumber(CD_IBLUE, "CD_IBLUE"); + cdlua_pushnumber(CD_IALPHA, "CD_IALPHA"); + cdlua_pushnumber(CD_INDEX, "CD_INDEX"); + cdlua_pushnumber(CD_COLORS, "CD_COLORS"); + cdlua_pushnumber(CD_MAP, "CD_MAP"); + cdlua_pushnumber(CD_A0, "CD_A0"); + cdlua_pushnumber(CD_A2, "CD_A2"); + cdlua_pushnumber(CD_A3, "CD_A3"); + cdlua_pushnumber(CD_A1, "CD_A1"); + cdlua_pushnumber(CD_A4, "CD_A4"); + cdlua_pushnumber(CD_A5, "CD_A5"); + cdlua_pushnumber(CD_LETTER, "CD_LETTER"); + cdlua_pushnumber(CD_LEGAL, "CD_LEGAL"); + cdlua_pushnumber(CD_UNION, "CD_UNION"); + cdlua_pushnumber(CD_INTERSECT, "CD_INTERSECT"); + cdlua_pushnumber(CD_DIFFERENCE, "CD_DIFFERENCE"); + cdlua_pushnumber(CD_NOTINTERSECT, "CD_NOTINTERSECT"); + cdlua_pushnumber(CD_REGION, "CD_REGION"); + cdlua_pushnumber(CD_EVENODD, "CD_EVENODD"); + cdlua_pushnumber(CD_WINDING, "CD_WINDING"); + cdlua_pushnumber(CD_BEVEL, "CD_BEVEL"); + cdlua_pushnumber(CD_MITER, "CD_MITER"); + cdlua_pushnumber(CD_ROUND, "CD_ROUND"); + cdlua_pushnumber(CD_CAPROUND, "CD_CAPROUND"); + cdlua_pushnumber(CD_CAPSQUARE, "CD_CAPSQUARE"); + cdlua_pushnumber(CD_CAPFLAT, "CD_CAPFLAT"); + cdlua_pushnumber(CD_CUSTOM, "CD_CUSTOM"); + cdlua_pushnumber(CD_ABORT, "CD_ABORT"); + cdlua_pushnumber(CD_CONTINUE, "CD_CONTINUE"); + + cdlua_register("cdFlush",L_cdFlush); + cdlua_register("cdSimulate",L_cdSimulate); + cdlua_register("cdOrigin",L_cdOrigin); + cdlua_register("cdClear",L_cdClear); + cdlua_register("cdClip",L_cdClip); + cdlua_register("cdClipArea",L_cdClipArea); + cdlua_register("cdLine",L_cdLine); + cdlua_register("cdBox",L_cdBox); + cdlua_register("cdRect",L_cdRect); + cdlua_register("cdArc",L_cdArc); + cdlua_register("cdSector",L_cdSector); + cdlua_register("cdChord",L_cdChord); + cdlua_register("cdText",L_cdText); + cdlua_register("cdBegin",L_cdBegin); + cdlua_register("cdVertex",L_cdVertex); + cdlua_register("cdEnd",L_cdEnd); + cdlua_register("cdOffsetRegion",L_cdOffsetRegion); + cdlua_register("cdPointInRegion",L_cdPointInRegion); + cdlua_register("cdMark",L_cdMark); + cdlua_register("cdBackOpacity",L_cdBackOpacity); + cdlua_register("cdWriteMode",L_cdWriteMode); + cdlua_register("cdRegionCombineMode",L_cdRegionCombineMode); + cdlua_register("cdLineJoin",L_cdLineJoin); + cdlua_register("cdLineCap",L_cdLineCap); + cdlua_register("cdFillMode",L_cdFillMode); + cdlua_register("cdLineStyle",L_cdLineStyle); + cdlua_register("cdLineWidth",L_cdLineWidth); + cdlua_register("cdInteriorStyle",L_cdInteriorStyle); + cdlua_register("cdHatch",L_cdHatch); + cdlua_register("cdFont",L_cdFont); + cdlua_register("cdNativeFont",L_cdNativeFont); + cdlua_register("cdTextAlignment",L_cdTextAlignment); + cdlua_register("cdTextOrientation",L_cdTextOrientation); + cdlua_register("cdMarkType",L_cdMarkType); + cdlua_register("cdMarkSize",L_cdMarkSize); + cdlua_register("cdGetColorPlanes",L_cdGetColorPlanes); + cdlua_register("cdScrollArea",L_cdScrollArea); + cdlua_register("cdVectorFont",L_cdVectorFont); + cdlua_register("cdVectorTextDirection",L_cdVectorTextDirection); + cdlua_register("cdVectorTextSize",L_cdVectorTextSize); + cdlua_register("cdVectorCharSize",L_cdVectorCharSize); + cdlua_register("cdVectorText",L_cdVectorText); + cdlua_register("cdMultiLineVectorText",L_cdMultiLineVectorText); + cdlua_register("cdSetAttribute",L_cdSetAttribute); + cdlua_register("cdGetAttribute",L_cdGetAttribute); + return 1; +} + diff --git a/src/lua3/toluawd.c b/src/lua3/toluawd.c new file mode 100644 index 0000000..2549bcc --- /dev/null +++ b/src/lua3/toluawd.c @@ -0,0 +1,228 @@ +#include <stdlib.h> +#include <stdio.h> + +#include <lua.h> +#include <lauxlib.h> + +#include "cd.h" +#include "wd.h" + +#include "cdlua.h" +#include "cdlua3_private.h" + + +static void L_wdWindow(void) +{ + double xmin = (double)luaL_check_number(1); + double xmax = (double)luaL_check_number(2); + double ymin = (double)luaL_check_number(3); + double ymax = (double)luaL_check_number(4); + wdWindow(xmin,xmax,ymin,ymax); +} + +static void L_wdViewport(void) +{ + int xmin = (int)luaL_check_number(1); + int xmax = (int)luaL_check_number(2); + int ymin = (int)luaL_check_number(3); + int ymax = (int)luaL_check_number(4); + wdViewport(xmin,xmax,ymin,ymax); +} + +static void L_wdClipArea(void) +{ + double xmin = (double)luaL_check_number(1); + double xmax = (double)luaL_check_number(2); + double ymin = (double)luaL_check_number(3); + double ymax = (double)luaL_check_number(4); + wdClipArea(xmin,xmax,ymin,ymax); +} + +static void L_wdLine(void) +{ + double x1 = (double)luaL_check_number(1); + double y1 = (double)luaL_check_number(2); + double x2 = (double)luaL_check_number(3); + double y2 = (double)luaL_check_number(4); + wdLine(x1,y1,x2,y2); +} + +static void L_wdBox(void) +{ + double xmin = (double)luaL_check_number(1); + double xmax = (double)luaL_check_number(2); + double ymin = (double)luaL_check_number(3); + double ymax = (double)luaL_check_number(4); + wdBox(xmin,xmax,ymin,ymax); +} + +static void L_wdRect(void) +{ + double xmin = (double)luaL_check_number(1); + double xmax = (double)luaL_check_number(2); + double ymin = (double)luaL_check_number(3); + double ymax = (double)luaL_check_number(4); + wdRect(xmin,xmax,ymin,ymax); +} + +static void L_wdArc(void) +{ + double xc = (double)luaL_check_number(1); + double yc = (double)luaL_check_number(2); + double w = (double)luaL_check_number(3); + double h = (double)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + wdArc(xc,yc,w,h,angle1,angle2); +} + +static void L_wdSector(void) +{ + double xc = (double)luaL_check_number(1); + double yc = (double)luaL_check_number(2); + double w = (double)luaL_check_number(3); + double h = (double)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + wdSector(xc,yc,w,h,angle1,angle2); +} + +static void L_wdChord(void) +{ + double xc = (double)luaL_check_number(1); + double yc = (double)luaL_check_number(2); + double w = (double)luaL_check_number(3); + double h = (double)luaL_check_number(4); + double angle1 = (double)luaL_check_number(5); + double angle2 = (double)luaL_check_number(6); + wdChord(xc,yc,w,h,angle1,angle2); +} + +static void L_wdText(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + wdText(x,y,s); +} + +static void L_wdVertex(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + wdVertex(x,y); +} + +static void L_wdMark(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + wdMark(x,y); +} + +static void L_wdOffsetRegion(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + wdOffsetRegion(x,y); +} + +static void L_wdPointInRegion(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + int L_result = wdPointInRegion(x,y); + lua_pushnumber((double)L_result); +} + +static void L_wdLineWidth(void) +{ + double width = (double)luaL_check_number(1); + double L_result = wdLineWidth(width); + lua_pushnumber(L_result); +} + +static void L_wdFont(void) +{ + int type_face = (int)luaL_check_number(1); + int style = (int)luaL_check_number(2); + double size = (double)luaL_check_number(3); + wdFont(type_face,style,size); +} + +static void L_wdMarkSize(void) +{ + double size = (double)luaL_check_number(1); + double L_result = wdMarkSize(size); + lua_pushnumber(L_result); +} + +static void L_wdVectorTextDirection(void) +{ + double x1 = (double)luaL_check_number(1); + double y1 = (double)luaL_check_number(2); + double x2 = (double)luaL_check_number(3); + double y2 = (double)luaL_check_number(4); + wdVectorTextDirection(x1,y1,x2,y2); +} + +static void L_wdVectorTextSize(void) +{ + double size_x = (double)luaL_check_number(1); + double size_y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + wdVectorTextSize(size_x,size_y,s); +} + +static void L_wdVectorCharSize(void) +{ + double size = (double)luaL_check_number(1); + double L_result = wdVectorCharSize(size); + lua_pushnumber(L_result); +} + +static void L_wdVectorText(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + wdVectorText(x,y,s); +} + +static void L_wdMultiLineVectorText(void) +{ + double x = (double)luaL_check_number(1); + double y = (double)luaL_check_number(2); + char* s = (char*)luaL_check_string(3); + wdMultiLineVectorText(x,y,s); +} + + +/* ---------------------------------------- public interface */ +int luaL_wd_open(void) +{ + cdlua_register("wdWindow",L_wdWindow); + cdlua_register("wdViewport",L_wdViewport); + cdlua_register("wdClipArea",L_wdClipArea); + cdlua_register("wdLine",L_wdLine); + cdlua_register("wdBox",L_wdBox); + cdlua_register("wdRect",L_wdRect); + cdlua_register("wdArc",L_wdArc); + cdlua_register("wdSector",L_wdSector); + cdlua_register("wdChord",L_wdChord); + cdlua_register("wdText",L_wdText); + cdlua_register("wdVertex",L_wdVertex); + cdlua_register("wdMark",L_wdMark); + cdlua_register("wdOffsetRegion",L_wdOffsetRegion); + cdlua_register("wdPointInRegion",L_wdPointInRegion); + cdlua_register("wdLineWidth",L_wdLineWidth); + cdlua_register("wdFont",L_wdFont); + cdlua_register("wdMarkSize",L_wdMarkSize); + cdlua_register("wdVectorTextDirection",L_wdVectorTextDirection); + cdlua_register("wdVectorTextSize",L_wdVectorTextSize); + cdlua_register("wdVectorCharSize",L_wdVectorCharSize); + cdlua_register("wdVectorText",L_wdVectorText); + cdlua_register("wdMultiLineVectorText",L_wdMultiLineVectorText); + return 1; +} + diff --git a/src/lua5/cdlua5.c b/src/lua5/cdlua5.c new file mode 100644 index 0000000..9ee3d4e --- /dev/null +++ b/src/lua5/cdlua5.c @@ -0,0 +1,1819 @@ +/** \file + * \brief Lua Binding + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "cd.h" +#include "cdgdiplus.h" +#include "cdnative.h" +#include "cdps.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdlua5_private.h" + + +/***************************************************************************\ +* Initialization * +\***************************************************************************/ + +static const char* cdlua_key = "cdlua5"; + +static void cdlua_SetState(lua_State * L, cdluaLuaState* cdL) +{ + lua_pushlightuserdata(L, (void*)cdlua_key); + lua_pushlightuserdata(L, (void*)cdL); + lua_settable(L, LUA_REGISTRYINDEX); /* registry[address("cdlua5")]=cdL */ + lua_pop(L, 1); +} + +cdluaLuaState* cdlua_getstate(lua_State * L) +{ + cdluaLuaState* cdL; + lua_pushlightuserdata(L, (void*)cdlua_key); + lua_gettable(L, LUA_REGISTRYINDEX); + cdL = (cdluaLuaState*)lua_touserdata(L, -1); + lua_pop(L, 1); + return cdL; +} + +cdluaContext* cdlua_getcontext(lua_State * L, int param) +{ + cdluaLuaState* cdL = cdlua_getstate(L); + + int driver = luaL_checkint(L, param); + if ((driver < 0) || (driver >= cdL->numdrivers)) + luaL_argerror(L, param, "unknown driver"); + + return cdL->drivers[driver]; +} + +static lua_State* cdlua5_play_luaState = NULL; + +lua_State* cdlua_getplaystate(void) +{ + return cdlua5_play_luaState; +} + +void cdlua_setplaystate(lua_State* L) +{ + cdlua5_play_luaState = L; +} + +static cdluaPalette* cdlua_rawcheckpalette(lua_State *L, int param) +{ + void *p = lua_touserdata(L, param); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, param)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, "cdPalette"); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return (cdluaPalette*)p; + } + lua_pop(L, 1); /* remove previous metatable */ + + /* check also for IM palette */ + lua_getfield(L, LUA_REGISTRYINDEX, "imPalette"); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return (cdluaPalette*)p; + } + } + } + luaL_typerror(L, param, "cdPalette"); /* else error */ + return NULL; /* to avoid warnings */ +} + +cdluaPalette * cdlua_checkpalette(lua_State * L, int param) +{ + cdluaPalette * pal = cdlua_rawcheckpalette(L, param); + if (!pal->color) + luaL_argerror(L, param, "killed cdPalette"); + return pal; +} + +void cdlua_pushpalette(lua_State* L, long* palette, int size) +{ + cdluaPalette* pal = (cdluaPalette*)lua_newuserdata(L, sizeof(cdluaPalette)); + luaL_getmetatable(L, "cdPalette"); + lua_setmetatable(L, -2); + + pal->count = size; + pal->color = palette; +} + +cdState * cdlua_checkstate(lua_State* L, int param) +{ + cdState** state_p = (cdState**)luaL_checkudata(L, param, "cdState"); + if (!(*state_p)) + luaL_argerror(L, param, "released cdState"); + return *state_p; +} + +void cdlua_pushstate(lua_State* L, cdState* state) +{ + cdState** state_p = (cdState**)lua_newuserdata(L, sizeof(cdState*)); + luaL_getmetatable(L, "cdState"); + lua_setmetatable(L, -2); + + *state_p = state; +} + +cdluaPattern* cdlua_checkpattern(lua_State* L, int param) +{ + cdluaPattern* pattern_p = (cdluaPattern*) luaL_checkudata(L, param, "cdPattern"); + if (!pattern_p->pattern) + luaL_argerror(L, param, "killed cdPattern"); + return pattern_p; +} + +void cdlua_pushpattern(lua_State* L, long int* pattern, int width, int height) +{ + cdluaPattern* pattern_p = (cdluaPattern*)lua_newuserdata(L, sizeof(cdluaPattern)); + luaL_getmetatable(L, "cdPattern"); + lua_setmetatable(L, -2); + + pattern_p->pattern = pattern; + pattern_p->width = width; + pattern_p->height = height; + pattern_p->size = width * height; +} + +cdluaStipple* cdlua_checkstipple(lua_State* L, int param) +{ + cdluaStipple* stipple_p = (cdluaStipple*) luaL_checkudata(L, param, "cdStipple"); + if (!stipple_p->stipple) + luaL_argerror(L, param, "killed cdStipple"); + return stipple_p; +} + +void cdlua_pushstipple(lua_State* L, unsigned char* stipple, int width, int height) +{ + cdluaStipple* stipple_p = (cdluaStipple*)lua_newuserdata(L, sizeof(cdluaStipple)); + luaL_getmetatable(L, "cdStipple"); + lua_setmetatable(L, -2); + + stipple_p->stipple = stipple; + stipple_p->width = width; + stipple_p->height = height; + stipple_p->size = width * height; +} + +cdluaImageRGB* cdlua_checkimagergb(lua_State* L, int param) +{ + cdluaImageRGB* imagergb_p = (cdluaImageRGB*) luaL_checkudata(L, param, "cdImageRGB"); + if (!imagergb_p->red) + luaL_argerror(L, param, "killed cdImageRGB"); + return imagergb_p; +} + +void cdlua_pushimagergb(lua_State* L, unsigned char* red, unsigned char* green, unsigned char* blue, int width, int height) +{ + cdluaImageRGB* imagergb_p = (cdluaImageRGB*)lua_newuserdata(L, sizeof(cdluaImageRGB)); + luaL_getmetatable(L, "cdImageRGB"); + lua_setmetatable(L, -2); + + imagergb_p->red = red; + imagergb_p->green = green; + imagergb_p->blue = blue; + imagergb_p->width = width; + imagergb_p->height = height; + imagergb_p->size = width * height; + imagergb_p->free = 1; +} + +void cdlua_pushimagergb_ex(lua_State* L, unsigned char* red, unsigned char* green, unsigned char* blue, int width, int height) +{ + cdluaImageRGB* imagergb_p = (cdluaImageRGB*)lua_newuserdata(L, sizeof(cdluaImageRGB)); + luaL_getmetatable(L, "cdImageRGB"); + lua_setmetatable(L, -2); + + imagergb_p->red = red; + imagergb_p->green = green; + imagergb_p->blue = blue; + imagergb_p->width = width; + imagergb_p->height = height; + imagergb_p->size = width * height; + imagergb_p->free = 0; +} + +cdluaImageRGBA* cdlua_checkimagergba(lua_State* L, int param) +{ + cdluaImageRGBA* imagergba_p = (cdluaImageRGBA*) luaL_checkudata(L, param, "cdImageRGBA"); + if (!imagergba_p->red) + luaL_argerror(L, param, "killed cdImageRGBA"); + return imagergba_p; +} + +void cdlua_pushimagergba(lua_State* L, unsigned char* red, unsigned char* green, unsigned char* blue, unsigned char* alpha, int width, int height) +{ + cdluaImageRGBA* imagergba_p = (cdluaImageRGBA*)lua_newuserdata(L, sizeof(cdluaImageRGBA)); + luaL_getmetatable(L, "cdImageRGBA"); + lua_setmetatable(L, -2); + + imagergba_p->red = red; + imagergba_p->green = green; + imagergba_p->blue = blue; + imagergba_p->alpha = alpha; + imagergba_p->width = width; + imagergba_p->height = height; + imagergba_p->size = width * height; + imagergba_p->free = 1; +} + +void cdlua_pushimagergba_ex(lua_State* L, unsigned char* red, unsigned char* green, unsigned char* blue, unsigned char* alpha, int width, int height) +{ + cdluaImageRGBA* imagergba_p = (cdluaImageRGBA*)lua_newuserdata(L, sizeof(cdluaImageRGBA)); + luaL_getmetatable(L, "cdImageRGBA"); + lua_setmetatable(L, -2); + + imagergba_p->red = red; + imagergba_p->green = green; + imagergba_p->blue = blue; + imagergba_p->alpha = alpha; + imagergba_p->width = width; + imagergba_p->height = height; + imagergba_p->size = width * height; + imagergba_p->free = 0; +} + +cdluaImageMap* cdlua_checkimagemap(lua_State* L, int param) +{ + cdluaImageMap* imagemap_p = (cdluaImageMap*) luaL_checkudata(L, param, "cdImageMap"); + if (!imagemap_p->index) + luaL_argerror(L, param, "killed cdImageMap"); + return imagemap_p; +} + +void cdlua_pushimagemap(lua_State* L, unsigned char* index, int width, int height) +{ + cdluaImageMap* imagemap_p = (cdluaImageMap*)lua_newuserdata(L, sizeof(cdluaImageMap)); + luaL_getmetatable(L, "cdImageMap"); + lua_setmetatable(L, -2); + + imagemap_p->index = index; + imagemap_p->width = width; + imagemap_p->height = height; + imagemap_p->size = width * height; +} + +cdluaImageChannel* cdlua_checkchannel(lua_State* L, int param) +{ + cdluaImageChannel* channel_p = (cdluaImageChannel*) luaL_checkudata(L, param, "cdImageChannel"); + if (!channel_p->channel) + luaL_argerror(L, param, "killed cdImageChannel"); + return channel_p; +} + +void cdlua_pushchannel(lua_State* L, unsigned char* channel, int size) +{ + cdluaImageChannel* channel_p = (cdluaImageChannel*)lua_newuserdata(L, sizeof(cdluaImageChannel)); + luaL_getmetatable(L, "cdImageChannel"); + lua_setmetatable(L, -2); + + channel_p->channel = channel; + channel_p->size = size; +} + +long cdlua_checkcolor(lua_State* L, int param) +{ + if (!lua_islightuserdata(L, param)) + luaL_argerror(L, param, "invalid color, must be a light user data"); + + return (long int)lua_touserdata(L, param); +} + +cdImage* cdlua_checkimage(lua_State* L, int param) +{ + cdImage** image_p = (cdImage**)luaL_checkudata(L, param, "cdImage"); + if (!(*image_p)) + luaL_argerror(L, param, "killed cdImage"); + return *image_p; +} + +void cdlua_pushimage(lua_State* L, cdImage* image) +{ + cdImage** image_p = (cdImage**)lua_newuserdata(L, sizeof(cdImage*)); + luaL_getmetatable(L, "cdImage"); + lua_setmetatable(L, -2); + + *image_p = image; +} + +cdBitmap * cdlua_checkbitmap(lua_State* L, int param) +{ + cdBitmap** bitmap_p = (cdBitmap**)luaL_checkudata(L, param, "cdBitmap"); + if (!(*bitmap_p)) + luaL_argerror(L, param, "killed cdBitmap"); + return *bitmap_p; +} + +void cdlua_pushbitmap(lua_State* L, cdBitmap* bitmap) +{ + cdBitmap** bitmap_p = (cdBitmap**)lua_newuserdata(L, sizeof(cdBitmap*)); + luaL_getmetatable(L, "cdBitmap"); + lua_setmetatable(L, -2); + + *bitmap_p = bitmap; +} + +/***************************************************************************\ +* cd.ContextCaps(ctx: number) -> (caps: number) * +\***************************************************************************/ +static int cdlua5_contextcaps(lua_State * L) +{ + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 1); + lua_pushnumber(L, cdContextCaps(cdlua_ctx->ctx())); + return 1; +} + +static int cdlua5_releasestate(lua_State * L) +{ + cdState* *state_p = (cdState* *) luaL_checkudata(L, 1, "cdState"); + if (*state_p) + { + cdReleaseState(*state_p); + *state_p = NULL; /* mark as released */ + } + + return 0; +} + +static int cdlua5_createstipple(lua_State *L) +{ + int size; + unsigned char* stipple; + + int width = luaL_checkint(L, 1); + int height = luaL_checkint(L, 2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "stipple dimensions should be positive integers"); + + size = width * height; + stipple = (unsigned char *) malloc(size); + memset(stipple, '\0', size); + + cdlua_pushstipple(L, stipple, width, height); + + return 1; +} + +static int cdlua5_killstipple(lua_State *L) +{ + cdluaStipple *stipple_p = (cdluaStipple*)luaL_checkudata(L, 1, "cdStipple"); + if (stipple_p->stipple) + { + free(stipple_p->stipple); + stipple_p->stipple = NULL; /* mark as killed */ + } + + return 0; +} + +/***************************************************************************\ +* number = stipple[i] * +\***************************************************************************/ +static int cdlua5_indexstipple(lua_State *L) +{ + cdluaStipple* stipple_p = cdlua_checkstipple(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= stipple_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + lua_pushnumber(L, stipple_p->stipple[index]); + return 1; +} + +/***************************************************************************\ +* stipple[i] = number . * +\***************************************************************************/ +static int cdlua5_newindexstipple(lua_State *L) +{ + unsigned char value; + + cdluaStipple* stipple_p = cdlua_checkstipple(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= stipple_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + value = (unsigned char)luaL_checkint(L, 3); + if ((value != 0 && value != 1)) + luaL_argerror(L, 3, "value must be 0 or 1"); + + stipple_p->stipple[index] = value; + return 0; +} + +static int cdlua5_createpattern(lua_State *L) +{ + int size; + long int *pattern; + + int width = luaL_checkint(L, 1); + int height = luaL_checkint(L, 2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "pattern dimensions should be positive integers"); + + size = width * height; + pattern = (long int *) malloc(size * sizeof(long int)); + memset(pattern, 255, size * sizeof(long int)); + + cdlua_pushpattern(L, pattern, width, height); + + return 1; +} + +static int cdlua5_killpattern(lua_State *L) +{ + cdluaPattern *pattern_p = (cdluaPattern *) luaL_checkudata(L, 1, "cdPattern"); + if (pattern_p->pattern) + { + free(pattern_p->pattern); + pattern_p->pattern = NULL; /* mark as killed */ + } + + return 0; +} + +/***************************************************************************\ +* color = pattern[i] * +\***************************************************************************/ +static int cdlua5_indexpattern(lua_State *L) +{ + cdluaPattern* pattern_p = cdlua_checkpattern(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= pattern_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + lua_pushlightuserdata(L, (void *) pattern_p->pattern[index]); + return 1; +} + +/***************************************************************************\ +* pattern[i] = color * +\***************************************************************************/ +static int cdlua5_newindexpattern(lua_State *L) +{ + long int color; + + cdluaPattern* pattern_p = cdlua_checkpattern(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= pattern_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + color = cdlua_checkcolor(L, 3); + + pattern_p->pattern[index] = color; + return 0; +} + +static int cdlua5_rgb2map(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 1); + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 2); + cdluaPalette* pal = cdlua_checkpalette(L, 3); + cdRGB2Map(imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue, + imagemap_p->index, pal->count, pal->color); + return 0; +} + +static int cdlua5_createbitmap(lua_State *L) +{ + cdBitmap *bitmap; + + int width = luaL_checkint(L, 1); + int height = luaL_checkint(L, 2); + int type = luaL_checkint(L, 3); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "bitmap dimensions should be positive integers"); + + bitmap = cdCreateBitmap(width, height, type); + if (bitmap) + cdlua_pushbitmap(L, bitmap); + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_killbitmap(lua_State *L) +{ + cdBitmap* *bitmap_p = (cdBitmap* *) luaL_checkudata(L, 1, "cdBitmap"); + if (*bitmap_p) + { + cdKillBitmap(*bitmap_p); + *bitmap_p = NULL; /* mark as killed */ + } + + return 0; +} + +static int cdlua5_bitmapgetdata(lua_State *L) +{ + cdBitmap* bitmap = cdlua_checkbitmap(L, 1); + int dataptr = luaL_checkint(L, 2); + + unsigned char *data = cdBitmapGetData(bitmap, dataptr); + if (data) + cdlua_pushchannel(L, data, bitmap->w * bitmap->h); + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_bitmapsetrect(lua_State *L) +{ + cdBitmap* bitmap = cdlua_checkbitmap(L, 1); + int xmin = (int) luaL_checkint(L, 2); + int xmax = (int) luaL_checkint(L, 3); + int ymin = (int) luaL_checkint(L, 4); + int ymax = (int) luaL_checkint(L, 5); + + cdBitmapSetRect(bitmap, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_bitmaprgb2map(lua_State *L) +{ + cdBitmap* bitmaprgb = cdlua_checkbitmap(L, 1); + cdBitmap* bitmapmap = cdlua_checkbitmap(L, 2); + + if (bitmaprgb->type != CD_RGB) + luaL_argerror(L, 1, "invalid bitmap type, must be RGB"); + if (bitmapmap->type != CD_MAP) + luaL_argerror(L, 2, "invalid bitmap type, must be Map"); + + cdBitmapRGB2Map(bitmaprgb, bitmapmap); + return 0; +} + +static int cdlua5_createimagergb(lua_State * L) +{ + unsigned char *red, *green, *blue; + int size; + int width = luaL_checkint(L,1); + int height = luaL_checkint(L,2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "image dimensions should be positive integers"); + + size = width*height; + red = (unsigned char*)malloc(3*size); + + if (red) + { + memset(red, 255, 3*size); /* white */ + green = red + size; + blue = red + 2*size; + cdlua_pushimagergb(L, red, green, blue, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_killimagergb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = (cdluaImageRGB*)luaL_checkudata(L, 1, "cdImageRGB"); + if (imagergb_p->red && imagergb_p->free) + { + free(imagergb_p->red); + imagergb_p->red = NULL; /* mark as killed */ + imagergb_p->green = NULL; + imagergb_p->blue = NULL; + } + + return 0; +} + +static int cdlua5_createimagergba(lua_State * L) +{ + unsigned char *red, *green, *blue, *alpha; + int size; + int width = luaL_checkint(L,1); + int height = luaL_checkint(L,2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "image dimensions should be positive integers"); + + size = width*height; + red = (unsigned char*)malloc(4*size); + + if (red) + { + memset(red, 255, 3*size); /* white */ + green = red + size; + blue = red + 2*size; + alpha = red + 3*size; + memset(alpha, 0, size); /* transparent */ + cdlua_pushimagergba(L, red, green, blue, alpha, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_killimagergba(lua_State *L) +{ + cdluaImageRGBA* imagergba_p = (cdluaImageRGBA*)luaL_checkudata(L, 1, "cdImageRGBA"); + if (imagergba_p->red && imagergba_p->free) + { + free(imagergba_p->red); + imagergba_p->red = NULL; /* mark as killed */ + imagergba_p->green = NULL; + imagergba_p->blue = NULL; + imagergba_p->alpha = NULL; + } + + return 0; +} + +static int cdlua5_createimagemap(lua_State *L) +{ + int size; + unsigned char *index; + int width = luaL_checkint(L,1); + int height = luaL_checkint(L,2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "imagemap dimensions should be positive integers"); + + size = width * height; + index = (unsigned char *) malloc(size); + + if (index) + { + memset(index, 0, size); + cdlua_pushimagemap(L, index, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_killimagemap(lua_State *L) +{ + cdluaImageMap *imagemap_p = (cdluaImageMap *) luaL_checkudata(L, 1, "cdImageMap"); + if (imagemap_p->index) + { + free(imagemap_p->index); + imagemap_p->index = NULL; /* mark as killed */ + } + + return 0; +} + +/***************************************************************************\ +* number = imagemap[i] * +\***************************************************************************/ +static int cdlua5_indeximagemap(lua_State *L) +{ + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= imagemap_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + lua_pushnumber(L, imagemap_p->index[index]); + return 1; +} + +/***************************************************************************\ +* imagemap[i] = number * +\***************************************************************************/ +static int cdlua5_newindeximagemap(lua_State *L) +{ + int value; + + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= imagemap_p->size) + luaL_argerror(L, 2, "index is out of bounds"); + + value = luaL_checkint(L, 3); + if ((value < 0 || value > 255)) + luaL_argerror(L, 3, "value should be in range [0, 255]"); + + imagemap_p->index[index] = (unsigned char) value; + return 0; +} + +/***************************************************************************\ +* channel "gettable" fallback. This fallback is called when a LUA line like * +* "c = imagergb.r[y*w + x]" is executed. The imagergb "gettable" fallback * +* fills and returns a channel structure with info about the buffer. This * +* structure is consulted and the appropriate value is returned. * +\***************************************************************************/ +static int cdlua5_indexchannel(lua_State *L) +{ + cdluaImageChannel* channel_p = cdlua_checkchannel(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || + (channel_p->size > 0 && index >= channel_p->size) || + (channel_p->size == -1 && index >= 256)) { + luaL_argerror(L, 2, "index is out of bounds"); + } + + if (channel_p->size == -1) /* COLORS */ + lua_pushlightuserdata(L, (void *)((long int*)channel_p->channel)[index]); + else + lua_pushnumber(L, channel_p->channel[index]); + + return 1; +} + +/***************************************************************************\ +* channel "settable" fallback. This fallback is called when a LUA line like * +* "imagergb.r[y*w + x] = c" is executed. The imagergb "gettable" fallback * +* fills and returns a channel structure with info about the buffer. This * +* structure is consulted and the value is assigned where it should. * +\***************************************************************************/ +static int cdlua5_newindexchannel(lua_State *L) +{ + int value; + + cdluaImageChannel* channel_p = cdlua_checkchannel(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || + (channel_p->size > 0 && index >= channel_p->size) || + (channel_p->size == -1 && index >= 256)) { + luaL_argerror(L, 2, "index is out of bounds"); + } + + if (channel_p->size > 0) + { + value = luaL_checkint(L, 3); + if ((value < 0 || value > 255)) + luaL_argerror(L, 3, "value should be in range [0, 255]"); + channel_p->channel[index] = (unsigned char) value; + } + else /* COLORS */ + { + value = (long int) cdlua_checkcolor(L, 3); + ((long int*)channel_p->channel)[index] = value; + } + return 0; +} + +/***************************************************************************\ +* imagergb "gettable" fallback. This fallback is called when a LUA line * +* like "c = imagergb.r[y*w + x]" or "imagergb.r[y*w + x] = c" is executed. * +* The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static int cdlua5_indeximagergb(lua_State *L) +{ + unsigned char* channel = NULL; + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 1); + const char *index_s = luaL_checkstring(L, 2); + + if (*index_s == 'r' || *index_s == 'R') + channel = imagergb_p->red; + else if (*index_s == 'g' || *index_s == 'G') + channel = imagergb_p->green; + else if (*index_s == 'b' || *index_s == 'B') + channel = imagergb_p->blue; + else + luaL_argerror(L, 2, "index is an invalid channel name"); + + cdlua_pushchannel(L, channel, imagergb_p->size); + + return 1; +} + +/***************************************************************************\ +* imagergba "gettable" fallback. This fallback is called when a LUA line * +* like "c = imagergba.r[y*w + x]" or "imagergba.r[y*w + x] = c" is executed.* +* The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static int cdlua5_indeximagergba(lua_State *L) +{ + unsigned char* channel = NULL; + cdluaImageRGBA* imagergba_p = cdlua_checkimagergba(L, 1); + const char *index_s = luaL_checkstring(L, 2); + + if (*index_s == 'r' || *index_s == 'R') + channel = imagergba_p->red; + else if (*index_s == 'g' || *index_s == 'G') + channel = imagergba_p->green; + else if (*index_s == 'b' || *index_s == 'B') + channel = imagergba_p->blue; + else if (*index_s == 'a' || *index_s == 'A') + channel = imagergba_p->alpha; + else + luaL_argerror(L, 2, "index is an invalid channel name"); + + cdlua_pushchannel(L, channel, imagergba_p->size); + + return 1; +} + +/***************************************************************************\ +* bitmap "gettable" fallback. This fallback is called when a LUA line * +* like "c = bitmap.r[y*w + x]" or "bitmap.r[y*w + x] = c" is executed. * +* The following "gettable" or "settable" * +* then assigns or returns the appropriate value. * +\***************************************************************************/ +static int cdlua5_indexbitmap(lua_State *L) +{ + unsigned char* channel = NULL; + + cdBitmap* bitmap = cdlua_checkbitmap(L, 1); + const char *index_s = luaL_checkstring(L, 2); + + int size = bitmap->w * bitmap->h; + + if (*index_s == 'r' || *index_s == 'R') + channel = cdBitmapGetData(bitmap, CD_IRED); + else if (*index_s == 'g' || *index_s == 'G') + channel = cdBitmapGetData(bitmap, CD_IGREEN); + else if (*index_s == 'b' || *index_s == 'B') + channel = cdBitmapGetData(bitmap, CD_IBLUE); + else if (*index_s == 'a' || *index_s == 'A') + channel = cdBitmapGetData(bitmap, CD_IALPHA); + else if (*index_s == 'i' || *index_s == 'I') + channel = cdBitmapGetData(bitmap, CD_INDEX); + else if (*index_s == 'c' || *index_s == 'C') + { + channel = cdBitmapGetData(bitmap, CD_COLORS); + size = -1; + } + else + luaL_argerror(L, 2, "index is an invalid channel name"); + + cdlua_pushchannel(L, channel, size); + + return 1; +} + +static int cdlua5_killimage(lua_State *L) +{ + cdImage* *image_p = (cdImage* *) luaL_checkudata(L, 1, "cdImage"); + if (*image_p) + { + cdKillImage(*image_p); + *image_p = NULL; /* mark as killed */ + } + return 0; +} + +/***************************************************************************\ +* cd.Version() -> (version: string) * +\***************************************************************************/ +static int cdlua5_version(lua_State *L) +{ + lua_pushstring(L, cdVersion()); + return 1; +} + +/***************************************************************************\ +* Register callback functions. * +* cd.ContextRegisterCallback(ctx, cb: number, func: function) -> (status: number) * +\***************************************************************************/ +static int cdlua5_registercallback(lua_State *L) +{ + int cb_i, func_lock; + cdluaCallback* cdCB; + cdluaContext* cdlua_ctx; + + cdlua_ctx = cdlua_getcontext(L, 1); + + cb_i = luaL_checkint(L, 2); + if (cb_i >= cdlua_ctx->cb_n) + luaL_argerror(L, 2, "invalid callback parameter"); + + if (lua_isnil(L, 3)) + func_lock = -1; + else if (!lua_isfunction(L, 3)) + luaL_argerror(L, 3, "invalid function parameter"); + else + lua_pushvalue(L, 3); + func_lock = lua_ref(L, 1); + + cdCB = &cdlua_ctx->cb_list[cb_i]; + + if (cdCB->lock != -1) + { + lua_unref(L,cdCB->lock); + cdCB->lock = func_lock; + if (func_lock == -1) + { + cdContextRegisterCallback(cdlua_ctx->ctx(), cb_i, NULL); + } + } + else + { + if (func_lock != -1) + { + cdContextRegisterCallback(cdlua_ctx->ctx(), cb_i, (cdCallback)cdCB->func); + cdCB->lock = func_lock; + } + } + return 0; +} + + + +/***************************************************************************\ +* Color Coding * +\***************************************************************************/ + +/***************************************************************************\ +* Creates a color as a light userdata. The color value is * +* placed in the (void *) value. Not beautiful, but works best. * +* cd.EncodeColor(r, g, b: number) -> (old_color: color) * +\***************************************************************************/ +static int cdlua5_encodecolor(lua_State *L) +{ + int red_f, green_f, blue_f; + unsigned char red_i, green_i, blue_i; + long int color; + + red_f = luaL_checkint(L, 1); + green_f = luaL_checkint(L, 2); + blue_f = luaL_checkint(L, 3); + + if (red_f < 0 || red_f > 255) + luaL_argerror(L, 1, "color components values should be in range [0, 255]"); + if (green_f < 0 || green_f > 255) + luaL_argerror(L, 2, "color components values should be in range [0, 255]"); + if (blue_f < 0 || blue_f > 255) + luaL_argerror(L, 3, "color components values should be in range [0, 255]"); + + red_i = (unsigned char) (red_f); + green_i = (unsigned char) (green_f); + blue_i = (unsigned char) (blue_f); + + color = cdEncodeColor(red_i, green_i, blue_i); + lua_pushlightuserdata(L, (void *)color); + + return 1; +} + +/***************************************************************************\ +* Decodes a color previously created. * +* cd.DecodeColor(color: color) -> (r, g, b: number) * +\***************************************************************************/ +static int cdlua5_decodecolor(lua_State *L) +{ + unsigned char red_i, green_i, blue_i; + long int color = cdlua_checkcolor(L, 1); + cdDecodeColor(color, &red_i, &green_i, &blue_i); + lua_pushnumber(L, red_i); + lua_pushnumber(L, green_i); + lua_pushnumber(L, blue_i); + + return 3; +} + +/***************************************************************************\ +* cd.EncodeAlpha(color: color_tag, alpha: number) -> (color: color) * +\***************************************************************************/ +static int cdlua5_encodealpha(lua_State *L) +{ + float alpha_f; + unsigned char alpha_i; + long int color; + + color = cdlua_checkcolor(L, 1); + + if (!lua_isnumber(L, 2)) + luaL_argerror(L, 2, "invalid alpha parameter"); + + alpha_f = (float) lua_tonumber(L, 2); + + if (alpha_f < 0 || alpha_f > 255) + luaL_argerror(L, 2, "alpha components values should be in range [0, 255]"); + + alpha_i = (unsigned char) (alpha_f); + + color = cdEncodeAlpha(color, alpha_i); + lua_pushlightuserdata(L, (void *) color); + return 1; +} + +/***************************************************************************\ +* cd.DecodeAlpha(color: color) -> (a: number) * +\***************************************************************************/ +static int cdlua5_decodealpha(lua_State* L) +{ + long int color = cdlua_checkcolor(L, 1); + unsigned char alpha_i = cdDecodeAlpha(color); + lua_pushnumber(L, alpha_i); + return 1; +} + +/***************************************************************************\ +* cd.Alpha(color: color) -> (r: number) * +\***************************************************************************/ +static int cdlua5_alpha(lua_State* L) +{ + long int color = cdlua_checkcolor(L, 1); + lua_pushnumber(L, cdAlpha(color)); + return 1; +} + +/***************************************************************************\ +* cd.Red(color: color) -> (r: number) * +\***************************************************************************/ +static int cdlua5_red(lua_State* L) +{ + long int color = cdlua_checkcolor(L, 1); + lua_pushnumber(L, cdRed(color)); + return 1; +} + +/***************************************************************************\ +* cd.Blue(color: color) -> (r: number) * +\***************************************************************************/ +static int cdlua5_blue(lua_State *L) +{ + long int color = cdlua_checkcolor(L, 1); + lua_pushnumber(L, cdBlue(color)); + return 1; +} + +/***************************************************************************\ +* cd.Green(color: color) -> (r: number) * +\***************************************************************************/ +static int cdlua5_green(lua_State *L) +{ + long int color = cdlua_checkcolor(L, 1); + lua_pushnumber(L, cdGreen(color)); + return 1; +} + +static int cdlua5_createpalette(lua_State *L) +{ + int size_i; + long int *palette; + + size_i = luaL_checkint(L, 1); + if (size_i < 1) + luaL_argerror(L, 1, "palette size should be a positive integer"); + + palette = (long int *) malloc(256 * sizeof(long int)); + memset(palette, 0, 256 * sizeof(long int)); + + cdlua_pushpalette(L, palette, size_i); + + return 1; +} + +static int cdlua5_killpalette(lua_State *L) +{ + cdluaPalette* pal = (cdluaPalette *)luaL_checkudata(L, 1, "cdPalette"); + if (pal->color) + { + free(pal->color); + pal->color = NULL; /* mark as killed */ + } + + return 0; +} + +/***************************************************************************\ +* color = palette[i] * +\***************************************************************************/ +static int cdlua5_indexpalette(lua_State *L) +{ + cdluaPalette* pal = cdlua_checkpalette(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= pal->count) + luaL_argerror(L, 2, "index is out of bounds"); + + lua_pushlightuserdata(L, (void*) pal->color[index]); + return 1; +} + +/***************************************************************************\ +* palette[i] = color * +\***************************************************************************/ +static int cdlua5_newindexpalette(lua_State *L) +{ + long int color; + cdluaPalette* pal = cdlua_checkpalette(L, 1); + + int index = luaL_checkint(L, 2); + if (index < 0 || index >= pal->count) + luaL_argerror(L, 2, "index is out of bounds"); + + color = cdlua_checkcolor(L, 3); + + pal->color[index] = color; + return 0; +} + +/*****************************************************************************\ + len +\*****************************************************************************/ +static int cdluaPalette_len(lua_State *L) +{ + cdluaPalette *pal = (cdluaPalette*)lua_touserdata(L, 1); + lua_pushinteger(L, pal->count); + return 1; +} + +/*****************************************************************************\ + tostring +\*****************************************************************************/ +static int cdlua5_tostringpalette (lua_State *L) +{ + cdluaPalette *pal = (cdluaPalette*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdPalette(%p)%s", pal, (pal->color)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringimage (lua_State *L) +{ + cdImage* *image_p = (cdImage**)lua_touserdata(L, 1); + lua_pushfstring(L, "cdImage(%p)%s", image_p, (*image_p)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringbitmap (lua_State *L) +{ + cdBitmap* *bitmap_p = (cdBitmap**)lua_touserdata(L, 1); + lua_pushfstring(L, "cdBitmap(%p)%s", bitmap_p, (*bitmap_p)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringchannel (lua_State *L) +{ + cdluaImageChannel *imagechannel_p = (cdluaImageChannel*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdImageChannel(%p)%s", imagechannel_p, (imagechannel_p->channel)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringstate (lua_State *L) +{ + cdState* *state_p = (cdState**)lua_touserdata(L, 1); + lua_pushfstring(L, "cdState(%p)%s", state_p, (*state_p)? "": "-released"); + return 1; +} + +static int cdlua5_tostringpattern (lua_State *L) +{ + cdluaPattern *pattern_p = (cdluaPattern*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdPattern(%p)%s", pattern_p, (pattern_p->pattern)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringstipple (lua_State *L) +{ + cdluaStipple *stipple_p = (cdluaStipple*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdStipple(%p)%s", stipple_p, (stipple_p->stipple)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringimagergba (lua_State *L) +{ + cdluaImageRGBA *imagergba_p = (cdluaImageRGBA*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdImageRGBA(%p)%s", imagergba_p, (imagergba_p->red)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringimagergb (lua_State *L) +{ + cdluaImageRGB *imagergb_p = (cdluaImageRGB*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdImageRGB(%p)%s", imagergb_p, (imagergb_p->red)? "": "-killed"); + return 1; +} + +static int cdlua5_tostringimagemap (lua_State *L) +{ + cdluaImageMap *imagemap_p = (cdluaImageMap*)lua_touserdata(L, 1); + lua_pushfstring(L, "cdImageMap(%p)%s", imagemap_p, (imagemap_p->index)? "": "-killed"); + return 1; +} + +/***************************************************************************\ +* cd.Reserved * +\***************************************************************************/ +static int cdlua5_reserved(lua_State *L) +{ + long int color = cdlua_checkcolor(L, 1); + lua_pushnumber(L, cdReserved(color)); + return 1; +} + +/***************************************************************************\ +* cd.GetScreenColorPlanes * +\***************************************************************************/ +static int cdlua5_getscreencolorplanes(lua_State *L) +{ + lua_pushnumber(L, cdGetScreenColorPlanes()); + return 1; +} + +/***************************************************************************\ +* cd.GetScreenSize * +\***************************************************************************/ +static int cdlua5_getscreensize(lua_State *L) +{ + int width; + int height; + double mm_width; + double mm_height; + cdGetScreenSize(&width, &height, &mm_width, &mm_height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + lua_pushnumber(L, mm_width); + lua_pushnumber(L, mm_height); + return 4; +} + +/***************************************************************************\ +* cd.UseContextPlus * +\***************************************************************************/ +static int cdlua5_usecontextplus(lua_State *L) +{ + lua_pushnumber(L, cdUseContextPlus(luaL_checkint(L, 1))); + return 1; +} + + +/********************************************************************************\ +* CDLua Exported functions * +\********************************************************************************/ +static const struct luaL_reg cdlib[] = { + + /* Initialization */ + {"ContextCaps" , cdlua5_contextcaps}, + + /* Control */ + {"ReleaseState" , cdlua5_releasestate}, + + /* Stipple */ + {"CreateStipple", cdlua5_createstipple}, + {"KillStipple" , cdlua5_killstipple}, + + /* Pattern */ + {"CreatePattern", cdlua5_createpattern}, + {"KillPattern" , cdlua5_killpattern}, + + /* Client Images */ + {"RGB2Map" , cdlua5_rgb2map}, + {"CreateBitmap" , cdlua5_createbitmap}, + {"KillBitmap" , cdlua5_killbitmap}, + {"BitmapGetData" , cdlua5_bitmapgetdata}, + {"BitmapSetRect" , cdlua5_bitmapsetrect}, + {"BitmapRGB2Map" , cdlua5_bitmaprgb2map}, + + {"CreateImageRGB" , cdlua5_createimagergb}, + {"KillImageRGB" , cdlua5_killimagergb}, + {"CreateImageRGBA" , cdlua5_createimagergba}, + {"KillImageRGBA" , cdlua5_killimagergba}, + {"CreateImageMap" , cdlua5_createimagemap}, + {"KillImageMap" , cdlua5_killimagemap}, + + /* Server Images */ + {"KillImage" , cdlua5_killimage}, + + /* Other */ + {"Version" , cdlua5_version}, + {"RegisterCallback" , cdlua5_registercallback}, + {"ContextRegisterCallback" , cdlua5_registercallback}, + + /* Color Coding */ + {"EncodeColor" , cdlua5_encodecolor}, + {"DecodeColor" , cdlua5_decodecolor}, + {"EncodeAlpha" , cdlua5_encodealpha}, + {"DecodeAlpha" , cdlua5_decodealpha}, + {"Alpha" , cdlua5_alpha}, + {"Red" , cdlua5_red}, + {"Blue" , cdlua5_blue}, + {"Green" , cdlua5_green}, + {"Reserved" , cdlua5_reserved}, + + /* Palette */ + {"CreatePalette", cdlua5_createpalette}, + {"KillPalette" , cdlua5_killpalette}, + + /* native window functions */ + {"GetScreenColorPlanes" , cdlua5_getscreencolorplanes}, + {"GetScreenSize" , cdlua5_getscreensize}, + + /* gdi+ functions */ + {"UseContextPlus" , cdlua5_usecontextplus}, + + {NULL, NULL}, +}; + +void cdlua_addcontext(lua_State *L, cdluaLuaState* cdL, cdluaContext *cdlua_ctx) +{ + int i; + cdlua_ctx->id = cdL->numdrivers; + cdL->drivers[cdL->numdrivers] = cdlua_ctx; + + lua_pushstring(L, cdlua_ctx->name); + lua_pushnumber(L, cdL->numdrivers); + lua_settable(L, -3); + + /* skip CD_SIZECB, register other callbacks */ + for (i=1; i < cdlua_ctx->cb_n; i++) + { + lua_pushstring(L, cdlua_ctx->cb_list[i].name); + lua_pushnumber(L, i); + lua_settable(L, -3); + } + + cdL->numdrivers++; +} + + +/********************************************************************************\ +* Exports all CD constants * +\********************************************************************************/ +typedef struct cdlua5_constant { + const char *name; + lua_Number value; +} cdlua5_constant; + +typedef struct cdlua5_color { + const char *name; + long int value; +} cdlua5_color; + +static const struct cdlua5_constant cdlibconstant[] = { + /* query value */ + {"QUERY", CD_QUERY}, + + /* these definitions are compatible with the IM library */ + {"RGB" , CD_RGB}, + {"MAP" , CD_MAP}, + {"RGBA", CD_RGBA}, + + {"IRED" , CD_IRED}, + {"IGREEN", CD_IGREEN}, + {"IBLUE" , CD_IBLUE}, + {"IALPHA", CD_IALPHA}, + {"INDEX" , CD_INDEX}, + {"COLORS", CD_COLORS}, + + /* status report */ + {"ERROR", CD_ERROR}, + {"OK" , CD_OK}, + + /* clip mode */ + {"CLIPOFF" , CD_CLIPOFF}, + {"CLIPAREA" , CD_CLIPAREA}, + {"CLIPPOLYGON", CD_CLIPPOLYGON}, + {"CLIPREGION" , CD_CLIPREGION}, + + /* region combine mode */ + {"UNION" , CD_UNION}, + {"INTERSECT" , CD_INTERSECT}, + {"DIFFERENCE" , CD_DIFFERENCE}, + {"NOTINTERSECT", CD_NOTINTERSECT}, + + /* polygon mode (begin...end) */ + {"FILL" , CD_FILL}, + {"OPEN_LINES" , CD_OPEN_LINES}, + {"CLOSED_LINES", CD_CLOSED_LINES}, + {"CLIP" , CD_CLIP}, + {"BEZIER" , CD_BEZIER}, + {"REGION" , CD_REGION}, + {"POLYCUSTOM" , CD_POLYCUSTOM}, + + /* fill mode */ + {"EVENODD", CD_EVENODD}, + {"WINDING", CD_WINDING}, + + /* line join */ + {"MITER", CD_MITER}, + {"BEVEL", CD_BEVEL}, + {"ROUND", CD_ROUND}, + + /* line cap */ + {"CAPFLAT" , CD_CAPFLAT}, + {"CAPSQUARE", CD_CAPSQUARE}, + {"CAPROUND" , CD_CAPROUND}, + + /* background opacity mode */ + {"OPAQUE" , CD_OPAQUE}, + {"TRANSPARENT", CD_TRANSPARENT}, + + /* write mode */ + {"REPLACE", CD_REPLACE}, + {"XOR" , CD_XOR}, + {"NOT_XOR", CD_NOT_XOR}, + + /* color allocation mode (palette) */ + {"POLITE", CD_POLITE}, + {"FORCE" , CD_FORCE}, + + /* line style */ + {"CONTINUOUS" , CD_CONTINUOUS}, + {"DASHED" , CD_DASHED}, + {"DOTTED" , CD_DOTTED}, + {"DASH_DOT" , CD_DASH_DOT}, + {"DASH_DOT_DOT", CD_DASH_DOT_DOT}, + {"CUSTOM" , CD_CUSTOM}, + + /* marker type */ + {"PLUS" , CD_PLUS}, + {"STAR" , CD_STAR}, + {"CIRCLE" , CD_CIRCLE}, + {"X" , CD_X}, + {"BOX" , CD_BOX}, + {"DIAMOND" , CD_DIAMOND}, + {"HOLLOW_CIRCLE" , CD_HOLLOW_CIRCLE}, + {"HOLLOW_BOX" , CD_HOLLOW_BOX}, + {"HOLLOW_DIAMOND", CD_HOLLOW_DIAMOND}, + + /* hatch type */ + {"HORIZONTAL", CD_HORIZONTAL}, + {"VERTICAL" , CD_VERTICAL}, + {"FDIAGONAL" , CD_FDIAGONAL}, + {"BDIAGONAL" , CD_BDIAGONAL}, + {"CROSS" , CD_CROSS}, + {"DIAGCROSS" , CD_DIAGCROSS}, + + /* interior style */ + {"SOLID" , CD_SOLID}, + {"HATCH" , CD_HATCH}, + {"STIPPLE", CD_STIPPLE}, + {"PATTERN", CD_PATTERN}, + {"HOLLOW" , CD_HOLLOW}, + + /* text alignment */ + {"NORTH" , CD_NORTH}, + {"SOUTH" , CD_SOUTH}, + {"EAST" , CD_EAST}, + {"WEST" , CD_WEST}, + {"NORTH_EAST" , CD_NORTH_EAST}, + {"NORTH_WEST" , CD_NORTH_WEST}, + {"SOUTH_EAST" , CD_SOUTH_EAST}, + {"SOUTH_WEST" , CD_SOUTH_WEST}, + {"CENTER" , CD_CENTER}, + {"BASE_LEFT" , CD_BASE_LEFT}, + {"BASE_CENTER", CD_BASE_CENTER}, + {"BASE_RIGHT" , CD_BASE_RIGHT}, + + /* style */ + {"PLAIN" , CD_PLAIN}, + {"BOLD" , CD_BOLD}, + {"ITALIC" , CD_ITALIC}, + {"BOLD_ITALIC", CD_BOLD_ITALIC}, + {"UNDERLINE" , CD_UNDERLINE}, + {"STRIKEOUT" , CD_STRIKEOUT}, + + /* font size */ + {"SMALL" , CD_SMALL}, + {"STANDARD", CD_STANDARD}, + {"LARGE" , CD_LARGE}, + + /* Canvas Capabilities */ + {"CAP_NONE" , CD_CAP_NONE}, + {"CAP_FLUSH" , CD_CAP_FLUSH}, + {"CAP_CLEAR" , CD_CAP_CLEAR}, + {"CAP_PLAY" , CD_CAP_PLAY}, + {"CAP_YAXIS" , CD_CAP_YAXIS}, + {"CAP_CLIPAREA" , CD_CAP_CLIPAREA}, + {"CAP_CLIPPOLY" , CD_CAP_CLIPPOLY}, + {"CAP_RECT" , CD_CAP_RECT}, + {"CAP_IMAGERGB" , CD_CAP_IMAGERGB}, + {"CAP_IMAGERGBA" , CD_CAP_IMAGERGBA}, + {"CAP_IMAGEMAP" , CD_CAP_IMAGEMAP}, + {"CAP_GETIMAGERGB" , CD_CAP_GETIMAGERGB}, + {"CAP_IMAGESRV" , CD_CAP_IMAGESRV}, + {"CAP_BACKGROUND" , CD_CAP_BACKGROUND}, + {"CAP_BACKOPACITY" , CD_CAP_BACKOPACITY}, + {"CAP_WRITEMODE" , CD_CAP_WRITEMODE}, + {"CAP_LINESTYLE" , CD_CAP_LINESTYLE}, + {"CAP_LINEWITH" , CD_CAP_LINEWITH}, + {"CAP_WD" , CD_CAP_FPRIMTIVES}, + {"CAP_HATCH" , CD_CAP_HATCH}, + {"CAP_STIPPLE" , CD_CAP_STIPPLE}, + {"CAP_PATTERN" , CD_CAP_PATTERN}, + {"CAP_FONT" , CD_CAP_FONT}, + {"CAP_FONTDIM" , CD_CAP_FONTDIM}, + {"CAP_TEXTSIZE" , CD_CAP_TEXTSIZE}, + {"CAP_TEXTORIENTATION", CD_CAP_TEXTORIENTATION}, + {"CAP_PALETTE" , CD_CAP_PALETTE}, + {"CAP_LINECAP" , CD_CAP_LINECAP}, + {"CAP_LINEJOIN" , CD_CAP_LINEJOIN}, + {"CAP_REGION" , CD_CAP_REGION}, + {"CAP_CHORD" , CD_CAP_CHORD}, + {"CAP_ALL" , CD_CAP_ALL}, + + /* cdPlay definitions */ + {"SIZECB", CD_SIZECB}, + {"ABORT", CD_ABORT}, + {"CONTINUE", CD_CONTINUE}, + + /* simulation flags */ + {"SIM_NONE" , CD_SIM_NONE}, + {"SIM_TEXT" , CD_SIM_TEXT}, + {"SIM_LINE" , CD_SIM_LINE}, + {"SIM_RECT" , CD_SIM_RECT}, + {"SIM_ARC" , CD_SIM_ARC}, + {"SIM_POLYLINE" , CD_SIM_POLYLINE}, + {"SIM_BOX" , CD_SIM_BOX}, + {"SIM_SECTOR" , CD_SIM_SECTOR}, + {"SIM_POLYGON" , CD_SIM_POLYGON}, + {"SIM_CHORD" , CD_SIM_CHORD}, + {"SIM_ALL" , CD_SIM_ALL}, + {"SIM_LINES" , CD_SIM_LINES}, + {"SIM_FILLS" , CD_SIM_FILLS}, + + /* some conversion factors */ + {"MM2PT" , CD_MM2PT}, + {"RAD2DEG", CD_RAD2DEG}, + + /* cdcgm.h (the callback names are registered in cdlua_addcontext) */ + + /* cdgdiplus.h */ + {"SPLINE" , CD_SPLINE}, + {"FILLSPLINE" , CD_FILLSPLINE}, + {"FILLGRADIENT", CD_FILLGRADIENT}, + + /* cdps.h */ + {"A0" , CD_A0}, + {"A1" , CD_A1}, + {"A2" , CD_A2}, + {"A3" , CD_A3}, + {"A4" , CD_A4}, + {"A5" , CD_A5}, + {"LETTER", CD_LETTER}, + {"LEGAL" , CD_LEGAL}, + + {NULL, -1}, +}; + +static void initconst(lua_State *L) +{ + const cdlua5_constant *l = cdlibconstant; + for (; l->name; l++) { + lua_pushstring(L, l->name); + lua_pushnumber(L, l->value); + lua_settable(L, -3); + } +} + +/* some predefined colors for convenience */ +static const struct cdlua5_color cdlibcolor[] = { + {"RED" , CD_RED}, + {"DARK_RED" , CD_DARK_RED}, + {"GREEN" , CD_GREEN}, + {"DARK_GREEN" , CD_DARK_GREEN}, + {"BLUE" , CD_BLUE}, + {"DARK_BLUE" , CD_DARK_BLUE}, + {"YELLOW" , CD_YELLOW}, + {"DARK_YELLOW" , CD_DARK_YELLOW}, + {"MAGENTA" , CD_MAGENTA}, + {"DARK_MAGENTA", CD_DARK_MAGENTA}, + {"CYAN" , CD_CYAN}, + {"DARK_CYAN" , CD_DARK_CYAN}, + {"WHITE" , CD_WHITE}, + {"BLACK" , CD_BLACK}, + {"DARK_GRAY" , CD_DARK_GRAY}, + {"GRAY" , CD_GRAY}, + {NULL, -1}, +}; + +static void initcolor(lua_State *L) +{ + const cdlua5_color *l = cdlibcolor; + for (; l->name; l++) + { + lua_pushstring(L, l->name); + lua_pushlightuserdata(L, (void*) l->value); + lua_settable(L, -3); + } +} + +static void initmetatables(lua_State *L) +{ + /* there is no object orientation for these metatables, + only gc and optionaly array access */ + + luaL_newmetatable(L, "cdState"); /* create new metatable for cdState handles */ + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_releasestate); /* register the method */ + lua_settable (L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringstate); + lua_settable(L, -3); + lua_pop(L, 1); /* removes the metatable from the top of the stack */ + + luaL_newmetatable(L, "cdImage"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killimage); + lua_settable (L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringimage); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdBitmap"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killbitmap); + lua_settable (L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indexbitmap); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringbitmap); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdImageRGB"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killimagergb); + lua_settable (L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indeximagergb); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringimagergb); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdImageRGBA"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killimagergba); + lua_settable (L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indeximagergba); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringimagergba); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdImageChannel"); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indexchannel); + lua_settable(L, -3); + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, cdlua5_newindexchannel); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringchannel); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdStipple"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killstipple); + lua_settable (L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indexstipple); + lua_settable(L, -3); + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, cdlua5_newindexstipple); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringstipple); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdPattern"); + lua_pushliteral (L, "__gc"); + lua_pushcfunction (L, cdlua5_killpattern); + lua_settable (L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indexpattern); + lua_settable(L, -3); + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, cdlua5_newindexpattern); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringpattern); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdPalette"); + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, cdlua5_killpalette); + lua_settable(L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indexpalette); + lua_settable(L, -3); + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, cdlua5_newindexpalette); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringpalette); + lua_settable(L, -3); + lua_pushliteral(L, "__len"); + lua_pushcfunction(L, cdluaPalette_len); + lua_settable(L, -3); + lua_pop(L, 1); + + luaL_newmetatable(L, "cdImageMap"); + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, cdlua5_killimagemap); + lua_settable(L, -3); + lua_pushliteral(L, "__index"); + lua_pushcfunction(L, cdlua5_indeximagemap); + lua_settable(L, -3); + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, cdlua5_newindeximagemap); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, cdlua5_tostringimagemap); + lua_settable(L, -3); + lua_pop(L, 1); +} + +static void setinfo (lua_State *L) +{ + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, CD_COPYRIGHT); + lua_settable (L, -3); + + lua_pushliteral (L, "_DESCRIPTION"); + lua_pushliteral (L, CD_DESCRIPTION); + lua_settable (L, -3); + + lua_pushliteral (L, "_NAME"); + lua_pushliteral (L, CD_NAME); + lua_settable (L, -3); + + lua_pushliteral (L, "_VERSION"); + lua_pushliteral (L, CD_VERSION); + lua_settable (L, -3); + + lua_pushliteral (L, "_VERSION_DATE"); + lua_pushliteral(L, CD_VERSION_DATE); + lua_settable (L, -3); + + lua_pushliteral (L, "_VERSION_NUMBER"); + lua_pushinteger(L, CD_VERSION_NUMBER); + lua_settable (L, -3); +} + + +/********************************************************************************\ +* CDLua OpenLib * +\********************************************************************************/ + + +int cdlua_open (lua_State *L) +{ + cdluaLuaState* cdL = malloc(sizeof(cdluaLuaState)); + memset(cdL, 0, sizeof(cdluaLuaState)); + cdlua_SetState(L, cdL); + + initmetatables(L); + + luaL_register(L, "cd", cdlib); /* leave "cd" table at the top of the stack */ + setinfo(L); + + cdlua_open_active(L, cdL); + cdlua_open_canvas(L); + + cdlua_initdrivers(L, cdL); + initconst(L); + initcolor(L); + + return 1; +} + +int cdlua_close(lua_State *L) +{ + cdluaLuaState* cdL = cdlua_getstate(L); + if (cdL) + { + cdKillCanvas(cdL->void_canvas); + free(cdL); + } + return 0; +} + +int luaopen_cdlua(lua_State* L) +{ + return cdlua_open(L); +} + +int luaopen_cdlua51(lua_State* L) +{ + return cdlua_open(L); +} diff --git a/src/lua5/cdlua5.def b/src/lua5/cdlua5.def new file mode 100644 index 0000000..b4811b2 --- /dev/null +++ b/src/lua5/cdlua5.def @@ -0,0 +1,13 @@ +EXPORTS + cdlua_open + cdlua_close + cdlua_getcanvas + cdlua_addcontext + cdlua_getplaystate + cdlua_getstate + cdlua_checkcanvas + cdlua_pushcanvas + luaopen_cdlua + luaopen_cdlua51 + cdlua_pushbitmap + cdlua_checkbitmap \ No newline at end of file diff --git a/src/lua5/cdlua5_active.c b/src/lua5/cdlua5_active.c new file mode 100644 index 0000000..ad4398e --- /dev/null +++ b/src/lua5/cdlua5_active.c @@ -0,0 +1,2163 @@ +/** \file + * \brief Lua Binding of the OLD API that needs an active canvas + * + * See Copyright Notice in cd.h + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifdef CD_NO_OLD_INTERFACE +#undef CD_NO_OLD_INTERFACE +#endif + +#include "cd.h" +#include "wd.h" +#include "cdirgb.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdlua5_private.h" +#include "cdvoid5.h" + + +void cdlua_kill_active(lua_State * L, cdCanvas* canvas) +{ + cdluaLuaState* cdL = cdlua_getstate(L); + cdCanvas* void_canvas = cdL->void_canvas; + + /* find out about the currently active canvas */ + cdCanvas *current_canvas = cdActiveCanvas(); + + /* this should never happen, unless the user did it on purpouse! */ + if (canvas == void_canvas) + luaL_error(L, "trying to kill the void canvas"); + + /* if the user killed the currently active canvas, activate void canvas */ + if (canvas == current_canvas) + cdActivate(void_canvas); +} + +/***************************************************************************\ +* Activates a cd canvas. * +\***************************************************************************/ +static int cdlua5_activate(lua_State * L) +{ + cdCanvas* canvas; + + /* if canvas is nil, activate a void canvas */ + if (lua_isnil(L, 1)) + { + cdluaLuaState* cdL = cdlua_getstate(L); + cdCanvas* void_canvas = cdL->void_canvas; + lua_pushnumber(L, cdActivate(void_canvas)); + return 1; + } + + canvas = cdlua_checkcanvas(L, 1); + lua_pushnumber(L, cdActivate(canvas)); + return 1; +} + +/***************************************************************************\ +* Returns the active canvas. * +\***************************************************************************/ +static int cdlua5_activecanvas(lua_State* L) +{ + cdCanvas* canvas = cdActiveCanvas(); + if (canvas) + cdlua_pushcanvas(L, canvas); + else + lua_pushnil(L); + + return 1; +} + +/***************************************************************************\ +* cd.Simulate(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_simulate(lua_State *L) +{ + lua_pushnumber(L, cdSimulate(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* Control * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Clear() * +\***************************************************************************/ +static int cdlua5_clear(lua_State *L) +{ + (void)L; + cdClear(); + return 0; +} + +/***************************************************************************\ +* cd.Flush() * +\***************************************************************************/ +static int cdlua5_flush(lua_State *L) +{ + (void)L; + cdFlush(); + return 0; +} + +static int cdlua5_savestate(lua_State *L) +{ + cdState* state = cdSaveState(); + if (state) + cdlua_pushstate(L, state); + else + lua_pushnil(L); + return 1; +} + +static int cdlua5_restorestate(lua_State * L) +{ + cdRestoreState(cdlua_checkstate(L, 1)); + return 0; +} + +/***************************************************************************\ +* cd.SetAttribute(name, data: string) * +\***************************************************************************/ + +static int cdlua_isuserdata(const char* name) +{ + if (strcmp(name, "HDC")==0) return 1; + if (strcmp(name, "GC")==0) return 1; + return 0; +} + +static int cdlua5_setattribute(lua_State *L) +{ + const char* name = luaL_checkstring(L, 1); + + if (lua_isnil(L, 2)) + { + cdSetAttribute(name, NULL); + } + else + { + char* data; + if (cdlua_isuserdata(name)) + data = (char*) lua_touserdata(L, 2); + else + data = (char*) luaL_checkstring(L, 2); + cdSetAttribute(name, data); + } + return 0; +} + + +/***************************************************************************\ +* cd.SetAttribute(name: string) -> (data: string) * +\***************************************************************************/ +static int cdlua5_getattribute(lua_State *L) +{ + char* name = (char *)luaL_checkstring(L, 1); + char* data = cdGetAttribute(name); + if (data) + { + if (cdlua_isuserdata(name)) + lua_pushlightuserdata(L, data); + else + lua_pushstring(L, data); + } + else + lua_pushnil(L); + return 1; +} + + + +/***************************************************************************\ +* Coordinate System * +\***************************************************************************/ + +/***************************************************************************\ +* cd.GetCanvasSize() -> (width, heigth, mm_width, mm_height: number) * +\***************************************************************************/ +static int cdlua5_getcanvassize(lua_State *L) +{ + int width; + int height; + double mm_width; + double mm_height; + + cdGetCanvasSize(&width, &height, &mm_width, &mm_height); + + lua_pushnumber(L, width); + lua_pushnumber(L, height); + lua_pushnumber(L, mm_width); + lua_pushnumber(L, mm_height); + return 4; +} + +/***************************************************************************\ +* cd.UpdateYAxis(yc: number) -> (yr: number) * +\***************************************************************************/ +static int cdlua5_updateyaxis(lua_State *L) +{ + int y = luaL_checkint(L, 1); + cdUpdateYAxis(&y); + lua_pushnumber(L, y); + return 1; +} + +/***************************************************************************\ +* cd.MM2Pixel(mm_dx, mm_dy: number) -> (dx, dy: number) * +\***************************************************************************/ +static int cdlua5_mm2pixel(lua_State *L) +{ + double mm_dx_d, mm_dy_d; + int dx, dy; + + mm_dx_d = luaL_checknumber(L,1); + mm_dy_d = luaL_checknumber(L,2); + + cdMM2Pixel(mm_dx_d, mm_dy_d, &dx, &dy); + lua_pushnumber(L, dx); + lua_pushnumber(L, dy); + return 2; +} + +/***************************************************************************\ +* cd.Pixel2MM(dx, dy: number) -> (mm_dx, mm_dy: number) * +\***************************************************************************/ +static int cdlua5_pixel2mm(lua_State *L) +{ + double mm_dx_d, mm_dy_d; + int dx, dy; + + dx = luaL_checkint(L,1); + dy = luaL_checkint(L,2); + + cdPixel2MM(dx, dy, &mm_dx_d, &mm_dy_d); + lua_pushnumber(L, mm_dx_d); + lua_pushnumber(L, mm_dy_d); + return 2; +} + +/***************************************************************************\ +* cd.Origin(x, y: number) * +\***************************************************************************/ +static int cdlua5_origin(lua_State *L) +{ + cdOrigin(luaL_checkint(L,1), luaL_checkint(L,2)); + return 0; +} + + + +/***************************************************************************\ +* World Coordinates * +\***************************************************************************/ + +/***************************************************************************\ +* wd.Window(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_window(lua_State *L) +{ + double xmin = luaL_checknumber(L, 1); + double xmax = luaL_checknumber(L, 2); + double ymin = luaL_checknumber(L, 3); + double ymax = luaL_checknumber(L, 4); + wdWindow(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* wd.GetWindow() -> (xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_getwindow(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + + wdGetWindow(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* wd.Viewport(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_viewport(lua_State *L) +{ + int xmin = luaL_checkint(L, 1); + int xmax = luaL_checkint(L, 2); + int ymin = luaL_checkint(L, 3); + int ymax = luaL_checkint(L, 4); + wdViewport(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* wd.GetViewport() -> (xmin, xmax, ymin, ymax: number * +\***************************************************************************/ +static int wdlua5_getviewport(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + + wdGetViewport(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* wd.World2Canvas(xw, yw: number) -> (xv, yv: number) * +\***************************************************************************/ +static int wdlua5_world2canvas(lua_State *L) +{ + double xw_d, yw_d; + int xv_i, yv_i; + + xw_d = luaL_checknumber(L, 1); + yw_d = luaL_checknumber(L, 2); + + wdWorld2Canvas(xw_d, yw_d, &xv_i, &yv_i); + lua_pushnumber(L, xv_i); + lua_pushnumber(L, yv_i); + return 2; +} + +/***************************************************************************\ +* wd.Canvas2World(xv, yv: number) -> (xw, yw: number) * +\***************************************************************************/ +static int wdlua5_canvas2world(lua_State *L) +{ + int xv_i, yv_i; + double xw_d, yw_d; + + xv_i = luaL_checkint(L, 1); + yv_i = luaL_checkint(L, 2); + + wdCanvas2World(xv_i, yv_i, &xw_d, &yw_d); + lua_pushnumber(L, xw_d); + lua_pushnumber(L, yw_d); + return 2; +} + + + +/***************************************************************************\ +* General Attributes * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Foreground(color) -> color * +\***************************************************************************/ +static int cdlua5_foreground(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + color_i = cdForeground(color_i); + lua_pushlightuserdata(L, (void*)color_i); + return 1; +} + +/***************************************************************************\ +* cd.Background(color) -> color * +\***************************************************************************/ +static int cdlua5_background(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + color_i = cdBackground(color_i); + lua_pushlightuserdata(L, (void*) color_i); + return 1; +} + +/***************************************************************************\ +* cd.WriteMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_writemode(lua_State *L) +{ + lua_pushnumber(L, cdWriteMode(luaL_checkint(L, 1))); + return 1; +} + + + +/***************************************************************************\ +* Clipping * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Clip(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_clip(lua_State *L) +{ + lua_pushnumber(L, cdClip(luaL_checkint(L,1))); + return 1; +} + +/***************************************************************************\ +* cd.ClipArea(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int cdlua5_cliparea(lua_State *L) +{ + int xmin = luaL_checkint(L, 1); + int xmax = luaL_checkint(L, 2); + int ymin = luaL_checkint(L, 3); + int ymax = luaL_checkint(L, 4); + + cdClipArea(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.wClipArea(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_cliparea(lua_State *L) +{ + double xmin = luaL_checknumber(L, 1); + double xmax = luaL_checknumber(L, 2); + double ymin = luaL_checknumber(L, 3); + double ymax = luaL_checknumber(L, 4); + + wdClipArea(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.GetClipArea() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int cdlua5_getcliparea(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + int status; + + status = cdGetClipArea(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + lua_pushnumber(L, status); + return 5; +} + +/***************************************************************************\ +* cd.wGetClipArea() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int wdlua5_getcliparea(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + int status; + + status = wdGetClipArea(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + lua_pushnumber(L, status); + return 5; +} + +/***************************************************************************\ +* cd.GetClipPoly() -> (n: number, points: table) * +\***************************************************************************/ +static int cdlua5_getclippoly(lua_State *L) +{ + int n, i; + int *pts; + + pts = cdGetClipPoly(&n); + if (pts) + { + lua_pushnumber(L, n); + + lua_newtable(L); + for (i=0; i < 2*n; i++) + { + lua_pushnumber(L, i+1); + lua_pushnumber(L, pts[i]); + lua_settable(L, -3); + } + + return 2; + } + else + { + lua_pushnil(L); + return 1; + } +} + +/***************************************************************************\ +* cd.wGetClipPoly() -> (n: number, points: table) * +\***************************************************************************/ +static int wdlua5_getclippoly(lua_State *L) +{ + int n, i; + double *pts; + + pts = wdGetClipPoly(&n); + if (pts) + { + lua_pushnumber(L, n); + + lua_newtable(L); + for (i=0; i < 2*n; i++) + { + lua_pushnumber(L, i+1); + lua_pushnumber(L, pts[i]); + lua_settable(L,-3); + } + + return 2; + } + else + { + lua_pushnil(L); + return 1; + } +} + + +/***************************************************************************\ +* Regions * +\***************************************************************************/ + +/***************************************************************************\ +* cd.RegionCombineMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_regioncombinemode(lua_State *L) +{ + lua_pushnumber(L, cdRegionCombineMode(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.PointInRegion(x, y: number) -> (status: number) * +\***************************************************************************/ +static int cdlua5_pointinregion(lua_State *L) +{ + lua_pushnumber(L, cdPointInRegion(luaL_checkint(L, 1),luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.wPointInRegion(x, y: number) -> (status: number) * +\***************************************************************************/ +static int wdlua5_pointinregion(lua_State *L) +{ + lua_pushnumber(L, wdPointInRegion(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.OffsetRegion(dx, dy: number) * +\***************************************************************************/ +static int cdlua5_offsetregion(lua_State *L) +{ + cdOffsetRegion(luaL_checkint(L, 1), luaL_checkint(L, 2)); + return 0; +} + +/***************************************************************************\ +* cd.wOffsetRegion(dx, dy: number) * +\***************************************************************************/ +static int wdlua5_offsetregion(lua_State *L) +{ + wdOffsetRegion(luaL_checknumber(L, 1), luaL_checknumber(L, 2)); + return 0; +} + +/***************************************************************************\ +* cd.RegionBox() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int cdlua5_regionbox(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + + cdRegionBox(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* cd.wRegionBox() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int wdlua5_regionbox(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + + wdRegionBox(&xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + + + +/***************************************************************************\ +* Primitives * +\***************************************************************************/ + + + +/***************************************************************************\ +* Marks * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Pixel(x, y: number, color) * +\***************************************************************************/ +static int cdlua5_pixel (lua_State *L) +{ + cdPixel(luaL_checkint(L, 1), luaL_checkint(L, 2), cdlua_checkcolor(L, 3)); + return 0 ; +} + +/***************************************************************************\ +* cd.wPixel(x, y: number, color) * +\***************************************************************************/ +static int wdlua5_pixel (lua_State *L) +{ + wdPixel(luaL_checknumber(L, 1), luaL_checknumber(L, 2), cdlua_checkcolor(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.Mark(x, y: number) * +\***************************************************************************/ +static int cdlua5_mark(lua_State *L) +{ + cdMark(luaL_checkint(L,1), luaL_checkint(L,2)); + return 0; +} + +/***************************************************************************\ +* cd.wMark(x, y: number) * +\***************************************************************************/ +static int wdlua5_mark(lua_State *L) +{ + wdMark(luaL_checknumber(L, 1), luaL_checknumber(L, 2)); + return 0; +} + +/***************************************************************************\ +* cd.MarkType(type: number) -> (old_type: number) * +\***************************************************************************/ +static int cdlua5_marktype(lua_State *L) +{ + lua_pushnumber(L, cdMarkType(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.MarkSize(size: number) -> (old_size: number) * +\***************************************************************************/ +static int cdlua5_marksize(lua_State *L) +{ + lua_pushnumber(L, cdMarkSize(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.wMarkSize(size: number) -> (old_size: number) * +\***************************************************************************/ +static int wdlua5_marksize(lua_State *L) +{ + lua_pushnumber(L, wdMarkSize(luaL_checknumber(L, 1))); + return 1; +} + + + +/***************************************************************************\ +* Lines * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Line(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int cdlua5_line(lua_State *L) +{ + int x1 = luaL_checkint(L,1); + int y1 = luaL_checkint(L,2); + int x2 = luaL_checkint(L,3); + int y2 = luaL_checkint(L,4); + cdLine(x1, y1, x2, y2); + return 0; +} + +/***************************************************************************\ +* cd.wLine(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int wdlua5_line(lua_State *L) +{ + double x1 = luaL_checknumber(L, 1); + double y1 = luaL_checknumber(L, 2); + double x2 = luaL_checknumber(L, 3); + double y2 = luaL_checknumber(L, 4); + wdLine(x1, y1, x2, y2); + return 0; +} + +/***************************************************************************\ +* cd.Rect(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int cdlua5_rect(lua_State *L) +{ + int xmin = luaL_checkint(L,1); + int xmax = luaL_checkint(L,2); + int ymin = luaL_checkint(L,3); + int ymax = luaL_checkint(L,4); + cdRect(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.wRect(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_rect(lua_State *L) +{ + double xmin = luaL_checknumber(L, 1); + double xmax = luaL_checknumber(L, 2); + double ymin = luaL_checknumber(L, 3); + double ymax = luaL_checknumber(L, 4); + wdRect(xmin,xmax,ymin,ymax); + return 0; +} + +/***************************************************************************\ +* cd.Arc(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int cdlua5_arc(lua_State *L) +{ + int xc = luaL_checkint(L,1); + int yc = luaL_checkint(L,2); + int w = luaL_checkint(L,3); + int h = luaL_checkint(L,4); + double angle1 = luaL_checknumber(L,5); + double angle2 = luaL_checknumber(L,6); + cdArc(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.wArc(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int wdlua5_arc(lua_State *L) +{ + double xc = luaL_checknumber(L, 1); + double yc = luaL_checknumber(L, 2); + double w = luaL_checknumber(L, 3); + double h = luaL_checknumber(L, 4); + double angle1 = luaL_checknumber(L, 5); + double angle2 = luaL_checknumber(L, 6); + wdArc(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.LineStyle(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linestyle(lua_State *L) +{ + lua_pushnumber(L, cdLineStyle(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.LineStyleDashes(dashes: table, count: number) * +\***************************************************************************/ +static int cdlua5_linestyledashes(lua_State *L) +{ + int *dashes_int, dashes_count, i; + + if (!lua_istable(L, 1)) + luaL_argerror(L, 1, "invalid dashes, must be a table"); + + dashes_count = luaL_checkint(L, 2); + dashes_int = (int*) malloc(dashes_count * sizeof(int)); + + for (i=0; i < dashes_count; i++) + { + lua_pushnumber(L, i+1); + lua_gettable(L,1); + + dashes_int[i] = luaL_checkint(L,-1); + } + + cdLineStyleDashes(dashes_int, dashes_count); + free(dashes_int); + + return 0; +} + +/***************************************************************************\ +* cd.LineWidth(width: number) -> (old_width: number) * +\***************************************************************************/ +static int cdlua5_linewidth(lua_State *L) +{ + lua_pushnumber(L, cdLineWidth(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.wLineWidth(width: number) -> (old_width: number) * +\***************************************************************************/ +static int wdlua5_linewidth(lua_State *L) +{ + lua_pushnumber(L, wdLineWidth(luaL_checknumber(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.LineJoin(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linejoin(lua_State *L) +{ + lua_pushnumber(L, cdLineJoin(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.LineCap(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linecap(lua_State *L) +{ + lua_pushnumber(L, cdLineCap(luaL_checkint(L, 1))); + return 1; +} + + + +/***************************************************************************\ +* Filled Areas * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Box(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int cdlua5_box(lua_State *L) +{ + int xmin = luaL_checkint(L, 1); + int xmax = luaL_checkint(L, 2); + int ymin = luaL_checkint(L, 3); + int ymax = luaL_checkint(L, 4); + cdBox(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.wBox(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_box(lua_State *L) +{ + double xmin = luaL_checknumber(L, 1); + double xmax = luaL_checknumber(L, 2); + double ymin = luaL_checknumber(L, 3); + double ymax = luaL_checknumber(L, 4); + wdBox(xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.Sector(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int cdlua5_sector(lua_State *L) +{ + int xc = luaL_checkint(L,1); + int yc = luaL_checkint(L,2); + int w = luaL_checkint(L,3); + int h = luaL_checkint(L,4); + double angle1 = luaL_checknumber(L,5); + double angle2 = luaL_checknumber(L,6); + cdSector(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.wSector(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int wdlua5_sector(lua_State *L) +{ + double xc = luaL_checknumber(L, 1); + double yc = luaL_checknumber(L, 2); + double w = luaL_checknumber(L, 3); + double h = luaL_checknumber(L, 4); + double angle1 = luaL_checknumber(L, 5); + double angle2 = luaL_checknumber(L, 6); + wdSector(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.Chord(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int cdlua5_chord(lua_State *L) +{ + int xc = luaL_checkint(L,1); + int yc = luaL_checkint(L,2); + int w = luaL_checkint(L,3); + int h = luaL_checkint(L,4); + double angle1 = luaL_checknumber(L,5); + double angle2 = luaL_checknumber(L,6); + cdChord(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.wChord(xc, yc, w, h, angle1, angle2: number) * +\***************************************************************************/ +static int wdlua5_chord(lua_State *L) +{ + double xc = luaL_checknumber(L, 1); + double yc = luaL_checknumber(L, 2); + double w = luaL_checknumber(L, 3); + double h = luaL_checknumber(L, 4); + double angle1 = luaL_checknumber(L, 5); + double angle2 = luaL_checknumber(L, 6); + wdChord(xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.BackOpacity(opacity: number) -> (old_opacity: number) * +\***************************************************************************/ +static int cdlua5_backopacity(lua_State *L) +{ + lua_pushnumber(L, cdBackOpacity(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.FillMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_fillmode(lua_State *L) +{ + lua_pushnumber(L, cdFillMode(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.InteriorStyle(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_interiorstyle(lua_State *L) +{ + lua_pushnumber(L, cdInteriorStyle(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.Hatch(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_hatch(lua_State *L) +{ + lua_pushnumber(L, cdHatch(luaL_checkint(L, 1))); + return 1; +} + +static int cdlua5_stipple(lua_State *L) +{ + cdluaStipple *stipple_p = cdlua_checkstipple(L, 1); + cdStipple(stipple_p->width, stipple_p->height, stipple_p->stipple); + return 0 ; +} + +static int wdlua5_stipple(lua_State *L) +{ + cdluaStipple *stipple_p = cdlua_checkstipple(L, 1); + double w_mm = luaL_checknumber(L, 2); + double h_mm = luaL_checknumber(L, 3); + wdStipple(stipple_p->width, stipple_p->height, stipple_p->stipple, w_mm, h_mm); + return 0; +} + +static int cdlua5_getstipple(lua_State *L) +{ + int width, height, size; + unsigned char *stipple, *new_stipple = NULL; + + stipple = cdGetStipple(&width, &height); + + size = width * height; + + if (stipple) + new_stipple = (unsigned char *)malloc(size); + + if (new_stipple) + { + memcpy(new_stipple, stipple, size); + cdlua_pushstipple(L, new_stipple, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_pattern(lua_State *L) +{ + cdluaPattern* pattern_p = cdlua_checkpattern(L, 1); + cdPattern(pattern_p->width, pattern_p->height, pattern_p->pattern); + return 0; +} + +static int wdlua5_pattern(lua_State *L) +{ + cdluaPattern* pattern_p = cdlua_checkpattern(L, 1); + double w_mm = luaL_checknumber(L, 2); + double h_mm = luaL_checknumber(L, 3); + wdPattern(pattern_p->width, pattern_p->height, pattern_p->pattern, w_mm, h_mm); + return 0; +} + +static int cdlua5_getpattern(lua_State *L) +{ + int width, height, size; + long int *pattern, *new_pattern = NULL; + + pattern = cdGetPattern(&width, &height); + + size = width * height; + + if (pattern) + new_pattern = (long int *) malloc(size * sizeof(long int)); + + if (new_pattern) + { + memcpy(new_pattern, pattern, size * sizeof(long int)); + cdlua_pushpattern(L, new_pattern, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +/***************************************************************************\ +* Text * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Text(x, y: number, text: string) * +\***************************************************************************/ +static int cdlua5_text(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + cdText(luaL_checkint(L, 1), luaL_checkint(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.wText(x, y: number, text: string) * +\***************************************************************************/ +static int wdlua5_text(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + wdText(luaL_checknumber(L, 1), luaL_checknumber(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.Font(typeface, style, size: number) * +\***************************************************************************/ +static int cdlua5_font(lua_State *L) +{ + cdFont(luaL_checkint(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.wFont(typeface, style, size: number) * +\***************************************************************************/ +static int wdlua5_font(lua_State *L) +{ + wdFont(luaL_checkint(L, 1), luaL_checkint(L, 2), luaL_checknumber(L, 3)); + return 0; +} + + +/***************************************************************************\ +* cd.GetFont() -> (typeface, style, size: number) * +\***************************************************************************/ +static int cdlua5_getfont(lua_State *L) +{ + int type_face, style, size; + + cdGetFont(&type_face, &style, &size); + lua_pushnumber(L, type_face); + lua_pushnumber(L, style); + lua_pushnumber(L, size); + return 3; +} + +/***************************************************************************\ +* cd.wGetFont() -> (typeface, style, size: number) * +\***************************************************************************/ +static int wdlua5_getfont(lua_State *L) +{ + int type_face, style; + double size; + + wdGetFont(&type_face, &style, &size); + lua_pushnumber(L, type_face); + lua_pushnumber(L, style); + lua_pushnumber(L, size); + return 3; +} + +/***************************************************************************\ +* cd.NativeFont(font: string) * +\***************************************************************************/ +static int cdlua5_nativefont(lua_State *L) +{ + lua_pushstring(L, cdNativeFont(luaL_checkstring(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.TextAlignment(alignment: number) -> (old_alignment: number) * +\***************************************************************************/ +static int cdlua5_textalignment(lua_State *L) +{ + lua_pushnumber(L, cdTextAlignment(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.TextOrientation(angle: number) -> (old_angle: number) * +\***************************************************************************/ +static int cdlua5_textorientation(lua_State *L) +{ + lua_pushnumber(L, cdTextOrientation(luaL_checknumber(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.FontDim() -> (max_width, max_height, ascent, descent: number) * +\***************************************************************************/ +static int cdlua5_fontdim(lua_State *L) +{ + int max_width; + int height; + int ascent; + int descent; + + cdFontDim(&max_width, &height, &ascent, &descent); + lua_pushnumber(L, max_width); + lua_pushnumber(L, height); + lua_pushnumber(L, ascent); + lua_pushnumber(L, descent); + return 4; +} + +/***************************************************************************\ +* cd.wFontDim() -> (max_width, max_height, ascent, descent: number) * +\***************************************************************************/ +static int wdlua5_fontdim(lua_State *L) +{ + double max_width; + double height; + double ascent; + double descent; + + wdFontDim(&max_width, &height, &ascent, &descent); + lua_pushnumber(L, max_width); + lua_pushnumber(L, height); + lua_pushnumber(L, ascent); + lua_pushnumber(L, descent); + return 4; +} + +/***************************************************************************\ +* cd.TextSize(text: string) -> (width, heigth: number) * +\***************************************************************************/ +static int cdlua5_textsize(lua_State *L) +{ + int width; + int height; + + const char* text_s = luaL_checkstring(L, 1); + + cdTextSize(text_s, &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.wTextSize(text: string) -> (width, heigth: number) * +\***************************************************************************/ +static int wdlua5_textsize(lua_State *L) +{ + double width; + double height; + + const char* text_s = luaL_checkstring(L, 1); + + wdTextSize(text_s, &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/****************************************************************************\ +* cd.TextBox(x, y: number, text: string) -> (xmin, xmax, ymin, ymax: number) * +\****************************************************************************/ +static int cdlua5_textbox(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + const char* s = luaL_checkstring(L, 3); + + cdTextBox(x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/*****************************************************************************\ +* cd.wTextBox(x, y: number, text: string) -> (xmin, xmax, ymin, ymax: number) * +\*****************************************************************************/ +static int wdlua5_textbox(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + double x = luaL_checknumber(L, 1); + double y = luaL_checknumber(L, 2); + const char* s = luaL_checkstring(L, 3); + + wdTextBox(x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************************************************\ +* cd.TextBounds(x, y: number, text: string) -> (rect0, rect1, rect2, rect3, rect4, rect5, rect6, rect7: number) * +\***************************************************************************************************************/ +static int cdlua5_textbounds(lua_State *L) +{ + int rect[8]; + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + const char* s = luaL_checkstring(L, 3); + + cdTextBounds(x, y, s, rect); + lua_pushnumber(L, rect[0]); + lua_pushnumber(L, rect[1]); + lua_pushnumber(L, rect[2]); + lua_pushnumber(L, rect[3]); + lua_pushnumber(L, rect[4]); + lua_pushnumber(L, rect[5]); + lua_pushnumber(L, rect[6]); + lua_pushnumber(L, rect[7]); + return 4; +} + +/****************************************************************************************************************\ +* cd.wTextBounds(x, y: number, text: string) -> (rect0, rect1, rect2, rect3, rect4, rect5, rect6, rect7: number) * +\****************************************************************************************************************/ +static int wdlua5_textbounds(lua_State *L) +{ + double rect[8]; + double x = luaL_checknumber(L, 1); + double y = luaL_checknumber(L, 2); + const char* s = luaL_checkstring(L, 3); + + wdTextBounds(x, y, s, rect); + lua_pushnumber(L, rect[0]); + lua_pushnumber(L, rect[1]); + lua_pushnumber(L, rect[2]); + lua_pushnumber(L, rect[3]); + lua_pushnumber(L, rect[4]); + lua_pushnumber(L, rect[5]); + lua_pushnumber(L, rect[6]); + lua_pushnumber(L, rect[7]); + return 4; +} + + + +/***************************************************************************\ +* Text * +\***************************************************************************/ + +/***************************************************************************\ +* cd.VectorText(x, y: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L,3); + cdVectorText(luaL_checkint(L, 1), luaL_checkint(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.wVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + wdVectorText(luaL_checknumber(L, 1), luaL_checknumber(L, 2),s); + return 0; +} + +/***************************************************************************\ +* cd.MultiLineVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int cdlua5_multilinevectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + cdMultiLineVectorText(luaL_checkint(L, 1), luaL_checkint(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.wMultiLineVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int wdlua5_multilinevectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + wdMultiLineVectorText(luaL_checknumber(L, 1), luaL_checknumber(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.VectorTextDirection(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int cdlua5_vectortextdirection(lua_State *L) +{ + int x1 = luaL_checkint(L,1); + int y1 = luaL_checkint(L,2); + int x2 = luaL_checkint(L,3); + int y2 = luaL_checkint(L,4); + cdVectorTextDirection(x1, y1, x2, y2); + return 0; +} + +/***************************************************************************\ +* cd.wVectorTextDirection(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int wdlua5_vectortextdirection(lua_State *L) +{ + double x1 = luaL_checknumber(L, 1); + double y1 = luaL_checknumber(L, 2); + double x2 = luaL_checknumber(L, 3); + double y2 = luaL_checknumber(L, 4); + wdVectorTextDirection(x1, y1, x2, y2); + return 0; +} + + +/***************************************************************************\ +* cd.VectorTextTransform(matrix: table) -> (old_matrix: table) * +\***************************************************************************/ +static int cdlua5_vectortexttransform(lua_State *L) +{ + double matrix[6], *old_matrix; + int i; + + if (!lua_istable(L, 1)) + luaL_argerror(L, 1, "invalid matrix, must be a table"); + + for (i=0; i < 6; i++) + { + lua_rawgeti(L, 1, i+1); + + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 1, "invalid matrix value, must be a number"); + + matrix[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + old_matrix = cdVectorTextTransform(matrix); + lua_newtable(L); + for (i=0; i < 6; i++) + { + lua_pushnumber(L, old_matrix[i]); + lua_rawseti(L, 1, i+1); + } + return 1; +} + +/***************************************************************************\ +* cd.VectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectortextsize(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + cdVectorTextSize(luaL_checkint(L,1), luaL_checkint(L,2), s); + return 0; +} + +/***************************************************************************\ +* cd.wVectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectortextsize(lua_State *L) +{ + const char* s = luaL_checkstring(L, 3); + wdVectorTextSize(luaL_checknumber(L, 1), luaL_checknumber(L, 2), s); + return 0; +} + +/***************************************************************************\ +* cd.VectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectorcharsize(lua_State *L) +{ + lua_pushnumber(L, cdVectorCharSize(luaL_checkint(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.wVectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectorcharsize(lua_State *L) +{ + lua_pushnumber(L, wdVectorCharSize(luaL_checknumber(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.VectorFont(filename: string) -> (font_name: string) * +\***************************************************************************/ +static int cdlua5_vectorfont(lua_State *L) +{ + lua_pushstring(L, cdVectorFont(luaL_checkstring(L, 1))); + return 1; +} + +/***************************************************************************\ +* cd.GetVectorTextSize(text: string) -> (w, h: number) * +\***************************************************************************/ +static int cdlua5_getvectortextsize(lua_State *L) +{ + int width; + int height; + + const char* text_s = luaL_checkstring(L, 1); + + cdGetVectorTextSize(text_s, &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.wGetVectorTextSize(text: string) -> (w, h: number) * +\***************************************************************************/ +static int wdlua5_getvectortextsize(lua_State *L) +{ + double width; + double height; + + const char* text_s = luaL_checkstring(L, 1); + + wdGetVectorTextSize(text_s, &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.GetVectorTextBounds(s: string, px,py: number) -> (rect: table) * +\***************************************************************************/ +static int cdlua5_vectortextbounds(lua_State *L) +{ + const char* s = luaL_checkstring(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int rect[8], i; + + cdGetVectorTextBounds(s, x, y, rect); + lua_newtable(L); + for (i=0; i < 8; i++) + { + lua_pushnumber(L, rect[i]); + lua_rawseti(L, -2, i+1); + } + return 1; +} + +/***************************************************************************\ +* cd.wGetVectorTextBounds(s: string, px,py: number) -> (rect: table) * +\***************************************************************************/ +static int wdlua5_vectortextbounds(lua_State *L) +{ + const char* s = luaL_checkstring(L, 1); + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + double rect[8]; + int i; + + wdGetVectorTextBounds(s, x, y, rect); + lua_newtable(L); + for (i=0; i < 8; i++) + { + lua_pushnumber(L, rect[i]); + lua_rawseti(L, -2, i+1); + } + return 1; +} + + + +/***************************************************************************\ +* Client Images. * +\***************************************************************************/ + +static int cdlua5_getimagergb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + + cdGetImageRGB(imagergb_p->red, imagergb_p->green, imagergb_p->blue, + x, y, imagergb_p->width, imagergb_p->height); + return 0; +} + +static int cdlua5_putimagerectrgb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int w = luaL_checkint(L, 4); + int h = luaL_checkint(L, 5); + int xmin = luaL_checkint(L, 6); + int xmax = luaL_checkint(L, 7); + int ymin = luaL_checkint(L, 8); + int ymax = luaL_checkint(L, 9); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + cdPutImageRectRGB(imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectrgb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 1); + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + int xmin = luaL_checkint(L, 6); + int xmax = luaL_checkint(L, 7); + int ymin = luaL_checkint(L, 8); + int ymax = luaL_checkint(L, 9); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + wdPutImageRectRGB(imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putimagerectrgba(lua_State *L) +{ + cdluaImageRGBA* imagergba_p = cdlua_checkimagergba(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int w = luaL_checkint(L, 4); + int h = luaL_checkint(L, 5); + int xmin = luaL_checkint(L, 6); + int xmax = luaL_checkint(L, 7); + int ymin = luaL_checkint(L, 8); + int ymax = luaL_checkint(L, 9); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + cdPutImageRectRGBA(imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectrgba(lua_State *L) +{ + cdluaImageRGBA* imagergba_p = cdlua_checkimagergba(L, 1); + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + int xmin = luaL_checkint(L, 6); + int xmax = luaL_checkint(L, 7); + int ymin = luaL_checkint(L, 8); + int ymax = luaL_checkint(L, 9); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + wdPutImageRectRGBA(imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putimagerectmap(lua_State *L) +{ + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 1); + cdluaPalette *pal = cdlua_checkpalette(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int w = luaL_checkint(L, 5); + int h = luaL_checkint(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + cdPutImageRectMap(imagemap_p->width, imagemap_p->height, imagemap_p->index, + pal->color, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectmap(lua_State *L) +{ + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 1); + cdluaPalette *pal = cdlua_checkpalette(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double w = luaL_checknumber(L, 5); + double h = luaL_checknumber(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + wdPutImageRectMap(imagemap_p->width, imagemap_p->height, imagemap_p->index, + pal->color, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int w = luaL_checkint(L, 4); + int h = luaL_checkint(L, 5); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + cdPutBitmap(bitmap, x, y, w, h); + return 0; +} + +static int wdlua5_putbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 1); + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + + if (w < 0 || h < 0) + luaL_argerror(L, 4, "target region dimensions should be positive integers"); + + wdPutBitmap(bitmap, x, y, w, h); + return 0; +} + +static int cdlua5_getbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + cdGetBitmap(bitmap, x, y); + return 0; +} + +/***************************************************************************\ +* Server Images. * +\***************************************************************************/ + +static int cdlua5_createimage(lua_State *L) +{ + cdImage *image; + int width = luaL_checkint(L, 1); + int height = luaL_checkint(L, 2); + + if (width < 1 || height < 1) + luaL_argerror(L, 1, "image dimensions should be positive integers"); + + image = cdCreateImage(width, height); + if (image) + cdlua_pushimage(L, image); + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_getimage(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + cdGetImage(image, x, y); + return 0; +} + +static int cdlua5_putimagerect(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int xmin = luaL_checkint(L, 4); + int xmax = luaL_checkint(L, 5); + int ymin = luaL_checkint(L, 6); + int ymax = luaL_checkint(L, 7); + cdPutImageRect(image, x, y, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerect(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 1); + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + int xmin = luaL_checkint(L, 4); + int xmax = luaL_checkint(L, 5); + int ymin = luaL_checkint(L, 6); + int ymax = luaL_checkint(L, 7); + wdPutImageRect(image, x, y, xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.ScrollArea(xmin, xmax, ymin, ymax, dx, dy: number) * +\***************************************************************************/ +static int cdlua5_scrollarea(lua_State *L) +{ + int xmin = luaL_checkint(L, 1); + int xmax = luaL_checkint(L, 2); + int ymin = luaL_checkint(L, 3); + int ymax = luaL_checkint(L, 4); + int dx = luaL_checkint(L, 5); + int dy = luaL_checkint(L, 6); + cdScrollArea(xmin, xmax, ymin, ymax, dx, dy); + return 0; +} + + + +/***************************************************************************\ +* Other * +\***************************************************************************/ + +/********************************************************************************\ +* cd.Play(ctx, xmin, xmax, ymin, ymax: number, data: string) -> (status: number) * +\********************************************************************************/ + +static int cdlua5_play(lua_State *L) +{ + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 1); + int xmin = luaL_checkint(L,2); + int xmax = luaL_checkint(L,3); + int ymin = luaL_checkint(L,4); + int ymax = luaL_checkint(L,5); + const char *data_s = luaL_checkstring(L,6); + + cdlua_setplaystate(L); + cdPlay(cdlua_ctx->ctx(), xmin, xmax, ymin, ymax, (void*)data_s); + cdlua_setplaystate(NULL); + return 0; +} + +/***************************************************************************\ +* cd.GetColorPlanes() -> (bpp: number) * +\***************************************************************************/ +static int cdlua5_getcolorplanes(lua_State *L) +{ + lua_pushnumber(L, cdGetColorPlanes()); + return 1; +} + +static int cdlua5_palette(lua_State *L) +{ + cdluaPalette *pal = cdlua_checkpalette(L, 1); + int mode_i = luaL_checkint(L, 2); + cdPalette(pal->count, pal->color, mode_i); + return 0; +} + +/***************************************************************************\ +* cd.ImageRGB * +\***************************************************************************/ +static int cdlua5_imagergb(lua_State *L) +{ + cdCanvas *current_canvas; + int w, h, type = CD_RGB; + + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + + if (cdCanvasGetContext(canvas) != CD_IMAGERGB) + luaL_argerror(L, 1, "invalid canvas, must be CD_IMAGERGB"); + + if (cdAlphaImage(canvas)) + type = CD_RGBA; + + current_canvas = cdActiveCanvas(); + cdActivate(canvas); + cdGetCanvasSize(&w, &h, NULL, NULL); + cdActivate(current_canvas); + + /* mark the image NOT to be freed */ + if (type == CD_RGBA) + cdlua_pushimagergba_ex(L, cdRedImage(canvas), cdGreenImage(canvas), cdBlueImage(canvas), cdAlphaImage(canvas), w, h); + else + cdlua_pushimagergb_ex(L, cdRedImage(canvas), cdGreenImage(canvas), cdBlueImage(canvas), w, h); + + return 1; +} + +/***************************************************************************\ +* cd.ImageRGBBitmap * +\***************************************************************************/ +static int cdlua5_imagergbbitmap(lua_State *L) +{ + cdCanvas *current_canvas; + int w, h, type = CD_RGB; + + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + + if (cdCanvasGetContext(canvas) != CD_IMAGERGB) + luaL_argerror(L, 1, "invalid canvas, must be CD_IMAGERGB"); + + if (cdAlphaImage(canvas)) + type = CD_RGBA; + + current_canvas = cdActiveCanvas(); + cdActivate(canvas); + cdGetCanvasSize(&w, &h, NULL, NULL); + cdActivate(current_canvas); + + cdlua_pushbitmap(L, cdInitBitmap(w, h, type, + cdRedImage(canvas), + cdGreenImage(canvas), + cdBlueImage(canvas), + cdAlphaImage(canvas))); + + return 1; +} + +/***************************************************************************\ +* Hardcopy * +\***************************************************************************/ +static lua_State* wdlua5_hardcopy_luaState = NULL; + +static void wdlua5_hardcopy_func(void) +{ + lua_State* L = wdlua5_hardcopy_luaState; + lua_pushvalue(L, 4); /* push the function in the stack */ + if(lua_pcall(L, 0, 0, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); +} + +static int wdlua5_hardcopy(lua_State *L) +{ + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 1); + void *data_p = cdlua_ctx->checkdata(L, 2); + cdCanvas* canvas = cdlua_checkcanvas(L, 3); + luaL_argcheck(L, !lua_isfunction(L, 4), 4, "invalid draw function"); + + wdlua5_hardcopy_luaState = L; + wdHardcopy(cdlua_ctx->ctx(), data_p, canvas, wdlua5_hardcopy_func); + + return 0; +} + + +/***************************************************************************\ +* Polygon functions * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Begin(mode: number) * +\***************************************************************************/ +static int cdlua5_begin(lua_State *L) +{ + cdBegin(luaL_checkint(L, 1)); + return 0; +} + +/***************************************************************************\ +* cd.Vertex(x, y: number) * +\***************************************************************************/ +static int cdlua5_vertex(lua_State *L) +{ + cdVertex(luaL_checkint(L, 1), luaL_checkint(L, 2)); + return 0; +} + +/***************************************************************************\ +* cd.wVertex(x, y: number) * +\***************************************************************************/ +static int wdlua5_vertex(lua_State *L) +{ + wdVertex(luaL_checknumber(L, 1), luaL_checknumber(L, 2)); + return 0; +} + +/***************************************************************************\ +* cd.End() * +\***************************************************************************/ +static int cdlua5_end(lua_State *L) +{ + (void)L; + cdEnd(); + return 0; +} + + +/********************************************************************************\ +* CDLua Exported functions * +\********************************************************************************/ +static const struct luaL_reg cdlib_active[] = { + + /* Initialization */ + {"Activate" , cdlua5_activate}, + {"ActiveCanvas" , cdlua5_activecanvas}, + {"Simulate" , cdlua5_simulate}, + + /* Control */ + {"Clear" , cdlua5_clear}, + {"Flush" , cdlua5_flush}, + {"SaveState" , cdlua5_savestate}, + {"RestoreState" , cdlua5_restorestate}, + {"SetAttribute" , cdlua5_setattribute}, + {"GetAttribute" , cdlua5_getattribute}, + + /* Coordinate System */ + {"GetCanvasSize" , cdlua5_getcanvassize}, + {"UpdateYAxis" , cdlua5_updateyaxis}, + {"MM2Pixel" , cdlua5_mm2pixel}, + {"Pixel2MM" , cdlua5_pixel2mm}, + {"Origin" , cdlua5_origin}, + + /* World Coordinates */ + {"wWindow" , wdlua5_window}, + {"wGetWindow" , wdlua5_getwindow}, + {"wViewport" , wdlua5_viewport}, + {"wGetViewport" , wdlua5_getviewport}, + {"wWorld2Canvas" , wdlua5_world2canvas}, + {"wCanvas2World" , wdlua5_canvas2world}, + + {"wHardcopy" , wdlua5_hardcopy}, + + /* General Attributes */ + {"Foreground" , cdlua5_foreground}, + {"Background" , cdlua5_background}, + {"WriteMode" , cdlua5_writemode}, + + /* Clipping */ + {"Clip" , cdlua5_clip}, + {"ClipArea" , cdlua5_cliparea}, + {"wClipArea" , wdlua5_cliparea}, + {"GetClipArea" , cdlua5_getcliparea}, + {"wGetClipArea" , wdlua5_getcliparea}, + {"GetClipPoly" , cdlua5_getclippoly}, + {"wGetClipPoly" , wdlua5_getclippoly}, + + /* Regions */ + {"RegionCombineMode" , cdlua5_regioncombinemode}, + {"PointInRegion" , cdlua5_pointinregion}, + {"wPointInRegion" , wdlua5_pointinregion}, + {"OffsetRegion" , cdlua5_offsetregion}, + {"wOffsetRegion" , wdlua5_offsetregion}, + {"RegionBox" , cdlua5_regionbox}, + {"wRegionBox" , wdlua5_regionbox}, + + /* Marks */ + {"Pixel" , cdlua5_pixel}, + {"wPixel" , wdlua5_pixel}, + {"Mark" , cdlua5_mark}, + {"wMark" , wdlua5_mark}, + {"MarkType" , cdlua5_marktype}, + {"MarkSize" , cdlua5_marksize}, + {"wMarkSize" , wdlua5_marksize}, + + /* Line */ + {"Line" , cdlua5_line}, + {"wLine" , wdlua5_line}, + {"Rect" , cdlua5_rect}, + {"wRect" , wdlua5_rect}, + {"Arc" , cdlua5_arc}, + {"wArc" , wdlua5_arc}, + {"LineStyle" , cdlua5_linestyle}, + {"LineStyleDashes" , cdlua5_linestyledashes}, + {"LineWidth" , cdlua5_linewidth}, + {"wLineWidth" , wdlua5_linewidth}, + {"LineJoin" , cdlua5_linejoin}, + {"LineCap" , cdlua5_linecap}, + + /* Filled Areas */ + {"Box" , cdlua5_box}, + {"wBox" , wdlua5_box}, + {"Sector" , cdlua5_sector}, + {"wSector" , wdlua5_sector}, + {"Chord" , cdlua5_chord}, + {"wChord" , wdlua5_chord}, + {"BackOpacity" , cdlua5_backopacity}, + {"FillMode" , cdlua5_fillmode}, + {"InteriorStyle" , cdlua5_interiorstyle}, + {"Hatch" , cdlua5_hatch}, + + /* Stipple */ + {"Stipple" , cdlua5_stipple}, + {"wStipple" , wdlua5_stipple}, + {"GetStipple" , cdlua5_getstipple}, + + /* Pattern */ + {"Pattern" , cdlua5_pattern}, + {"wPattern" , wdlua5_pattern}, + {"GetPattern" , cdlua5_getpattern}, + + /* Text */ + {"Text" , cdlua5_text}, + {"wText" , wdlua5_text}, + {"Font" , cdlua5_font}, + {"wFont" , wdlua5_font}, + {"GetFont" , cdlua5_getfont}, + {"wGetFont" , wdlua5_getfont}, + {"NativeFont" , cdlua5_nativefont}, + {"TextAlignment" , cdlua5_textalignment}, + {"TextOrientation" , cdlua5_textorientation}, + {"FontDim" , cdlua5_fontdim}, + {"wFontDim" , wdlua5_fontdim}, + {"TextSize" , cdlua5_textsize}, + {"wTextSize" , wdlua5_textsize}, + {"TextBox" , cdlua5_textbox}, + {"wTextBox" , wdlua5_textbox}, + {"TextBounds" , cdlua5_textbounds}, + {"wTextBounds" , wdlua5_textbounds}, + + /* Vector Text */ + {"VectorText" , cdlua5_vectortext}, + {"wVectorText" , wdlua5_vectortext}, + {"MultiLineVectorText" , cdlua5_multilinevectortext}, + {"wMultiLineVectorText" , wdlua5_multilinevectortext}, + {"VectorTextDirection" , cdlua5_vectortextdirection}, + {"wVectorTextDirection" , wdlua5_vectortextdirection}, + {"VectorTextTransform" , cdlua5_vectortexttransform}, + {"VectorTextSize" , cdlua5_vectortextsize}, + {"wVectorTextSize" , wdlua5_vectortextsize}, + {"VectorCharSize" , cdlua5_vectorcharsize}, + {"wVectorCharSize" , wdlua5_vectorcharsize}, + {"VectorFont" , cdlua5_vectorfont}, + {"GetVectorTextSize" , cdlua5_getvectortextsize}, + {"wGetVectorTextSize" , wdlua5_getvectortextsize}, + {"VectorTextBounds" , cdlua5_vectortextbounds}, + {"wVectorTextBounds" , wdlua5_vectortextbounds}, + + /* Client Images */ + {"GetImageRGB" , cdlua5_getimagergb}, + {"PutImageRectRGB" , cdlua5_putimagerectrgb}, + {"wPutImageRectRGB" , wdlua5_putimagerectrgb}, + {"PutImageRectRGBA" , cdlua5_putimagerectrgba}, + {"wPutImageRectRGBA", wdlua5_putimagerectrgba}, + {"PutImageRectMap" , cdlua5_putimagerectmap}, + {"wPutImageRectMap" , wdlua5_putimagerectmap}, + {"GetBitmap" , cdlua5_getbitmap}, + {"PutBitmap" , cdlua5_putbitmap}, + {"wPutBitmap" , wdlua5_putbitmap}, + + {"ImageRGB" , cdlua5_imagergb}, + {"ImageRGBBitmap" , cdlua5_imagergbbitmap}, + + /* Server Images */ + {"CreateImage" , cdlua5_createimage}, + {"GetImage" , cdlua5_getimage}, + {"PutImageRect" , cdlua5_putimagerect}, + {"wPutImageRect" , wdlua5_putimagerect}, + {"ScrollArea" , cdlua5_scrollarea}, + + /* Other */ + {"Play" , cdlua5_play}, + + /* Color Coding */ + {"GetColorPlanes" , cdlua5_getcolorplanes}, + + /* Palette */ + {"Palette" , cdlua5_palette}, + + /* Polygon */ + {"Begin" , cdlua5_begin}, + {"Vertex" , cdlua5_vertex}, + {"wVertex" , wdlua5_vertex}, + {"End" , cdlua5_end}, + + {NULL, NULL}, +}; + +typedef struct cdlua5_constant { + const char *name; + lua_Number value; +} cdlua5_constant; + +/* old backward compatible constants */ +static const struct cdlua5_constant cdlibconstant[] = { + {"SYSTEM", CD_SYSTEM}, + {"COURIER", CD_COURIER}, + {"TIMES_ROMAN", CD_TIMES_ROMAN}, + {"HELVETICA", CD_HELVETICA}, + {"NATIVE", CD_NATIVE}, + {"CLIPON", CD_CLIPON}, + {"CENTER_BASE", CD_CENTER_BASE}, + {"LEFT_BASE", CD_LEFT_BASE}, + {"RIGHT_BASE", CD_RIGHT_BASE}, + {"ITALIC_BOLD", CD_ITALIC_BOLD}, + + {NULL, -1} +}; + +static void initconst(lua_State *L) +{ + const cdlua5_constant *l = cdlibconstant; + for (; l->name; l++) { + lua_pushstring(L, l->name); + lua_pushnumber(L, l->value); + lua_settable(L, -3); + } +} + +void cdlua_open_active (lua_State *L, cdluaLuaState* cdL) +{ + /* "cd" table is at the top of the stack */ + luaL_register(L, NULL, cdlib_active); + initconst(L); + + cdL->void_canvas = cdCreateCanvas(CD_VOID, NULL); + cdlua_setvoidstate(cdL->void_canvas, L); + cdActivate(cdL->void_canvas); +} diff --git a/src/lua5/cdlua5_canvas.c b/src/lua5/cdlua5_canvas.c new file mode 100644 index 0000000..8800123 --- /dev/null +++ b/src/lua5/cdlua5_canvas.c @@ -0,0 +1,2343 @@ +/** \file + * \brief Lua Binding of the Canvas dependent API + * + * See Copyright Notice in cd.h + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "cd.h" +#include "wd.h" +#include "cdirgb.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdlua5_private.h" + +#define _cdCheckCanvas(_canvas) (_canvas!=NULL && ((unsigned char*)_canvas)[0] == 'C' && ((unsigned char*)_canvas)[1] == 'D') + + +void cdlua_pushcanvas(lua_State * L, cdCanvas* canvas) +{ + cdCanvas* *canvas_p = (cdCanvas* *) lua_newuserdata(L, sizeof(cdCanvas*)); + *canvas_p = canvas; + luaL_getmetatable(L, "cdCanvas"); + lua_setmetatable(L, -2); +} + +cdCanvas* cdlua_checkcanvas(lua_State * L, int pos) +{ + cdCanvas* *canvas_p = (cdCanvas**)luaL_checkudata(L, pos, "cdCanvas"); + if (!(*canvas_p)) + luaL_argerror(L, pos, "killed cdCanvas"); + if (!_cdCheckCanvas(*canvas_p)) + luaL_argerror(L, pos, "invalid Lua object, killed cdCanvas in C but not in Lua"); + return *canvas_p; +} + +cdCanvas* cdlua_getcanvas(lua_State * L) +{ + return cdlua_checkcanvas(L, 1); +} + +static int cdlua5_createcanvas(lua_State * L) +{ + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 1); + void *data_p = cdlua_ctx->checkdata(L, 2); + + cdCanvas* canvas = cdCreateCanvas(cdlua_ctx->ctx(), data_p); + + /* if creation failed, return nil so that the user can compare */ + /* the result with nil and know that it failed */ + if (canvas) + cdlua_pushcanvas(L, canvas); + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_killcanvas(lua_State *L) +{ + cdCanvas* *canvas_p = (cdCanvas**) luaL_checkudata(L, 1, "cdCanvas"); + if (!(*canvas_p)) + luaL_argerror(L, 1, "killed cdCanvas"); + if (!_cdCheckCanvas(*canvas_p)) + luaL_argerror(L, 1, "invalid Lua object, killed cdCanvas in C but not in Lua"); + + cdlua_kill_active(L, *canvas_p); + + cdKillCanvas(*canvas_p); + *canvas_p = NULL; /* mark as killed */ + + return 0; +} + +static int cdluaCanvas_eq (lua_State *L) +{ + cdCanvas* canvas1 = cdlua_checkcanvas(L, 1); + cdCanvas* canvas2 = cdlua_checkcanvas(L, 2); + lua_pushboolean(L, canvas1 == canvas2); + return 1; +} + +static int cdluaCanvas_tostring (lua_State *L) +{ + cdCanvas* *canvas_p = (cdCanvas**) luaL_checkudata(L, 1, "cdCanvas"); + if (!(*canvas_p)) + lua_pushfstring(L, "cdCanvas(%p - NULL)-killed", canvas_p); + else if (!_cdCheckCanvas(*canvas_p)) + lua_pushfstring(L, "cdCanvas(%p - INVALID)-killed in C but not in Lua", canvas_p); + else + lua_pushfstring(L, "cdCanvas(%p - %p)", canvas_p, *canvas_p); + return 1; +} + +static int cdlua5_getcontext(lua_State * L) +{ + cdluaLuaState* cdL; + cdContext* ctx; + int i; + int driver = -1; + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + + ctx = cdCanvasGetContext(canvas); + cdL = cdlua_getstate(L); + + for (i=0; i < cdL->numdrivers; i++) + { + if (ctx == cdL->drivers[i]->ctx()) + { + driver = i; + break; + } + } + + if (i == cdL->numdrivers) + luaL_argerror(L, 1, "unknown driver"); + + lua_pushnumber(L, driver); + return 1; +} + +/***************************************************************************\ +* Activates a cd canvas. * +\***************************************************************************/ +static int cdlua5_activate(lua_State * L) +{ + lua_pushnumber(L, cdCanvasActivate(cdlua_checkcanvas(L, 1))); + return 1; +} + +static int cdlua5_deactivate(lua_State * L) +{ + cdCanvasDeactivate(cdlua_checkcanvas(L, 1)); + return 0; +} + +/***************************************************************************\ +* cd.Simulate(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_simulate(lua_State *L) +{ + lua_pushnumber(L, cdCanvasSimulate(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* Control * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Clear() * +\***************************************************************************/ +static int cdlua5_clear(lua_State *L) +{ + cdCanvasClear(cdlua_checkcanvas(L, 1)); + return 0; +} + +/***************************************************************************\ +* cd.Flush() * +\***************************************************************************/ +static int cdlua5_flush(lua_State *L) +{ + cdCanvasFlush(cdlua_checkcanvas(L, 1)); + return 0; +} + +static int cdlua5_savestate(lua_State *L) +{ + cdState* state = cdCanvasSaveState(cdlua_checkcanvas(L, 1)); + if (state) + cdlua_pushstate(L, state); + else + lua_pushnil(L); + return 1; +} + +static int cdlua5_restorestate(lua_State * L) +{ + cdCanvasRestoreState(cdlua_checkcanvas(L, 1), cdlua_checkstate(L, 2)); + return 0; +} + +static int cdlua_isuserdata(const char* name) +{ + if (strcmp(name, "HDC")==0) return 1; + if (strcmp(name, "GC")==0) return 1; + return 0; +} + +/***************************************************************************\ +* cd.SetAttribute(name, data: string) * +\***************************************************************************/ +static int cdlua5_setattribute(lua_State *L) +{ + const char* name = luaL_checkstring(L, 2); + + if (lua_isnil(L, 2)) + { + cdCanvasSetAttribute(cdlua_checkcanvas(L, 1), name, NULL); + } + else + { + char* data; + if (cdlua_isuserdata(name)) + data = (char*) lua_touserdata(L, 3); + else + data = (char*) luaL_checkstring(L, 3); + cdCanvasSetAttribute(cdlua_checkcanvas(L, 1), name, data); + } + return 0; +} + + +/***************************************************************************\ +* cd.SetAttribute(name: string) -> (data: string) * +\***************************************************************************/ +static int cdlua5_getattribute(lua_State *L) +{ + const char* name = luaL_checkstring(L, 2); + char* data = cdCanvasGetAttribute(cdlua_checkcanvas(L, 1), name); + if (data) + { + if (cdlua_isuserdata(name)) + lua_pushlightuserdata(L, data); + else + lua_pushstring(L, data); + } + else + lua_pushnil(L); + return 1; +} + + + +/***************************************************************************\ +* Coordinate System * +\***************************************************************************/ + +/***************************************************************************\ +* cd.GetCanvasSize() -> (width, heigth, mm_width, mm_height: number) * +\***************************************************************************/ +static int cdlua5_getcanvassize(lua_State *L) +{ + int width; + int height; + double mm_width; + double mm_height; + + cdCanvasGetSize(cdlua_checkcanvas(L, 1), &width, &height, &mm_width, &mm_height); + + lua_pushnumber(L, width); + lua_pushnumber(L, height); + lua_pushnumber(L, mm_width); + lua_pushnumber(L, mm_height); + return 4; +} + +/***************************************************************************\ +* cd.UpdateYAxis(yc: number) -> (yr: number) * +\***************************************************************************/ +static int cdlua5_updateyaxis(lua_State *L) +{ + double y = luaL_checknumber(L, 2); + cdfCanvasUpdateYAxis(cdlua_checkcanvas(L, 1), &y); + lua_pushnumber(L, y); + return 1; +} + +static int cdlua5_invertyaxis(lua_State *L) +{ + lua_pushnumber(L, cdfCanvasInvertYAxis(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int cdlua5_mm2pixel(lua_State *L) +{ + double mm_dx, mm_dy; + int dx, dy; + + mm_dx = luaL_checknumber(L,2); + mm_dy = luaL_checknumber(L,3); + + cdCanvasMM2Pixel(cdlua_checkcanvas(L, 1), mm_dx, mm_dy, &dx, &dy); + lua_pushnumber(L, dx); + lua_pushnumber(L, dy); + return 2; +} + +static int cdlua5_pixel2mm(lua_State *L) +{ + double mm_dx_d, mm_dy_d; + int dx, dy; + + dx = luaL_checkint(L,2); + dy = luaL_checkint(L,3); + + cdCanvasPixel2MM(cdlua_checkcanvas(L, 1), dx, dy, &mm_dx_d, &mm_dy_d); + lua_pushnumber(L, mm_dx_d); + lua_pushnumber(L, mm_dy_d); + return 2; +} + +static int cdlua5_fmm2pixel(lua_State *L) +{ + double mm_dx, mm_dy; + double dx, dy; + + mm_dx = luaL_checknumber(L,2); + mm_dy = luaL_checknumber(L,3); + + cdfCanvasMM2Pixel(cdlua_checkcanvas(L, 1), mm_dx, mm_dy, &dx, &dy); + lua_pushnumber(L, dx); + lua_pushnumber(L, dy); + return 2; +} + +static int cdlua5_fpixel2mm(lua_State *L) +{ + double mm_dx_d, mm_dy_d; + double dx, dy; + + dx = luaL_checknumber(L,2); + dy = luaL_checknumber(L,3); + + cdfCanvasPixel2MM(cdlua_checkcanvas(L, 1), dx, dy, &mm_dx_d, &mm_dy_d); + lua_pushnumber(L, mm_dx_d); + lua_pushnumber(L, mm_dy_d); + return 2; +} + +static int cdlua5_origin(lua_State *L) +{ + cdCanvasOrigin(cdlua_checkcanvas(L, 1), luaL_checkint(L,2), luaL_checkint(L,3)); + return 0; +} + +static int cdlua5_getorigin(lua_State *L) +{ + int x, y; + cdCanvasGetOrigin(cdlua_checkcanvas(L, 1), &x, &y); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + return 2; +} + +static int cdlua5_forigin(lua_State *L) +{ + cdfCanvasOrigin(cdlua_checkcanvas(L, 1), luaL_checknumber(L,2), luaL_checknumber(L,3)); + return 0; +} + +static int cdlua5_fgetorigin(lua_State *L) +{ + double x, y; + cdfCanvasGetOrigin(cdlua_checkcanvas(L, 1), &x, &y); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + return 2; +} + +static int cdlua5_transform(lua_State *L) +{ + double matrix[6]; + int i; + + if (!lua_istable(L, 2)) + luaL_argerror(L, 2, "invalid matrix, must be a table"); + + for (i=0; i < 6; i++) + { + lua_rawgeti(L, 2, i+1); + + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 2, "invalid matrix value, must be a number"); + + matrix[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + cdCanvasTransform(cdlua_checkcanvas(L, 1), matrix); + return 0; +} + +static int cdlua5_gettransform(lua_State *L) +{ + int i; + double* matrix = cdCanvasGetTransform(cdlua_checkcanvas(L, 1)); + lua_newtable(L); + for (i=0; i < 6; i++) + { + lua_pushnumber(L, matrix[i]); + lua_rawseti(L, 1, i+1); + } + return 1; +} + +static int cdlua5_transformmultiply(lua_State *L) +{ + double matrix[6]; + int i; + + if (!lua_istable(L, 2)) + luaL_argerror(L, 2, "invalid matrix, must be a table"); + + for (i=0; i < 6; i++) + { + lua_rawgeti(L, 2, i+1); + + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 1, "invalid matrix value, must be a number"); + + matrix[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + cdCanvasTransformMultiply(cdlua_checkcanvas(L, 1), matrix); + return 0; +} + +static int cdlua5_transformrotate(lua_State *L) +{ + cdCanvasTransformRotate(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2)); + return 0; +} + +static int cdlua5_transformscale(lua_State *L) +{ + cdCanvasTransformScale(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +static int cdlua5_transformtranslate(lua_State *L) +{ + cdCanvasTransformTranslate(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +static int cdlua5_transformpoint(lua_State *L) +{ + int x, y; + cdCanvasTransformPoint(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), &x, &y); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + return 2; +} + +static int cdlua5_ftransformpoint(lua_State *L) +{ + double x, y; + cdfCanvasTransformPoint(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), &x, &y); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + return 2; +} + +/***************************************************************************\ +* World Coordinates * +\***************************************************************************/ + +/***************************************************************************\ +* wd.Window(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_window(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + wdCanvasWindow(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* wd.GetWindow() -> (xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_getwindow(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + + wdCanvasGetWindow(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* wd.Viewport(xmin, xmax, ymin, ymax: number) * +\***************************************************************************/ +static int wdlua5_viewport(lua_State *L) +{ + int xmin = luaL_checkint(L, 2); + int xmax = luaL_checkint(L, 3); + int ymin = luaL_checkint(L, 4); + int ymax = luaL_checkint(L, 5); + wdCanvasViewport(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* wd.GetViewport() -> (xmin, xmax, ymin, ymax: number * +\***************************************************************************/ +static int wdlua5_getviewport(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + + wdCanvasGetViewport(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* wd.World2Canvas(xw, yw: number) -> (xv, yv: number) * +\***************************************************************************/ +static int wdlua5_world2canvas(lua_State *L) +{ + double xw_d, yw_d; + int xv_i, yv_i; + + xw_d = luaL_checknumber(L, 2); + yw_d = luaL_checknumber(L, 3); + + wdCanvasWorld2Canvas(cdlua_checkcanvas(L, 1), xw_d, yw_d, &xv_i, &yv_i); + lua_pushnumber(L, xv_i); + lua_pushnumber(L, yv_i); + return 2; +} + +/***************************************************************************\ +* wd.Canvas2World(xv, yv: number) -> (xw, yw: number) * +\***************************************************************************/ +static int wdlua5_canvas2world(lua_State *L) +{ + int xv_i, yv_i; + double xw_d, yw_d; + + xv_i = luaL_checkint(L, 2); + yv_i = luaL_checkint(L, 3); + + wdCanvasCanvas2World(cdlua_checkcanvas(L, 1), xv_i, yv_i, &xw_d, &yw_d); + lua_pushnumber(L, xw_d); + lua_pushnumber(L, yw_d); + return 2; +} + + + +/***************************************************************************\ +* General Attributes * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Foreground(color) -> color * +\***************************************************************************/ +static int cdlua5_foreground(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + color_i = cdCanvasForeground(cdlua_checkcanvas(L, 1), color_i); + lua_pushlightuserdata(L, (void*) color_i); + return 1; +} + +static int cdlua5_setforeground(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + cdCanvasSetForeground(cdlua_checkcanvas(L, 1), color_i); + return 0; +} + +/***************************************************************************\ +* cd.Background(color) -> color * +\***************************************************************************/ +static int cdlua5_background(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + color_i = cdCanvasBackground(cdlua_checkcanvas(L, 1), color_i); + lua_pushlightuserdata(L, (void*) color_i); + return 1; +} + +static int cdlua5_setbackground(lua_State *L) +{ + long int color_i = cdlua_checkcolor(L, 1); + cdCanvasSetBackground(cdlua_checkcanvas(L, 1), color_i); + return 0; +} +/***************************************************************************\ +* cd.WriteMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_writemode(lua_State *L) +{ + lua_pushnumber(L, cdCanvasWriteMode(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + + + +/***************************************************************************\ +* Clipping * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Clip(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_clip(lua_State *L) +{ + lua_pushnumber(L, cdCanvasClip(cdlua_checkcanvas(L, 1), luaL_checkint(L,2))); + return 1; +} + +static int cdlua5_cliparea(lua_State *L) +{ + int xmin = luaL_checkint(L, 2); + int xmax = luaL_checkint(L, 3); + int ymin = luaL_checkint(L, 4); + int ymax = luaL_checkint(L, 5); + + cdCanvasClipArea(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_cliparea(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + + wdCanvasClipArea(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_fcliparea(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + + cdfCanvasClipArea(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_getcliparea(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + int status; + + status = cdCanvasGetClipArea(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + lua_pushnumber(L, status); + return 5; +} + +static int wdlua5_getcliparea(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + int status; + + status = wdCanvasGetClipArea(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + lua_pushnumber(L, status); + return 5; +} + +static int cdlua5_fgetcliparea(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + int status; + + status = cdfCanvasGetClipArea(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + lua_pushnumber(L, status); + return 5; +} + +/***************************************************************************\ +* Regions * +\***************************************************************************/ + +/***************************************************************************\ +* cd.RegionCombineMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_regioncombinemode(lua_State *L) +{ + lua_pushnumber(L, cdCanvasRegionCombineMode(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.PointInRegion(x, y: number) -> (status: number) * +\***************************************************************************/ +static int cdlua5_pointinregion(lua_State *L) +{ + lua_pushnumber(L, cdCanvasIsPointInRegion(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3))); + return 1; +} + +/***************************************************************************\ +* cd.wPointInRegion(x, y: number) -> (status: number) * +\***************************************************************************/ +static int wdlua5_pointinregion(lua_State *L) +{ + lua_pushnumber(L, wdCanvasIsPointInRegion(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3))); + return 1; +} + +/***************************************************************************\ +* cd.OffsetRegion(dx, dy: number) * +\***************************************************************************/ +static int cdlua5_offsetregion(lua_State *L) +{ + cdCanvasOffsetRegion(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.wOffsetRegion(dx, dy: number) * +\***************************************************************************/ +static int wdlua5_offsetregion(lua_State *L) +{ + wdCanvasOffsetRegion(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.RegionBox() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int cdlua5_regionbox(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + + cdCanvasGetRegionBox(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************\ +* cd.wRegionBox() -> (xmin, xmax, ymin, ymax, status: number) * +\***************************************************************************/ +static int wdlua5_regionbox(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + + wdCanvasGetRegionBox(cdlua_checkcanvas(L, 1), &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + + +/***************************************************************************\ +* Primitives * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Pixel(x, y: number, color) * +\***************************************************************************/ +static int cdlua5_pixel (lua_State *L) +{ + cdCanvasPixel(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), cdlua_checkcolor(L, 4)); + return 0 ; +} + +/***************************************************************************\ +* cd.wPixel(x, y: number, color) * +\***************************************************************************/ +static int wdlua5_pixel (lua_State *L) +{ + wdCanvasPixel(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), cdlua_checkcolor(L, 4)); + return 0; +} + +/***************************************************************************\ +* cd.Mark(x, y: number) * +\***************************************************************************/ +static int cdlua5_mark(lua_State *L) +{ + cdCanvasMark(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.wMark(x, y: number) * +\***************************************************************************/ +static int wdlua5_mark(lua_State *L) +{ + wdCanvasMark(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +/***************************************************************************\ +* cd.MarkType(type: number) -> (old_type: number) * +\***************************************************************************/ +static int cdlua5_marktype(lua_State *L) +{ + lua_pushnumber(L, cdCanvasMarkType(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.MarkSize(size: number) -> (old_size: number) * +\***************************************************************************/ +static int cdlua5_marksize(lua_State *L) +{ + lua_pushnumber(L, cdCanvasMarkSize(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.wMarkSize(size: number) -> (old_size: number) * +\***************************************************************************/ +static int wdlua5_marksize(lua_State *L) +{ + lua_pushnumber(L, wdCanvasMarkSize(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2))); + return 1; +} + + + +/***************************************************************************\ +* Lines * +\***************************************************************************/ + +static int cdlua5_line(lua_State *L) +{ + int x1 = luaL_checkint(L,2); + int y1 = luaL_checkint(L,3); + int x2 = luaL_checkint(L,4); + int y2 = luaL_checkint(L,5); + cdCanvasLine(cdlua_checkcanvas(L, 1), x1, y1, x2, y2); + return 0; +} + +static int wdlua5_line(lua_State *L) +{ + double x1 = luaL_checknumber(L, 2); + double y1 = luaL_checknumber(L, 3); + double x2 = luaL_checknumber(L, 4); + double y2 = luaL_checknumber(L, 5); + wdCanvasLine(cdlua_checkcanvas(L, 1), x1, y1, x2, y2); + return 0; +} + +static int cdlua5_fline(lua_State *L) +{ + double x1 = luaL_checknumber(L, 2); + double y1 = luaL_checknumber(L, 3); + double x2 = luaL_checknumber(L, 4); + double y2 = luaL_checknumber(L, 5); + cdfCanvasLine(cdlua_checkcanvas(L, 1), x1, y1, x2, y2); + return 0; +} + +static int cdlua5_rect(lua_State *L) +{ + int xmin = luaL_checkint(L,2); + int xmax = luaL_checkint(L,3); + int ymin = luaL_checkint(L,4); + int ymax = luaL_checkint(L,5); + cdCanvasRect(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_rect(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + wdCanvasRect(cdlua_checkcanvas(L, 1), xmin,xmax,ymin,ymax); + return 0; +} + +static int cdlua5_frect(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + cdfCanvasRect(cdlua_checkcanvas(L, 1), xmin,xmax,ymin,ymax); + return 0; +} + +static int cdlua5_arc(lua_State *L) +{ + int xc = luaL_checkint(L,2); + int yc = luaL_checkint(L,3); + int w = luaL_checkint(L,4); + int h = luaL_checkint(L,5); + double angle1 = luaL_checknumber(L,6); + double angle2 = luaL_checknumber(L,7); + cdCanvasArc(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int wdlua5_arc(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + wdCanvasArc(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int cdlua5_farc(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + cdfCanvasArc(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.LineStyle(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linestyle(lua_State *L) +{ + lua_pushnumber(L, cdCanvasLineStyle(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.LineStyleDashes(dashes: table, count: number) * +\***************************************************************************/ +static int cdlua5_linestyledashes(lua_State *L) +{ + int *dashes_int, dashes_count, i; + + if (!lua_istable(L, 2)) + luaL_argerror(L, 2, "invalid dashes, must be a table"); + + dashes_count = luaL_checkint(L, 3); + dashes_int = (int*) malloc(dashes_count * sizeof(int)); + + for (i=0; i < dashes_count; i++) + { + lua_pushnumber(L, i+1); + lua_gettable(L, 2); + + dashes_int[i] = luaL_checkint(L,-1); + } + + cdCanvasLineStyleDashes(cdlua_checkcanvas(L, 1), dashes_int, dashes_count); + free(dashes_int); + + return 0; +} + +/***************************************************************************\ +* cd.LineWidth(width: number) -> (old_width: number) * +\***************************************************************************/ +static int cdlua5_linewidth(lua_State *L) +{ + lua_pushnumber(L, cdCanvasLineWidth(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.wLineWidth(width: number) -> (old_width: number) * +\***************************************************************************/ +static int wdlua5_linewidth(lua_State *L) +{ + lua_pushnumber(L, wdCanvasLineWidth(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.LineJoin(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linejoin(lua_State *L) +{ + lua_pushnumber(L, cdCanvasLineJoin(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.LineCap(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_linecap(lua_State *L) +{ + lua_pushnumber(L, cdCanvasLineCap(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + + + +/***************************************************************************\ +* Filled Areas * +\***************************************************************************/ + +static int cdlua5_box(lua_State *L) +{ + int xmin = luaL_checkint(L, 2); + int xmax = luaL_checkint(L, 3); + int ymin = luaL_checkint(L, 4); + int ymax = luaL_checkint(L, 5); + cdCanvasBox(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_box(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + wdCanvasBox(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_fbox(lua_State *L) +{ + double xmin = luaL_checknumber(L, 2); + double xmax = luaL_checknumber(L, 3); + double ymin = luaL_checknumber(L, 4); + double ymax = luaL_checknumber(L, 5); + cdfCanvasBox(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_sector(lua_State *L) +{ + int xc = luaL_checkint(L,2); + int yc = luaL_checkint(L,3); + int w = luaL_checkint(L,4); + int h = luaL_checkint(L,5); + double angle1 = luaL_checknumber(L,6); + double angle2 = luaL_checknumber(L,7); + cdCanvasSector(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int wdlua5_sector(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + wdCanvasSector(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int cdlua5_fsector(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + cdfCanvasSector(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int cdlua5_chord(lua_State *L) +{ + int xc = luaL_checkint(L,2); + int yc = luaL_checkint(L,3); + int w = luaL_checkint(L,4); + int h = luaL_checkint(L,5); + double angle1 = luaL_checknumber(L,6); + double angle2 = luaL_checknumber(L,7); + cdCanvasChord(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int wdlua5_chord(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + wdCanvasChord(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +static int cdlua5_fchord(lua_State *L) +{ + double xc = luaL_checknumber(L, 2); + double yc = luaL_checknumber(L, 3); + double w = luaL_checknumber(L, 4); + double h = luaL_checknumber(L, 5); + double angle1 = luaL_checknumber(L, 6); + double angle2 = luaL_checknumber(L, 7); + cdfCanvasChord(cdlua_checkcanvas(L, 1), xc, yc, w, h, angle1, angle2); + return 0; +} + +/***************************************************************************\ +* cd.BackOpacity(opacity: number) -> (old_opacity: number) * +\***************************************************************************/ +static int cdlua5_backopacity(lua_State *L) +{ + lua_pushnumber(L, cdCanvasBackOpacity(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.FillMode(mode: number) -> (old_mode: number) * +\***************************************************************************/ +static int cdlua5_fillmode(lua_State *L) +{ + lua_pushnumber(L, cdCanvasFillMode(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.InteriorStyle(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_interiorstyle(lua_State *L) +{ + lua_pushnumber(L, cdCanvasInteriorStyle(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.Hatch(style: number) -> (old_style: number) * +\***************************************************************************/ +static int cdlua5_hatch(lua_State *L) +{ + lua_pushnumber(L, cdCanvasHatch(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +static int cdlua5_stipple(lua_State *L) +{ + cdluaStipple *stipple_p = cdlua_checkstipple(L, 2); + cdCanvasStipple(cdlua_checkcanvas(L, 1), stipple_p->width, stipple_p->height, stipple_p->stipple); + return 0 ; +} + +static int wdlua5_stipple(lua_State *L) +{ + cdluaStipple *stipple_p = cdlua_checkstipple(L, 2); + double w_mm = luaL_checknumber(L, 3); + double h_mm = luaL_checknumber(L, 4); + wdCanvasStipple(cdlua_checkcanvas(L, 1), stipple_p->width, stipple_p->height, stipple_p->stipple, w_mm, h_mm); + return 0; +} + +static int cdlua5_getstipple(lua_State *L) +{ + int width, height, size; + unsigned char *stipple, *new_stipple = NULL; + + stipple = cdCanvasGetStipple(cdlua_checkcanvas(L, 1), &width, &height); + + size = width * height; + + if (stipple) + new_stipple = (unsigned char *)malloc(size); + + if (new_stipple) + { + memcpy(new_stipple, stipple, size); + cdlua_pushstipple(L, new_stipple, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_pattern(lua_State *L) +{ + cdluaPattern* pattern_p = cdlua_checkpattern(L, 2); + cdCanvasPattern(cdlua_checkcanvas(L, 1), pattern_p->width, pattern_p->height, pattern_p->pattern); + return 0; +} + +static int wdlua5_pattern(lua_State *L) +{ + cdluaPattern* pattern_p = cdlua_checkpattern(L, 2); + double w_mm = luaL_checknumber(L, 3); + double h_mm = luaL_checknumber(L, 4); + wdCanvasPattern(cdlua_checkcanvas(L, 1), pattern_p->width, pattern_p->height, pattern_p->pattern, w_mm, h_mm); + return 0; +} + +static int cdlua5_getpattern(lua_State *L) +{ + int width, height, size; + long int *pattern, *new_pattern = NULL; + + pattern = cdCanvasGetPattern(cdlua_checkcanvas(L, 1), &width, &height); + + size = width * height; + + if (pattern) + new_pattern = (long int *) malloc(size * sizeof(long int)); + + if (new_pattern) + { + memcpy(new_pattern, pattern, size * sizeof(long int)); + cdlua_pushpattern(L, new_pattern, width, height); + } + else + lua_pushnil(L); + + return 1; +} + +/***************************************************************************\ +* Text * +\***************************************************************************/ + +static int cdlua5_text(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + cdCanvasText(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), s); + return 0; +} + +static int wdlua5_text(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + wdCanvasText(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), s); + return 0; +} + +static int cdlua5_ftext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + cdfCanvasText(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.Font(typeface, style, size: number) * +\***************************************************************************/ +static int cdlua5_font(lua_State *L) +{ + lua_pushnumber(L, cdCanvasFont(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), luaL_checkint(L, 3), luaL_checkint(L, 4))); + return 1; +} + +/***************************************************************************\ +* cd.wFont(typeface, style, size: number) * +\***************************************************************************/ +static int wdlua5_font(lua_State *L) +{ + lua_pushnumber(L, wdCanvasFont(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), luaL_checkint(L, 3), luaL_checknumber(L, 4))); + return 1; +} + + +/***************************************************************************\ +* cd.GetFont() -> (typeface, style, size: number) * +\***************************************************************************/ +static int cdlua5_getfont(lua_State *L) +{ + char type_face[1024]; + int style, size; + + cdCanvasGetFont(cdlua_checkcanvas(L, 1), type_face, &style, &size); + lua_pushstring(L, type_face); + lua_pushnumber(L, style); + lua_pushnumber(L, size); + return 3; +} + +/***************************************************************************\ +* cd.wGetFont() -> (typeface, style, size: number) * +\***************************************************************************/ +static int wdlua5_getfont(lua_State *L) +{ + char type_face[1024]; + int style; + double size; + + wdCanvasGetFont(cdlua_checkcanvas(L, 1), type_face, &style, &size); + lua_pushstring(L, type_face); + lua_pushnumber(L, style); + lua_pushnumber(L, size); + return 3; +} + +/***************************************************************************\ +* cd.NativeFont(font: string) * +\***************************************************************************/ +static int cdlua5_nativefont(lua_State *L) +{ + lua_pushstring(L, cdCanvasNativeFont(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.TextAlignment(alignment: number) -> (old_alignment: number) * +\***************************************************************************/ +static int cdlua5_textalignment(lua_State *L) +{ + lua_pushnumber(L, cdCanvasTextAlignment(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.TextOrientation(angle: number) -> (old_angle: number) * +\***************************************************************************/ +static int cdlua5_textorientation(lua_State *L) +{ + lua_pushnumber(L, cdCanvasTextOrientation(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.FontDim() -> (max_width, max_height, ascent, descent: number) * +\***************************************************************************/ +static int cdlua5_fontdim(lua_State *L) +{ + int max_width; + int height; + int ascent; + int descent; + + cdCanvasGetFontDim(cdlua_checkcanvas(L, 1), &max_width, &height, &ascent, &descent); + lua_pushnumber(L, max_width); + lua_pushnumber(L, height); + lua_pushnumber(L, ascent); + lua_pushnumber(L, descent); + return 4; +} + +/***************************************************************************\ +* cd.wFontDim() -> (max_width, max_height, ascent, descent: number) * +\***************************************************************************/ +static int wdlua5_fontdim(lua_State *L) +{ + double max_width; + double height; + double ascent; + double descent; + + wdCanvasGetFontDim(cdlua_checkcanvas(L, 1), &max_width, &height, &ascent, &descent); + lua_pushnumber(L, max_width); + lua_pushnumber(L, height); + lua_pushnumber(L, ascent); + lua_pushnumber(L, descent); + return 4; +} + +/***************************************************************************\ +* cd.TextSize(text: string) -> (width, heigth: number) * +\***************************************************************************/ +static int cdlua5_textsize(lua_State *L) +{ + int width; + int height; + cdCanvasGetTextSize(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.wTextSize(text: string) -> (width, heigth: number) * +\***************************************************************************/ +static int wdlua5_textsize(lua_State *L) +{ + double width; + double height; + wdCanvasGetTextSize(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/****************************************************************************\ +* cd.TextBox(x, y: number, text: string) -> (xmin, xmax, ymin, ymax: number) * +\****************************************************************************/ +static int cdlua5_textbox(lua_State *L) +{ + int xmin, xmax, ymin, ymax; + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + const char* s = luaL_checkstring(L, 4); + + cdCanvasGetTextBox(cdlua_checkcanvas(L, 1), x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/*****************************************************************************\ +* cd.wTextBox(x, y: number, text: string) -> (xmin, xmax, ymin, ymax: number) * +\*****************************************************************************/ +static int wdlua5_textbox(lua_State *L) +{ + double xmin, xmax, ymin, ymax; + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + const char* s = luaL_checkstring(L, 4); + + wdCanvasGetTextBox(cdlua_checkcanvas(L, 1), x, y, s, &xmin, &xmax, &ymin, &ymax); + lua_pushnumber(L, xmin); + lua_pushnumber(L, xmax); + lua_pushnumber(L, ymin); + lua_pushnumber(L, ymax); + return 4; +} + +/***************************************************************************************************************\ +* cd.TextBounds(x, y: number, text: string) -> (rect0, rect1, rect2, rect3, rect4, rect5, rect6, rect7: number) * +\***************************************************************************************************************/ +static int cdlua5_textbounds(lua_State *L) +{ + int rect[8]; + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + const char* s = luaL_checkstring(L, 4); + + cdCanvasGetTextBounds(cdlua_checkcanvas(L, 1), x, y, s, rect); + lua_pushnumber(L, rect[0]); + lua_pushnumber(L, rect[1]); + lua_pushnumber(L, rect[2]); + lua_pushnumber(L, rect[3]); + lua_pushnumber(L, rect[4]); + lua_pushnumber(L, rect[5]); + lua_pushnumber(L, rect[6]); + lua_pushnumber(L, rect[7]); + return 4; +} + +/****************************************************************************************************************\ +* cd.wTextBounds(x, y: number, text: string) -> (rect0, rect1, rect2, rect3, rect4, rect5, rect6, rect7: number) * +\****************************************************************************************************************/ +static int wdlua5_textbounds(lua_State *L) +{ + double rect[8]; + double x = luaL_checknumber(L, 2); + double y = luaL_checknumber(L, 3); + const char* s = luaL_checkstring(L, 4); + + wdCanvasGetTextBounds(cdlua_checkcanvas(L, 1), x, y, s, rect); + lua_pushnumber(L, rect[0]); + lua_pushnumber(L, rect[1]); + lua_pushnumber(L, rect[2]); + lua_pushnumber(L, rect[3]); + lua_pushnumber(L, rect[4]); + lua_pushnumber(L, rect[5]); + lua_pushnumber(L, rect[6]); + lua_pushnumber(L, rect[7]); + return 4; +} + + + +/***************************************************************************\ +* Text * +\***************************************************************************/ + +/***************************************************************************\ +* cd.VectorText(x, y: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L,4); + cdCanvasVectorText(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.wVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + wdCanvasVectorText(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3),s); + return 0; +} + +/***************************************************************************\ +* cd.MultiLineVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int cdlua5_multilinevectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + cdCanvasMultiLineVectorText(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.wMultiLineVectorText(x, y: number, text: string) * +\***************************************************************************/ +static int wdlua5_multilinevectortext(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + wdCanvasMultiLineVectorText(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.VectorTextDirection(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int cdlua5_vectortextdirection(lua_State *L) +{ + int x1 = luaL_checkint(L,2); + int y1 = luaL_checkint(L,3); + int x2 = luaL_checkint(L,4); + int y2 = luaL_checkint(L,5); + cdCanvasVectorTextDirection(cdlua_checkcanvas(L, 1), x1, y1, x2, y2); + return 0; +} + +/***************************************************************************\ +* cd.wVectorTextDirection(x1, y1, x2, y2: number) * +\***************************************************************************/ +static int wdlua5_vectortextdirection(lua_State *L) +{ + double x1 = luaL_checknumber(L, 2); + double y1 = luaL_checknumber(L, 3); + double x2 = luaL_checknumber(L, 4); + double y2 = luaL_checknumber(L, 5); + wdCanvasVectorTextDirection(cdlua_checkcanvas(L, 1), x1, y1, x2, y2); + return 0; +} + + +/***************************************************************************\ +* cd.VectorTextTransform(matrix: table) -> (old_matrix: table) * +\***************************************************************************/ +static int cdlua5_vectortexttransform(lua_State *L) +{ + double matrix[6], *old_matrix; + int i; + + if (!lua_istable(L, 2)) + luaL_argerror(L, 2, "invalid matrix, must be a table"); + + for (i=0; i < 6; i++) + { + lua_rawgeti(L, 2, i+1); + + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 2, "invalid matrix value, must be a number"); + + matrix[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + old_matrix = cdCanvasVectorTextTransform(cdlua_checkcanvas(L, 1), matrix); + lua_newtable(L); + for (i=0; i < 6; i++) + { + lua_pushnumber(L, old_matrix[i]); + lua_rawseti(L, 1, i+1); + } + return 1; +} + +/***************************************************************************\ +* cd.VectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectortextsize(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + cdCanvasVectorTextSize(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.wVectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectortextsize(lua_State *L) +{ + const char* s = luaL_checkstring(L, 4); + wdCanvasVectorTextSize(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3), s); + return 0; +} + +/***************************************************************************\ +* cd.VectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int cdlua5_vectorcharsize(lua_State *L) +{ + lua_pushnumber(L, cdCanvasVectorCharSize(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.wVectorTextSize(w, h: number, text: string) * +\***************************************************************************/ +static int wdlua5_vectorcharsize(lua_State *L) +{ + lua_pushnumber(L, wdCanvasVectorCharSize(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.VectorFont(filename: string) -> (font_name: string) * +\***************************************************************************/ +static int cdlua5_vectorfont(lua_State *L) +{ + lua_pushstring(L, cdCanvasVectorFont(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2))); + return 1; +} + +/***************************************************************************\ +* cd.GetVectorTextSize(text: string) -> (w, h: number) * +\***************************************************************************/ +static int cdlua5_getvectortextsize(lua_State *L) +{ + int width; + int height; + cdCanvasGetVectorTextSize(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.wGetVectorTextSize(text: string) -> (w, h: number) * +\***************************************************************************/ +static int wdlua5_getvectortextsize(lua_State *L) +{ + double width; + double height; + wdCanvasGetVectorTextSize(cdlua_checkcanvas(L, 1), luaL_checkstring(L, 2), &width, &height); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + return 2; +} + +/***************************************************************************\ +* cd.GetVectorTextBounds(s: string, px,py: number) -> (rect: table) * +\***************************************************************************/ +static int cdlua5_vectortextbounds(lua_State *L) +{ + const char* s = luaL_checkstring(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int rect[8], i; + + cdCanvasGetVectorTextBounds(cdlua_checkcanvas(L, 1), s, x, y, rect); + lua_newtable(L); + for (i=0; i < 8; i++) + { + lua_pushnumber(L, rect[i]); + lua_rawseti(L, -2, i+1); + } + return 1; +} + +/***************************************************************************\ +* cd.wGetVectorTextBounds(s: string, px,py: number) -> (rect: table) * +\***************************************************************************/ +static int wdlua5_vectortextbounds(lua_State *L) +{ + const char* s = luaL_checkstring(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double rect[8]; + int i; + + wdCanvasGetVectorTextBounds(cdlua_checkcanvas(L, 1), s, x, y, rect); + lua_newtable(L); + for (i=0; i < 8; i++) + { + lua_pushnumber(L, rect[i]); + lua_rawseti(L, -2, i+1); + } + return 1; +} + + + +/***************************************************************************\ +* Client Images. * +\***************************************************************************/ + +static int cdlua5_getimagergb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + cdCanvasGetImageRGB(cdlua_checkcanvas(L, 1), imagergb_p->red, imagergb_p->green, imagergb_p->blue, + x, y, imagergb_p->width, imagergb_p->height); + return 0; +} + +static int cdlua5_putimagerectrgb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int w = luaL_checkint(L, 5); + int h = luaL_checkint(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + cdCanvasPutImageRectRGB(cdlua_checkcanvas(L, 1), imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectrgb(lua_State *L) +{ + cdluaImageRGB* imagergb_p = cdlua_checkimagergb(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double w = luaL_checknumber(L, 5); + double h = luaL_checknumber(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + wdCanvasPutImageRectRGB(cdlua_checkcanvas(L, 1), imagergb_p->width, imagergb_p->height, imagergb_p->red, + imagergb_p->green, imagergb_p->blue, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putimagerectrgba(lua_State *L) +{ + cdluaImageRGBA* imagergba_p = cdlua_checkimagergba(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int w = luaL_checkint(L, 5); + int h = luaL_checkint(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + cdCanvasPutImageRectRGBA(cdlua_checkcanvas(L, 1), imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectrgba(lua_State *L) +{ + cdluaImageRGBA* imagergba_p = cdlua_checkimagergba(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double w = luaL_checknumber(L, 5); + double h = luaL_checknumber(L, 6); + int xmin = luaL_checkint(L, 7); + int xmax = luaL_checkint(L, 8); + int ymin = luaL_checkint(L, 9); + int ymax = luaL_checkint(L, 10); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + wdCanvasPutImageRectRGBA(cdlua_checkcanvas(L, 1), imagergba_p->width, imagergba_p->height, imagergba_p->red, + imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putimagerectmap(lua_State *L) +{ + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 2); + cdluaPalette *pal = cdlua_checkpalette(L, 3); + int x = luaL_checkint(L, 4); + int y = luaL_checkint(L, 5); + int w = luaL_checkint(L, 6); + int h = luaL_checkint(L, 7); + int xmin = luaL_checkint(L, 8); + int xmax = luaL_checkint(L, 9); + int ymin = luaL_checkint(L, 10); + int ymax = luaL_checkint(L, 11); + + if (w < 0 || h < 0) + luaL_argerror(L, 6, "target region dimensions should be positive integers"); + + cdCanvasPutImageRectMap(cdlua_checkcanvas(L, 1), imagemap_p->width, imagemap_p->height, imagemap_p->index, + pal->color, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerectmap(lua_State *L) +{ + cdluaImageMap* imagemap_p = cdlua_checkimagemap(L, 2); + cdluaPalette *pal = cdlua_checkpalette(L, 3); + double x = luaL_checknumber(L, 4); + double y = luaL_checknumber(L, 5); + double w = luaL_checknumber(L, 6); + double h = luaL_checknumber(L, 7); + int xmin = luaL_checkint(L, 8); + int xmax = luaL_checkint(L, 9); + int ymin = luaL_checkint(L, 10); + int ymax = luaL_checkint(L, 11); + + if (w < 0 || h < 0) + luaL_argerror(L, 6, "target region dimensions should be positive integers"); + + wdCanvasPutImageRectMap(cdlua_checkcanvas(L, 1), imagemap_p->width, imagemap_p->height, imagemap_p->index, + pal->color, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +static int cdlua5_putbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int w = luaL_checkint(L, 5); + int h = luaL_checkint(L, 6); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + cdCanvasPutBitmap(cdlua_checkcanvas(L, 1), bitmap, x, y, w, h); + return 0; +} + +static int wdlua5_putbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double w = luaL_checknumber(L, 5); + double h = luaL_checknumber(L, 6); + + if (w < 0 || h < 0) + luaL_argerror(L, 5, "target region dimensions should be positive integers"); + + wdCanvasPutBitmap(cdlua_checkcanvas(L, 1), bitmap, x, y, w, h); + return 0; +} + +static int cdlua5_getbitmap(lua_State *L) +{ + cdBitmap *bitmap = cdlua_checkbitmap(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + cdCanvasGetBitmap(cdlua_checkcanvas(L, 1), bitmap, x, y); + return 0; +} + +/***************************************************************************\ +* Server Images. * +\***************************************************************************/ + +static int cdlua5_createimage(lua_State *L) +{ + cdImage *image; + int width = luaL_checkint(L, 2); + int height = luaL_checkint(L, 3); + + if (width < 1 || height < 1) + luaL_argerror(L, 2, "image dimensions should be positive integers"); + + image = cdCanvasCreateImage(cdlua_checkcanvas(L, 1), width, height); + if (image) + cdlua_pushimage(L, image); + else + lua_pushnil(L); + + return 1; +} + +static int cdlua5_getimage(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + cdCanvasGetImage(cdlua_checkcanvas(L, 1), image, x, y); + return 0; +} + +static int cdlua5_putimagerect(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int xmin = luaL_checkint(L, 5); + int xmax = luaL_checkint(L, 6); + int ymin = luaL_checkint(L, 7); + int ymax = luaL_checkint(L, 8); + cdCanvasPutImageRect(cdlua_checkcanvas(L, 1), image, x, y, xmin, xmax, ymin, ymax); + return 0; +} + +static int wdlua5_putimagerect(lua_State *L) +{ + cdImage* image = cdlua_checkimage(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + int xmin = luaL_checkint(L, 5); + int xmax = luaL_checkint(L, 6); + int ymin = luaL_checkint(L, 7); + int ymax = luaL_checkint(L, 8); + wdCanvasPutImageRect(cdlua_checkcanvas(L, 1), image, x, y, xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* cd.ScrollArea(xmin, xmax, ymin, ymax, dx, dy: number) * +\***************************************************************************/ +static int cdlua5_scrollarea(lua_State *L) +{ + int xmin = luaL_checkint(L, 2); + int xmax = luaL_checkint(L, 3); + int ymin = luaL_checkint(L, 4); + int ymax = luaL_checkint(L, 5); + int dx = luaL_checkint(L, 6); + int dy = luaL_checkint(L, 7); + cdCanvasScrollArea(cdlua_checkcanvas(L, 1), xmin, xmax, ymin, ymax, dx, dy); + return 0; +} + + + +/***************************************************************************\ +* Other * +\***************************************************************************/ + +/********************************************************************************\ +* cd.Play(ctx, xmin, xmax, ymin, ymax: number, data: string) -> (status: number) * +\********************************************************************************/ + +static int cdlua5_play(lua_State *L) +{ + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 2); + int xmin = luaL_checkint(L,3); + int xmax = luaL_checkint(L,4); + int ymin = luaL_checkint(L,5); + int ymax = luaL_checkint(L,6); + const char *data_s = luaL_checkstring(L,7); + + cdlua_setplaystate(L); + cdCanvasPlay(cdlua_checkcanvas(L, 1), cdlua_ctx->ctx(), xmin, xmax, ymin, ymax, (void*)data_s); + cdlua_setplaystate(NULL); + return 0; +} + +/***************************************************************************\ +* cd.GetColorPlanes() -> (bpp: number) * +\***************************************************************************/ +static int cdlua5_getcolorplanes(lua_State *L) +{ + lua_pushnumber(L, cdCanvasGetColorPlanes(cdlua_checkcanvas(L, 1))); + return 1; +} + +static int cdlua5_palette(lua_State *L) +{ + cdluaPalette *pal = cdlua_checkpalette(L, 2); + int mode_i = luaL_checkint(L, 3); + cdCanvasPalette(cdlua_checkcanvas(L, 1), pal->count, pal->color, mode_i); + return 0; +} + +/***************************************************************************\ +* cd.ImageRGB * +\***************************************************************************/ +static int cdlua5_imagergb(lua_State *L) +{ + int w, h, type = CD_RGB; + + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + + if (cdCanvasGetContext(canvas) != CD_IMAGERGB) + luaL_argerror(L, 1, "invalid canvas, must be CD_IMAGERGB"); + + if (cdAlphaImage(canvas)) + type = CD_RGBA; + + cdCanvasGetSize(canvas, &w, &h, NULL, NULL); + + /* mark the image NOT to be freed */ + if (type == CD_RGBA) + cdlua_pushimagergba_ex(L, cdRedImage(canvas), cdGreenImage(canvas), cdBlueImage(canvas), cdAlphaImage(canvas), w, h); + else + cdlua_pushimagergb_ex(L, cdRedImage(canvas), cdGreenImage(canvas), cdBlueImage(canvas), w, h); + + return 1; +} + +/***************************************************************************\ +* cd.ImageRGBBitmap * +\***************************************************************************/ +static int cdlua5_imagergbbitmap(lua_State *L) +{ + int w, h, type = CD_RGB; + + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + + if (cdCanvasGetContext(canvas) != CD_IMAGERGB) + luaL_argerror(L, 1, "invalid canvas, must be CD_IMAGERGB"); + + if (cdAlphaImage(canvas)) + type = CD_RGBA; + + cdCanvasGetSize(canvas, &w, &h, NULL, NULL); + + cdlua_pushbitmap(L, cdInitBitmap(w, h, type, + cdRedImage(canvas), + cdGreenImage(canvas), + cdBlueImage(canvas), + cdAlphaImage(canvas))); + + return 1; +} + +/***************************************************************************\ +* Hardcopy * +\***************************************************************************/ +static lua_State* wdlua5_hardcopy_luaState = NULL; + +static void wdlua5_hardcopy_func(cdCanvas* canvas) +{ + lua_State* L = wdlua5_hardcopy_luaState; + lua_pushvalue(L, 4); /* push the function in the stack */ + cdlua_pushcanvas(L, canvas); + if(lua_pcall(L, 1, 0, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); +} + +static int wdlua5_hardcopy(lua_State *L) +{ + cdCanvas* canvas = cdlua_checkcanvas(L, 1); + cdluaContext* cdlua_ctx = cdlua_getcontext(L, 2); + void *data_p = cdlua_ctx->checkdata(L,3); + luaL_argcheck(L, !lua_isfunction(L, 4), 4, "invalid draw function"); + + wdlua5_hardcopy_luaState = L; + wdCanvasHardcopy(canvas, cdlua_ctx->ctx(), data_p, wdlua5_hardcopy_func); + wdlua5_hardcopy_luaState = NULL; + + return 0; +} + + +/***************************************************************************\ +* Polygon functions * +\***************************************************************************/ + +/***************************************************************************\ +* cd.Begin(mode: number) * +\***************************************************************************/ +static int cdlua5_begin(lua_State *L) +{ + cdCanvasBegin(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2)); + return 0; +} + +static int cdlua5_vertex(lua_State *L) +{ + cdCanvasVertex(cdlua_checkcanvas(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3)); + return 0; +} + +static int wdlua5_vertex(lua_State *L) +{ + wdCanvasVertex(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +static int cdlua5_fvertex(lua_State *L) +{ + cdfCanvasVertex(cdlua_checkcanvas(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +static int cdlua5_end(lua_State *L) +{ + cdCanvasEnd(cdlua_checkcanvas(L, 1)); + return 0; +} + + +/********************************************************************************\ +* Lua Exported functions * +\********************************************************************************/ + +static const struct luaL_reg cdlib_canvas_meta[] = { + + /* Initialization */ + {"GetContext" , cdlua5_getcontext}, + {"Kill" , cdlua5_killcanvas}, + {"Activate" , cdlua5_activate}, + {"Deactivate" , cdlua5_deactivate}, + {"Simulate" , cdlua5_simulate}, + + /* Control */ + {"Clear" , cdlua5_clear}, + {"Flush" , cdlua5_flush}, + {"SaveState" , cdlua5_savestate}, + {"RestoreState" , cdlua5_restorestate}, + {"SetAttribute" , cdlua5_setattribute}, + {"GetAttribute" , cdlua5_getattribute}, + + /* Coordinate System */ + {"GetSize" , cdlua5_getcanvassize}, + {"UpdateYAxis" , cdlua5_updateyaxis}, + {"InvertYAxis" , cdlua5_invertyaxis}, + {"MM2Pixel" , cdlua5_mm2pixel}, + {"Pixel2MM" , cdlua5_pixel2mm}, + {"Origin" , cdlua5_origin}, + {"GetOrigin" , cdlua5_getorigin}, + {"fMM2Pixel" , cdlua5_fmm2pixel}, + {"fPixel2MM" , cdlua5_fpixel2mm}, + {"fOrigin" , cdlua5_forigin}, + {"fGetOrigin" , cdlua5_fgetorigin}, + {"Transform" , cdlua5_transform}, + {"GetTransform" , cdlua5_gettransform}, + {"TransformMultiply" , cdlua5_transformmultiply}, + {"TransformRotate" , cdlua5_transformrotate}, + {"TransformScale" , cdlua5_transformscale}, + {"TransformTranslate" , cdlua5_transformtranslate}, + {"TransformPoint" , cdlua5_transformpoint}, + {"fTransformPoint" , cdlua5_ftransformpoint}, + + /* World Coordinates */ + {"wWindow" , wdlua5_window}, + {"wGetWindow" , wdlua5_getwindow}, + {"wViewport" , wdlua5_viewport}, + {"wGetViewport" , wdlua5_getviewport}, + {"wWorld2Canvas" , wdlua5_world2canvas}, + {"wCanvas2World" , wdlua5_canvas2world}, + + {"wHardcopy" , wdlua5_hardcopy}, + + /* General Attributes */ + {"Foreground" , cdlua5_foreground}, + {"Background" , cdlua5_background}, + {"SetForeground" , cdlua5_setforeground}, + {"SetBackground" , cdlua5_setbackground}, + {"WriteMode" , cdlua5_writemode}, + + /* Clipping */ + {"Clip" , cdlua5_clip}, + {"ClipArea" , cdlua5_cliparea}, + {"GetClipArea" , cdlua5_getcliparea}, + {"wClipArea" , wdlua5_cliparea}, + {"wGetClipArea" , wdlua5_getcliparea}, + {"fClipArea" , cdlua5_fcliparea}, + {"fGetClipArea" , cdlua5_fgetcliparea}, + + /* Regions */ + {"RegionCombineMode" , cdlua5_regioncombinemode}, + {"IsPointInRegion" , cdlua5_pointinregion}, + {"wIsPointInRegion" , wdlua5_pointinregion}, + {"OffsetRegion" , cdlua5_offsetregion}, + {"wOffsetRegion" , wdlua5_offsetregion}, + {"GetRegionBox" , cdlua5_regionbox}, + {"wGetRegionBox" , wdlua5_regionbox}, + + /* Marks */ + {"Pixel" , cdlua5_pixel}, + {"wPixel" , wdlua5_pixel}, + {"Mark" , cdlua5_mark}, + {"wMark" , wdlua5_mark}, + {"MarkType" , cdlua5_marktype}, + {"MarkSize" , cdlua5_marksize}, + {"wMarkSize" , wdlua5_marksize}, + + /* Line */ + {"Line" , cdlua5_line}, + {"wLine" , wdlua5_line}, + {"fLine" , cdlua5_fline}, + {"Rect" , cdlua5_rect}, + {"wRect" , wdlua5_rect}, + {"fRect" , cdlua5_frect}, + {"Arc" , cdlua5_arc}, + {"wArc" , wdlua5_arc}, + {"fArc" , cdlua5_farc}, + {"LineStyle" , cdlua5_linestyle}, + {"LineStyleDashes" , cdlua5_linestyledashes}, + {"LineWidth" , cdlua5_linewidth}, + {"wLineWidth" , wdlua5_linewidth}, + {"LineJoin" , cdlua5_linejoin}, + {"LineCap" , cdlua5_linecap}, + + /* Filled Areas */ + {"Box" , cdlua5_box}, + {"wBox" , wdlua5_box}, + {"fBox" , cdlua5_fbox}, + {"Sector" , cdlua5_sector}, + {"wSector" , wdlua5_sector}, + {"fSector" , cdlua5_fsector}, + {"Chord" , cdlua5_chord}, + {"wChord" , wdlua5_chord}, + {"fChord" , cdlua5_fchord}, + {"BackOpacity" , cdlua5_backopacity}, + {"FillMode" , cdlua5_fillmode}, + {"InteriorStyle" , cdlua5_interiorstyle}, + {"Hatch" , cdlua5_hatch}, + + /* Stipple */ + {"Stipple" , cdlua5_stipple}, + {"wStipple" , wdlua5_stipple}, + {"GetStipple" , cdlua5_getstipple}, + + /* Pattern */ + {"Pattern" , cdlua5_pattern}, + {"wPattern" , wdlua5_pattern}, + {"GetPattern" , cdlua5_getpattern}, + + /* Text */ + {"Text" , cdlua5_text}, + {"wText" , wdlua5_text}, + {"fText" , cdlua5_ftext}, + {"Font" , cdlua5_font}, + {"wFont" , wdlua5_font}, + {"GetFont" , cdlua5_getfont}, + {"wGetFont" , wdlua5_getfont}, + {"NativeFont" , cdlua5_nativefont}, + {"TextAlignment" , cdlua5_textalignment}, + {"TextOrientation" , cdlua5_textorientation}, + {"GetFontDim" , cdlua5_fontdim}, + {"wGetFontDim" , wdlua5_fontdim}, + {"GetTextSize" , cdlua5_textsize}, + {"wGetTextSize" , wdlua5_textsize}, + {"GetTextBox" , cdlua5_textbox}, + {"wGetTextBox" , wdlua5_textbox}, + {"GetTextBounds" , cdlua5_textbounds}, + {"wGetTextBounds" , wdlua5_textbounds}, + + /* Vector Text */ + {"VectorText" , cdlua5_vectortext}, + {"wVectorText" , wdlua5_vectortext}, + {"MultiLineVectorText" , cdlua5_multilinevectortext}, + {"wMultiLineVectorText" , wdlua5_multilinevectortext}, + {"VectorTextDirection" , cdlua5_vectortextdirection}, + {"wVectorTextDirection" , wdlua5_vectortextdirection}, + {"VectorTextTransform" , cdlua5_vectortexttransform}, + {"VectorTextSize" , cdlua5_vectortextsize}, + {"wVectorTextSize" , wdlua5_vectortextsize}, + {"VectorCharSize" , cdlua5_vectorcharsize}, + {"wVectorCharSize" , wdlua5_vectorcharsize}, + {"VectorFont" , cdlua5_vectorfont}, + {"GetVectorTextSize" , cdlua5_getvectortextsize}, + {"wGetVectorTextSize" , wdlua5_getvectortextsize}, + {"VectorTextBounds" , cdlua5_vectortextbounds}, + {"wVectorTextBounds" , wdlua5_vectortextbounds}, + + /* Client Images */ + {"GetImageRGB" , cdlua5_getimagergb}, + {"PutImageRectRGB" , cdlua5_putimagerectrgb}, + {"wPutImageRectRGB" , wdlua5_putimagerectrgb}, + {"PutImageRectRGBA" , cdlua5_putimagerectrgba}, + {"wPutImageRectRGBA", wdlua5_putimagerectrgba}, + {"PutImageRectMap" , cdlua5_putimagerectmap}, + {"wPutImageRectMap" , wdlua5_putimagerectmap}, + {"GetBitmap" , cdlua5_getbitmap}, + {"PutBitmap" , cdlua5_putbitmap}, + {"wPutBitmap" , wdlua5_putbitmap}, + + /* Server Images */ + {"CreateImage" , cdlua5_createimage}, + {"GetImage" , cdlua5_getimage}, + {"PutImageRect" , cdlua5_putimagerect}, + {"wPutImageRect" , wdlua5_putimagerect}, + {"ScrollArea" , cdlua5_scrollarea}, + + /* Other */ + {"Play" , cdlua5_play}, + + /* Color Coding */ + {"GetColorPlanes" , cdlua5_getcolorplanes}, + + /* Palette */ + {"Palette" , cdlua5_palette}, + + /* Polygon */ + {"Begin" , cdlua5_begin}, + {"Vertex" , cdlua5_vertex}, + {"wVertex" , wdlua5_vertex}, + {"fVertex" , cdlua5_fvertex}, + {"End" , cdlua5_end}, + + {"__eq", cdluaCanvas_eq}, + {"__tostring", cdluaCanvas_tostring}, + + {NULL, NULL}, +}; + +static const struct luaL_reg cdlib_canvas[] = { + /* Initialization */ + {"CreateCanvas" , cdlua5_createcanvas}, + {"KillCanvas" , cdlua5_killcanvas}, + {"GetContext" , cdlua5_getcontext}, /* compatibility name */ + {"ImageRGB" , cdlua5_imagergb}, + {"ImageRGBBitmap" , cdlua5_imagergbbitmap}, + {NULL, NULL}, +}; + +void cdlua_open_canvas (lua_State *L) +{ + /* "cd" table is at the top of the stack */ + + /* Object Oriented Access */ + luaL_newmetatable(L, "cdCanvas"); /* create new metatable for cdCanvas handles */ + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); /* push metatable */ + lua_rawset(L, -3); /* metatable.__index = metatable */ + luaL_register(L, NULL, cdlib_canvas_meta); /* register methods */ + lua_pop(L, 1); /* removes the metatable from the top of the stack */ + + luaL_register(L, NULL, cdlib_canvas); +} diff --git a/src/lua5/cdlua5ctx.c b/src/lua5/cdlua5ctx.c new file mode 100644 index 0000000..e3bd19e --- /dev/null +++ b/src/lua5/cdlua5ctx.c @@ -0,0 +1,802 @@ +/***************************************************************************\ +* $Id: cdlua5ctx.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ +* * +\***************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "cd.h" +#include "wd.h" + +#include "cdimage.h" +#include "cdirgb.h" +#include "cddxf.h" +#include "cddgn.h" +#include "cdcgm.h" +#include "cdwmf.h" +#include "cdemf.h" +#include "cdnative.h" +#include "cdprint.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdps.h" +#include "cddbuf.h" +#include "cdgdiplus.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdlua5_private.h" + + +/***************************************************************************\ +* CD_CGM. * +\***************************************************************************/ +static void *cdcgm_checkdata(lua_State * L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static int cgm_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); +static int cgm_countercb(cdCanvas *canvas, double percent); +static int cgm_sclmdecb(cdCanvas *canvas, short scl_mde, short *draw_mode_i, double *factor_f); +static int cgm_vdcextcb(cdCanvas *canvas, short type, void *xmn, void *ymn, void *xmx, void *ymx); +static int cgm_begpictcb(cdCanvas *canvas, char *pict); +static int cgm_begpictbcb(cdCanvas *canvas); +static int cgm_begmtfcb(cdCanvas *canvas, int *xmn, int *ymn, int *xmx, int *ymx); + +static cdluaCallback cdluacgmcb[7] = { +{ + -1, + "SIZECB", + (cdCallback)cgm_sizecb +}, +{ + -1, + "CGMCOUNTERCB", + (cdCallback)cgm_countercb +}, +{ + -1, + "CGMSCLMDECB", + (cdCallback)cgm_sclmdecb +}, +{ + -1, + "CGMVDCEXTCB", + (cdCallback)cgm_vdcextcb +}, +{ + -1, + "CGMBEGPICTCB", + (cdCallback)cgm_begpictcb +}, +{ + -1, + "CGMBEGPICTBCB", + (cdCallback)cgm_begpictbcb +}, +{ + -1, + "CGMBEGMTFCB", + (cdCallback)cgm_begmtfcb +} +}; + +static cdluaContext cdluacgmctx = +{ + 0, + "CGM", + cdContextCGM, + cdcgm_checkdata, + cdluacgmcb, + 7 +}; + +/***************************************************************************\ +* CGM CD_COUNTERCB. * +\***************************************************************************/ +static int cgm_countercb(cdCanvas *canvas, double percent) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluacgmcb[CD_CGMCOUNTERCB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, percent); + if(lua_pcall(L, 2, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L,-1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CGM CD_BEGPICTCB. * +\***************************************************************************/ +static int cgm_begpictcb(cdCanvas *canvas, char *pict) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluacgmcb[CD_CGMBEGPICTCB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushstring(L, pict); + if(lua_pcall(L, 2, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L,-1)) + luaL_error(L,"invalid return value"); + + return luaL_checkint(L,-1); +} + +static int cgm_begmtfcb(cdCanvas *canvas, int *xmn, int *ymn, int *xmx, int *ymx) +{ + int result_i; + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluacgmcb[CD_CGMBEGMTFCB].lock); + + cdlua_pushcanvas(L, canvas); + if(lua_pcall(L, 1, 5, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -5)) + luaL_error(L, "invalid return value"); + + result_i = luaL_checkint(L, -5); + if (result_i == 1) + return 1; + + if (!lua_isnumber(L, -4)) + luaL_error(L, "invalid xmn return value"); + *xmn = luaL_checkint(L, -4); + + if (!lua_isnumber(L, -3)) + luaL_error(L, "invalid ymn return value"); + *ymn = luaL_checkint(L, -3); + + if (!lua_isnumber(L, -2)) + luaL_error(L, "invalid xmx return value"); + *xmx = luaL_checkint(L, -2); + + if (!lua_isnumber(L, -1)) + luaL_error(L, "invalid ymx return value"); + *ymx = luaL_checkint(L, -1); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_BEGPICTBCB. * +\***************************************************************************/ +static int cgm_begpictbcb(cdCanvas *canvas) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluacgmcb[CD_CGMBEGPICTBCB].lock); + + cdlua_pushcanvas(L, canvas); + if(lua_pcall(L, 1, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CGM CD_SIZECB. * +\***************************************************************************/ +static int cgm_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L,cdluacgmcb[CD_SIZECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, w ); + lua_pushnumber(L, h ); + lua_pushnumber(L, mm_w ); + lua_pushnumber(L, mm_h ); + if(lua_pcall(L, 5, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CGM CD_SCLMDE. * +\***************************************************************************/ +static int cgm_sclmdecb(cdCanvas *canvas, short scl_mde, short *draw_mode_i, double *factor_f) +{ + int result_i; + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L,cdluacgmcb[CD_CGMSCLMDECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, scl_mde); + if(lua_pcall(L, 2, 3, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -3)) + luaL_error(L, "invalid return value"); + + result_i = luaL_checkint(L, -3); + + if (result_i == 1) + return 1; + + if (!lua_isnumber(L, -2)) + luaL_error(L, "invalid draw mode return value"); + *draw_mode_i = (short) lua_tonumber(L,-2); + + if (!lua_isnumber(L, -1)) + luaL_error(L, "invalid factor return value"); + + *factor_f = (double) lua_tonumber(L, -1); + + return result_i; +} + +/***************************************************************************\ +* CGM CD_VDCEXTCB. * +\***************************************************************************/ +static int cgm_vdcextcb(cdCanvas *canvas, short type, void *xmn, void *ymn, void *xmx, void *ymx) +{ + int result_i; + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluacgmcb[CD_CGMVDCEXTCB].lock); + + cdlua_pushcanvas(L, canvas); + if(lua_pcall(L, 1, 5, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -5)) + luaL_error(L, "invalid return value"); + result_i = luaL_checkint(L,-5); + if (result_i == 1) + return 1; + + if (!lua_isnumber(L, -4)) + luaL_error(L, "invalid xmn return value"); + if (type == 1) *((float *) xmn) = (float) lua_tonumber(L, -4); + else *((int *) xmn) = luaL_checkint(L, -4); + + if (!lua_isnumber(L, -3)) + luaL_error(L, "invalid ymn return value"); + if (type == 1) *((float *) ymn) = (float) lua_tonumber(L, -3); + else *((int *) ymn) = luaL_checkint(L, -3); + + if (!lua_isnumber(L, -2)) + luaL_error(L,"invalid xmx return value"); + if (type == 1) *((float *) xmx) = (float) lua_tonumber(L, -2); + else *((int *) xmx) = luaL_checkint(L, -2); + + if (!lua_isnumber(L, -1)) + luaL_error(L,"invalid ymx return value"); + if (type == 1) *((float *) ymx) = (float) lua_tonumber(L, -1); + else *((int *) ymx) = (int) luaL_checkint(L, -1); + + return result_i; +} + +/***************************************************************************\ +* CD_DBUFFER. * +\***************************************************************************/ +static void *cddbuf_checkdata(lua_State * L, int param) +{ + return cdlua_checkcanvas(L, param); +} + +static cdluaContext cdluadbufctx = +{ + 0, + "DBUFFER", + cdContextDBuffer, + cddbuf_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_IMAGE. * +\***************************************************************************/ +static void *cdimage_checkdata(lua_State *L, int param) +{ + return cdlua_checkimage(L, param); +} + +static cdluaContext cdluaimagectx = +{ + 0, + "IMAGE", + cdContextImage, + cdimage_checkdata, + NULL, + 0 +}; + +static int cdlua_rawchecktype(lua_State *L, int param, const char* type) +{ + if (lua_isuserdata(L, param)) /* value is a userdata? */ + { + if (lua_getmetatable(L, param)) /* does it have a metatable? */ + { + lua_getfield(L, LUA_REGISTRYINDEX, type); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */ + { + lua_pop(L, 2); /* remove both metatables */ + return 1; + } + else + { + lua_pop(L, 2); /* remove both metatables */ + return -1; /* test for other metatables */ + } + } + } + return 0; /* do not continue */ +} + +/***************************************************************************\ +* CD_IMAGERGB. * +\***************************************************************************/ +static void *cdimagergb_checkdata(lua_State* L, int param) +{ + static char data_s[100] = ""; + + if (lua_isstring(L, param)) + { + const char* str = lua_tostring(L, param); + strcpy(data_s, str); + } + else + { + int ret = cdlua_rawchecktype(L, param, "cdBitmap"); + + if (ret == 0) + luaL_typerror(L, param, "cdBitmap"); /* not a user data and not a metatable */ + + if (ret == 1) + { + cdBitmap* *bitmap_p = (cdBitmap**)luaL_checkudata(L, param, "cdBitmap"); + if (!(*bitmap_p)) + luaL_argerror(L, param, "killed cdBitmap"); + + if ((*bitmap_p)->type != CD_RGB && (*bitmap_p)->type != CD_RGBA) + luaL_argerror(L, param, "bitmap should be of type rgb or rgba"); + + if (lua_isnoneornil(L, param+1)) + { + if ((*bitmap_p)->type == CD_RGBA) + sprintf(data_s, "%dx%d %p %p %p %p -a", (*bitmap_p)->w, (*bitmap_p)->h, + cdBitmapGetData(*bitmap_p, CD_IRED), + cdBitmapGetData(*bitmap_p, CD_IGREEN), + cdBitmapGetData(*bitmap_p, CD_IBLUE), + cdBitmapGetData(*bitmap_p, CD_IALPHA)); + else + sprintf(data_s, "%dx%d %p %p %p", (*bitmap_p)->w, (*bitmap_p)->h, + cdBitmapGetData(*bitmap_p, CD_IRED), + cdBitmapGetData(*bitmap_p, CD_IGREEN), + cdBitmapGetData(*bitmap_p, CD_IBLUE)); + } + else + { + double res_f = luaL_checknumber(L, param+1); + if ((*bitmap_p)->type == CD_RGBA) + sprintf(data_s, "%dx%d %p %p %p %p -r%g -a", (*bitmap_p)->w, (*bitmap_p)->h, + cdBitmapGetData(*bitmap_p, CD_IRED), + cdBitmapGetData(*bitmap_p, CD_IGREEN), + cdBitmapGetData(*bitmap_p, CD_IBLUE), + cdBitmapGetData(*bitmap_p, CD_IALPHA), + res_f); + else + sprintf(data_s, "%dx%d %p %p %p -r%g", (*bitmap_p)->w, (*bitmap_p)->h, + cdBitmapGetData(*bitmap_p, CD_IRED), + cdBitmapGetData(*bitmap_p, CD_IGREEN), + cdBitmapGetData(*bitmap_p, CD_IBLUE), + res_f); + } + + return data_s; + } + + ret = cdlua_rawchecktype(L, param, "cdImageRGB"); + if (ret == 1) + { + cdluaImageRGB *imagergb_p = (cdluaImageRGB*) luaL_checkudata(L, param, "cdImageRGB"); + if (!imagergb_p->red) + luaL_argerror(L, param, "killed cdImageRGB"); + + if (lua_isnoneornil(L, param+1)) + { + sprintf(data_s, "%dx%d %p %p %p", imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue); + } + else + { + double res_f = luaL_checknumber(L, param+1); + sprintf(data_s, "%dx%d %p %p %p -r%g", imagergb_p->width, imagergb_p->height, + imagergb_p->red, imagergb_p->green, imagergb_p->blue, res_f); + } + + return data_s; + } + + ret = cdlua_rawchecktype(L, param, "cdImageRGBA"); + if (ret == 1) + { + cdluaImageRGBA *imagergba_p = (cdluaImageRGBA*) luaL_checkudata(L, param, "cdImageRGBA"); + if (!imagergba_p->red) + luaL_argerror(L, param, "killed cdImageRGBA"); + + if (lua_isnoneornil(L, param+1)) + { + sprintf(data_s, "%dx%d %p %p %p %p -a", imagergba_p->width, imagergba_p->height, + imagergba_p->red, imagergba_p->green, imagergba_p->blue, imagergba_p->alpha); + } + else + { + double res_f = luaL_checknumber(L, param+1); + sprintf(data_s, "%dx%d %p %p %p %p -r%g -a", imagergba_p->width, imagergba_p->height, + imagergba_p->red, imagergba_p->green, imagergba_p->blue, imagergba_p->alpha, res_f); + } + + return data_s; + } + + luaL_typerror(L, param, "cdBitmap"); /* is a metatable but it is not one of the accepted */ + } + + return data_s; +} + +static cdluaContext cdluaimagergbctx = +{ + 0, + "IMAGERGB", + cdContextImageRGB, + cdimagergb_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_DXF. * +\***************************************************************************/ +static void *cddxf_checkdata(lua_State * L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static cdluaContext cdluadxfctx = +{ + 0, + "DXF", + cdContextDXF, + cddxf_checkdata +}; + +/***************************************************************************\ +* CD_DGN. * +\***************************************************************************/ +static void *cddgn_checkdata(lua_State * L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static cdluaContext cdluadgnctx = +{ + 0, + "DGN", + cdContextDGN, + cddgn_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_WMF. * +\***************************************************************************/ +static void *cdwmf_checkdata(lua_State * L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static int wmf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdluaCallback cdluawmfcb[1] = +{{ + -1, + "SIZECB", + (cdCallback)wmf_sizecb +}}; + +static cdluaContext cdluawmfctx = +{ + 0, + "WMF", + cdContextWMF, + cdwmf_checkdata, + cdluawmfcb, + 1 +}; + +/***************************************************************************\ +* WMF CD_SIZECB. * +\***************************************************************************/ +static int wmf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L,cdluawmfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, w); + lua_pushnumber(L, h); + lua_pushnumber(L, mm_w); + lua_pushnumber(L, mm_h); + if(lua_pcall(L, 5, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -1)) + luaL_error(L,"invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CD_EMF. * +\***************************************************************************/ +static void *cdemf_checkdata(lua_State *L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static int emf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdluaCallback cdluaemfcb[1] = +{{ + -1, + "SIZECB", + (cdCallback)emf_sizecb +}}; + +static cdluaContext cdluaemfctx = +{ + 0, + "EMF", + cdContextEMF, + cdemf_checkdata, + cdluaemfcb, + 1 +}; + +/***************************************************************************\ +* EMF CD_SIZECB. * +\***************************************************************************/ +static int emf_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L,cdluaemfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, w); + lua_pushnumber(L, h); + lua_pushnumber(L, mm_w); + lua_pushnumber(L, mm_h); + if(lua_pcall(L, 5, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L,-1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CD_METAFILE. * +\***************************************************************************/ +static void *cdmetafile_checkdata(lua_State *L,int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static int metafile_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdluaCallback cdluamfcb[1] = +{{ + -1, + "SIZECB", + (cdCallback)metafile_sizecb +}}; + +static cdluaContext cdluamfctx = +{ + 0, + "METAFILE", + cdContextMetafile, + cdmetafile_checkdata, + cdluamfcb, + 1 +}; + +/***************************************************************************\ +* METAFILE CD_SIZECB. * +\***************************************************************************/ +static int metafile_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + + lua_getref(L, cdluamfcb[CD_SIZECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, w); + lua_pushnumber(L, h); + lua_pushnumber(L, mm_w); + lua_pushnumber(L, mm_h); + if(lua_pcall(L, 5, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L, -1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CD_PS. * +\***************************************************************************/ +static void *cdps_checkdata( lua_State *L, int param) +{ + return (void *)luaL_checkstring(L, param); +} + +static cdluaContext cdluapsctx = +{ + 0, + "PS", + cdContextPS, + cdps_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_PRINTER. * +\***************************************************************************/ +static void *cdprinter_checkdata(lua_State *L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static cdluaContext cdluaprinterctx = +{ + 0, + "PRINTER", + cdContextPrinter, + cdprinter_checkdata, + NULL, + 0 +}; + +/***************************************************************************\ +* CD_CLIPBOARD. * +\***************************************************************************/ +static void *cdclipboard_checkdata(lua_State *L, int param) +{ + return (void *)luaL_checkstring(L,param); +} + +static int clipboard_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h); + +static cdluaCallback cdluaclipboardcb[1] = +{{ + -1, + "SIZECB", + (cdCallback)clipboard_sizecb +}}; + +static cdluaContext cdluaclipboardctx = +{ + 0, + "CLIPBOARD", + cdContextClipboard, + cdclipboard_checkdata, + cdluaclipboardcb, + 1 +}; + +/***************************************************************************\ +* CLIPBOARD CD_SIZECB. * +\***************************************************************************/ +static int clipboard_sizecb(cdCanvas *canvas, int w, int h, double mm_w, double mm_h) +{ + /* little Wrapper */ + lua_State * L = cdlua_getplaystate(); + lua_getref(L, cdluaclipboardcb[CD_SIZECB].lock); + + cdlua_pushcanvas(L, canvas); + lua_pushnumber(L, w); + lua_pushnumber(L, h); + lua_pushnumber(L, mm_w); + lua_pushnumber(L, mm_h); + if(lua_pcall(L, 5, 1, 0) != 0) + luaL_error(L, "error running function: %s", lua_tostring(L, -1)); + + if (!lua_isnumber(L,-1)) + luaL_error(L, "invalid return value"); + + return luaL_checkint(L,-1); +} + +/***************************************************************************\ +* CD_NATIVEWINDOW. * +\***************************************************************************/ +static void *cdnativewindow_checkdata(lua_State *L, int param) +{ +#ifdef WIN32 + if (!lua_isnil(L,param) && !lua_isuserdata(L,param)) + luaL_argerror(L, param, "data should be of type userdata"); + + return lua_touserdata(L,param); +#else + return (void *)luaL_checkstring(L,param); +#endif +} + +static cdluaContext cdluanativewindowctx = +{ + 0, + "NATIVEWINDOW", + cdContextNativeWindow, + cdnativewindow_checkdata, + NULL, + 0 +}; + + +/*******************************************************************************\ +* Init all CD Drivers * +*********************************************************************************/ +void cdlua_initdrivers(lua_State * L, cdluaLuaState* cdL) +{ + cdlua_addcontext(L, cdL, &cdluaimagectx); + cdlua_addcontext(L, cdL, &cdluaimagergbctx); + cdlua_addcontext(L, cdL, &cdluadxfctx); + cdlua_addcontext(L, cdL, &cdluadgnctx); + cdlua_addcontext(L, cdL, &cdluacgmctx); + cdlua_addcontext(L, cdL, &cdluamfctx); + cdlua_addcontext(L, cdL, &cdluapsctx); + cdlua_addcontext(L, cdL, &cdluaclipboardctx); + cdlua_addcontext(L, cdL, &cdluanativewindowctx); + cdlua_addcontext(L, cdL, &cdluaprinterctx); + cdlua_addcontext(L, cdL, &cdluawmfctx); + cdlua_addcontext(L, cdL, &cdluaemfctx); + cdlua_addcontext(L, cdL, &cdluadbufctx); +} diff --git a/src/lua5/cdluacontextplus5.c b/src/lua5/cdluacontextplus5.c new file mode 100644 index 0000000..de69167 --- /dev/null +++ b/src/lua5/cdluacontextplus5.c @@ -0,0 +1,44 @@ +/** \file + * \brief Context Plus Lua 5 Binding + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" + +#include <lua.h> +#include <lauxlib.h> + + +static int cdlua5_initcontextplus(lua_State *L) +{ + (void)L; + cdInitContextPlus(); + return 0; +} + +static const struct luaL_reg cdlib[] = { + {"InitContextPlus", cdlua5_initcontextplus}, + {NULL, NULL}, +}; + + +static int cdluacontextplus_open (lua_State *L) +{ + cdInitContextPlus(); + luaL_register(L, "cd", cdlib); /* leave "cd" table at the top of the stack */ + return 1; +} + +int luaopen_cdluacontextplus(lua_State* L) +{ + return cdluacontextplus_open(L); +} + +int luaopen_cdluacontextplus51(lua_State* L) +{ + return cdluacontextplus_open(L); +} diff --git a/src/lua5/cdluacontextplus5.def b/src/lua5/cdluacontextplus5.def new file mode 100644 index 0000000..55e478b --- /dev/null +++ b/src/lua5/cdluacontextplus5.def @@ -0,0 +1,4 @@ +EXPORTS + luaopen_cdluacontextplus + luaopen_cdluacontextplus51 + \ No newline at end of file diff --git a/src/lua5/cdluaim5.c b/src/lua5/cdluaim5.c new file mode 100644 index 0000000..77ffc4f --- /dev/null +++ b/src/lua5/cdluaim5.c @@ -0,0 +1,265 @@ +/** \file + * \brief CD+IM Lua 5 Binding + * + * See Copyright Notice in im_lib.h + */ + +#include <string.h> +#include <memory.h> + +#define CD_NO_OLD_INTERFACE + +#include <im.h> +#include <im_image.h> + +#include "cd.h" +#include "cdirgb.h" +#include "wd.h" + +#include <lua.h> +#include <lauxlib.h> + +#include <imlua.h> + +#include "cdlua.h" +#include "cdlua5_private.h" + + +/*****************************************************************************\ + image:cdInitBitmap() -> cdBitmap +\*****************************************************************************/ +static int imlua_cdInitBitmap(lua_State *L) +{ + cdBitmap* bitmap; + imImage *image = imlua_checkimage(L, 1); + + if (!imImageIsBitmap(image)) + luaL_argerror(L, 1, "image is not a bitmap"); + + if (image->color_space == IM_RGB) + bitmap = cdInitBitmap(image->width, image->height, CD_RGB, image->data[0], image->data[1], image->data[2]); + else + bitmap = cdInitBitmap(image->width, image->height, CD_MAP, image->data[0], image->palette); + + if (!bitmap) + luaL_error(L, "insuficient memory to create bitmap"); + + cdlua_pushbitmap(L, bitmap); + return 1; +} + +/*****************************************************************************\ + image:cdCreateBitmap() -> cdBitmap +\*****************************************************************************/ +static int imlua_cdCreateBitmap(lua_State *L) +{ + cdBitmap* bitmap; + imImage *image = imlua_checkimage(L, 1); + + if (!imImageIsBitmap(image)) + luaL_argerror(L, 1, "image is not a bitmap"); + + if (image->color_space == IM_RGB) + bitmap = cdCreateBitmap(image->width, image->height, CD_RGB); + else + bitmap = cdCreateBitmap(image->width, image->height, CD_MAP); + + if (!bitmap) + luaL_error(L, "insuficient memory to create bitmap"); + + if (image->color_space == IM_RGB) + { + memcpy(cdBitmapGetData(bitmap, CD_IRED), image->data[0], image->plane_size); + memcpy(cdBitmapGetData(bitmap, CD_IGREEN), image->data[1], image->plane_size); + memcpy(cdBitmapGetData(bitmap, CD_IBLUE), image->data[2], image->plane_size); + } + else + { + memcpy(cdBitmapGetData(bitmap, CD_INDEX), image->data[0], image->plane_size); + memcpy(cdBitmapGetData(bitmap, CD_COLORS), image->palette, image->palette_count*sizeof(long int)); + } + + cdlua_pushbitmap(L, bitmap); + return 1; +} + +/*****************************************************************************\ + cd:imImageCreate(bitmap: cdBitmap) -> imImage +\*****************************************************************************/ +static int cdlua_imImageCreate(lua_State *L) +{ + imImage *image; + cdBitmap* bitmap = cdlua_checkbitmap(L, 1); + + if (bitmap->type == CD_RGB) + image = imImageCreate(bitmap->w, bitmap->h, IM_RGB, IM_BYTE); + else + image = imImageCreate(bitmap->w, bitmap->h, IM_MAP, IM_BYTE); + + if (!image) + luaL_error(L, "insuficient memory to create image"); + + if (bitmap->type == CD_RGB) + { + memcpy(image->data[0], cdBitmapGetData(bitmap, CD_IRED), image->plane_size); + memcpy(image->data[1], cdBitmapGetData(bitmap, CD_IGREEN), image->plane_size); + memcpy(image->data[2], cdBitmapGetData(bitmap, CD_IBLUE), image->plane_size); + } + else + { + memcpy(image->data[0], cdBitmapGetData(bitmap, CD_INDEX), image->plane_size); + memcpy(image->palette, cdBitmapGetData(bitmap, CD_COLORS), 256*sizeof(long int)); + } + + imlua_pushimage(L, image); + return 1; +} + +/*****************************************************************************\ + image:wdCanvasPutImageRect(_canvas, _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax) +\*****************************************************************************/ +static int imlua_wdCanvasPutImageRect(lua_State *L) +{ + int xr, yr, wr, hr; + imImage *image = imlua_checkimage(L, 1); + cdCanvas* canvas = cdlua_checkcanvas(L, 2); + double x = luaL_checknumber(L, 3); + double y = luaL_checknumber(L, 4); + double w = luaL_checknumber(L, 5); + double h = luaL_checknumber(L, 6); + int xmin = luaL_optint(L, 7, 0); + int xmax = luaL_optint(L, 8, 0); + int ymin = luaL_optint(L, 9, 0); + int ymax = luaL_optint(L, 10, 0); + + if (!imImageIsBitmap(image)) + luaL_argerror(L, 1, "image is not a bitmap"); + + wdCanvasWorld2Canvas(canvas, x, y, &xr, &yr); + wdCanvasWorld2CanvasSize(canvas, w, h, &wr, &hr); + + imcdCanvasPutImage(canvas, image, xr, yr, wr, hr, xmin, xmax, ymin, ymax); + return 0; +} + +/*****************************************************************************\ + image:cdCanvasPutImageRect(_canvas, _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax) +\*****************************************************************************/ +static int imlua_cdCanvasPutImageRect(lua_State *L) +{ + imImage *image = imlua_checkimage(L, 1); + cdCanvas* canvas = cdlua_checkcanvas(L, 2); + int x = luaL_checkint(L, 3); + int y = luaL_checkint(L, 4); + int w = luaL_checkint(L, 5); + int h = luaL_checkint(L, 6); + int xmin = luaL_optint(L, 7, 0); + int xmax = luaL_optint(L, 8, 0); + int ymin = luaL_optint(L, 9, 0); + int ymax = luaL_optint(L, 10, 0); + + if (!imImageIsBitmap(image)) + luaL_argerror(L, 1, "image is not a bitmap"); + + imcdCanvasPutImage(canvas, image, x, y, w, h, xmin, xmax, ymin, ymax); + return 0; +} + +/***************************************************************************\ +* image:cdCanvasGetImage(_canvas, x, y: number) * +\***************************************************************************/ +static int imlua_cdCanvasGetImage(lua_State *L) +{ + imImage *image = imlua_checkimage(L, 1); + cdCanvas* canvas = cdlua_checkcanvas(L, 2); + int x = luaL_optint(L, 3, 0); + int y = luaL_optint(L, 4, 0); + + if (image->color_space != IM_RGB || image->data_type != IM_BYTE) + luaL_argerror(L, 1, "image is not RGB/byte"); + + cdCanvasGetImageRGB(canvas, image->data[0], image->data[1], image->data[2], x, y, image->width, image->height); + return 0; +} + +/***************************************************************************\ +* image:cdCreateCanvas(res: number) -> cdCanvas * +\***************************************************************************/ +static int imlua_cdCreateCanvas(lua_State * L) +{ + cdCanvas**canvas_p, *canvas; + char data_s[100]; + + imImage *image = imlua_checkimage(L, 1); + + if (lua_isnoneornil(L, 2)) + { + sprintf(data_s, "%dx%d %p %p %p", image->width, image->height, + image->data[0], image->data[1], image->data[2]); + } + else + { + double res_f = luaL_checknumber(L, 2); + sprintf(data_s, "%dx%d %p %p %p -r%g", image->width, image->height, + image->data[0], image->data[1], image->data[2], res_f); + } + + canvas = cdCreateCanvas(CD_IMAGERGB, data_s); + if (!canvas) + { + lua_pushnil(L); + return 1; + } + + canvas_p = (cdCanvas**) lua_newuserdata(L, sizeof(cdCanvas*)); + luaL_getmetatable(L, "cdCanvas"); + lua_setmetatable(L, -2); + *canvas_p = canvas; + + return 1; +} + +static const luaL_reg cdim_metalib[] = { + {"imImageCreate", cdlua_imImageCreate}, + {NULL, NULL} +}; + +static const luaL_reg imcd_metalib[] = { + {"cdCreateBitmap", imlua_cdCreateBitmap}, + {"cdInitBitmap", imlua_cdInitBitmap}, + {"cdCreateCanvas", imlua_cdCreateCanvas}, + {"wdCanvasPutImageRect", imlua_wdCanvasPutImageRect}, + {"cdCanvasPutImageRect", imlua_cdCanvasPutImageRect}, + {"cdCanvasGetImage", imlua_cdCanvasGetImage}, + + {NULL, NULL} +}; + +static void createmeta (lua_State *L) +{ + /* add methods to already created metatables */ + + luaL_getmetatable(L, "imImage"); + luaL_register(L, NULL, imcd_metalib); /* register methods */ + lua_pop(L, 1); /* removes the metatable from the top of the stack */ + + luaL_getmetatable(L, "cdBitmap"); + luaL_register(L, NULL, cdim_metalib); /* register methods */ + lua_pop(L, 1); /* removes the metatable from the top of the stack */ +} + +int cdluaim_open(lua_State *L) +{ + createmeta(L); + return 0; +} + +int luaopen_cdluaim(lua_State *L) +{ + return cdluaim_open(L); +} + +int luaopen_cdluaim51(lua_State *L) +{ + return cdluaim_open(L); +} diff --git a/src/lua5/cdluaim5.def b/src/lua5/cdluaim5.def new file mode 100644 index 0000000..0b26928 --- /dev/null +++ b/src/lua5/cdluaim5.def @@ -0,0 +1,4 @@ +EXPORTS + cdluaim_open + luaopen_cdluaim + luaopen_cdluaim51 diff --git a/src/lua5/cdluapdf5.c b/src/lua5/cdluapdf5.c new file mode 100644 index 0000000..eb3f221 --- /dev/null +++ b/src/lua5/cdluapdf5.c @@ -0,0 +1,53 @@ +/** \file + * \brief PDF Canvas Lua 5 Binding + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" +#include "cdpdf.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua.h" +#include "cdluapdf.h" +#include "cdlua5_private.h" + + +static void *cdpdf_checkdata(lua_State *L, int param) +{ + return (void *)luaL_checkstring(L, param); +} + +static cdluaContext cdluapdfctx = +{ + 0, + "PDF", + cdContextPDF, + cdpdf_checkdata, + NULL, + 0 +}; + +int cdluapdf_open (lua_State *L) +{ + cdluaLuaState* cdL = cdlua_getstate(L); + lua_pushliteral(L, "cd"); + lua_gettable(L, LUA_GLOBALSINDEX); /* leave "cd" table at the top of the stack */ + cdlua_addcontext(L, cdL, &cdluapdfctx); + return 1; +} + +int luaopen_cdluapdf(lua_State* L) +{ + return cdluapdf_open(L); +} + +int luaopen_cdluapdf51(lua_State* L) +{ + return cdluapdf_open(L); +} diff --git a/src/lua5/cdluapdf5.def b/src/lua5/cdluapdf5.def new file mode 100644 index 0000000..bfbc889 --- /dev/null +++ b/src/lua5/cdluapdf5.def @@ -0,0 +1,4 @@ +EXPORTS + cdluapdf_open + luaopen_cdluapdf + luaopen_cdluapdf51 \ No newline at end of file diff --git a/src/lua5/cdvoid5.c b/src/lua5/cdvoid5.c new file mode 100644 index 0000000..2424e1d --- /dev/null +++ b/src/lua5/cdvoid5.c @@ -0,0 +1,130 @@ +/** \file + * \brief CD Void driver for error checking while there is no active canvas + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" +#include "cd_private.h" + +#include <lua.h> +#include <lauxlib.h> + +#include "cdlua5_private.h" + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + lua_State * L; +}; + +void cdlua_setvoidstate(cdCanvas* canvas, lua_State * L) +{ + canvas->ctxcanvas->L = L; +} + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas*) malloc(sizeof(cdCtxCanvas)); + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + (void)data; +} + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + free(ctxcanvas); +} + +/***************************************************************************\ +* Echos an error if called. * +\***************************************************************************/ +static void cdvoid_error(cdCtxCanvas* ctxcanvas) +{ + luaL_error(ctxcanvas->L, "cdlua: there is no active canvas"); +} + +/***************************************************************************\ +* Dummy. * +\***************************************************************************/ +static int cdvoid_dummy(void) +{ + return CD_OK; +} + +/***************************************************************************\ +* Driver function table. * +\***************************************************************************/ + +void cdinittable(cdCanvas* canvas) +{ + /* attribute functions can not be set, because of default attributes */ + + canvas->cxClip = (int (*)(cdCtxCanvas*, int))cdvoid_error; + canvas->cxClipArea = (void (*)(cdCtxCanvas*, int, int, int, int))cdvoid_error; + canvas->cxNewRegion = (void (*)(cdCtxCanvas*))cdvoid_error; + canvas->cxIsPointInRegion = (int (*)(cdCtxCanvas*, int, int))cdvoid_error; + canvas->cxOffsetRegion = (void (*)(cdCtxCanvas*, int, int))cdvoid_error; + canvas->cxGetRegionBox = (void (*)(cdCtxCanvas*, int *, int *, int *, int *))cdvoid_error; + canvas->cxFlush = (void ( *)(cdCtxCanvas*))cdvoid_error; + canvas->cxClear = (void ( *)(cdCtxCanvas*))cdvoid_error; + canvas->cxPixel = (void ( *)(cdCtxCanvas*, int ,int ,long ))cdvoid_error; + canvas->cxLine = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxPoly = (void ( *)(cdCtxCanvas*, int ,struct _cdPoint *,int ))cdvoid_error; + canvas->cxRect = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxBox = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ))cdvoid_error; + canvas->cxArc = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxSector = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxChord = (void ( *)(cdCtxCanvas*, int ,int ,int ,int ,double ,double ))cdvoid_error; + canvas->cxText = (void (*)(cdCtxCanvas*, int ,int ,const char *))cdvoid_error; + canvas->cxGetFontDim = (void (*)(cdCtxCanvas*, int *,int *,int *,int *))cdvoid_error; + canvas->cxGetTextSize = (void (*)(cdCtxCanvas*, const char *,int *,int *))cdvoid_error; + canvas->cxPutImageRectRGB = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const unsigned char *,const unsigned char *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxPutImageRectRGBA = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxPutImageRectMap = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *,const long *,int ,int ,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxScrollArea = (void (*)(cdCtxCanvas*, int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxFLine = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFPoly = (void (*)(cdCtxCanvas*, int , cdfPoint*,int ))cdvoid_error; + canvas->cxFRect = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFBox = (void (*)(cdCtxCanvas*, double ,double ,double ,double ))cdvoid_error; + canvas->cxFArc = (void (*)(cdCtxCanvas*, double ,double ,double ,double ,double ,double ))cdvoid_error; + canvas->cxFSector = (void (*)(cdCtxCanvas*, double ,double ,double ,double ,double ,double ))cdvoid_error; + canvas->cxFText = (void (*)(cdCtxCanvas*, double ,double ,const char *))cdvoid_error; + canvas->cxStipple = (void (*)(cdCtxCanvas*, int ,int ,const unsigned char *))cdvoid_error; + canvas->cxPattern = (void (*)(cdCtxCanvas*, int ,int , const long *))cdvoid_error; + canvas->cxNativeFont = (int (*)(cdCtxCanvas*, const char*))cdvoid_error; + canvas->cxPalette = (void (*)(cdCtxCanvas*, int ,const long *,int ))cdvoid_error; + canvas->cxGetImageRGB = (void (*)(cdCtxCanvas*, unsigned char *,unsigned char *,unsigned char *,int ,int ,int ,int ))cdvoid_error; + canvas->cxCreateImage = (cdCtxImage* (*)(cdCtxCanvas*, int ,int ))cdvoid_error; + canvas->cxGetImage = (void (*)(cdCtxCanvas*, cdCtxImage*, int ,int ))cdvoid_error; + canvas->cxPutImageRect = (void (*)(cdCtxCanvas*, cdCtxImage*,int ,int ,int ,int ,int ,int ))cdvoid_error; + canvas->cxKillImage = (void (*)(cdCtxImage*))cdvoid_error; + canvas->cxFClipArea = (void (*)(cdCtxCanvas*, double,double,double,double))cdvoid_error; + + /* must not be the error callback */ + canvas->cxActivate = (int (*)(cdCtxCanvas*))cdvoid_dummy; + canvas->cxDeactivate = (void (*)(cdCtxCanvas*))cdvoid_dummy; + canvas->cxFont = (int (*)(cdCtxCanvas*, const char *, int, int))cdvoid_dummy; + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdVoidContext = +{ + 0, + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextVoid(void) +{ + return &cdVoidContext; +} + diff --git a/src/lua5/cdvoid5.h b/src/lua5/cdvoid5.h new file mode 100644 index 0000000..75bf6e7 --- /dev/null +++ b/src/lua5/cdvoid5.h @@ -0,0 +1,18 @@ +#ifndef _CD_VOID_ +#define _CD_VOID_ + +#ifdef __cplusplus +extern "C" { +#endif + +cdContext* cdContextVoid(void); +void cdlua_setvoidstate(cdCanvas* cnv, lua_State * L); + +#define CD_VOID cdContextVoid() + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _CD_VOID_ */ + diff --git a/src/make_uname b/src/make_uname new file mode 100644 index 0000000..9e5b483 --- /dev/null +++ b/src/make_uname @@ -0,0 +1,16 @@ +#This builds all the libraries of the folder for 1 uname + +tecmake $1 MF=cd_freetype $2 $3 $4 $5 $6 $7 $8 +tecmake $1 $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cd_pdflib $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdpdf $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdlua3 $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdluapdf3 $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdlua5 $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdluaim5 $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdluapdf5 $2 $3 $4 $5 $6 $7 $8 + +# XRender is NOT available in AIX, IRIX and SunOS +# It is available in Linux, Darwin and FreeBSD +tecmake $1 MF=cdcontextplus $2 $3 $4 $5 $6 $7 $8 +tecmake $1 MF=cdluacontextplus5 $2 $3 $4 $5 $6 $7 $8 diff --git a/src/make_uname.bat b/src/make_uname.bat new file mode 100644 index 0000000..9d0af62 --- /dev/null +++ b/src/make_uname.bat @@ -0,0 +1,57 @@ +@echo off +REM This builds all the libraries of the folder for 1 uname + +if "%1"=="VC" goto gdiplus_VC +if "%1"=="vc-all" goto all-vc + +call tecmake %1 "MF=cd_freetype" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cd_pdflib" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdpdf" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdlua3" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdluapdf3" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdlua5" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdluapdf5" %2 %3 %4 %5 %6 %7 %8 +call tecmake %1 "MF=cdluaim5" %2 %3 %4 %5 %6 %7 %8 + +if "%1"=="vc6" goto gdiplus +if "%1"=="vc7" goto gdiplus +if "%1"=="vc8" goto gdiplus +if "%1"=="vc8_64" goto gdiplus +if "%1"=="vc9" goto gdiplus +if "%1"=="vc9_64" goto gdiplus +if "%1"=="dll" goto gdiplus +if "%1"=="dll7" goto gdiplus +if "%1"=="dll8" goto gdiplus +if "%1"=="dll8_64" goto gdiplus +if "%1"=="dll9" goto gdiplus +if "%1"=="dll9_64" goto gdiplus +if "%1"=="all" goto all-vc +goto end + +:gdiplus +call tecmake %1 "MF=cdcontextplus" %2 %3 %4 %5 %6 +call tecmake %1 "MF=cdluacontextplus5" %2 %3 %4 %5 %6 %7 %8 +goto end + +:gdiplus_VC +call tecmake %2 "MF=cdcontextplus" %3 %4 %5 %6 +call tecmake %2 "MF=cdluacontextplus5" %2 %3 %4 %5 %6 %7 %8 +goto end + +:all-vc +call make_uname VC vc6 %2 %3 %4 %5 %6 +call make_uname VC vc7 %2 %3 %4 %5 %6 +call make_uname VC vc8 %2 %3 %4 %5 %6 +call make_uname VC vc8_64 %2 %3 %4 %5 %6 +call make_uname VC vc9 %2 %3 %4 %5 %6 +call make_uname VC vc9_64 %2 %3 %4 %5 %6 +call make_uname VC dll %2 %3 %4 %5 %6 +call make_uname VC dll7 %2 %3 %4 %5 %6 +call make_uname VC dll8 %2 %3 %4 %5 %6 +call make_uname VC dll8_64 %2 %3 %4 %5 %6 +call make_uname VC dll9 %2 %3 %4 %5 %6 +call make_uname VC dll9_64 %2 %3 %4 %5 %6 +goto end + +:end diff --git a/src/pdflib/flate/adler32.c b/src/pdflib/flate/adler32.c new file mode 100644 index 0000000..3f309ba --- /dev/null +++ b/src/pdflib/flate/adler32.c @@ -0,0 +1,144 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id: adler32.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: adler32.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/src/pdflib/flate/compress.c b/src/pdflib/flate/compress.c new file mode 100644 index 0000000..64dd6f3 --- /dev/null +++ b/src/pdflib/flate/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id: compress.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: compress.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 ( + Bytef *dest, + uLongf *destLen, + const Bytef *source, + uLong sourceLen, + int level) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress ( + Bytef *dest, + uLongf *destLen, + const Bytef *source, + uLong sourceLen) +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (uLong sourceLen) +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/src/pdflib/flate/crc32.c b/src/pdflib/flate/crc32.c new file mode 100644 index 0000000..df92f90 --- /dev/null +++ b/src/pdflib/flate/crc32.c @@ -0,0 +1,424 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* $Id: crc32.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: crc32.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include <stdio.h> +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include <limits.h> +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table( + FILE *out, + const unsigned long FAR *table) +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32( + unsigned long crc, + const unsigned char FAR *buf, + unsigned len) +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little( + unsigned long crc, + const unsigned char FAR *buf, + unsigned len) +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big( + unsigned long crc, + const unsigned char FAR *buf, + unsigned len) +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times( + unsigned long *mat, + unsigned long vec) +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square( + unsigned long *square, + unsigned long *mat) +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine( + uLong crc1, + uLong crc2, + z_off_t len2) +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/src/pdflib/flate/crc32.h b/src/pdflib/flate/crc32.h new file mode 100644 index 0000000..8053b61 --- /dev/null +++ b/src/pdflib/flate/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/src/pdflib/flate/deflate.c b/src/pdflib/flate/deflate.c new file mode 100644 index 0000000..5454e60 --- /dev/null +++ b/src/pdflib/flate/deflate.c @@ -0,0 +1,1740 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* $Id: deflate.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: deflate.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_( + z_streamp strm, + int level, + const char *version, + int stream_size) +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_( + z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy, + const char *version, + int stream_size) +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + /* we don't use calloc -> to satisfy purify + * at least here memset is needed */ + memset((void *)s->window, 0, (size_t) s->w_size * 2*sizeof(Byte)); + + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary ( + z_streamp strm, + const Bytef *dictionary, + uInt dictLength) +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset ( + z_streamp strm) +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader ( + z_streamp strm, + gz_headerp head) +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime ( + z_streamp strm, + int bits, + int value) +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams( + z_streamp strm, + int level, + int strategy) +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune( + z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain) +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound( + z_streamp strm, + uLong sourceLen) +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB ( + deflate_state *s, + uInt b) +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending( + z_streamp strm) +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate ( + z_streamp strm, + int flush) +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd ( + z_streamp strm) +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy ( + z_streamp dest, + z_streamp source) +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf( + z_streamp strm, + Bytef *buf, + unsigned size) +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init ( + deflate_state *s) +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match( + deflate_state *s, + IPos cur_match) /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast( + deflate_state *s, + IPos cur_match) /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match( + deflate_state *s, + IPos start, IPos match, + int length) +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window( + deflate_state *s) +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored( + deflate_state *s, + int flush) +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast( + deflate_state *s, + int flush) +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow( + deflate_state *s, + int flush) +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/src/pdflib/flate/deflate.h b/src/pdflib/flate/deflate.h new file mode 100644 index 0000000..36e0961 --- /dev/null +++ b/src/pdflib/flate/deflate.h @@ -0,0 +1,334 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + + +/* $Id: deflate.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +/* @(#) $Id: deflate.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/src/pdflib/flate/inffast.c b/src/pdflib/flate/inffast.c new file mode 100644 index 0000000..c3d8a1d --- /dev/null +++ b/src/pdflib/flate/inffast.c @@ -0,0 +1,319 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* $Id: inffast.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast( +z_streamp strm, +unsigned start) /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wwrite; /* window wwrite index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code tthis; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wwrite = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + tthis = lcode[hold & lmask]; + dolen: + op = (unsigned)(tthis.bits); + hold >>= op; + bits -= op; + op = (unsigned)(tthis.op); + if (op == 0) { /* literal */ + Tracevv((stderr, tthis.val >= 0x20 && tthis.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", tthis.val)); + PUP(out) = (unsigned char)(tthis.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(tthis.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + tthis = dcode[hold & dmask]; + dodist: + op = (unsigned)(tthis.bits); + hold >>= op; + bits -= op; + op = (unsigned)(tthis.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(tthis.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (wwrite == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wwrite < op) { /* wrap around window */ + from += wsize + wwrite - op; + op -= wwrite; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wwrite < len) { /* some from start of window */ + op = wwrite; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wwrite - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + tthis = dcode[tthis.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + tthis = lcode[tthis.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/src/pdflib/flate/inffast.h b/src/pdflib/flate/inffast.h new file mode 100644 index 0000000..1e88d2d --- /dev/null +++ b/src/pdflib/flate/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/src/pdflib/flate/inffixed.h b/src/pdflib/flate/inffixed.h new file mode 100644 index 0000000..75ed4b5 --- /dev/null +++ b/src/pdflib/flate/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/src/pdflib/flate/inflate.c b/src/pdflib/flate/inflate.c new file mode 100644 index 0000000..87cd287 --- /dev/null +++ b/src/pdflib/flate/inflate.c @@ -0,0 +1,1369 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ +/* $Id: inflate.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset( +z_streamp strm) +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime( +z_streamp strm, +int bits, +int value) +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_( +z_streamp strm, +int windowBits, +const char *version, +int stream_size) +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_( +z_streamp strm, +const char *version, +int stream_size) +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables( +struct inflate_state FAR *state) +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include <stdio.h> + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow( +z_streamp strm, +unsigned out) +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate( +z_streamp strm, +int flush) +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code tthis; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + tthis = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(tthis.bits) <= bits) break; + PULLBYTE(); + } + if (tthis.val < 16) { + NEEDBITS(tthis.bits); + DROPBITS(tthis.bits); + state->lens[state->have++] = tthis.val; + } + else { + if (tthis.val == 16) { + NEEDBITS(tthis.bits + 2); + DROPBITS(tthis.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (tthis.val == 17) { + NEEDBITS(tthis.bits + 3); + DROPBITS(tthis.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(tthis.bits + 7); + DROPBITS(tthis.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + tthis = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(tthis.bits) <= bits) break; + PULLBYTE(); + } + if (tthis.op && (tthis.op & 0xf0) == 0) { + last = tthis; + for (;;) { + tthis = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + tthis.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(tthis.bits); + state->length = (unsigned)tthis.val; + if ((int)(tthis.op) == 0) { + Tracevv((stderr, tthis.val >= 0x20 && tthis.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", tthis.val)); + state->mode = LIT; + break; + } + if (tthis.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (tthis.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(tthis.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + tthis = state->distcode[BITS(state->distbits)]; + if ((unsigned)(tthis.bits) <= bits) break; + PULLBYTE(); + } + if ((tthis.op & 0xf0) == 0) { + last = tthis; + for (;;) { + tthis = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + tthis.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(tthis.bits); + if (tthis.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)tthis.val; + state->extra = (unsigned)(tthis.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd( +z_streamp strm) +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary( +z_streamp strm, +const Bytef *dictionary, +uInt dictLength) +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader( +z_streamp strm, +gz_headerp head) +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch( +unsigned FAR *have, +unsigned char FAR *buf, +unsigned len) +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync( +z_streamp strm) +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint( +z_streamp strm) +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy( +z_streamp dest, +z_streamp source) +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/src/pdflib/flate/inflate.h b/src/pdflib/flate/inflate.h new file mode 100644 index 0000000..07bd3e7 --- /dev/null +++ b/src/pdflib/flate/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/src/pdflib/flate/inftrees.c b/src/pdflib/flate/inftrees.c new file mode 100644 index 0000000..0f67881 --- /dev/null +++ b/src/pdflib/flate/inftrees.c @@ -0,0 +1,330 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* $Id: inftrees.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table( +codetype type, +unsigned short FAR *lens, +unsigned codes, +code FAR * FAR *table, +unsigned FAR *bits, +unsigned short FAR *work) +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code tthis; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + tthis.op = (unsigned char)64; /* invalid code marker */ + tthis.bits = (unsigned char)1; + tthis.val = (unsigned short)0; + *(*table)++ = tthis; /* make a table to force an error */ + *(*table)++ = tthis; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + tthis.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + tthis.op = (unsigned char)0; + tthis.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + tthis.op = (unsigned char)(extra[work[sym]]); + tthis.val = base[work[sym]]; + } + else { + tthis.op = (unsigned char)(32 + 64); /* end of block */ + tthis.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = tthis; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + tthis.op = (unsigned char)64; /* invalid code marker */ + tthis.bits = (unsigned char)(len - drop); + tthis.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + tthis.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = tthis; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/src/pdflib/flate/inftrees.h b/src/pdflib/flate/inftrees.h new file mode 100644 index 0000000..b1104c8 --- /dev/null +++ b/src/pdflib/flate/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/src/pdflib/flate/trees.c b/src/pdflib/flate/trees.c new file mode 100644 index 0000000..a885cd4 --- /dev/null +++ b/src/pdflib/flate/trees.c @@ -0,0 +1,1220 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* $Id: trees.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: trees.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include <ctype.h> +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits( + deflate_state *s, + int value, /* value to send */ + int length) /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1<<extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length-1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<<extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include <stdio.h> +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init( + deflate_state *s) +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block( + deflate_state *s) +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap( + deflate_state *s, + ct_data *tree, /* the tree to restore */ + int k) /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen( + deflate_state *s, + tree_desc *desc) /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes ( + ct_data *tree, /* the tree to decorate */ + int max_code, /* largest code with non zero frequency */ + ushf *bl_count) /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree( + deflate_state *s, + tree_desc *desc) /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree ( + deflate_state *s, + ct_data *tree, /* the tree to be scanned */ + int max_code) /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree ( + deflate_state *s, + ct_data *tree, /* the tree to be scanned */ + int max_code) /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree( + deflate_state *s) +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees( + deflate_state *s, + int lcodes, int dcodes, int blcodes) /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block( + deflate_state *s, + charf *buf, /* input block */ + ulg stored_len, /* length of input block */ + int eof) /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align( + deflate_state *s) +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block( + deflate_state *s, + charf *buf, /* input block, or NULL if too old */ + ulg stored_len, /* length of input block */ + int eof) /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally ( + deflate_state *s, + unsigned dist, /* distance of matched string */ + unsigned lc) /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block( + deflate_state *s, + ct_data *ltree, /* literal tree */ + ct_data *dtree) /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type( + deflate_state *s) +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse( + unsigned code, /* the value to invert */ + int len) /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush( + deflate_state *s) +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup( + deflate_state *s) +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block( + deflate_state *s, + charf *buf, /* the input data */ + unsigned len, /* its length */ + int header) /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/src/pdflib/flate/trees.h b/src/pdflib/flate/trees.h new file mode 100644 index 0000000..3669ef9 --- /dev/null +++ b/src/pdflib/flate/trees.h @@ -0,0 +1,131 @@ +/* header created automatically with -DGEN_TREES_H */ + + +/* $Id: trees.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/src/pdflib/flate/uncompr.c b/src/pdflib/flate/uncompr.c new file mode 100644 index 0000000..e01ad4b --- /dev/null +++ b/src/pdflib/flate/uncompr.c @@ -0,0 +1,62 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id: uncompr.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: uncompr.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress ( + Bytef *dest, + uLongf *destLen, + const Bytef *source, + uLong sourceLen) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/src/pdflib/flate/zconf.h b/src/pdflib/flate/zconf.h new file mode 100644 index 0000000..1e664a8 --- /dev/null +++ b/src/pdflib/flate/zconf.h @@ -0,0 +1,280 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +/* $Id: zconf.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: zconf.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#include "pc_config.h" +#include "zprefix.h" + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* PDFlib GmbH: Windows CE portability */ +#ifdef _WIN32_WCE +#define NO_ERRNO_H +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifndef STDC /* PDFlib GmbH: we require ANSI C anyway */ +#define STDC +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include <windows.h> + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +/* PDFlib GmbH: also do the typedef on the Mac +#if defined(MAC) || defined(MACOSX) +#include <MacTypes.h> +#else +*/ +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif + +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +/* PDFlib GmbH: Windows portability */ +#if !defined(WIN32) && !defined(OS2) && !defined(MAC) +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# define FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ + +/* PDFlib GmbH: This is not true anymore.... +** But it won't hurt anything to do it . +*/ + +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/src/pdflib/flate/zlib.h b/src/pdflib/flate/zlib.h new file mode 100644 index 0000000..977a8bd --- /dev/null +++ b/src/pdflib/flate/zlib.h @@ -0,0 +1,1360 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + + +/* $Id: zlib.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/src/pdflib/flate/zprefix.h b/src/pdflib/flate/zprefix.h new file mode 100644 index 0000000..ddac287 --- /dev/null +++ b/src/pdflib/flate/zprefix.h @@ -0,0 +1,134 @@ +/* $Id: zprefix.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +/* PDFlib GmbH: We use "pdf_z_". +** The original list was incomplete, by the way. +*/ +#ifndef ZPREFIX_H +#define ZPREFIX_H + +#define Z_PREFIX +#ifdef Z_PREFIX + +/* redefine names of all functions for integrating into + * TET/PLOP/PCOS library, to avoid name clashes if used together with + * pdflib */ +#ifdef PDFLIB_TET_BUILD +#define FLATE_PREFIX(x) tet_z_##x +#define _FLATE_PREFIX(x) _tet_z_##x +#else +#ifdef PDFLIB_PLOP_BUILD +#define FLATE_PREFIX(x) plop_z_##x +#define _FLATE_PREFIX(x) _plop_z_##x +#else +#ifdef PDFLIB_PCOS_BUILD +#define FLATE_PREFIX(x) pcos_z_##x +#define _FLATE_PREFIX(x) _pcos_z_##x +#else +#define FLATE_PREFIX(x) pdf_z_##x +#define _FLATE_PREFIX(x) _pdf_z_##x +#endif /* PDFLIB_PCOS_BUILD */ +#endif /* PDFLIB_PLOP_BUILD */ +#endif /* PDFLIB_TET_BUILD */ + +# define longest_match FLATE_PREFIX(longest_match) +# define match_init FLATE_PREFIX(match_init) +# define longest_match_7fff FLATE_PREFIX(longest_match_7fff) +# define cpudetect32 FLATE_PREFIX(cpudetect32) +# define longest_match_686 FLATE_PREFIX(longest_match_686) +# define inflate_fast FLATE_PREFIX(inflate_fast) + +# define _longest_match _FLATE_PREFIX(longest_match) +# define _match_init _FLATE_PREFIX(match_init) +# define _longest_match_7fff _FLATE_PREFIX(longest_match_7fff) +# define _cpudetect32 _FLATE_PREFIX(cpudetect32) +# define _longest_match_686 _FLATE_PREFIX(longest_match_686) +# define _inflate_fast _FLATE_PREFIX(inflate_fast) + + +# define inflate_copyright FLATE_PREFIX(inflate_copyright) +# define inflate_table FLATE_PREFIX(inflate_table) +# define _dist_code FLATE_PREFIX(_dist_code) +# define _length_code FLATE_PREFIX(_length_code) +# define _tr_align FLATE_PREFIX(_tr_align) +# define _tr_flush_block FLATE_PREFIX(_tr_flush_block) +# define _tr_init FLATE_PREFIX(_tr_init) +# define _tr_stored_block FLATE_PREFIX(_tr_stored_block) +# define _tr_tally FLATE_PREFIX(_tr_tally) +# define zcalloc FLATE_PREFIX(zcalloc) +# define zcfree FLATE_PREFIX(zcfree) +# define z_errmsg FLATE_PREFIX(z_errmsg) +# define z_error FLATE_PREFIX(z_error) +# define zlibCompileFlags FLATE_PREFIX(zlibCompileFlags) +# define zlibVersion FLATE_PREFIX(zlibVersion) +# define z_verbose FLATE_PREFIX(z_verbose) +# define inflateGetHeader FLATE_PREFIX(inflateGetHeader) +# define inflatePrime FLATE_PREFIX(inflatePrime) +# define adler32_combine FLATE_PREFIX(adler32_combine) +# define crc32_combine FLATE_PREFIX(crc32_combine) +# define deflate_copyright FLATE_PREFIX(deflate_copyright) +# define deflateSetHeader FLATE_PREFIX(deflateSetHeader) +# define deflateTune FLATE_PREFIX(deflateTune) + +# define deflateInit_ FLATE_PREFIX(deflateInit_) +# define deflate FLATE_PREFIX(deflate) +# define deflateEnd FLATE_PREFIX(deflateEnd) +# define inflateInit_ FLATE_PREFIX(inflateInit_) +# define inflate FLATE_PREFIX(inflate) +# define inflateEnd FLATE_PREFIX(inflateEnd) +# define deflateInit2_ FLATE_PREFIX(deflateInit2_) +# define deflateSetDictionary FLATE_PREFIX(deflateSetDictionary) +# define deflateCopy FLATE_PREFIX(deflateCopy) +# define deflateReset FLATE_PREFIX(deflateReset) +# define deflateParams FLATE_PREFIX(deflateParams) +# define deflateBound FLATE_PREFIX(deflateBound) +# define deflatePrime FLATE_PREFIX(deflatePrime) +# define inflateInit2_ FLATE_PREFIX(inflateInit2_) +# define inflateSetDictionary FLATE_PREFIX(inflateSetDictionary) +# define inflateSync FLATE_PREFIX(inflateSync) +# define inflateSyncPoint FLATE_PREFIX(inflateSyncPoint) +# define inflateCopy FLATE_PREFIX(inflateCopy) +# define inflateReset FLATE_PREFIX(inflateReset) +# define inflateBack FLATE_PREFIX(inflateBack) +# define inflateBackEnd FLATE_PREFIX(inflateBackEnd) +# define compress FLATE_PREFIX(compress) +# define compress2 FLATE_PREFIX(compress2) +# define compressBound FLATE_PREFIX(compressBound) +# define uncompress FLATE_PREFIX(uncompress) +# define adler32 FLATE_PREFIX(adler32) +# define crc32 FLATE_PREFIX(crc32) +# define get_crc_table FLATE_PREFIX(get_crc_table) +# define zError FLATE_PREFIX(zError) + +#if 0 +/* + * PDFlib GmbH: Avoid these redefinitions since they are not required + * for typedefs, and can break functions of the same name in other + * modules. + */ +# define alloc_func FLATE_PREFIX(alloc_func) +# define free_func FLATE_PREFIX(free_func) +# define in_func FLATE_PREFIX(in_func) +# define out_func FLATE_PREFIX(out_func) +#endif + +/* special handling required on the Mac where Byte is alread defined */ +#if !(defined(MAC) || defined(MACOSX)) +# define Byte z_Byte +#endif + +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#endif /* ZPREFIX_H */ diff --git a/src/pdflib/flate/zutil.c b/src/pdflib/flate/zutil.c new file mode 100644 index 0000000..2fa45b3 --- /dev/null +++ b/src/pdflib/flate/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id: zutil.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: zutil.c,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error ( + char *m) +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError( + int err) +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy( + Bytef* dest, + const Bytef* source, + uInt len) +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp( + const Bytef* s1, + const Bytef* s2, + uInt len) +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero( + Bytef* dest, + uInt len) +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc ( + voidpf opaque, + unsigned items, + unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree ( + voidpf opaque, + voidpf ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/src/pdflib/flate/zutil.h b/src/pdflib/flate/zutil.h new file mode 100644 index 0000000..0db04c2 --- /dev/null +++ b/src/pdflib/flate/zutil.h @@ -0,0 +1,276 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + + +/* $Id: zutil.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ +/* @(#) $Id: zutil.h,v 1.1 2008/10/17 06:10:42 scuri Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include <stddef.h> +# endif +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include <errno.h> +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include <alloc.h> +# endif +# else /* MSC or DJGPP */ +# include <malloc.h> +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include <malloc.h> +# endif +#endif + +#if defined(MAC) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include <stdio.h> + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +#else +# define Assert(cond,msg) +#endif + +/* PDFlib GmbH: we don't like trace messages from here. */ +#if 0 +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/src/pdflib/font/ft_cid.c b/src/pdflib/font/ft_cid.c new file mode 100644 index 0000000..aff9784 --- /dev/null +++ b/src/pdflib/font/ft_cid.c @@ -0,0 +1,295 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_cid.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT CID functions + * + */ + +#define FT_CID_C + +#include <errno.h> + +#include "ft_font.h" +#include "pc_file.h" + +/* ------------------------ Predefined CMaps ------------------------ */ + +/* Predefined CMaps and the corresponding character collection */ +static const fnt_cmap_info fnt_predefined_cmaps[] = +{ + { "83pv-RKSJ-H", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "90ms-RKSJ-H", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 0}, + { "90ms-RKSJ-V", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 1}, + { "90msp-RKSJ-H", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 0}, + { "90msp-RKSJ-V", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 1}, + { "90pv-RKSJ-H", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "Add-RKSJ-H", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "Add-RKSJ-V", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 1}, + { "EUC-H", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "EUC-V", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 1}, + { "Ext-RKSJ-H", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 0}, + { "Ext-RKSJ-V", cc_japanese, 0, PDC_1_3, 2, 2, 2, 2, 1}, + { "H", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "V", cc_japanese, 0, PDC_1_3, 1, 1, 1, 1, 1}, + { "UniJIS-UCS2-H", cc_japanese, 2, PDC_1_3, 2, 4, 4, 6, 0}, + { "UniJIS-UCS2-V", cc_japanese, 2, PDC_1_3, 2, 4, 4, 6, 1}, + { "UniJIS-UCS2-HW-H", cc_japanese,-2, PDC_1_3, 2, 4, 4, 6, 0}, + { "UniJIS-UCS2-HW-V", cc_japanese -2, PDC_1_3, 2, 4, 4, 6, 1}, + { "UniJIS-UTF16-H", cc_japanese, 2, PDC_1_5, 0, 0, 5, 6, 0}, + { "UniJIS-UTF16-V", cc_japanese, 2, PDC_1_5, 0, 0, 5, 6, 1}, + + { "GB-EUC-H", cc_simplified_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "GB-EUC-V", cc_simplified_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "GBpc-EUC-H", cc_simplified_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "GBpc-EUC-V", cc_simplified_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "GBK-EUC-H", cc_simplified_chinese, 0, PDC_1_3, 2, 2, 2, 2, 0}, + { "GBK-EUC-V", cc_simplified_chinese, 0, PDC_1_3, 2, 2, 2, 2, 1}, + { "GBKp-EUC-H", cc_simplified_chinese, 0, PDC_1_4, 0, 2, 2, 2, 0}, + { "GBKp-EUC-V", cc_simplified_chinese, 0, PDC_1_4, 0, 2, 2, 2, 1}, + { "GBK2K-H", cc_simplified_chinese, 0, PDC_1_4, 0, 4, 4, 4, 0}, + { "GBK2K-V", cc_simplified_chinese, 0, PDC_1_4, 0, 4, 4, 4, 1}, + { "UniGB-UCS2-H", cc_simplified_chinese, 2, PDC_1_3, 2, 4, 4, 4, 0}, + { "UniGB-UCS2-V", cc_simplified_chinese, 2, PDC_1_3, 2, 4, 4, 4, 1}, + { "UniGB-UTF16-H", cc_simplified_chinese, 2, PDC_1_5, 0, 0, 4, 4, 0}, + { "UniGB-UTF16-V", cc_simplified_chinese, 2, PDC_1_5, 0, 0, 4, 4, 1}, + + { "B5pc-H", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "B5pc-V", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "HKscs-B5-H", cc_traditional_chinese, 0, PDC_1_4, 0, 3, 3, 3, 0}, + { "HKscs-B5-V", cc_traditional_chinese, 0, PDC_1_4, 0, 3, 3, 3, 1}, + { "ETen-B5-H", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "ETen-B5-V", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "ETenms-B5-H", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "ETenms-B5-V", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "CNS-EUC-H", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "CNS-EUC-V", cc_traditional_chinese, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "UniCNS-UCS2-H", cc_traditional_chinese, 2, PDC_1_3, 0, 3, 3, 3, 0}, + { "UniCNS-UCS2-V", cc_traditional_chinese, 2, PDC_1_3, 0, 3, 3, 3, 1}, + { "UniCNS-UTF16-H", cc_traditional_chinese, 2, PDC_1_5, 0, 0, 4, 4, 0}, + { "UniCNS-UTF16-V", cc_traditional_chinese, 2, PDC_1_5, 0, 0, 4, 4, 1}, + + { "KSC-EUC-H", cc_korean, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "KSC-EUC-V", cc_korean, 0, PDC_1_3, 0, 0, 0, 0, 1}, + { "KSCms-UHC-H", cc_korean, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "KSCms-UHC-V", cc_korean, 0, PDC_1_3, 1, 1, 1, 1, 1}, + { "KSCms-UHC-HW-H", cc_korean, 0, PDC_1_3, 1, 1, 1, 1, 0}, + { "KSCms-UHC-HW-V", cc_korean, 0, PDC_1_3, 1, 1, 1, 1, 1}, + { "KSCpc-EUC-H", cc_korean, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "UniKS-UCS2-H", cc_korean, 2, PDC_1_3, 1, 1, 1, 1, 0}, + { "UniKS-UCS2-V", cc_korean, 2, PDC_1_3, 1, 1, 1, 1, 1}, + { "UniKS-UTF16-H", cc_korean, 2, PDC_1_5, 0, 0, 2, 2, 0}, + { "UniKS-UTF16-V", cc_korean, 2, PDC_1_5, 0, 0, 2, 2, 1}, + + { "Identity-H", cc_identity, 0, PDC_1_3, 0, 0, 0, 0, 0}, + { "Identity-V", cc_identity, 0, PDC_1_3, 0, 0, 0, 0, 1}, + + { NULL, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +static int +fnt_get_predefined_cmap_slot(const char *cmapname) +{ + int slot; + + for (slot = 0; ; slot++) + { + if (fnt_predefined_cmaps[slot].name == NULL) + { + slot = -1; + break; + } + if (!strcmp(fnt_predefined_cmaps[slot].name, cmapname)) + break; + } + + return slot; +} + +int +fnt_get_predefined_cmap_info(const char *cmapname, fnt_cmap_info *cmapinfo) +{ + int slot; + + slot = fnt_get_predefined_cmap_slot(cmapname); + + if (slot == -1) + return cc_none; + + if (cmapinfo) + *cmapinfo = fnt_predefined_cmaps[slot]; + + return fnt_predefined_cmaps[slot].charcoll; +} + +static const pdc_keyconn fnt_charcoll_keylist[] = +{ + { "Japan1", cc_japanese}, + { "GB1", cc_simplified_chinese}, + { "CNS1", cc_traditional_chinese}, + { "Korea1", cc_korean}, + { "Identity", cc_identity}, + { "Unknown", cc_unknown}, + { NULL, 0} +}; + +const char * +fnt_get_ordering_cid(int charcoll) +{ + return pdc_get_keyword(charcoll, fnt_charcoll_keylist); +} + +int +fnt_get_charcoll(const char *ordering) +{ + int charcoll; + + charcoll = (int) pdc_get_keycode(ordering, fnt_charcoll_keylist); + + if (charcoll == PDC_KEY_NOTFOUND) + return cc_unknown; + else + return charcoll; +} + +int +fnt_get_supplement(fnt_cmap_info *cmapinfo, int compatibility) +{ + int retval = 0; + + switch(compatibility) + { + case PDC_1_3: + retval = cmapinfo->supplement13; + break; + + case PDC_1_4: + retval = cmapinfo->supplement14; + break; + + case PDC_1_5: + retval = cmapinfo->supplement15; + break; + + default: + case PDC_1_6: + retval = cmapinfo->supplement16; + break; + } + + return retval; +} + +/* + * See: + * Adobe Technical Note #5078 (Japanese1) + * Adobe Technical Note #5079 (GB1) + * Adobe Technical Note #5080 (CNS1) + * Adobe Technical Note #5093 (Korea1) + * + */ + +int +fnt_get_maxcid(int charcoll, int supplement) +{ + switch(charcoll) + { + case cc_japanese: + switch(supplement) + { + case 0: + return 8283; + + case 1: + return 8358; + + case 2: + return 8719; + + case 3: + return 9353; + + case 4: + return 15443; + + case 5: + return 20316; + + case 6: + default: + return 23057; + } + + case cc_simplified_chinese: + switch(supplement) + { + case 0: + return 7716; + + case 1: + return 9896; + + case 2: + return 22126; + + case 3: + return 22352; + + case 4: + default: + return 29063; + } + + case cc_traditional_chinese: + switch(supplement) + { + case 0: + return 14098; + + case 1: + return 17407; + + case 2: + return 17600; + + case 3: + return 18845; + + case 4: + default: + return 18964; + } + + case cc_korean: + switch(supplement) + { + case 0: + return 9332; + + case 1: + return 18154; + + case 2: + default: + return 18351; + } + + case cc_identity: + case cc_unknown: + return FNT_MAXCID; + + default: + return 0; + } +} + diff --git a/src/pdflib/font/ft_cid.h b/src/pdflib/font/ft_cid.h new file mode 100644 index 0000000..12187cb --- /dev/null +++ b/src/pdflib/font/ft_cid.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_cid.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * CID data structures + * + */ + +#ifndef FT_CID_H +#define FT_CID_H + +typedef struct fnt_cmap_s fnt_cmap; +typedef struct fnt_cmap_info_s fnt_cmap_info; +typedef struct fnt_cmap_stack_s fnt_cmap_stack; + +#define FNT_MAXCID 30000 /* actual maximal CID */ + +#define FNT_CIDMETRIC_INCR 5 /* increment of table fnt_cid_width_arrays */ + +#define FNT_MAX_ILLBYTES 8 /* maximal number of illegal bytes */ + + +/* Predefined CMap info */ +struct fnt_cmap_info_s +{ + const char *name; /* CMap name */ + int charcoll; /* character collection */ + short codesize; /* =0: not UTF-16, =2: UTF-16, -2: HW UTF-16 */ + short compatibility; /* PDF version */ + short supplement13; /* supplement for PDF 1.3 */ + short supplement14; /* supplement for PDF 1.4 */ + short supplement15; /* supplement for PDF 1.5 */ + short supplement16; /* supplement for PDF 1.6 */ + short vertical; /* =1: vertical, =0: horizontal */ +}; + +/* internal CMap types */ +typedef enum +{ + cmap_code2cid, + cmap_cid2unicode, + cmap_code2unicode +} +fnt_cmaptype; + +int fnt_get_predefined_cmap_info(const char *cmapname, fnt_cmap_info *cmapinfo); +const char *fnt_get_ordering_cid(int charcoll); +int fnt_get_maxcid(int charcoll, int supplement); +int fnt_get_charcoll(const char *ordering); +int fnt_get_supplement(fnt_cmap_info *cmapinfo, int compatibility); + + +#endif /* FT_CID_H */ diff --git a/src/pdflib/font/ft_corefont.c b/src/pdflib/font/ft_corefont.c new file mode 100644 index 0000000..b368f67 --- /dev/null +++ b/src/pdflib/font/ft_corefont.c @@ -0,0 +1,411 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_corefont.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT in-core and basic font metric functions + * + */ + +#define FT_COREFONT_C + +#include "ft_font.h" +#include "ft_corefont.h" + + +/* ------------------------------ core fonts ------------------------------ */ + +/* PDF basic font names */ +static const char *fnt_base14_names[] = +{ + "Courier", + "Courier-Bold", + "Courier-Oblique", + "Courier-BoldOblique", + "Helvetica", + "Helvetica-Bold", + "Helvetica-Oblique", + "Helvetica-BoldOblique", + "Symbol", + "Times-Roman", + "Times-Bold", + "Times-Italic", + "Times-BoldItalic", + "ZapfDingbats" +}; + +pdc_bool +fnt_is_standard_font(const char *fontname) +{ + int slot; + + for (slot = 0; + slot < (int)(sizeof(fnt_base14_names) / sizeof(fnt_base14_names[0])); + slot++) + { + if (!strcmp(fnt_base14_names[slot], fontname)) + return pdc_true; + } + + return pdc_false; +} + +/* abbreviations of PDF basic font names for form fields */ +static const char *fnt_abb_base14_names[] = +{ + "Cour", + "CoBo", + "CoOb", + "CoBO", + "Helv", + "HeBo", + "HeOb", + "HeBO", + "Symb", + "TiRo", + "TiBo", + "TiIt", + "TiBI", + "ZaDb" +}; + +const char * +fnt_get_abb_std_fontname(const char *fontname) +{ + int slot; + + for (slot = 0; + slot < (int)(sizeof(fnt_base14_names) / sizeof(fnt_base14_names[0])); + slot++) + { + if (!strcmp(fnt_base14_names[slot], fontname)) + return fnt_abb_base14_names[slot]; + } + + return NULL; +} + + +/* Basic fonts core metrics */ +static const fnt_font_metric *fnt_base_font_metrics[] = +{ + &fnt_font_metric_01, + &fnt_font_metric_02, + &fnt_font_metric_03, + &fnt_font_metric_04, + &fnt_font_metric_05, + &fnt_font_metric_06, + &fnt_font_metric_07, + &fnt_font_metric_08, + &fnt_font_metric_09, + &fnt_font_metric_10, + &fnt_font_metric_11, + &fnt_font_metric_12, + &fnt_font_metric_13, + &fnt_font_metric_14 +}; + +const fnt_font_metric * +fnt_get_core_metric(const char *fontname) +{ +#ifdef PDF_BUILTINMETRIC_SUPPORTED + const fnt_font_metric *metric = NULL; + int slot; + + for (slot = 0; + slot < (int)(sizeof(fnt_base_font_metrics) / + sizeof(fnt_base_font_metrics[0])); + slot++) + { + metric = fnt_base_font_metrics[slot]; + if (!strcmp(metric->name, fontname)) + return metric; + } +#endif /* PDF_BUILTINMETRIC_SUPPORTED */ + return(NULL); +} + + +/* --------------------- Pre-installed CID fonts ---------------------- */ + +int +fnt_get_preinstalled_cidfont(const char *fontname, + const fnt_font_metric **fontmetric) +{ + int slot; + + for (slot = 0; slot < FNT_NUM_OF_CIDFONTS; slot++) + { + if (!strcmp(fnt_cid_metrics[slot].name, fontname)) + { + if (fontmetric) + *fontmetric = &fnt_cid_metrics[slot]; + return fnt_cid_metrics[slot].charcoll; + } + } + + if (fontmetric) + *fontmetric = NULL; + + return (int) cc_none; +} + +/* abbreviations of PDF basic CJK font names for form fields */ +static const char *fnt_abb_cjk_names[] = +{ + "KaGo", + "KaMi", + "HyGo", + "HySm", + "MHei", + "MSun", + "STSo", +}; + +const char * +fnt_get_abb_cjk_fontname(const char *fontname) +{ + int slot; + + for (slot = 0; + slot < (int)(sizeof(fnt_abb_cjk_names) / sizeof(fnt_abb_cjk_names[0])); + slot++) + { + if (!strcmp(fnt_cid_metrics[slot].name, fontname)) + return fnt_abb_cjk_names[slot]; + } + + return NULL; +} + +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED + +const char ** +fnt_get_cid_widths_array(pdc_core *pdc, fnt_font *font) +{ + int slot, slotm; + + (void) pdc; + + /* search for font name */ + slotm = 100; + for (slot = 0; slot < slotm; slot += FNT_CIDMETRIC_INCR) + { + if (!strcmp(fnt_cid_width_arrays[slot], font->name)) + break; + } + + return &fnt_cid_width_arrays[slot + 1]; /* skip font name */ +} + +static void +fnt_parse_cid_widths(pdc_core *pdc, fnt_font *font) +{ + static const char fn[] = "fnt_parse_cid_widths"; + int slot, slota, slotm; + const char *chunk; + char **strlist = NULL, **sstrlist = NULL, *str; + int cid = 0, cidfirst, cidlast, width; + int il, is, ns, nss = 0; + int wformat = 2; + + /* search for font name */ + slotm = 100; + for (slot = 0; slot < slotm; slot += FNT_CIDMETRIC_INCR) + { + if (!strcmp(fnt_cid_width_arrays[slot], font->name)) + break; + } + if (slot == slotm) + return; + + /* we take the maximum */ + font->m.numwidths = fnt_get_maxcid(font->m.charcoll, -1) + 1; + font->m.widths = (int *) pdc_malloc(pdc, + font->m.numwidths * sizeof(int), fn); + + slota = slot + 1; /* skip font name */ + slotm = slot + FNT_CIDMETRIC_INCR; + for (slot = slota; slot < slotm; slot++) + { + chunk = fnt_cid_width_arrays[slot]; + + ns = pdc_split_stringlist(pdc, chunk, " \n", 0, &strlist); + for (is = 0; is < ns; is++) + { + str = strlist[is]; + + /* check for next format 1 chunk */ + if (wformat == 2 && strchr(str, '[')) + { + nss = pdc_split_stringlist(pdc, str, " [", 0, &sstrlist); + str = sstrlist[0]; + pdc_str2integer(str, 0, &cidfirst); + for (; cid < cidfirst; cid++) + font->m.widths[cid] = FNT_DEFAULT_CIDWIDTH; + str = sstrlist[1]; + wformat = 1; + } + + /* format 1: cid [width_1 width_2 ... width_n] */ + if (wformat == 1) + { + il = (int) strlen(str) - 1; + if (str[il] == ']') + { + str[il] = 0; + wformat = 2; + } + + pdc_str2integer(str, 0, &font->m.widths[cid]); + cid++; + + if (nss) + { + pdc_cleanup_stringlist(pdc, sstrlist); + nss = 0; + } + } + else + { + /* format 2: cid_first cid_last width */ + pdc_str2integer(str, 0, &cidfirst); + is++; + str = strlist[is]; + pdc_str2integer(str, 0, &cidlast); + is++; + str = strlist[is]; + pdc_str2integer(str, 0, &width); + + for (; cid < cidfirst; cid++) + font->m.widths[cid] = FNT_DEFAULT_CIDWIDTH; + for (; cid <= cidlast; cid++) + font->m.widths[cid] = width; + } + } + + pdc_cleanup_stringlist(pdc, strlist); + } + + for (; cid < font->m.numwidths; cid++) + font->m.widths[cid] = FNT_DEFAULT_CIDWIDTH; + + if (pdc_logg_is_enabled(pdc, 5, trc_font)) + { + for (cid = 0; cid < font->m.numwidths; cid++) + pdc_logg(pdc, "\t\t\tCID width[%d]: %d\n", + cid, font->m.widths[cid]); + } +} + +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ + + +/* ------------------------- general functions -------------------------- */ + +/* + * Fill font metric struct from core metric struct + */ +void +fnt_fill_font_metric(pdc_core *pdc, fnt_font *font, pdc_bool kerning, + const fnt_font_metric *metric) +{ + static const char fn[] = "fnt_fill_font_metric"; + + (void) kerning; + + /* Fill font metric struct. Font struct must be initialized */ + font->m = *metric; + font->m.charcoll = abs(font->m.charcoll); + font->m.name = pdc_strdup(pdc, metric->name); + font->name = pdc_strdup(pdc, metric->name); + + /* Fill glyph widths array (double mapping Unicode <-> code <-> width) */ + if (font->m.numglwidths) + { + font->m.glw = (fnt_glyphwidth *) pdc_calloc(pdc, + metric->numglwidths * sizeof(fnt_glyphwidth), fn); + memcpy(font->m.glw, metric->glw, + metric->numglwidths * sizeof(fnt_glyphwidth)); + } + + /* Fill glyph width array (mapping Unicode interval <-> width) */ + if (metric->numinters) + { + /* We must convert */ + if (font->m.type == fnt_Type1) + { + int i, j, iw, iwe; + pdc_ushort uv; + + for (i = 0; i < metric->numinters; i++) + { + if (i && metric->ciw[i-1].width != 0) + font->m.numglwidths += metric->ciw[i].startcode - + metric->ciw[i-1].startcode; + } + font->m.glw = (fnt_glyphwidth *) pdc_calloc(pdc, + font->m.numglwidths * sizeof(fnt_glyphwidth), fn); + + j = 0; + iw = 0; + for (i = 0; i < metric->numinters; i++) + { + if (i && metric->ciw[j].width != 0) + { + uv = metric->ciw[j].startcode; + iwe = iw + metric->ciw[i].startcode - uv; + for (; iw < iwe; iw++) + { + font->m.glw[iw].unicode = uv; + font->m.glw[iw].width = metric->ciw[j].width; + uv++; + } + } + j = i; + } + font->m.numinters = 0; + font->m.ciw = NULL; + } + else + { + font->m.ciw = (fnt_interwidth *) pdc_calloc(pdc, + font->m.numinters * sizeof(fnt_interwidth), fn); + memcpy(font->m.ciw, metric->ciw, + metric->numinters * sizeof(fnt_interwidth)); + } + } + +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED + /* Fill glyph width array (mapping CID -> width) */ + if (font->m.type == fnt_CIDFontType0) + fnt_parse_cid_widths(pdc, font); +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ + + /* Number of glyphs */ + if (font->m.type == fnt_Type1) + font->numglyphs = font->m.numglwidths; + + + /* font weight */ + font->weight = fnt_stemv2weight(font->m.StdVW); + + /* standard Adobe font */ + font->isstdfont = pdc_true; + + /* symbol font */ + if (!(font->m.flags & FNT_SYMBOL)) + font->issymbfont = pdc_false; +} + + + diff --git a/src/pdflib/font/ft_corefont.h b/src/pdflib/font/ft_corefont.h new file mode 100644 index 0000000..526212e --- /dev/null +++ b/src/pdflib/font/ft_corefont.h @@ -0,0 +1,2642 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_corefont.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * This file contains the metric for the base and + * pre-installed CID fonts of PDF + * + * ft_corefont.h is included only in ft_corefont.c. + * + */ + +#ifndef FT_COREMETR_H +#define FT_COREMETR_H + +#ifdef PDF_BUILTINMETRIC_SUPPORTED + +/* -------- Generated from CourierStd.otf -------- */ + +static fnt_interwidth fnt_glyph_width_01[203] = +{ + {0x0000, 600}, {0x0001, 0}, {0x0020, 600}, {0x007F, 0}, + {0x00A0, 600}, {0x0100, 0}, {0x0111, 600}, {0x0112, 0}, + {0x0126, 600}, {0x0128, 0}, {0x0131, 600}, {0x0134, 0}, + {0x0138, 600}, {0x0139, 0}, {0x013F, 600}, {0x0143, 0}, + {0x0149, 600}, {0x014C, 0}, {0x0152, 600}, {0x0154, 0}, + {0x0160, 600}, {0x0162, 0}, {0x0166, 600}, {0x0168, 0}, + {0x0178, 600}, {0x0179, 0}, {0x017D, 600}, {0x017F, 0}, + {0x0192, 600}, {0x0193, 0}, {0x02C6, 600}, {0x02C8, 0}, + {0x02C9, 600}, {0x02CA, 0}, {0x02D8, 600}, {0x02DE, 0}, + {0x0393, 600}, {0x0394, 0}, {0x0398, 600}, {0x0399, 0}, + {0x03A6, 600}, {0x03A7, 0}, {0x03A9, 600}, {0x03AA, 0}, + {0x03B1, 600}, {0x03B2, 0}, {0x03B4, 600}, {0x03B6, 0}, + {0x03BC, 600}, {0x03BD, 0}, {0x03C0, 600}, {0x03C1, 0}, + {0x03C3, 600}, {0x03C5, 0}, {0x03D5, 600}, {0x03D6, 0}, + {0x2013, 600}, {0x2015, 0}, {0x2017, 600}, {0x201F, 0}, + {0x2020, 600}, {0x2023, 0}, {0x2026, 600}, {0x2027, 0}, + {0x2030, 600}, {0x2031, 0}, {0x2039, 600}, {0x203B, 0}, + {0x203C, 600}, {0x203D, 0}, {0x203E, 600}, {0x203F, 0}, + {0x2044, 600}, {0x2045, 0}, {0x207F, 600}, {0x2080, 0}, + {0x20A3, 600}, {0x20A4, 0}, {0x20A7, 600}, {0x20A8, 0}, + {0x20AC, 600}, {0x20AD, 0}, {0x2113, 600}, {0x2114, 0}, + {0x2122, 600}, {0x2123, 0}, {0x2126, 600}, {0x2127, 0}, + {0x212E, 600}, {0x212F, 0}, {0x215B, 600}, {0x215F, 0}, + {0x2190, 600}, {0x2196, 0}, {0x21A8, 600}, {0x21A9, 0}, + {0x2202, 600}, {0x2203, 0}, {0x2206, 600}, {0x2207, 0}, + {0x220F, 600}, {0x2210, 0}, {0x2211, 600}, {0x2213, 0}, + {0x2215, 600}, {0x2216, 0}, {0x2219, 600}, {0x221B, 0}, + {0x221E, 600}, {0x221F, 0}, {0x2229, 600}, {0x222A, 0}, + {0x222B, 600}, {0x222C, 0}, {0x2248, 600}, {0x2249, 0}, + {0x2260, 600}, {0x2262, 0}, {0x2264, 600}, {0x2266, 0}, + {0x22C5, 600}, {0x22C6, 0}, {0x2302, 600}, {0x2303, 0}, + {0x2304, 600}, {0x2305, 0}, {0x2310, 600}, {0x2311, 0}, + {0x2319, 600}, {0x231A, 0}, {0x2320, 600}, {0x2322, 0}, + {0x2500, 600}, {0x2501, 0}, {0x2502, 600}, {0x2503, 0}, + {0x250C, 600}, {0x250D, 0}, {0x2510, 600}, {0x2511, 0}, + {0x2514, 600}, {0x2515, 0}, {0x2518, 600}, {0x2519, 0}, + {0x251C, 600}, {0x251D, 0}, {0x2524, 600}, {0x2525, 0}, + {0x252C, 600}, {0x252D, 0}, {0x2534, 600}, {0x2535, 0}, + {0x253C, 600}, {0x253D, 0}, {0x2550, 600}, {0x256D, 0}, + {0x2580, 600}, {0x2581, 0}, {0x2584, 600}, {0x2585, 0}, + {0x2588, 600}, {0x2589, 0}, {0x258C, 600}, {0x258D, 0}, + {0x2590, 600}, {0x2594, 0}, {0x25A0, 600}, {0x25A1, 0}, + {0x25B2, 600}, {0x25B3, 0}, {0x25B6, 600}, {0x25B7, 0}, + {0x25BC, 600}, {0x25BD, 0}, {0x25C0, 600}, {0x25C1, 0}, + {0x25CA, 600}, {0x25CC, 0}, {0x25D8, 600}, {0x25DA, 0}, + {0x263A, 600}, {0x263D, 0}, {0x2640, 600}, {0x2641, 0}, + {0x2642, 600}, {0x2643, 0}, {0x2660, 600}, {0x2661, 0}, + {0x2662, 600}, {0x2664, 0}, {0x2665, 600}, {0x2667, 0}, + {0x266A, 600}, {0x266B, 0}, {0x266C, 600}, {0x266D, 0}, + {0xE000, 600}, {0xE002, 0}, {0xF638, 600}, {0xF639, 0}, + {0xFB01, 600}, {0xFB03, 0}, {0xFFFF, 0} +}; + +static const fnt_font_metric fnt_font_metric_01 = +{ + "Courier", + 35L, + fnt_Type1, + cc_none, + 0, + 1, + -56, + -250, + 678, + 857, + -198, + 52, + 573, + 435, + 627, + -373, + 109, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 203, + fnt_glyph_width_01, + 0, + NULL, + +}; + +/* -------- Generated from CourierStd-Bold.otf -------- */ + +static fnt_interwidth fnt_glyph_width_02[203] = +{ + {0x0000, 600}, {0x0001, 0}, {0x0020, 600}, {0x007F, 0}, + {0x00A0, 600}, {0x0100, 0}, {0x0111, 600}, {0x0112, 0}, + {0x0126, 600}, {0x0128, 0}, {0x0131, 600}, {0x0134, 0}, + {0x0138, 600}, {0x0139, 0}, {0x013F, 600}, {0x0143, 0}, + {0x0149, 600}, {0x014C, 0}, {0x0152, 600}, {0x0154, 0}, + {0x0160, 600}, {0x0162, 0}, {0x0166, 600}, {0x0168, 0}, + {0x0178, 600}, {0x0179, 0}, {0x017D, 600}, {0x017F, 0}, + {0x0192, 600}, {0x0193, 0}, {0x02C6, 600}, {0x02C8, 0}, + {0x02C9, 600}, {0x02CA, 0}, {0x02D8, 600}, {0x02DE, 0}, + {0x0393, 600}, {0x0394, 0}, {0x0398, 600}, {0x0399, 0}, + {0x03A6, 600}, {0x03A7, 0}, {0x03A9, 600}, {0x03AA, 0}, + {0x03B1, 600}, {0x03B2, 0}, {0x03B4, 600}, {0x03B6, 0}, + {0x03BC, 600}, {0x03BD, 0}, {0x03C0, 600}, {0x03C1, 0}, + {0x03C3, 600}, {0x03C5, 0}, {0x03D5, 600}, {0x03D6, 0}, + {0x2013, 600}, {0x2015, 0}, {0x2017, 600}, {0x201F, 0}, + {0x2020, 600}, {0x2023, 0}, {0x2026, 600}, {0x2027, 0}, + {0x2030, 600}, {0x2031, 0}, {0x2039, 600}, {0x203B, 0}, + {0x203C, 600}, {0x203D, 0}, {0x203E, 600}, {0x203F, 0}, + {0x2044, 600}, {0x2045, 0}, {0x207F, 600}, {0x2080, 0}, + {0x20A3, 600}, {0x20A4, 0}, {0x20A7, 600}, {0x20A8, 0}, + {0x20AC, 600}, {0x20AD, 0}, {0x2113, 600}, {0x2114, 0}, + {0x2122, 600}, {0x2123, 0}, {0x2126, 600}, {0x2127, 0}, + {0x212E, 600}, {0x212F, 0}, {0x215B, 600}, {0x215F, 0}, + {0x2190, 600}, {0x2196, 0}, {0x21A8, 600}, {0x21A9, 0}, + {0x2202, 600}, {0x2203, 0}, {0x2206, 600}, {0x2207, 0}, + {0x220F, 600}, {0x2210, 0}, {0x2211, 600}, {0x2213, 0}, + {0x2215, 600}, {0x2216, 0}, {0x2219, 600}, {0x221B, 0}, + {0x221E, 600}, {0x221F, 0}, {0x2229, 600}, {0x222A, 0}, + {0x222B, 600}, {0x222C, 0}, {0x2248, 600}, {0x2249, 0}, + {0x2260, 600}, {0x2262, 0}, {0x2264, 600}, {0x2266, 0}, + {0x22C5, 600}, {0x22C6, 0}, {0x2302, 600}, {0x2303, 0}, + {0x2304, 600}, {0x2305, 0}, {0x2310, 600}, {0x2311, 0}, + {0x2319, 600}, {0x231A, 0}, {0x2320, 600}, {0x2322, 0}, + {0x2500, 600}, {0x2501, 0}, {0x2502, 600}, {0x2503, 0}, + {0x250C, 600}, {0x250D, 0}, {0x2510, 600}, {0x2511, 0}, + {0x2514, 600}, {0x2515, 0}, {0x2518, 600}, {0x2519, 0}, + {0x251C, 600}, {0x251D, 0}, {0x2524, 600}, {0x2525, 0}, + {0x252C, 600}, {0x252D, 0}, {0x2534, 600}, {0x2535, 0}, + {0x253C, 600}, {0x253D, 0}, {0x2550, 600}, {0x256D, 0}, + {0x2580, 600}, {0x2581, 0}, {0x2584, 600}, {0x2585, 0}, + {0x2588, 600}, {0x2589, 0}, {0x258C, 600}, {0x258D, 0}, + {0x2590, 600}, {0x2594, 0}, {0x25A0, 600}, {0x25A1, 0}, + {0x25B2, 600}, {0x25B3, 0}, {0x25B6, 600}, {0x25B7, 0}, + {0x25BC, 600}, {0x25BD, 0}, {0x25C0, 600}, {0x25C1, 0}, + {0x25CA, 600}, {0x25CC, 0}, {0x25D8, 600}, {0x25DA, 0}, + {0x263A, 600}, {0x263D, 0}, {0x2640, 600}, {0x2641, 0}, + {0x2642, 600}, {0x2643, 0}, {0x2660, 600}, {0x2661, 0}, + {0x2662, 600}, {0x2664, 0}, {0x2665, 600}, {0x2667, 0}, + {0x266A, 600}, {0x266B, 0}, {0x266C, 600}, {0x266D, 0}, + {0xE000, 600}, {0xE002, 0}, {0xF638, 600}, {0xF639, 0}, + {0xFB01, 600}, {0xFB03, 0}, {0xFFFF, 0} +}; + +static const fnt_font_metric fnt_font_metric_02 = +{ + "Courier-Bold", + 262179L, + fnt_Type1, + cc_none, + 0, + 1, + -88, + -250, + 697, + 854, + -198, + 52, + 573, + 435, + 627, + -373, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 203, + fnt_glyph_width_02, + 0, + NULL, + +}; + +/* -------- Generated from CourierStd-Oblique.otf -------- */ + +static fnt_interwidth fnt_glyph_width_03[203] = +{ + {0x0000, 600}, {0x0001, 0}, {0x0020, 600}, {0x007F, 0}, + {0x00A0, 600}, {0x0100, 0}, {0x0111, 600}, {0x0112, 0}, + {0x0126, 600}, {0x0128, 0}, {0x0131, 600}, {0x0134, 0}, + {0x0138, 600}, {0x0139, 0}, {0x013F, 600}, {0x0143, 0}, + {0x0149, 600}, {0x014C, 0}, {0x0152, 600}, {0x0154, 0}, + {0x0160, 600}, {0x0162, 0}, {0x0166, 600}, {0x0168, 0}, + {0x0178, 600}, {0x0179, 0}, {0x017D, 600}, {0x017F, 0}, + {0x0192, 600}, {0x0193, 0}, {0x02C6, 600}, {0x02C8, 0}, + {0x02C9, 600}, {0x02CA, 0}, {0x02D8, 600}, {0x02DE, 0}, + {0x0393, 600}, {0x0394, 0}, {0x0398, 600}, {0x0399, 0}, + {0x03A6, 600}, {0x03A7, 0}, {0x03A9, 600}, {0x03AA, 0}, + {0x03B1, 600}, {0x03B2, 0}, {0x03B4, 600}, {0x03B6, 0}, + {0x03BC, 600}, {0x03BD, 0}, {0x03C0, 600}, {0x03C1, 0}, + {0x03C3, 600}, {0x03C5, 0}, {0x03D5, 600}, {0x03D6, 0}, + {0x2013, 600}, {0x2015, 0}, {0x2017, 600}, {0x201F, 0}, + {0x2020, 600}, {0x2023, 0}, {0x2026, 600}, {0x2027, 0}, + {0x2030, 600}, {0x2031, 0}, {0x2039, 600}, {0x203B, 0}, + {0x203C, 600}, {0x203D, 0}, {0x203E, 600}, {0x203F, 0}, + {0x2044, 600}, {0x2045, 0}, {0x207F, 600}, {0x2080, 0}, + {0x20A3, 600}, {0x20A4, 0}, {0x20A7, 600}, {0x20A8, 0}, + {0x20AC, 600}, {0x20AD, 0}, {0x2113, 600}, {0x2114, 0}, + {0x2122, 600}, {0x2123, 0}, {0x2126, 600}, {0x2127, 0}, + {0x212E, 600}, {0x212F, 0}, {0x215B, 600}, {0x215F, 0}, + {0x2190, 600}, {0x2196, 0}, {0x21A8, 600}, {0x21A9, 0}, + {0x2202, 600}, {0x2203, 0}, {0x2206, 600}, {0x2207, 0}, + {0x220F, 600}, {0x2210, 0}, {0x2211, 600}, {0x2213, 0}, + {0x2215, 600}, {0x2216, 0}, {0x2219, 600}, {0x221B, 0}, + {0x221E, 600}, {0x221F, 0}, {0x2229, 600}, {0x222A, 0}, + {0x222B, 600}, {0x222C, 0}, {0x2248, 600}, {0x2249, 0}, + {0x2260, 600}, {0x2262, 0}, {0x2264, 600}, {0x2266, 0}, + {0x22C5, 600}, {0x22C6, 0}, {0x2302, 600}, {0x2303, 0}, + {0x2304, 600}, {0x2305, 0}, {0x2310, 600}, {0x2311, 0}, + {0x2319, 600}, {0x231A, 0}, {0x2320, 600}, {0x2322, 0}, + {0x2500, 600}, {0x2501, 0}, {0x2502, 600}, {0x2503, 0}, + {0x250C, 600}, {0x250D, 0}, {0x2510, 600}, {0x2511, 0}, + {0x2514, 600}, {0x2515, 0}, {0x2518, 600}, {0x2519, 0}, + {0x251C, 600}, {0x251D, 0}, {0x2524, 600}, {0x2525, 0}, + {0x252C, 600}, {0x252D, 0}, {0x2534, 600}, {0x2535, 0}, + {0x253C, 600}, {0x253D, 0}, {0x2550, 600}, {0x256D, 0}, + {0x2580, 600}, {0x2581, 0}, {0x2584, 600}, {0x2585, 0}, + {0x2588, 600}, {0x2589, 0}, {0x258C, 600}, {0x258D, 0}, + {0x2590, 600}, {0x2594, 0}, {0x25A0, 600}, {0x25A1, 0}, + {0x25B2, 600}, {0x25B3, 0}, {0x25B6, 600}, {0x25B7, 0}, + {0x25BC, 600}, {0x25BD, 0}, {0x25C0, 600}, {0x25C1, 0}, + {0x25CA, 600}, {0x25CC, 0}, {0x25D8, 600}, {0x25DA, 0}, + {0x263A, 600}, {0x263D, 0}, {0x2640, 600}, {0x2641, 0}, + {0x2642, 600}, {0x2643, 0}, {0x2660, 600}, {0x2661, 0}, + {0x2662, 600}, {0x2664, 0}, {0x2665, 600}, {0x2667, 0}, + {0x266A, 600}, {0x266B, 0}, {0x266C, 600}, {0x266D, 0}, + {0xE000, 600}, {0xE002, 0}, {0xF638, 600}, {0xF639, 0}, + {0xFB01, 600}, {0xFB03, 0}, {0xFFFF, 0} +}; + +static const fnt_font_metric fnt_font_metric_03 = +{ + "Courier-Oblique", + 99L, + fnt_Type1, + cc_none, + -11, + 1, + -48, + -250, + 748, + 857, + -198, + 52, + 573, + 435, + 627, + -373, + 109, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 203, + fnt_glyph_width_03, + 0, + NULL, + +}; + +/* -------- Generated from CourierStd-BoldOblique.otf -------- */ + +static fnt_interwidth fnt_glyph_width_04[203] = +{ + {0x0000, 600}, {0x0001, 0}, {0x0020, 600}, {0x007F, 0}, + {0x00A0, 600}, {0x0100, 0}, {0x0111, 600}, {0x0112, 0}, + {0x0126, 600}, {0x0128, 0}, {0x0131, 600}, {0x0134, 0}, + {0x0138, 600}, {0x0139, 0}, {0x013F, 600}, {0x0143, 0}, + {0x0149, 600}, {0x014C, 0}, {0x0152, 600}, {0x0154, 0}, + {0x0160, 600}, {0x0162, 0}, {0x0166, 600}, {0x0168, 0}, + {0x0178, 600}, {0x0179, 0}, {0x017D, 600}, {0x017F, 0}, + {0x0192, 600}, {0x0193, 0}, {0x02C6, 600}, {0x02C8, 0}, + {0x02C9, 600}, {0x02CA, 0}, {0x02D8, 600}, {0x02DE, 0}, + {0x0393, 600}, {0x0394, 0}, {0x0398, 600}, {0x0399, 0}, + {0x03A6, 600}, {0x03A7, 0}, {0x03A9, 600}, {0x03AA, 0}, + {0x03B1, 600}, {0x03B2, 0}, {0x03B4, 600}, {0x03B6, 0}, + {0x03BC, 600}, {0x03BD, 0}, {0x03C0, 600}, {0x03C1, 0}, + {0x03C3, 600}, {0x03C5, 0}, {0x03D5, 600}, {0x03D6, 0}, + {0x2013, 600}, {0x2015, 0}, {0x2017, 600}, {0x201F, 0}, + {0x2020, 600}, {0x2023, 0}, {0x2026, 600}, {0x2027, 0}, + {0x2030, 600}, {0x2031, 0}, {0x2039, 600}, {0x203B, 0}, + {0x203C, 600}, {0x203D, 0}, {0x203E, 600}, {0x203F, 0}, + {0x2044, 600}, {0x2045, 0}, {0x207F, 600}, {0x2080, 0}, + {0x20A3, 600}, {0x20A4, 0}, {0x20A7, 600}, {0x20A8, 0}, + {0x20AC, 600}, {0x20AD, 0}, {0x2113, 600}, {0x2114, 0}, + {0x2122, 600}, {0x2123, 0}, {0x2126, 600}, {0x2127, 0}, + {0x212E, 600}, {0x212F, 0}, {0x215B, 600}, {0x215F, 0}, + {0x2190, 600}, {0x2196, 0}, {0x21A8, 600}, {0x21A9, 0}, + {0x2202, 600}, {0x2203, 0}, {0x2206, 600}, {0x2207, 0}, + {0x220F, 600}, {0x2210, 0}, {0x2211, 600}, {0x2213, 0}, + {0x2215, 600}, {0x2216, 0}, {0x2219, 600}, {0x221B, 0}, + {0x221E, 600}, {0x221F, 0}, {0x2229, 600}, {0x222A, 0}, + {0x222B, 600}, {0x222C, 0}, {0x2248, 600}, {0x2249, 0}, + {0x2260, 600}, {0x2262, 0}, {0x2264, 600}, {0x2266, 0}, + {0x22C5, 600}, {0x22C6, 0}, {0x2302, 600}, {0x2303, 0}, + {0x2304, 600}, {0x2305, 0}, {0x2310, 600}, {0x2311, 0}, + {0x2319, 600}, {0x231A, 0}, {0x2320, 600}, {0x2322, 0}, + {0x2500, 600}, {0x2501, 0}, {0x2502, 600}, {0x2503, 0}, + {0x250C, 600}, {0x250D, 0}, {0x2510, 600}, {0x2511, 0}, + {0x2514, 600}, {0x2515, 0}, {0x2518, 600}, {0x2519, 0}, + {0x251C, 600}, {0x251D, 0}, {0x2524, 600}, {0x2525, 0}, + {0x252C, 600}, {0x252D, 0}, {0x2534, 600}, {0x2535, 0}, + {0x253C, 600}, {0x253D, 0}, {0x2550, 600}, {0x256D, 0}, + {0x2580, 600}, {0x2581, 0}, {0x2584, 600}, {0x2585, 0}, + {0x2588, 600}, {0x2589, 0}, {0x258C, 600}, {0x258D, 0}, + {0x2590, 600}, {0x2594, 0}, {0x25A0, 600}, {0x25A1, 0}, + {0x25B2, 600}, {0x25B3, 0}, {0x25B6, 600}, {0x25B7, 0}, + {0x25BC, 600}, {0x25BD, 0}, {0x25C0, 600}, {0x25C1, 0}, + {0x25CA, 600}, {0x25CC, 0}, {0x25D8, 600}, {0x25DA, 0}, + {0x263A, 600}, {0x263D, 0}, {0x2640, 600}, {0x2641, 0}, + {0x2642, 600}, {0x2643, 0}, {0x2660, 600}, {0x2661, 0}, + {0x2662, 600}, {0x2664, 0}, {0x2665, 600}, {0x2667, 0}, + {0x266A, 600}, {0x266B, 0}, {0x266C, 600}, {0x266D, 0}, + {0xE000, 600}, {0xE002, 0}, {0xF638, 600}, {0xF639, 0}, + {0xFB01, 600}, {0xFB03, 0}, {0xFFFF, 0} +}; + +static const fnt_font_metric fnt_font_metric_04 = +{ + "Courier-BoldOblique", + 262243L, + fnt_Type1, + cc_none, + -11, + 1, + -48, + -250, + 757, + 854, + -198, + 52, + 573, + 435, + 627, + -373, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 203, + fnt_glyph_width_04, + 0, + NULL, + +}; + +/* -------- Generated from ARIAL.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_05[268] = +{ + {0x0000, 0}, {0x0020, 278}, {0x0022, 355}, {0x0023, 556}, + {0x0025, 889}, {0x0026, 667}, {0x0027, 191}, {0x0028, 333}, + {0x002A, 389}, {0x002B, 584}, {0x002C, 278}, {0x002D, 333}, + {0x002E, 278}, {0x0030, 556}, {0x003A, 278}, {0x003C, 584}, + {0x003F, 556}, {0x0040,1015}, {0x0041, 667}, {0x0043, 722}, + {0x0045, 667}, {0x0046, 611}, {0x0047, 778}, {0x0048, 722}, + {0x0049, 278}, {0x004A, 500}, {0x004B, 667}, {0x004C, 556}, + {0x004D, 833}, {0x004E, 722}, {0x004F, 778}, {0x0050, 667}, + {0x0051, 778}, {0x0052, 722}, {0x0053, 667}, {0x0054, 611}, + {0x0055, 722}, {0x0056, 667}, {0x0057, 944}, {0x0058, 667}, + {0x005A, 611}, {0x005B, 278}, {0x005E, 469}, {0x005F, 556}, + {0x0060, 333}, {0x0061, 556}, {0x0063, 500}, {0x0064, 556}, + {0x0066, 278}, {0x0067, 556}, {0x0069, 222}, {0x006B, 500}, + {0x006C, 222}, {0x006D, 833}, {0x006E, 556}, {0x0072, 333}, + {0x0073, 500}, {0x0074, 278}, {0x0075, 556}, {0x0076, 500}, + {0x0077, 722}, {0x0078, 500}, {0x007B, 334}, {0x007C, 260}, + {0x007D, 334}, {0x007E, 584}, {0x007F, 0}, {0x00A0, 278}, + {0x00A1, 333}, {0x00A2, 556}, {0x00A6, 260}, {0x00A7, 556}, + {0x00A8, 333}, {0x00A9, 737}, {0x00AA, 370}, {0x00AB, 556}, + {0x00AC, 584}, {0x00AD, 333}, {0x00AE, 737}, {0x00AF, 552}, + {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 333}, {0x00B5, 576}, + {0x00B6, 537}, {0x00B7, 278}, {0x00B8, 333}, {0x00BA, 365}, + {0x00BB, 556}, {0x00BC, 834}, {0x00BF, 611}, {0x00C0, 667}, + {0x00C6,1000}, {0x00C7, 722}, {0x00C8, 667}, {0x00CC, 278}, + {0x00D0, 722}, {0x00D2, 778}, {0x00D7, 584}, {0x00D8, 778}, + {0x00D9, 722}, {0x00DD, 667}, {0x00DF, 611}, {0x00E0, 556}, + {0x00E6, 889}, {0x00E7, 500}, {0x00E8, 556}, {0x00EC, 278}, + {0x00F0, 556}, {0x00F7, 549}, {0x00F8, 611}, {0x00F9, 556}, + {0x00FD, 500}, {0x00FE, 556}, {0x00FF, 500}, {0x0100, 667}, + {0x0101, 556}, {0x0102, 667}, {0x0103, 556}, {0x0104, 667}, + {0x0105, 556}, {0x0106, 722}, {0x0107, 500}, {0x0108, 0}, + {0x010C, 722}, {0x010D, 500}, {0x010E, 722}, {0x010F, 615}, + {0x0110, 722}, {0x0111, 556}, {0x0112, 667}, {0x0113, 556}, + {0x0114, 0}, {0x0116, 667}, {0x0117, 556}, {0x0118, 667}, + {0x0119, 556}, {0x011A, 667}, {0x011B, 556}, {0x011C, 0}, + {0x011E, 778}, {0x011F, 556}, {0x0120, 0}, {0x0122, 778}, + {0x0123, 556}, {0x0124, 0}, {0x0128, 278}, {0x012C, 0}, + {0x012E, 278}, {0x012F, 222}, {0x0130, 278}, {0x0132, 0}, + {0x0136, 667}, {0x0137, 500}, {0x0139, 556}, {0x013A, 222}, + {0x013B, 556}, {0x013C, 222}, {0x013D, 556}, {0x013E, 292}, + {0x013F, 0}, {0x0141, 556}, {0x0142, 222}, {0x0143, 722}, + {0x0144, 556}, {0x0145, 722}, {0x0146, 556}, {0x0147, 722}, + {0x0148, 556}, {0x0149, 0}, {0x014A, 723}, {0x014B, 556}, + {0x014C, 778}, {0x014D, 556}, {0x014E, 0}, {0x0150, 778}, + {0x0151, 556}, {0x0152,1000}, {0x0153, 944}, {0x0154, 722}, + {0x0155, 333}, {0x0156, 722}, {0x0157, 333}, {0x0158, 722}, + {0x0159, 333}, {0x015A, 667}, {0x015B, 500}, {0x015C, 0}, + {0x015E, 667}, {0x015F, 500}, {0x0160, 667}, {0x0161, 500}, + {0x0162, 611}, {0x0163, 278}, {0x0164, 611}, {0x0165, 375}, + {0x0166, 611}, {0x0167, 278}, {0x0168, 722}, {0x0169, 556}, + {0x016A, 722}, {0x016B, 556}, {0x016C, 0}, {0x016E, 722}, + {0x016F, 556}, {0x0170, 722}, {0x0171, 556}, {0x0172, 722}, + {0x0173, 556}, {0x0174, 0}, {0x0178, 667}, {0x0179, 611}, + {0x017A, 500}, {0x017B, 611}, {0x017C, 500}, {0x017D, 611}, + {0x017E, 500}, {0x017F, 0}, {0x0192, 556}, {0x0193, 0}, + {0x0218, 750}, {0x021A, 611}, {0x021B, 278}, {0x021C, 0}, + {0x02C6, 333}, {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, + {0x02DB, 333}, {0x02DE, 0}, {0x2013, 556}, {0x2014,1000}, + {0x2016, 0}, {0x2018, 222}, {0x201B, 0}, {0x201C, 333}, + {0x201F, 0}, {0x2020, 556}, {0x2022, 350}, {0x2023, 0}, + {0x2026,1000}, {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, + {0x2039, 333}, {0x203B, 0}, {0x20AC, 556}, {0x20AD, 0}, + {0x2122,1000}, {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, + {0x2211, 713}, {0x2212, 584}, {0x2213, 0}, {0x221A, 549}, + {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, + {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 750}, + {0xF6C4, 0}, {0xFB01, 500}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_05 = +{ + "Helvetica", + 32L, + fnt_Type1, + cc_none, + 0, + 0, + -665, + -325, + 2028, + 1037, + -106, + 73, + 718, + 523, + 718, + -207, + 88, + 0, + FNT_DEFAULT_WIDTH, + 0, + NULL, + 268, + fnt_glyph_width_05, + 0, + NULL, + +}; + +/* -------- Generated from ARIALBD.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_06[269] = +{ + {0x0000, 0}, {0x0020, 278}, {0x0021, 333}, {0x0022, 474}, + {0x0023, 556}, {0x0025, 889}, {0x0026, 722}, {0x0027, 238}, + {0x0028, 333}, {0x002A, 389}, {0x002B, 584}, {0x002C, 278}, + {0x002D, 333}, {0x002E, 278}, {0x0030, 556}, {0x003A, 333}, + {0x003C, 584}, {0x003F, 611}, {0x0040, 975}, {0x0041, 722}, + {0x0045, 667}, {0x0046, 611}, {0x0047, 778}, {0x0048, 722}, + {0x0049, 278}, {0x004A, 556}, {0x004B, 722}, {0x004C, 611}, + {0x004D, 833}, {0x004E, 722}, {0x004F, 778}, {0x0050, 667}, + {0x0051, 778}, {0x0052, 722}, {0x0053, 667}, {0x0054, 611}, + {0x0055, 722}, {0x0056, 667}, {0x0057, 944}, {0x0058, 667}, + {0x005A, 611}, {0x005B, 333}, {0x005C, 278}, {0x005D, 333}, + {0x005E, 584}, {0x005F, 556}, {0x0060, 333}, {0x0061, 556}, + {0x0062, 611}, {0x0063, 556}, {0x0064, 611}, {0x0065, 556}, + {0x0066, 333}, {0x0067, 611}, {0x0069, 278}, {0x006B, 556}, + {0x006C, 278}, {0x006D, 889}, {0x006E, 611}, {0x0072, 389}, + {0x0073, 556}, {0x0074, 333}, {0x0075, 611}, {0x0076, 556}, + {0x0077, 778}, {0x0078, 556}, {0x007A, 500}, {0x007B, 389}, + {0x007C, 280}, {0x007D, 389}, {0x007E, 584}, {0x007F, 0}, + {0x00A0, 278}, {0x00A1, 333}, {0x00A2, 556}, {0x00A6, 280}, + {0x00A7, 556}, {0x00A8, 333}, {0x00A9, 737}, {0x00AA, 370}, + {0x00AB, 556}, {0x00AC, 584}, {0x00AD, 333}, {0x00AE, 737}, + {0x00AF, 552}, {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 333}, + {0x00B5, 576}, {0x00B6, 556}, {0x00B7, 278}, {0x00B8, 333}, + {0x00BA, 365}, {0x00BB, 556}, {0x00BC, 834}, {0x00BF, 611}, + {0x00C0, 722}, {0x00C6,1000}, {0x00C7, 722}, {0x00C8, 667}, + {0x00CC, 278}, {0x00D0, 722}, {0x00D2, 778}, {0x00D7, 584}, + {0x00D8, 778}, {0x00D9, 722}, {0x00DD, 667}, {0x00DF, 611}, + {0x00E0, 556}, {0x00E6, 889}, {0x00E7, 556}, {0x00EC, 278}, + {0x00F0, 611}, {0x00F7, 549}, {0x00F8, 611}, {0x00FD, 556}, + {0x00FE, 611}, {0x00FF, 556}, {0x0100, 722}, {0x0101, 556}, + {0x0102, 722}, {0x0103, 556}, {0x0104, 722}, {0x0105, 556}, + {0x0106, 722}, {0x0107, 556}, {0x0108, 0}, {0x010C, 722}, + {0x010D, 556}, {0x010E, 722}, {0x010F, 719}, {0x0110, 722}, + {0x0111, 611}, {0x0112, 667}, {0x0113, 556}, {0x0114, 0}, + {0x0116, 667}, {0x0117, 556}, {0x0118, 667}, {0x0119, 556}, + {0x011A, 667}, {0x011B, 556}, {0x011C, 0}, {0x011E, 778}, + {0x011F, 611}, {0x0120, 0}, {0x0122, 778}, {0x0123, 611}, + {0x0124, 0}, {0x0128, 278}, {0x012C, 0}, {0x012E, 278}, + {0x0132, 0}, {0x0136, 722}, {0x0137, 556}, {0x0139, 611}, + {0x013A, 278}, {0x013B, 611}, {0x013C, 278}, {0x013D, 611}, + {0x013E, 385}, {0x013F, 0}, {0x0141, 611}, {0x0142, 278}, + {0x0143, 722}, {0x0144, 611}, {0x0145, 722}, {0x0146, 611}, + {0x0147, 722}, {0x0148, 611}, {0x0149, 0}, {0x014A, 723}, + {0x014B, 611}, {0x014C, 778}, {0x014D, 611}, {0x014E, 0}, + {0x0150, 778}, {0x0151, 611}, {0x0152,1000}, {0x0153, 944}, + {0x0154, 722}, {0x0155, 389}, {0x0156, 722}, {0x0157, 389}, + {0x0158, 722}, {0x0159, 389}, {0x015A, 667}, {0x015B, 556}, + {0x015C, 0}, {0x015E, 667}, {0x015F, 556}, {0x0160, 667}, + {0x0161, 556}, {0x0162, 611}, {0x0163, 333}, {0x0164, 611}, + {0x0165, 479}, {0x0166, 611}, {0x0167, 333}, {0x0168, 722}, + {0x0169, 611}, {0x016A, 722}, {0x016B, 611}, {0x016C, 0}, + {0x016E, 722}, {0x016F, 611}, {0x0170, 722}, {0x0171, 611}, + {0x0172, 722}, {0x0173, 611}, {0x0174, 0}, {0x0178, 667}, + {0x0179, 611}, {0x017A, 500}, {0x017B, 611}, {0x017C, 500}, + {0x017D, 611}, {0x017E, 500}, {0x017F, 0}, {0x0192, 556}, + {0x0193, 0}, {0x0218, 750}, {0x021A, 611}, {0x021B, 333}, + {0x021C, 0}, {0x02C6, 333}, {0x02C8, 0}, {0x02D8, 333}, + {0x02DA, 0}, {0x02DB, 333}, {0x02DE, 0}, {0x2013, 556}, + {0x2014,1000}, {0x2016, 0}, {0x2018, 278}, {0x201B, 0}, + {0x201C, 500}, {0x201F, 0}, {0x2020, 556}, {0x2022, 350}, + {0x2023, 0}, {0x2026,1000}, {0x2027, 0}, {0x2030,1000}, + {0x2031, 0}, {0x2039, 333}, {0x203B, 0}, {0x20AC, 556}, + {0x20AD, 0}, {0x2122,1000}, {0x2123, 0}, {0x2202, 494}, + {0x2203, 0}, {0x2211, 713}, {0x2212, 584}, {0x2213, 0}, + {0x221A, 549}, {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, + {0x2264, 549}, {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, + {0xF6C3, 750}, {0xF6C4, 0}, {0xFB01, 611}, {0xFB03, 0}, + {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_06 = +{ + "Helvetica-Bold", + 262176L, + fnt_Type1, + cc_none, + 0, + 0, + -628, + -376, + 2000, + 1010, + -106, + 105, + 718, + 532, + 718, + -207, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 269, + fnt_glyph_width_06, + 0, + NULL, + +}; + +/* -------- Generated from ARIALI.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_07[268] = +{ + {0x0000, 0}, {0x0020, 278}, {0x0022, 355}, {0x0023, 556}, + {0x0025, 889}, {0x0026, 667}, {0x0027, 191}, {0x0028, 333}, + {0x002A, 389}, {0x002B, 584}, {0x002C, 278}, {0x002D, 333}, + {0x002E, 278}, {0x0030, 556}, {0x003A, 278}, {0x003C, 584}, + {0x003F, 556}, {0x0040,1015}, {0x0041, 667}, {0x0043, 722}, + {0x0045, 667}, {0x0046, 611}, {0x0047, 778}, {0x0048, 722}, + {0x0049, 278}, {0x004A, 500}, {0x004B, 667}, {0x004C, 556}, + {0x004D, 833}, {0x004E, 722}, {0x004F, 778}, {0x0050, 667}, + {0x0051, 778}, {0x0052, 722}, {0x0053, 667}, {0x0054, 611}, + {0x0055, 722}, {0x0056, 667}, {0x0057, 944}, {0x0058, 667}, + {0x005A, 611}, {0x005B, 278}, {0x005E, 469}, {0x005F, 556}, + {0x0060, 333}, {0x0061, 556}, {0x0063, 500}, {0x0064, 556}, + {0x0066, 278}, {0x0067, 556}, {0x0069, 222}, {0x006B, 500}, + {0x006C, 222}, {0x006D, 833}, {0x006E, 556}, {0x0072, 333}, + {0x0073, 500}, {0x0074, 278}, {0x0075, 556}, {0x0076, 500}, + {0x0077, 722}, {0x0078, 500}, {0x007B, 334}, {0x007C, 260}, + {0x007D, 334}, {0x007E, 584}, {0x007F, 0}, {0x00A0, 278}, + {0x00A1, 333}, {0x00A2, 556}, {0x00A6, 260}, {0x00A7, 556}, + {0x00A8, 333}, {0x00A9, 737}, {0x00AA, 370}, {0x00AB, 556}, + {0x00AC, 584}, {0x00AD, 333}, {0x00AE, 737}, {0x00AF, 552}, + {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 333}, {0x00B5, 576}, + {0x00B6, 537}, {0x00B7, 278}, {0x00B8, 333}, {0x00BA, 365}, + {0x00BB, 556}, {0x00BC, 834}, {0x00BF, 611}, {0x00C0, 667}, + {0x00C6,1000}, {0x00C7, 722}, {0x00C8, 667}, {0x00CC, 278}, + {0x00D0, 722}, {0x00D2, 778}, {0x00D7, 584}, {0x00D8, 778}, + {0x00D9, 722}, {0x00DD, 667}, {0x00DF, 611}, {0x00E0, 556}, + {0x00E6, 889}, {0x00E7, 500}, {0x00E8, 556}, {0x00EC, 278}, + {0x00F0, 556}, {0x00F7, 549}, {0x00F8, 611}, {0x00F9, 556}, + {0x00FD, 500}, {0x00FE, 556}, {0x00FF, 500}, {0x0100, 667}, + {0x0101, 556}, {0x0102, 667}, {0x0103, 556}, {0x0104, 667}, + {0x0105, 556}, {0x0106, 722}, {0x0107, 500}, {0x0108, 0}, + {0x010C, 722}, {0x010D, 500}, {0x010E, 722}, {0x010F, 625}, + {0x0110, 722}, {0x0111, 556}, {0x0112, 667}, {0x0113, 556}, + {0x0114, 0}, {0x0116, 667}, {0x0117, 556}, {0x0118, 667}, + {0x0119, 556}, {0x011A, 667}, {0x011B, 556}, {0x011C, 0}, + {0x011E, 778}, {0x011F, 556}, {0x0120, 0}, {0x0122, 778}, + {0x0123, 556}, {0x0124, 0}, {0x0128, 278}, {0x012C, 0}, + {0x012E, 278}, {0x012F, 222}, {0x0130, 278}, {0x0132, 0}, + {0x0136, 667}, {0x0137, 500}, {0x0139, 556}, {0x013A, 222}, + {0x013B, 556}, {0x013C, 222}, {0x013D, 556}, {0x013E, 281}, + {0x013F, 0}, {0x0141, 556}, {0x0142, 222}, {0x0143, 722}, + {0x0144, 556}, {0x0145, 722}, {0x0146, 556}, {0x0147, 722}, + {0x0148, 556}, {0x0149, 0}, {0x014A, 723}, {0x014B, 556}, + {0x014C, 778}, {0x014D, 556}, {0x014E, 0}, {0x0150, 778}, + {0x0151, 556}, {0x0152,1000}, {0x0153, 944}, {0x0154, 722}, + {0x0155, 333}, {0x0156, 722}, {0x0157, 333}, {0x0158, 722}, + {0x0159, 333}, {0x015A, 667}, {0x015B, 500}, {0x015C, 0}, + {0x015E, 667}, {0x015F, 500}, {0x0160, 667}, {0x0161, 500}, + {0x0162, 611}, {0x0163, 278}, {0x0164, 611}, {0x0165, 354}, + {0x0166, 611}, {0x0167, 278}, {0x0168, 722}, {0x0169, 556}, + {0x016A, 722}, {0x016B, 556}, {0x016C, 0}, {0x016E, 722}, + {0x016F, 556}, {0x0170, 722}, {0x0171, 556}, {0x0172, 722}, + {0x0173, 556}, {0x0174, 0}, {0x0178, 667}, {0x0179, 611}, + {0x017A, 500}, {0x017B, 611}, {0x017C, 500}, {0x017D, 611}, + {0x017E, 500}, {0x017F, 0}, {0x0192, 556}, {0x0193, 0}, + {0x0218, 750}, {0x021A, 611}, {0x021B, 278}, {0x021C, 0}, + {0x02C6, 333}, {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, + {0x02DB, 333}, {0x02DE, 0}, {0x2013, 556}, {0x2014,1000}, + {0x2016, 0}, {0x2018, 222}, {0x201B, 0}, {0x201C, 333}, + {0x201F, 0}, {0x2020, 556}, {0x2022, 350}, {0x2023, 0}, + {0x2026,1000}, {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, + {0x2039, 333}, {0x203B, 0}, {0x20AC, 556}, {0x20AD, 0}, + {0x2122,1000}, {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, + {0x2211, 713}, {0x2212, 584}, {0x2213, 0}, {0x221A, 549}, + {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, + {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 750}, + {0xF6C4, 0}, {0xFB01, 500}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_07 = +{ + "Helvetica-Oblique", + 96L, + fnt_Type1, + cc_none, + -12, + 0, + -517, + -325, + 1082, + 998, + -106, + 73, + 718, + 523, + 718, + -207, + 88, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 268, + fnt_glyph_width_07, + 0, + NULL, + +}; + +/* -------- Generated from ARIALBI.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_08[269] = +{ + {0x0000, 0}, {0x0020, 278}, {0x0021, 333}, {0x0022, 474}, + {0x0023, 556}, {0x0025, 889}, {0x0026, 722}, {0x0027, 238}, + {0x0028, 333}, {0x002A, 389}, {0x002B, 584}, {0x002C, 278}, + {0x002D, 333}, {0x002E, 278}, {0x0030, 556}, {0x003A, 333}, + {0x003C, 584}, {0x003F, 611}, {0x0040, 975}, {0x0041, 722}, + {0x0045, 667}, {0x0046, 611}, {0x0047, 778}, {0x0048, 722}, + {0x0049, 278}, {0x004A, 556}, {0x004B, 722}, {0x004C, 611}, + {0x004D, 833}, {0x004E, 722}, {0x004F, 778}, {0x0050, 667}, + {0x0051, 778}, {0x0052, 722}, {0x0053, 667}, {0x0054, 611}, + {0x0055, 722}, {0x0056, 667}, {0x0057, 944}, {0x0058, 667}, + {0x005A, 611}, {0x005B, 333}, {0x005C, 278}, {0x005D, 333}, + {0x005E, 584}, {0x005F, 556}, {0x0060, 333}, {0x0061, 556}, + {0x0062, 611}, {0x0063, 556}, {0x0064, 611}, {0x0065, 556}, + {0x0066, 333}, {0x0067, 611}, {0x0069, 278}, {0x006B, 556}, + {0x006C, 278}, {0x006D, 889}, {0x006E, 611}, {0x0072, 389}, + {0x0073, 556}, {0x0074, 333}, {0x0075, 611}, {0x0076, 556}, + {0x0077, 778}, {0x0078, 556}, {0x007A, 500}, {0x007B, 389}, + {0x007C, 280}, {0x007D, 389}, {0x007E, 584}, {0x007F, 0}, + {0x00A0, 278}, {0x00A1, 333}, {0x00A2, 556}, {0x00A6, 280}, + {0x00A7, 556}, {0x00A8, 333}, {0x00A9, 737}, {0x00AA, 370}, + {0x00AB, 556}, {0x00AC, 584}, {0x00AD, 333}, {0x00AE, 737}, + {0x00AF, 552}, {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 333}, + {0x00B5, 576}, {0x00B6, 556}, {0x00B7, 278}, {0x00B8, 333}, + {0x00BA, 365}, {0x00BB, 556}, {0x00BC, 834}, {0x00BF, 611}, + {0x00C0, 722}, {0x00C6,1000}, {0x00C7, 722}, {0x00C8, 667}, + {0x00CC, 278}, {0x00D0, 722}, {0x00D2, 778}, {0x00D7, 584}, + {0x00D8, 778}, {0x00D9, 722}, {0x00DD, 667}, {0x00DF, 611}, + {0x00E0, 556}, {0x00E6, 889}, {0x00E7, 556}, {0x00EC, 278}, + {0x00F0, 611}, {0x00F7, 549}, {0x00F8, 611}, {0x00FD, 556}, + {0x00FE, 611}, {0x00FF, 556}, {0x0100, 722}, {0x0101, 556}, + {0x0102, 722}, {0x0103, 556}, {0x0104, 722}, {0x0105, 556}, + {0x0106, 722}, {0x0107, 556}, {0x0108, 0}, {0x010C, 722}, + {0x010D, 556}, {0x010E, 722}, {0x010F, 740}, {0x0110, 722}, + {0x0111, 611}, {0x0112, 667}, {0x0113, 556}, {0x0114, 0}, + {0x0116, 667}, {0x0117, 556}, {0x0118, 667}, {0x0119, 556}, + {0x011A, 667}, {0x011B, 556}, {0x011C, 0}, {0x011E, 778}, + {0x011F, 611}, {0x0120, 0}, {0x0122, 778}, {0x0123, 611}, + {0x0124, 0}, {0x0128, 278}, {0x012C, 0}, {0x012E, 278}, + {0x0132, 0}, {0x0136, 722}, {0x0137, 556}, {0x0139, 611}, + {0x013A, 278}, {0x013B, 611}, {0x013C, 278}, {0x013D, 611}, + {0x013E, 396}, {0x013F, 0}, {0x0141, 611}, {0x0142, 278}, + {0x0143, 722}, {0x0144, 611}, {0x0145, 722}, {0x0146, 611}, + {0x0147, 722}, {0x0148, 611}, {0x0149, 0}, {0x014A, 723}, + {0x014B, 611}, {0x014C, 778}, {0x014D, 611}, {0x014E, 0}, + {0x0150, 778}, {0x0151, 611}, {0x0152,1000}, {0x0153, 944}, + {0x0154, 722}, {0x0155, 389}, {0x0156, 722}, {0x0157, 389}, + {0x0158, 722}, {0x0159, 389}, {0x015A, 667}, {0x015B, 556}, + {0x015C, 0}, {0x015E, 667}, {0x015F, 556}, {0x0160, 667}, + {0x0161, 556}, {0x0162, 611}, {0x0163, 333}, {0x0164, 611}, + {0x0165, 479}, {0x0166, 611}, {0x0167, 333}, {0x0168, 722}, + {0x0169, 611}, {0x016A, 722}, {0x016B, 611}, {0x016C, 0}, + {0x016E, 722}, {0x016F, 611}, {0x0170, 722}, {0x0171, 611}, + {0x0172, 722}, {0x0173, 611}, {0x0174, 0}, {0x0178, 667}, + {0x0179, 611}, {0x017A, 500}, {0x017B, 611}, {0x017C, 500}, + {0x017D, 611}, {0x017E, 500}, {0x017F, 0}, {0x0192, 556}, + {0x0193, 0}, {0x0218, 750}, {0x021A, 611}, {0x021B, 333}, + {0x021C, 0}, {0x02C6, 333}, {0x02C8, 0}, {0x02D8, 333}, + {0x02DA, 0}, {0x02DB, 333}, {0x02DE, 0}, {0x2013, 556}, + {0x2014,1000}, {0x2016, 0}, {0x2018, 278}, {0x201B, 0}, + {0x201C, 500}, {0x201F, 0}, {0x2020, 556}, {0x2022, 350}, + {0x2023, 0}, {0x2026,1000}, {0x2027, 0}, {0x2030,1000}, + {0x2031, 0}, {0x2039, 333}, {0x203B, 0}, {0x20AC, 556}, + {0x20AD, 0}, {0x2122,1000}, {0x2123, 0}, {0x2202, 494}, + {0x2203, 0}, {0x2211, 713}, {0x2212, 584}, {0x2213, 0}, + {0x221A, 549}, {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, + {0x2264, 549}, {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, + {0xF6C3, 750}, {0xF6C4, 0}, {0xFB01, 611}, {0xFB03, 0}, + {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_08 = +{ + "Helvetica-BoldOblique", + 262240L, + fnt_Type1, + cc_none, + -12, + 0, + -560, + -376, + 1157, + 1000, + -106, + 105, + 718, + 532, + 718, + -207, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 269, + fnt_glyph_width_08, + 0, + NULL, + +}; + +/* -------- Generated from Symbol.afm -------- */ + +static fnt_glyphwidth fnt_glyph_width_09[191] = +{ + {0x0020, 32, 250}, {0x0021, 33, 333}, {0x2200, 34, 713}, + {0x0023, 35, 500}, {0x2203, 36, 549}, {0x0025, 37, 833}, + {0x0026, 38, 778}, {0x220b, 39, 439}, {0x0028, 40, 333}, + {0x0029, 41, 333}, {0x2217, 42, 500}, {0x002b, 43, 549}, + {0x002c, 44, 250}, {0x2212, 45, 549}, {0x002e, 46, 250}, + {0x002f, 47, 278}, {0x0030, 48, 500}, {0x0031, 49, 500}, + {0x0032, 50, 500}, {0x0033, 51, 500}, {0x0034, 52, 500}, + {0x0035, 53, 500}, {0x0036, 54, 500}, {0x0037, 55, 500}, + {0x0038, 56, 500}, {0x0039, 57, 500}, {0x003a, 58, 278}, + {0x003b, 59, 278}, {0x003c, 60, 549}, {0x003d, 61, 549}, + {0x003e, 62, 549}, {0x003f, 63, 444}, {0x2245, 64, 549}, + {0x0391, 65, 722}, {0x0392, 66, 667}, {0x03a7, 67, 722}, + {0x0394, 68, 612}, {0x0395, 69, 611}, {0x03a6, 70, 763}, + {0x0393, 71, 603}, {0x0397, 72, 722}, {0x0399, 73, 333}, + {0x03d1, 74, 631}, {0x039a, 75, 722}, {0x039b, 76, 686}, + {0x039c, 77, 889}, {0x039d, 78, 722}, {0x039f, 79, 722}, + {0x03a0, 80, 768}, {0x0398, 81, 741}, {0x03a1, 82, 556}, + {0x03a3, 83, 592}, {0x03a4, 84, 611}, {0x03a5, 85, 690}, + {0x03c2, 86, 439}, {0x03a9, 87, 768}, {0x039e, 88, 645}, + {0x03a8, 89, 795}, {0x0396, 90, 611}, {0x005b, 91, 333}, + {0x2234, 92, 863}, {0x005d, 93, 333}, {0x22a5, 94, 658}, + {0x005f, 95, 500}, {0xf8e5, 96, 500}, {0x03b1, 97, 631}, + {0x03b2, 98, 549}, {0x03c7, 99, 549}, {0x03b4, 100, 494}, + {0x03b5, 101, 439}, {0x03c6, 102, 521}, {0x03b3, 103, 411}, + {0x03b7, 104, 603}, {0x03b9, 105, 329}, {0x03d5, 106, 603}, + {0x03ba, 107, 549}, {0x03bb, 108, 549}, {0x03bc, 109, 576}, + {0x03bd, 110, 521}, {0x03bf, 111, 549}, {0x03c0, 112, 549}, + {0x03b8, 113, 521}, {0x03c1, 114, 549}, {0x03c3, 115, 603}, + {0x03c4, 116, 439}, {0x03c5, 117, 576}, {0x03d6, 118, 713}, + {0x03c9, 119, 686}, {0x03be, 120, 493}, {0x03c8, 121, 686}, + {0x03b6, 122, 494}, {0x007b, 123, 480}, {0x007c, 124, 200}, + {0x007d, 125, 480}, {0x223c, 126, 549}, {0x20ac, 160, 750}, + {0x03d2, 161, 620}, {0x2032, 162, 247}, {0x2264, 163, 549}, + {0x2044, 164, 167}, {0x221e, 165, 713}, {0x0192, 166, 500}, + {0x2663, 167, 753}, {0x2666, 168, 753}, {0x2665, 169, 753}, + {0x2660, 170, 753}, {0x2194, 171, 1042}, {0x2190, 172, 987}, + {0x2191, 173, 603}, {0x2192, 174, 987}, {0x2193, 175, 603}, + {0x00b0, 176, 400}, {0x00b1, 177, 549}, {0x2033, 178, 411}, + {0x2265, 179, 549}, {0x00d7, 180, 549}, {0x221d, 181, 713}, + {0x2202, 182, 494}, {0x2022, 183, 460}, {0x00f7, 184, 549}, + {0x2260, 185, 549}, {0x2261, 186, 549}, {0x2248, 187, 549}, + {0x2026, 188, 1000}, {0xf8e6, 189, 603}, {0xf8e7, 190, 1000}, + {0x21b5, 191, 658}, {0x2135, 192, 823}, {0x2111, 193, 686}, + {0x211c, 194, 795}, {0x2118, 195, 987}, {0x2297, 196, 768}, + {0x2295, 197, 768}, {0x2205, 198, 823}, {0x2229, 199, 768}, + {0x222a, 200, 768}, {0x2283, 201, 713}, {0x2287, 202, 713}, + {0x2284, 203, 713}, {0x2282, 204, 713}, {0x2286, 205, 713}, + {0x2208, 206, 713}, {0x2209, 207, 713}, {0x2220, 208, 768}, + {0x2207, 209, 713}, {0xf6da, 210, 790}, {0xf6d9, 211, 790}, + {0xf6db, 212, 890}, {0x220f, 213, 823}, {0x221a, 214, 549}, + {0x22c5, 215, 250}, {0x00ac, 216, 713}, {0x2227, 217, 603}, + {0x2228, 218, 603}, {0x21d4, 219, 1042}, {0x21d0, 220, 987}, + {0x21d1, 221, 603}, {0x21d2, 222, 987}, {0x21d3, 223, 603}, + {0x25ca, 224, 494}, {0x2329, 225, 329}, {0xf8e8, 226, 790}, + {0xf8e9, 227, 790}, {0xf8ea, 228, 786}, {0x2211, 229, 713}, + {0xf8eb, 230, 384}, {0xf8ec, 231, 384}, {0xf8ed, 232, 384}, + {0xf8ee, 233, 384}, {0xf8ef, 234, 384}, {0xf8f0, 235, 384}, + {0xf8f1, 236, 494}, {0xf8f2, 237, 494}, {0xf8f3, 238, 494}, + {0xf8f4, 239, 494}, {0x232a, 241, 329}, {0x222b, 242, 274}, + {0x2320, 243, 686}, {0xf8f5, 244, 686}, {0x2321, 245, 686}, + {0xf8f6, 246, 384}, {0xf8f7, 247, 384}, {0xf8f8, 248, 384}, + {0xf8f9, 249, 384}, {0xf8fa, 250, 384}, {0xf8fb, 251, 384}, + {0xf8fc, 252, 494}, {0xf8fd, 253, 494}, {0xf8fe, 254, 494}, + {0xf8ff, -1, 790}, {0x0000, -1, 790} +}; + +static const fnt_font_metric fnt_font_metric_09 = +{ + "Symbol", /* FontName */ + 4L, /* flags */ + fnt_Type1, /* font type */ + cc_none, /* Character collection */ + 0.0, /* ItalicAngle */ + 0, /* isFixedPitch */ + -180, /* llx */ + -293, /* lly */ + 1090, /* urx */ + 1010, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 700, /* CapHeight */ + 0, /* xHeight */ + 800, /* Ascender */ + -200, /* Descender */ + 85, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 0, + NULL, + 191, + fnt_glyph_width_09, + +}; + +/* -------- Generated from TIMES.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_10[271] = +{ + {0x0000, 0}, {0x0020, 250}, {0x0021, 333}, {0x0022, 408}, + {0x0023, 500}, {0x0025, 833}, {0x0026, 778}, {0x0027, 180}, + {0x0028, 333}, {0x002A, 500}, {0x002B, 564}, {0x002C, 250}, + {0x002D, 333}, {0x002E, 250}, {0x002F, 278}, {0x0030, 500}, + {0x003A, 278}, {0x003C, 564}, {0x003F, 444}, {0x0040, 921}, + {0x0041, 722}, {0x0042, 667}, {0x0044, 722}, {0x0045, 611}, + {0x0046, 556}, {0x0047, 722}, {0x0049, 333}, {0x004A, 389}, + {0x004B, 722}, {0x004C, 611}, {0x004D, 889}, {0x004E, 722}, + {0x0050, 556}, {0x0051, 722}, {0x0052, 667}, {0x0053, 556}, + {0x0054, 611}, {0x0055, 722}, {0x0057, 944}, {0x0058, 722}, + {0x005A, 611}, {0x005B, 333}, {0x005C, 278}, {0x005D, 333}, + {0x005E, 469}, {0x005F, 500}, {0x0060, 333}, {0x0061, 444}, + {0x0062, 500}, {0x0063, 444}, {0x0064, 500}, {0x0065, 444}, + {0x0066, 333}, {0x0067, 500}, {0x0069, 278}, {0x006B, 500}, + {0x006C, 278}, {0x006D, 778}, {0x006E, 500}, {0x0072, 333}, + {0x0073, 389}, {0x0074, 278}, {0x0075, 500}, {0x0077, 722}, + {0x0078, 500}, {0x007A, 444}, {0x007B, 480}, {0x007C, 200}, + {0x007D, 480}, {0x007E, 541}, {0x007F, 0}, {0x00A0, 250}, + {0x00A1, 333}, {0x00A2, 500}, {0x00A6, 200}, {0x00A7, 500}, + {0x00A8, 333}, {0x00A9, 760}, {0x00AA, 276}, {0x00AB, 500}, + {0x00AC, 564}, {0x00AD, 333}, {0x00AE, 760}, {0x00AF, 500}, + {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 300}, {0x00B4, 333}, + {0x00B5, 576}, {0x00B6, 453}, {0x00B7, 250}, {0x00B8, 333}, + {0x00B9, 300}, {0x00BA, 310}, {0x00BB, 500}, {0x00BC, 750}, + {0x00BF, 444}, {0x00C0, 722}, {0x00C6, 889}, {0x00C7, 667}, + {0x00C8, 611}, {0x00CC, 333}, {0x00D0, 722}, {0x00D7, 564}, + {0x00D8, 722}, {0x00DE, 556}, {0x00DF, 500}, {0x00E0, 444}, + {0x00E6, 667}, {0x00E7, 444}, {0x00EC, 278}, {0x00F0, 500}, + {0x00F7, 549}, {0x00F8, 500}, {0x0100, 722}, {0x0101, 444}, + {0x0102, 722}, {0x0103, 444}, {0x0104, 722}, {0x0105, 444}, + {0x0106, 667}, {0x0107, 444}, {0x0108, 0}, {0x010C, 667}, + {0x010D, 444}, {0x010E, 722}, {0x010F, 646}, {0x0110, 722}, + {0x0111, 500}, {0x0112, 611}, {0x0113, 444}, {0x0114, 0}, + {0x0116, 611}, {0x0117, 444}, {0x0118, 611}, {0x0119, 444}, + {0x011A, 611}, {0x011B, 444}, {0x011C, 0}, {0x011E, 722}, + {0x011F, 500}, {0x0120, 0}, {0x0122, 722}, {0x0123, 500}, + {0x0124, 0}, {0x0128, 333}, {0x0129, 278}, {0x012A, 333}, + {0x012B, 278}, {0x012C, 0}, {0x012E, 333}, {0x012F, 278}, + {0x0130, 333}, {0x0131, 278}, {0x0132, 0}, {0x0136, 722}, + {0x0137, 500}, {0x0139, 611}, {0x013A, 278}, {0x013B, 611}, + {0x013C, 278}, {0x013D, 611}, {0x013E, 406}, {0x013F, 0}, + {0x0141, 611}, {0x0142, 278}, {0x0143, 722}, {0x0144, 500}, + {0x0145, 722}, {0x0146, 500}, {0x0147, 722}, {0x0148, 500}, + {0x0149, 0}, {0x014A, 702}, {0x014B, 495}, {0x014C, 722}, + {0x014D, 500}, {0x014E, 0}, {0x0150, 722}, {0x0151, 500}, + {0x0152, 889}, {0x0153, 722}, {0x0154, 667}, {0x0155, 333}, + {0x0156, 667}, {0x0157, 333}, {0x0158, 667}, {0x0159, 333}, + {0x015A, 556}, {0x015B, 389}, {0x015C, 0}, {0x015E, 556}, + {0x015F, 389}, {0x0160, 556}, {0x0161, 389}, {0x0162, 611}, + {0x0163, 278}, {0x0164, 611}, {0x0165, 427}, {0x0166, 611}, + {0x0167, 278}, {0x0168, 722}, {0x0169, 500}, {0x016A, 722}, + {0x016B, 500}, {0x016C, 0}, {0x016E, 722}, {0x016F, 500}, + {0x0170, 722}, {0x0171, 500}, {0x0172, 722}, {0x0173, 500}, + {0x0174, 0}, {0x0178, 722}, {0x0179, 611}, {0x017A, 444}, + {0x017B, 611}, {0x017C, 444}, {0x017D, 611}, {0x017E, 444}, + {0x017F, 0}, {0x0192, 500}, {0x0193, 0}, {0x0218, 778}, + {0x021A, 611}, {0x021B, 278}, {0x021C, 0}, {0x02C6, 333}, + {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, {0x02DB, 333}, + {0x02DE, 0}, {0x2013, 500}, {0x2014,1000}, {0x2016, 0}, + {0x2018, 333}, {0x201B, 0}, {0x201C, 444}, {0x201F, 0}, + {0x2020, 500}, {0x2022, 350}, {0x2023, 0}, {0x2026,1000}, + {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, {0x2039, 333}, + {0x203B, 0}, {0x20AC, 500}, {0x20AD, 0}, {0x2122, 980}, + {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, {0x2211, 713}, + {0x2212, 564}, {0x2213, 0}, {0x221A, 549}, {0x221B, 0}, + {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, {0x2266, 0}, + {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 778}, {0xF6C4, 0}, + {0xFB01, 556}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_10 = +{ + "Times-Roman", + 32L, + fnt_Type1, + cc_none, + 0, + 0, + -568, + -307, + 2000, + 1007, + -109, + 49, + 662, + 450, + 683, + -217, + 88, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 271, + fnt_glyph_width_10, + 0, + NULL, + +}; + +/* -------- Generated from TIMESBD.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_11[284] = +{ + {0x0000, 0}, {0x0020, 250}, {0x0021, 333}, {0x0022, 555}, + {0x0023, 500}, {0x0025,1000}, {0x0026, 833}, {0x0027, 278}, + {0x0028, 333}, {0x002A, 500}, {0x002B, 570}, {0x002C, 250}, + {0x002D, 333}, {0x002E, 250}, {0x002F, 278}, {0x0030, 500}, + {0x003A, 333}, {0x003C, 570}, {0x003F, 500}, {0x0040, 930}, + {0x0041, 722}, {0x0042, 667}, {0x0043, 722}, {0x0045, 667}, + {0x0046, 611}, {0x0047, 778}, {0x0049, 389}, {0x004A, 500}, + {0x004B, 778}, {0x004C, 667}, {0x004D, 944}, {0x004E, 722}, + {0x004F, 778}, {0x0050, 611}, {0x0051, 778}, {0x0052, 722}, + {0x0053, 556}, {0x0054, 667}, {0x0055, 722}, {0x0057,1000}, + {0x0058, 722}, {0x005A, 667}, {0x005B, 333}, {0x005C, 278}, + {0x005D, 333}, {0x005E, 581}, {0x005F, 500}, {0x0060, 333}, + {0x0061, 500}, {0x0062, 556}, {0x0063, 444}, {0x0064, 556}, + {0x0065, 444}, {0x0066, 333}, {0x0067, 500}, {0x0068, 556}, + {0x0069, 278}, {0x006A, 333}, {0x006B, 556}, {0x006C, 278}, + {0x006D, 833}, {0x006E, 556}, {0x006F, 500}, {0x0070, 556}, + {0x0072, 444}, {0x0073, 389}, {0x0074, 333}, {0x0075, 556}, + {0x0076, 500}, {0x0077, 722}, {0x0078, 500}, {0x007A, 444}, + {0x007B, 394}, {0x007C, 220}, {0x007D, 394}, {0x007E, 520}, + {0x007F, 0}, {0x00A0, 250}, {0x00A1, 333}, {0x00A2, 500}, + {0x00A6, 220}, {0x00A7, 500}, {0x00A8, 333}, {0x00A9, 747}, + {0x00AA, 300}, {0x00AB, 500}, {0x00AC, 570}, {0x00AD, 333}, + {0x00AE, 747}, {0x00AF, 500}, {0x00B0, 400}, {0x00B1, 549}, + {0x00B2, 300}, {0x00B4, 333}, {0x00B5, 576}, {0x00B6, 540}, + {0x00B7, 250}, {0x00B8, 333}, {0x00B9, 300}, {0x00BA, 330}, + {0x00BB, 500}, {0x00BC, 750}, {0x00BF, 500}, {0x00C0, 722}, + {0x00C6,1000}, {0x00C7, 722}, {0x00C8, 667}, {0x00CC, 389}, + {0x00D0, 722}, {0x00D2, 778}, {0x00D7, 570}, {0x00D8, 778}, + {0x00D9, 722}, {0x00DE, 611}, {0x00DF, 556}, {0x00E0, 500}, + {0x00E6, 722}, {0x00E7, 444}, {0x00EC, 278}, {0x00F0, 500}, + {0x00F1, 556}, {0x00F2, 500}, {0x00F7, 549}, {0x00F8, 500}, + {0x00F9, 556}, {0x00FD, 500}, {0x00FE, 556}, {0x00FF, 500}, + {0x0100, 722}, {0x0101, 500}, {0x0102, 722}, {0x0103, 500}, + {0x0104, 722}, {0x0105, 500}, {0x0106, 722}, {0x0107, 444}, + {0x0108, 0}, {0x010C, 722}, {0x010D, 444}, {0x010E, 722}, + {0x010F, 733}, {0x0110, 722}, {0x0111, 556}, {0x0112, 667}, + {0x0113, 444}, {0x0114, 0}, {0x0116, 667}, {0x0117, 444}, + {0x0118, 667}, {0x0119, 444}, {0x011A, 667}, {0x011B, 444}, + {0x011C, 0}, {0x011E, 778}, {0x011F, 500}, {0x0120, 0}, + {0x0122, 778}, {0x0123, 500}, {0x0124, 0}, {0x0128, 389}, + {0x0129, 278}, {0x012A, 389}, {0x012B, 278}, {0x012C, 0}, + {0x012E, 389}, {0x012F, 278}, {0x0130, 389}, {0x0131, 278}, + {0x0132, 0}, {0x0136, 778}, {0x0137, 556}, {0x0139, 667}, + {0x013A, 278}, {0x013B, 667}, {0x013C, 278}, {0x013D, 667}, + {0x013E, 469}, {0x013F, 0}, {0x0141, 667}, {0x0142, 278}, + {0x0143, 722}, {0x0144, 556}, {0x0145, 722}, {0x0146, 556}, + {0x0147, 722}, {0x0148, 556}, {0x0149, 0}, {0x014A, 769}, + {0x014B, 556}, {0x014C, 778}, {0x014D, 500}, {0x014E, 0}, + {0x0150, 778}, {0x0151, 500}, {0x0152,1000}, {0x0153, 722}, + {0x0155, 444}, {0x0156, 722}, {0x0157, 444}, {0x0158, 722}, + {0x0159, 444}, {0x015A, 556}, {0x015B, 389}, {0x015C, 0}, + {0x015E, 556}, {0x015F, 389}, {0x0160, 556}, {0x0161, 389}, + {0x0162, 667}, {0x0163, 333}, {0x0164, 667}, {0x0165, 521}, + {0x0166, 667}, {0x0167, 333}, {0x0168, 722}, {0x0169, 556}, + {0x016A, 722}, {0x016B, 556}, {0x016C, 0}, {0x016E, 722}, + {0x016F, 556}, {0x0170, 722}, {0x0171, 556}, {0x0172, 722}, + {0x0173, 556}, {0x0174, 0}, {0x0178, 722}, {0x0179, 667}, + {0x017A, 444}, {0x017B, 667}, {0x017C, 444}, {0x017D, 667}, + {0x017E, 444}, {0x017F, 0}, {0x0192, 500}, {0x0193, 0}, + {0x0218, 778}, {0x021A, 667}, {0x021B, 333}, {0x021C, 0}, + {0x02C6, 333}, {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, + {0x02DB, 333}, {0x02DE, 0}, {0x2013, 500}, {0x2014,1000}, + {0x2016, 0}, {0x2018, 333}, {0x201B, 0}, {0x201C, 500}, + {0x201F, 0}, {0x2020, 500}, {0x2022, 350}, {0x2023, 0}, + {0x2026,1000}, {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, + {0x2039, 333}, {0x203B, 0}, {0x20AC, 500}, {0x20AD, 0}, + {0x2122,1000}, {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, + {0x2211, 713}, {0x2212, 570}, {0x2213, 0}, {0x221A, 549}, + {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, + {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 778}, + {0xF6C4, 0}, {0xFB01, 556}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_11 = +{ + "Times-Bold", + 262176L, + fnt_Type1, + cc_none, + 0, + 0, + -558, + -307, + 2000, + 1026, + -109, + 95, + 676, + 461, + 683, + -217, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 284, + fnt_glyph_width_11, + 0, + NULL, + +}; + +/* -------- Generated from TIMESI.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_12[276] = +{ + {0x0000, 0}, {0x0020, 250}, {0x0021, 333}, {0x0022, 420}, + {0x0023, 500}, {0x0025, 833}, {0x0026, 778}, {0x0027, 214}, + {0x0028, 333}, {0x002A, 500}, {0x002B, 675}, {0x002C, 250}, + {0x002D, 333}, {0x002E, 250}, {0x002F, 278}, {0x0030, 500}, + {0x003A, 333}, {0x003C, 675}, {0x003F, 500}, {0x0040, 920}, + {0x0041, 611}, {0x0043, 667}, {0x0044, 722}, {0x0045, 611}, + {0x0047, 722}, {0x0049, 333}, {0x004A, 444}, {0x004B, 667}, + {0x004C, 556}, {0x004D, 833}, {0x004E, 667}, {0x004F, 722}, + {0x0050, 611}, {0x0051, 722}, {0x0052, 611}, {0x0053, 500}, + {0x0054, 556}, {0x0055, 722}, {0x0056, 611}, {0x0057, 833}, + {0x0058, 611}, {0x0059, 556}, {0x005B, 389}, {0x005C, 278}, + {0x005D, 389}, {0x005E, 422}, {0x005F, 500}, {0x0060, 333}, + {0x0061, 500}, {0x0063, 444}, {0x0064, 500}, {0x0065, 444}, + {0x0066, 278}, {0x0067, 500}, {0x0069, 278}, {0x006B, 444}, + {0x006C, 278}, {0x006D, 722}, {0x006E, 500}, {0x0072, 389}, + {0x0074, 278}, {0x0075, 500}, {0x0076, 444}, {0x0077, 667}, + {0x0078, 444}, {0x007A, 389}, {0x007B, 400}, {0x007C, 275}, + {0x007D, 400}, {0x007E, 541}, {0x007F, 0}, {0x00A0, 250}, + {0x00A1, 389}, {0x00A2, 500}, {0x00A6, 275}, {0x00A7, 500}, + {0x00A8, 333}, {0x00A9, 760}, {0x00AA, 276}, {0x00AB, 500}, + {0x00AC, 675}, {0x00AD, 333}, {0x00AE, 760}, {0x00AF, 500}, + {0x00B0, 400}, {0x00B1, 549}, {0x00B2, 300}, {0x00B4, 333}, + {0x00B5, 576}, {0x00B6, 523}, {0x00B7, 250}, {0x00B8, 333}, + {0x00B9, 300}, {0x00BA, 310}, {0x00BB, 500}, {0x00BC, 750}, + {0x00BF, 500}, {0x00C0, 611}, {0x00C6, 889}, {0x00C7, 667}, + {0x00C8, 611}, {0x00CC, 333}, {0x00D0, 722}, {0x00D1, 667}, + {0x00D2, 722}, {0x00D7, 675}, {0x00D8, 722}, {0x00DD, 556}, + {0x00DE, 611}, {0x00DF, 500}, {0x00E6, 667}, {0x00E7, 444}, + {0x00EC, 278}, {0x00F0, 500}, {0x00F7, 549}, {0x00F8, 500}, + {0x00FD, 444}, {0x00FE, 500}, {0x00FF, 444}, {0x0100, 611}, + {0x0101, 500}, {0x0102, 611}, {0x0103, 500}, {0x0104, 611}, + {0x0105, 500}, {0x0106, 667}, {0x0107, 444}, {0x0108, 0}, + {0x010C, 667}, {0x010D, 444}, {0x010E, 722}, {0x010F, 608}, + {0x0110, 722}, {0x0111, 500}, {0x0112, 611}, {0x0113, 444}, + {0x0114, 0}, {0x0116, 611}, {0x0117, 444}, {0x0118, 611}, + {0x0119, 444}, {0x011A, 611}, {0x011B, 444}, {0x011C, 0}, + {0x011E, 722}, {0x011F, 500}, {0x0120, 0}, {0x0122, 722}, + {0x0123, 500}, {0x0124, 0}, {0x0128, 333}, {0x0129, 278}, + {0x012A, 333}, {0x012B, 278}, {0x012C, 0}, {0x012E, 333}, + {0x012F, 278}, {0x0130, 333}, {0x0131, 278}, {0x0132, 0}, + {0x0136, 667}, {0x0137, 444}, {0x0139, 556}, {0x013A, 278}, + {0x013B, 556}, {0x013C, 278}, {0x013D, 556}, {0x013E, 364}, + {0x013F, 0}, {0x0141, 556}, {0x0142, 278}, {0x0143, 667}, + {0x0144, 500}, {0x0145, 667}, {0x0146, 500}, {0x0147, 667}, + {0x0148, 500}, {0x0149, 0}, {0x014A, 696}, {0x014B, 482}, + {0x014C, 722}, {0x014D, 500}, {0x014E, 0}, {0x0150, 722}, + {0x0151, 500}, {0x0152, 944}, {0x0153, 667}, {0x0154, 611}, + {0x0155, 389}, {0x0156, 611}, {0x0157, 389}, {0x0158, 611}, + {0x0159, 389}, {0x015A, 500}, {0x015B, 389}, {0x015C, 0}, + {0x015E, 500}, {0x015F, 389}, {0x0160, 500}, {0x0161, 389}, + {0x0162, 556}, {0x0163, 278}, {0x0164, 556}, {0x0165, 364}, + {0x0166, 556}, {0x0167, 278}, {0x0168, 722}, {0x0169, 500}, + {0x016A, 722}, {0x016B, 500}, {0x016C, 0}, {0x016E, 722}, + {0x016F, 500}, {0x0170, 722}, {0x0171, 500}, {0x0172, 722}, + {0x0173, 500}, {0x0174, 0}, {0x0178, 556}, {0x017A, 389}, + {0x017B, 556}, {0x017C, 389}, {0x017D, 556}, {0x017E, 389}, + {0x017F, 0}, {0x0192, 500}, {0x0193, 0}, {0x0218, 778}, + {0x021A, 556}, {0x021B, 278}, {0x021C, 0}, {0x02C6, 333}, + {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, {0x02DB, 333}, + {0x02DE, 0}, {0x2013, 500}, {0x2014, 889}, {0x2015,1000}, + {0x2016, 0}, {0x2018, 333}, {0x201B, 0}, {0x201C, 556}, + {0x201F, 0}, {0x2020, 500}, {0x2022, 350}, {0x2023, 0}, + {0x2026, 889}, {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, + {0x2039, 333}, {0x203B, 0}, {0x20AC, 500}, {0x20AD, 0}, + {0x2122, 980}, {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, + {0x2211, 713}, {0x2212, 675}, {0x2213, 0}, {0x221A, 549}, + {0x221B, 0}, {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, + {0x2266, 0}, {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 778}, + {0xF6C4, 0}, {0xFB01, 500}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_12 = +{ + "Times-Italic", + 96L, + fnt_Type1, + cc_none, + -16.333, + 0, + -498, + -307, + 1120, + 1023, + -109, + 49, + 653, + 441, + 683, + -217, + 88, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 276, + fnt_glyph_width_12, + 0, + NULL, + +}; + +/* -------- Generated from TIMESBI.TTF -------- */ + +static fnt_interwidth fnt_glyph_width_13[275] = +{ + {0x0000, 0}, {0x0020, 250}, {0x0021, 389}, {0x0022, 555}, + {0x0023, 500}, {0x0025, 833}, {0x0026, 778}, {0x0027, 278}, + {0x0028, 333}, {0x002A, 500}, {0x002B, 570}, {0x002C, 250}, + {0x002D, 333}, {0x002E, 250}, {0x002F, 278}, {0x0030, 500}, + {0x003A, 333}, {0x003C, 570}, {0x003F, 500}, {0x0040, 832}, + {0x0041, 667}, {0x0044, 722}, {0x0045, 667}, {0x0047, 722}, + {0x0048, 778}, {0x0049, 389}, {0x004A, 500}, {0x004B, 667}, + {0x004C, 611}, {0x004D, 889}, {0x004E, 722}, {0x0050, 611}, + {0x0051, 722}, {0x0052, 667}, {0x0053, 556}, {0x0054, 611}, + {0x0055, 722}, {0x0056, 667}, {0x0057, 889}, {0x0058, 667}, + {0x0059, 611}, {0x005B, 333}, {0x005C, 278}, {0x005D, 333}, + {0x005E, 570}, {0x005F, 500}, {0x0060, 333}, {0x0061, 500}, + {0x0063, 444}, {0x0064, 500}, {0x0065, 444}, {0x0066, 333}, + {0x0067, 500}, {0x0068, 556}, {0x0069, 278}, {0x006B, 500}, + {0x006C, 278}, {0x006D, 778}, {0x006E, 556}, {0x006F, 500}, + {0x0072, 389}, {0x0074, 278}, {0x0075, 556}, {0x0076, 444}, + {0x0077, 667}, {0x0078, 500}, {0x0079, 444}, {0x007A, 389}, + {0x007B, 348}, {0x007C, 220}, {0x007D, 348}, {0x007E, 570}, + {0x007F, 0}, {0x00A0, 250}, {0x00A1, 389}, {0x00A2, 500}, + {0x00A6, 220}, {0x00A7, 500}, {0x00A8, 333}, {0x00A9, 747}, + {0x00AA, 266}, {0x00AB, 500}, {0x00AC, 606}, {0x00AD, 333}, + {0x00AE, 747}, {0x00AF, 500}, {0x00B0, 400}, {0x00B1, 549}, + {0x00B2, 300}, {0x00B4, 333}, {0x00B5, 576}, {0x00B6, 500}, + {0x00B7, 250}, {0x00B8, 333}, {0x00B9, 300}, {0x00BB, 500}, + {0x00BC, 750}, {0x00BF, 500}, {0x00C0, 667}, {0x00C6, 944}, + {0x00C7, 667}, {0x00CC, 389}, {0x00D0, 722}, {0x00D7, 570}, + {0x00D8, 722}, {0x00DD, 611}, {0x00DF, 500}, {0x00E6, 722}, + {0x00E7, 444}, {0x00EC, 278}, {0x00F0, 500}, {0x00F1, 556}, + {0x00F2, 500}, {0x00F7, 549}, {0x00F8, 500}, {0x00F9, 556}, + {0x00FD, 444}, {0x00FE, 500}, {0x00FF, 444}, {0x0100, 667}, + {0x0101, 500}, {0x0102, 667}, {0x0103, 500}, {0x0104, 667}, + {0x0105, 500}, {0x0106, 667}, {0x0107, 444}, {0x0108, 0}, + {0x010C, 667}, {0x010D, 444}, {0x010E, 722}, {0x010F, 749}, + {0x0110, 722}, {0x0111, 500}, {0x0112, 667}, {0x0113, 444}, + {0x0114, 0}, {0x0116, 667}, {0x0117, 444}, {0x0118, 667}, + {0x0119, 444}, {0x011A, 667}, {0x011B, 444}, {0x011C, 0}, + {0x011E, 722}, {0x011F, 500}, {0x0120, 0}, {0x0122, 722}, + {0x0123, 500}, {0x0124, 0}, {0x0128, 389}, {0x0129, 278}, + {0x012A, 389}, {0x012B, 278}, {0x012C, 0}, {0x012E, 389}, + {0x012F, 278}, {0x0130, 389}, {0x0131, 278}, {0x0132, 0}, + {0x0136, 667}, {0x0137, 500}, {0x0139, 611}, {0x013A, 278}, + {0x013B, 611}, {0x013C, 278}, {0x013D, 611}, {0x013E, 521}, + {0x013F, 0}, {0x0141, 611}, {0x0142, 278}, {0x0143, 722}, + {0x0144, 556}, {0x0145, 722}, {0x0146, 556}, {0x0147, 722}, + {0x0148, 556}, {0x0149, 0}, {0x014A, 784}, {0x014B, 541}, + {0x014C, 722}, {0x014D, 500}, {0x014E, 0}, {0x0150, 722}, + {0x0151, 500}, {0x0152, 944}, {0x0153, 722}, {0x0154, 667}, + {0x0155, 389}, {0x0156, 667}, {0x0157, 389}, {0x0158, 667}, + {0x0159, 389}, {0x015A, 556}, {0x015B, 389}, {0x015C, 0}, + {0x015E, 556}, {0x015F, 389}, {0x0160, 556}, {0x0161, 389}, + {0x0162, 611}, {0x0163, 278}, {0x0164, 611}, {0x0165, 531}, + {0x0166, 611}, {0x0167, 278}, {0x0168, 722}, {0x0169, 556}, + {0x016A, 722}, {0x016B, 556}, {0x016C, 0}, {0x016E, 722}, + {0x016F, 556}, {0x0170, 722}, {0x0171, 556}, {0x0172, 722}, + {0x0173, 556}, {0x0174, 0}, {0x0178, 611}, {0x017A, 389}, + {0x017B, 611}, {0x017C, 389}, {0x017D, 611}, {0x017E, 389}, + {0x017F, 0}, {0x0192, 500}, {0x0193, 0}, {0x0218, 778}, + {0x021A, 611}, {0x021B, 278}, {0x021C, 0}, {0x02C6, 333}, + {0x02C8, 0}, {0x02D8, 333}, {0x02DA, 0}, {0x02DB, 333}, + {0x02DE, 0}, {0x2013, 500}, {0x2014,1000}, {0x2016, 0}, + {0x2018, 333}, {0x201B, 0}, {0x201C, 500}, {0x201F, 0}, + {0x2020, 500}, {0x2022, 350}, {0x2023, 0}, {0x2026,1000}, + {0x2027, 0}, {0x2030,1000}, {0x2031, 0}, {0x2039, 333}, + {0x203B, 0}, {0x20AC, 500}, {0x20AD, 0}, {0x2122,1000}, + {0x2123, 0}, {0x2202, 494}, {0x2203, 0}, {0x2211, 713}, + {0x2212, 606}, {0x2213, 0}, {0x221A, 549}, {0x221B, 0}, + {0x2260, 549}, {0x2261, 0}, {0x2264, 549}, {0x2266, 0}, + {0x25CA, 494}, {0x25CB, 0}, {0xF6C3, 778}, {0xF6C4, 0}, + {0xFB01, 556}, {0xFB03, 0}, {0xFFFF, 0} +}; + + +static const fnt_font_metric fnt_font_metric_13 = +{ + "Times-BoldItalic", + 262240L, + fnt_Type1, + cc_none, + -16.333, + 0, + -547, + -307, + 1206, + 1032, + -109, + 95, + 669, + 462, + 683, + -217, + 166, + 0, + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 275, + fnt_glyph_width_13, + 0, + NULL, + +}; + +/* -------- Generated from ZapfDingbats.afm -------- */ + +static fnt_glyphwidth fnt_glyph_width_14[202] = +{ + {0x0020, 32, 278}, {0x2701, 33, 974}, {0x2702, 34, 961}, + {0x2703, 35, 974}, {0x2704, 36, 980}, {0x260e, 37, 719}, + {0x2706, 38, 789}, {0x2707, 39, 790}, {0x2708, 40, 791}, + {0x2709, 41, 690}, {0x261b, 42, 960}, {0x261e, 43, 939}, + {0x270c, 44, 549}, {0x270d, 45, 855}, {0x270e, 46, 911}, + {0x270f, 47, 933}, {0x2710, 48, 911}, {0x2711, 49, 945}, + {0x2712, 50, 974}, {0x2713, 51, 755}, {0x2714, 52, 846}, + {0x2715, 53, 762}, {0x2716, 54, 761}, {0x2717, 55, 571}, + {0x2718, 56, 677}, {0x2719, 57, 763}, {0x271a, 58, 760}, + {0x271b, 59, 759}, {0x271c, 60, 754}, {0x271d, 61, 494}, + {0x271e, 62, 552}, {0x271f, 63, 537}, {0x2720, 64, 577}, + {0x2721, 65, 692}, {0x2722, 66, 786}, {0x2723, 67, 788}, + {0x2724, 68, 788}, {0x2725, 69, 790}, {0x2726, 70, 793}, + {0x2727, 71, 794}, {0x2605, 72, 816}, {0x2729, 73, 823}, + {0x272a, 74, 789}, {0x272b, 75, 841}, {0x272c, 76, 823}, + {0x272d, 77, 833}, {0x272e, 78, 816}, {0x272f, 79, 831}, + {0x2730, 80, 923}, {0x2731, 81, 744}, {0x2732, 82, 723}, + {0x2733, 83, 749}, {0x2734, 84, 790}, {0x2735, 85, 792}, + {0x2736, 86, 695}, {0x2737, 87, 776}, {0x2738, 88, 768}, + {0x2739, 89, 792}, {0x273a, 90, 759}, {0x273b, 91, 707}, + {0x273c, 92, 708}, {0x273d, 93, 682}, {0x273e, 94, 701}, + {0x273f, 95, 826}, {0x2740, 96, 815}, {0x2741, 97, 789}, + {0x2742, 98, 789}, {0x2743, 99, 707}, {0x2744, 100, 687}, + {0x2745, 101, 696}, {0x2746, 102, 689}, {0x2747, 103, 786}, + {0x2748, 104, 787}, {0x2749, 105, 713}, {0x274a, 106, 791}, + {0x274b, 107, 785}, {0x25cf, 108, 791}, {0x274d, 109, 873}, + {0x25a0, 110, 761}, {0x274f, 111, 762}, {0x2750, 112, 762}, + {0x2751, 113, 759}, {0x2752, 114, 759}, {0x25b2, 115, 892}, + {0x25bc, 116, 892}, {0x25c6, 117, 788}, {0x2756, 118, 784}, + {0x25d7, 119, 438}, {0x2758, 120, 138}, {0x2759, 121, 277}, + {0x275a, 122, 415}, {0x275b, 123, 392}, {0x275c, 124, 392}, + {0x275d, 125, 668}, {0x275e, 126, 668}, {0x2768, 128, 390}, + {0x2769, 129, 390}, {0x276a, 130, 317}, {0x276b, 131, 317}, + {0x276c, 132, 276}, {0x276d, 133, 276}, {0x276e, 134, 509}, + {0x276f, 135, 509}, {0x2770, 136, 410}, {0x2771, 137, 410}, + {0x2772, 138, 234}, {0x2773, 139, 234}, {0x2774, 140, 334}, + {0x2775, 141, 334}, {0x2761, 161, 732}, {0x2762, 162, 544}, + {0x2763, 163, 544}, {0x2764, 164, 910}, {0x2765, 165, 667}, + {0x2766, 166, 760}, {0x2767, 167, 760}, {0x2663, 168, 776}, + {0x2666, 169, 595}, {0x2665, 170, 694}, {0x2660, 171, 626}, + {0x2460, 172, 788}, {0x2461, 173, 788}, {0x2462, 174, 788}, + {0x2463, 175, 788}, {0x2464, 176, 788}, {0x2465, 177, 788}, + {0x2466, 178, 788}, {0x2467, 179, 788}, {0x2468, 180, 788}, + {0x2469, 181, 788}, {0x2776, 182, 788}, {0x2777, 183, 788}, + {0x2778, 184, 788}, {0x2779, 185, 788}, {0x277a, 186, 788}, + {0x277b, 187, 788}, {0x277c, 188, 788}, {0x277d, 189, 788}, + {0x277e, 190, 788}, {0x277f, 191, 788}, {0x2780, 192, 788}, + {0x2781, 193, 788}, {0x2782, 194, 788}, {0x2783, 195, 788}, + {0x2784, 196, 788}, {0x2785, 197, 788}, {0x2786, 198, 788}, + {0x2787, 199, 788}, {0x2788, 200, 788}, {0x2789, 201, 788}, + {0x278a, 202, 788}, {0x278b, 203, 788}, {0x278c, 204, 788}, + {0x278d, 205, 788}, {0x278e, 206, 788}, {0x278f, 207, 788}, + {0x2790, 208, 788}, {0x2791, 209, 788}, {0x2792, 210, 788}, + {0x2793, 211, 788}, {0x2794, 212, 894}, {0x2192, 213, 838}, + {0x2194, 214, 1016}, {0x2195, 215, 458}, {0x2798, 216, 748}, + {0x2799, 217, 924}, {0x279a, 218, 748}, {0x279b, 219, 918}, + {0x279c, 220, 927}, {0x279d, 221, 928}, {0x279e, 222, 928}, + {0x279f, 223, 834}, {0x27a0, 224, 873}, {0x27a1, 225, 828}, + {0x27a2, 226, 924}, {0x27a3, 227, 924}, {0x27a4, 228, 917}, + {0x27a5, 229, 930}, {0x27a6, 230, 931}, {0x27a7, 231, 463}, + {0x27a8, 232, 883}, {0x27a9, 233, 836}, {0x27aa, 234, 836}, + {0x27ab, 235, 867}, {0x27ac, 236, 867}, {0x27ad, 237, 696}, + {0x27ae, 238, 696}, {0x27af, 239, 874}, {0x27b1, 241, 874}, + {0x27b2, 242, 760}, {0x27b3, 243, 946}, {0x27b4, 244, 771}, + {0x27b5, 245, 865}, {0x27b6, 246, 771}, {0x27b7, 247, 888}, + {0x27b8, 248, 967}, {0x27b9, 249, 888}, {0x27ba, 250, 831}, + {0x27bb, 251, 873}, {0x27bc, 252, 927}, {0x27bd, 253, 970}, + {0x27be, 254, 918}, + +}; + +static const fnt_font_metric fnt_font_metric_14 = +{ + "ZapfDingbats", /* FontName */ + 4L, /* flags */ + fnt_Type1, /* font type */ + cc_none, /* Character collection */ + 0.0, /* ItalicAngle */ + 0, /* isFixedPitch */ + -1, /* llx */ + -143, /* lly */ + 981, /* urx */ + 820, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 700, /* CapHeight */ + 0, /* xHeight */ + 800, /* Ascender */ + -200, /* Descender */ + 90, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_WIDTH, + 0, + NULL, + 0, + NULL, + 202, + fnt_glyph_width_14, + +}; + +#endif /* PDF_BUILTINMETRIC_SUPPORTED */ + + +/* --------------------- Pre-installed CID fonts ---------------------- */ + +/* Font descriptors for the pre-installed CID fonts */ + +static const fnt_font_metric fnt_cid_metrics[] = +{ + + /* Acrobat 4 standard fonts */ + /* ---------------------------------------------------------- */ + { + "HeiseiKakuGo-W5", /* FontName */ + 4L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + -1 * (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -92, /* llx */ + -250, /* lly */ + 1010, /* urx */ + 922, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -221, /* Descender */ + 114, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "HeiseiMin-W3", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + -1 * (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -123, /* llx */ + -257, /* lly */ + 1001, /* urx */ + 910, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 709, /* CapHeight */ + 450, /* xHeight */ + 723, /* Ascender */ + -241, /* Descender */ + 69, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "HYGoThic-Medium", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_korean, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -6, /* llx */ + -145, /* lly */ + 1003, /* urx */ + 880, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "HYSMyeongJo-Medium", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_korean, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -0, /* llx */ + -148, /* lly */ + 1001, /* urx */ + 880, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "MHei-Medium", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_traditional_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -45, /* llx */ + -250, /* lly */ + 1015, /* urx */ + 887, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "MSung-Light", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_traditional_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -160, /* llx */ + -259, /* lly */ + 1015, /* urx */ + 888, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "STSong-Light", /* FontName */ + 4L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_simplified_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -250, /* llx */ + -143, /* lly */ + 600, /* urx */ + 857, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 857, /* CapHeight */ + 599, /* xHeight */ + 857, /* Ascender */ + -143, /* Descender */ + 91, /* StdVW */ + 91, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* Acrobat 5 standard fonts */ + /* ---------------------------------------------------------- */ + { + "HYSMyeongJoStd-Medium-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_korean, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -28, /* llx */ + -148, /* lly */ + 1001, /* urx */ + 880, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "KozMinPro-Regular-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -195, /* llx */ + -272, /* lly */ + 1110, /* urx */ + 1075, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "MSungStd-Light-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_traditional_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -160, /* llx */ + -249, /* lly */ + 1015, /* urx */ + 1071, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 553, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "STSongStd-Light-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_simplified_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -134, /* llx */ + -254, /* lly */ + 1001, /* urx */ + 905, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 737, /* CapHeight */ + 535, /* xHeight */ + 752, /* Ascender */ + -271, /* Descender */ + 58, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* Acrobat 6 standard fonts */ + /* ---------------------------------------------------------- */ + { + "AdobeMingStd-Light-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_traditional_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -38, /* llx */ + -121, /* lly */ + 1002, /* urx */ + 1002, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 731, /* CapHeight */ + 466, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 71, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "AdobeMyungjoStd-Medium-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_korean, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -28, /* llx */ + -148, /* lly */ + 1001, /* urx */ + 1001, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 719, /* CapHeight */ + 478, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 109, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "AdobeSongStd-Light-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_simplified_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -134, /* llx */ + -254, /* lly */ + 1001, /* urx */ + 1001, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 626, /* CapHeight */ + 416, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 71, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "KozGoPro-Medium-Acro", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -149, /* llx */ + -374, /* lly */ + 1254, /* urx */ + 1008, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 763, /* CapHeight */ + 549, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 109, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* Acrobat 7 standard fonts */ + /* ---------------------------------------------------------- */ + { + "KozGoPro-Medium", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -149, /* llx */ + -374, /* lly */ + 1254, /* urx */ + 1008, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 763, /* CapHeight */ + 549, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 109, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "KozMinProVI-Regular", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_japanese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -437, /* llx */ + -340, /* lly */ + 1144, /* urx */ + 1317, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 742, /* CapHeight */ + 503, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 87, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "AdobeMyungjoStd-Medium", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_korean, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -28, /* llx */ + -148, /* lly */ + 1001, /* urx */ + 880, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 719, /* CapHeight */ + 478, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 109, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "AdobeSongStd-Light", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_simplified_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -134, /* llx */ + -254, /* lly */ + 1001, /* urx */ + 905, /* ury */ + -100, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 626, /* CapHeight */ + 416, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 71, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + }, + + /* ---------------------------------------------------------- */ + { + "AdobeMingStd-Light", /* FontName */ + 6L, /* Font flags */ + fnt_CIDFontType0, /* font type */ + (int) cc_traditional_chinese, /* Character collection */ + 0.0, /* ItalicAngle */ + pdc_true, /* isFixedPitch */ + -38, /* llx */ + -121, /* lly */ + 1002, /* urx */ + 918, /* ury */ + -75, /* UnderlinePosition */ + 50, /* UnderlineThickness */ + 731, /* CapHeight */ + 466, /* xHeight */ + 880, /* Ascender */ + -120, /* Descender */ + 71, /* StdVW */ + 0, /* StdHW */ + + FNT_DEFAULT_CIDWIDTH, + 0, + NULL, + + 0, + NULL, + + 0, + (fnt_glyphwidth *) NULL, + + } +}; + +#define FNT_NUM_OF_CIDFONTS \ + ((int) (sizeof(fnt_cid_metrics)/sizeof(fnt_font_metric))) + + +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED + +/* + * PDF width arrays for glyph widths indexed by CID + * of Acrobat CJK standard fonts (see above). + * + * Format: + * + * 1 font name string, + * 4 strings for widths + * --- + * 5 (see define FNT_CIDMETRIC_INCR in ft_cid.h) + * + * Because of compiler warnings each width block must + * be divided at least into 4 parts. + * + */ + +static const char *fnt_cid_width_arrays[] = +{ + /*------------------------------------------------------------------------*/ + "HeiseiKakuGo-W5", + + "1[278 278 355 556 556 889 667 191 333 333 389 584 278 333 278\n" + "278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584\n" + "556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722\n" + "778 667 778 722 667 611 722 667 944 667 667 611 278 556 278 469\n" + "556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556\n", + + "556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 333\n" + "1000 278 1000 260 1000 333 556 556 167 1000 1000 556 1000 556 333 333\n" + "500 500 556 1000 1000 278 1000 350 222 333 1000 556 1000 1000 611]\n" + "127 137 333\n" + "140[370 556 778 1000\n", + + "365 889 278 222 611 944 611 584 737 584 737 1000 1000 333 333 556\n" + "333 834 834 834 667 667 667 667 667 667 722 667 667 667 667 278\n" + "278 278 278 722 722 778 778 778 778 778 1000 722 722 722 722 667\n" + "667 556 556 556 556 556 556 500 556 556 556 556 278 278 278 278\n", + + "556 556 556 556 556 556 556 1000 556 556 556 556 500 556 500 667\n" + "667 611 556 500 1000 500 556]\n" + "231 632 500\n" + "8718 8719 500", + + + /*------------------------------------------------------------------------*/ + "HeiseiMin-W3", + + "1[250 333 408 500 500 833 778 180 333 333 500 564 250 333 250\n" + "278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564\n" + "444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722\n" + "722 556 722 667 556 611 722 722 944 722 722 611 333 500 333 469\n" + "500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500\n", + + "500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 333\n" + "1000 278 1000 200 1000 333 500 500 167 1000 1000 500 1000 500 333 333\n" + "556 556 500 1000 1000 250 1000 350 333 444 1000 500 1000 1000 444]\n" + "127 137 333\n", + + "139[889 276 611 722 889\n" + "310 667 278 278 500 722 500 564 760 564 760 1000 1000 300 300 500\n" + "300 750 750 750 722 722 722 722 722 722 667 611 611 611 611 333\n" + "333 333 333 722 722 722 722 722 722 722 1000 722 722 722 722 722\n" + "556 444 444 444 444 444 444 444 444 444 444 444 278 278 278 278\n", + + "500 500 500 500 500 500 500 1000 500 500 500 500 500 500 500 556\n" + "722 611 500 389 980 444]\n" + "230 632 500\n" + "8718 8719 500", + + + /*------------------------------------------------------------------------*/ + "HYGoThic-Medium", + + "1[333 416 416 833 666 916 750 250 416 416 583 833 375 833 375\n" + "375 583 583 583 583 583 583 583 583 583 583 416 416 833 833 833\n", + + "583 1000 666 708 750 750 666 625 833 750 291 541 708 583 875 750\n" + "791 666 791 708 666 583 750 625 916 625 625 625 416 375 416 500\n", + + "500 500 583 625 583 625 583 375 625 583 250 250 541 250 916 625\n", + + "625 625 625 333 541 333 583 500 750 500 500 500 500 500 500 750]", + + + /*------------------------------------------------------------------------*/ + "HYSMyeongJo-Medium", + + "1[278 278 355 556 556 889 667 222 333 333 389 584 278 333 278\n" + "278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584\n", + + "556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722\n" + "778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469\n", + + "556 222 556 556 500 556 556 278 556 556 222 222 500 222 833 556\n", + + "556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584]", + + + /*------------------------------------------------------------------------*/ + "MHei-Medium", /* identical with HYSMyeongJo-Medium */ + + "1[278 278 355 556 556 889 667 222 333 333 389 584 278 333 278\n" + "278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584\n", + + "556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722\n" + "778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469\n", + + "556 222 556 556 500 556 556 278 556 556 222 222 500 222 833 556\n", + + "556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584]", + + + /*------------------------------------------------------------------------*/ + "MSung-Light", + + "1[250 250 408 668 490 875 698 250 240 240 417 667 250 313 250\n" + "520 500 500 500 500 500 500 500 500 500 500 250 250 667 667 667\n", + + "396 921 677 615 719 760 625 552 771 802 354 354 781 604 927 750\n" + "823 563 823 729 542 698 771 729 948 771 677 635 344 520 344 469\n", + + "500 250 469 521 427 521 438 271 469 531 250 250 458 240 802 531\n", + + "500 521 521 365 333 292 521 458 677 479 458 427 480 496 480 667]", + + + /*------------------------------------------------------------------------*/ + "STSong-Light", + + "1[207 270 342 467 462 797 710 239 374 374 423 605 238 375 238\n" + "334 462 462 462 462 462 462 462 462 462 462 238 238 605 605 605\n", + + "344 748 684 560 695 739 563 511 729 793 318 312 666 526 896 758\n" + "772 544 772 628 465 607 753 711 972 647 620 607 374 333 374 606\n", + + "500 239 417 503 427 529 415 264 444 518 241 230 495 228 793 527\n", + + "524 524 504 338 336 277 517 450 652 466 452 407 370 258 370 605]", + + + /*------------------------------------------------------------------------*/ + "HYSMyeongJoStd-Medium-Acro", + + "1[333 416 416 833 625 916 833 250 500 500 500 833 291 833 291\n" + "375 625 625 625 625 625 625 625 625 625 625 333 333 833 833 916\n", + + "500 1000 791 708 708 750 708 666 750 791 375 500 791 666 916 791\n" + "750 666 750 708 666 791 791 750 1000 708 708 666 500 375 500 500\n", + + "500 333 541 583 541 583 583 375 583 583 291 333 583 291 875 583\n", + + "583 583 583 458 541 375 583 583 833 625 625 500 583 583 583 750]", + + + /*------------------------------------------------------------------------*/ + "KozMinPro-Regular-Acro", + + "1[278 299 353 614 614 721 735 216 323 323 449 529 219 306 219\n" + "453 614 614 614 614 614 614 614 614 614 614 219 219 529 529 529\n" + "486 744 646 604 617 681 567 537 647 738 320 433 637 566 904 710\n" + "716 605 716 623 517 601 690 668 990 681 634 578 316 614 316 529\n" + "500 387 509 566 478 565 503 337 549 580 275 266 544 276 854 579\n" + "550 578 566 410 444 340 575 512 760 503 529 453 326 380 326 387\n" + "1000 453 1000 380 1000 299 614 614 265 1000 1000 614 1000 451 291 291\n", + + "588 589 500 1000 1000 219 1000 452 216 353 1000 451 1000 1000 486 387]\n" + "128 135 387\n" + "136[387 387 1000 880 448 566 716 903\n" + "460 805 275 276 550 886 582 529 738 529 738 1000 1000 406 406 575\n" + "406 934 934 934 646 646 646 646 646 646 617 567 567 567 567 320\n" + "320 320 320 681 710 716 716 716 716 716 1000 690 690 690 690 634\n" + "605 509 509 509 509 509 509 478 503 503 503 503 275 275 275 275\n", + + "550 579 550 550 550 550 550 1000 575 575 575 575 529 578 529 517\n" + "634 578 445 444 842 453 1000 500]\n" + "323[500 1000 500 1000 500]\n" + "328 383 500\n" + "384[500 500 500 500 500 500]\n" + "9354[614 684 1000 1000 648 899\n", + + "903 509 275 575 503 550 646 320 690 567 716 934 934 934 934 934\n" + "934 426 426 426 426 426 426 426 426 425 425 425 439 426 426 426\n" + "426 426 646 567 1000 567 320 1000 320 716 1000 690 690 690 509 503\n" + "1000 503 275 1000 275 550 1000 575 575 575 513 1000 1000 805 1000 478\n" + "1000 1000 503 1000 1000 735 1000 1000 426 1000 1000 1000 578 553 512\n" + "1000 1000 640 594 284]", + + + /*------------------------------------------------------------------------*/ + "MSungStd-Light-Acro", + + "1[250 250 408 668 490 875 698 250 240 240 417 667 250 313 250\n" + "520 500 500 500 500 500 500 500 500 500 500 250 250 667 667 667\n", + + "396 921 677 615 719 760 625 552 771 802 354 354 781 604 927 750\n" + "823 563 823 729 542 698 771 729 948 771 677 635 344 520 344 469\n", + + "500 250 469 521 427 521 438 271 469 531 250 250 458 240 802 531\n", + + "500 521 521 365 333 292 521 458 677 479 458 427 480 496 480 667]\n" + "17601 17601 500", + + + /*------------------------------------------------------------------------*/ + "STSongStd-Light-Acro", + + "1[207 270 342 467 462 797 710 239 374 374 423 605 238 375 238\n" + "334 462 462 462 462 462 462 462 462 462 462 238 238 605 605 605\n", + + "344 748 684 560 695 739 563 511 729 793 318 312 666 526 896 758\n" + "772 544 772 628 465 607 753 711 972 647 620 607 374 333 374 606\n", + + "500 239 417 503 427 529 415 264 444 518 241 230 495 228 793 527\n", + + "524 524 504 338 336 277 517 450 652 466 452 407 370 258 370 605]\n" + "22353[462 462 1000 1000 500]", + + + /*------------------------------------------------------------------------*/ + "AdobeMingStd-Light-Acro", + + "0[1000 251 347 405 739 504 758 825 281 293 294 494 620 251 373 252\n" + "309 503 503 503 503 504 503 502 503 503 504 251 251 621 621 621\n", + + "405 1042 749 673 679 679 685 671 738 736 333 494 729 696 901 720\n" + "750 674 746 672 627 769 707 777 887 709 716 616 279 309 277 352\n", + + "575 294 500 511 502 549 494 356 516 550 321 321 510 317 738 533\n" + "535 545 533 376 443 361 529 526 742 534 576 439 447 262 446 472]\n", + + "96 17600 1000\n" + "17601[639]\n" + "17602 18964 1000", + + + /*------------------------------------------------------------------------*/ + "AdobeMyungjoStd-Medium-Acro", + + "0[1000 333 416 416 833 625 916 833 250 500 500 500 833 291\n" + "833 291 375]\n", + + "17 26 625\n" + "27[333 333 833 833 916 500 1000 791 708 708 750 708 666 750 791 375\n", + + "500 791 666 916 791 750 666 750 708 666 791 791 750 1000 708 708\n" + "666 500 375 500 500 500 333 541 583 541 583 583 375 583 583 291\n", + + "333 583 291 875 583 583 583 583 458 541 375 583 583 833 625 625\n" + "500 583 583 583 750 1000 500]\n" + "98 18351 1000", + + + /*------------------------------------------------------------------------*/ + "AdobeSongStd-Light-Acro", + + "0[1000 207 270 342 467 462 797 710 239 374 374 423 605 238 375\n" + "238 334]\n" + "17 26 462\n", + + "27[238 238 605 605 605 344 748 684 560 695 739 563 511 729 793 318\n" + "312 666 526 896 758 772 544 772 628 465 607 753 711 972 647 620\n" + "607 374 333 374 606 500 239 417 503 427 529 415 264 444 518 241\n", + + + "230 495 228 793 527 524 524 504 338 336 277 517 450 652 466 452\n" + "407 370 258 370 605]\n" + "96 22352 1000\n", + + "22353[462 462 1000 1000 500]\n" + "22358 29063 1000", + + + /*------------------------------------------------------------------------*/ + "KozGoPro-Medium-Acro", + + "0[1000 224 266 392 551 562 883 677 213 322 322 470 677 247 343\n" + "245 370]\n" + "17 26 562\n" + "27[245 247 677 677 677 447 808 661 602 610 708 535 528 689 703 275\n" + "404 602 514 871 708 727 585 727 595 539 541 696 619 922 612 591\n" + "584 322 562 322 677 568 340 532 612 475 608 543 332 603 601 265\n" + "276 524 264 901 601 590 612 607 367 433 369 597 527 800 511 518\n" + "468 321 273 321 341 1000 362 1000 273 1000 266 562 562 456 1000 1000\n", + + "562 1000 472 283 283 587 588 568 1000 1000 247 1000 330 239 418 1000\n" + "472 1000 1000 447 340 340 340 340 340 340 455 340 340 340 340 1136\n" + "857 384 519 727 952 398 834 264 275 590 918 605 677 769 677 473\n" + "1000 1000 347 340 599 284 845 845 845 661 661 661 661 661 661 610\n" + "535 535 535 535 275 275 275 275 715 708 727 727 727 727 727 1000\n" + "696 696 696 696 591 584 532 532 532 532 532 532 475 543 543 543\n", + + "543 264 264 264 264 584 601 590 590 590 590 590 1000 597 597 597\n" + "597 518 612 518 539 591 584 446 433 683 468 1000 500]\n" + "232 322 1000\n" + "323[500 1000 500 1000]\n" + "327 389 500\n" + "390 9353 1000\n" + "9354[562 753 1000 1000 650 909 909 532 264 597 543 590 661 275 696 535\n", + + "727 845 845 845 845 845 845 375 387 345 369 328 366 364 375 284\n" + "347 340 387 345 369 328 366 364 661 535 1000 535 275 1000 275 727\n" + "1000 696 696 696 532 543 1000 543 264 1000 264 590 1000 597 597 597\n" + "596 1000 1000 834 1000 475 1000 1000 543 1000 1000 759 1000 1000 478\n" + "1000 1000 1000 602 579 527 1000 1000 509 465 280]\n" + "9444 15443 1000", + + + /*------------------------------------------------------------------------*/ + "KozGoPro-Medium", + + "1[224 266 392 551 562 883 677 213 322 322 470 677 247 343 245 370]\n" + "17 26 562\n" + "27[245 247 677 677 677 447 808 661 602 610 708 535 528 689 703\n" + "275 404 602 514 871 708 727 585 727 595 539 541 696 619 922 612\n" + "591 584 322 562 322 677 568 340 532 612 475 608 543 332 603 601\n" + "265 276 524 264 901 601 590 612 607 367 433 369 597 527 800 511\n" + "518 468 321 273 321 341 241 362 241 273 677 266 562 562 456 562\n" + "571 562 416 472 283 283 587 588 568 545 545 247 561 330 239 418\n" + "416 472 1136 1288 447 340 340 340 340 340 340 455 340 340 340 340\n" + "1136 857 384 519 727 952 398 834 264 275 590 918 605 677 769 677\n" + "473 361 677 347 340 599 284 845 845 845 661 661 661 661 661 661\n" + "610 535 535 535 535 275 275 275 275 715 708 727 727 727 727 727\n", + + "677 696 696 696 696 591 584 532 532 532 532 532 532 475 543 543\n" + "543 543 264 264 264 264 584 601 590 590 590 590 590 677 597 597\n" + "597 597 518 612 518 539 591 584 446 433 683 468 562]\n" + "231 632 500\n" + "8718[500 500]\n" + "9354[562 753 245 436 650 909 909 532 264 597 543 590 661 275 696\n" + "535 727 845 845 845 845 845 845 375 387 345 369 328 366 364 375\n" + "284 347 340 387 345 369 328 366 364 661 535 535 535 275 275 275\n" + "727 727 696 696 696 532 543 543 543 264 264 264 590 590 597 597\n" + "597 596 596 596 834 834 475 475 475 543 543 543 759 759 759 478\n" + "478 478 276 602 579 527 527 527 509 465 280 197 270 359 545 546\n" + "869 664 188 322 322 469 676 249 343 249 359 545]\n", + + "9461 9469 546\n" + "9470[249 249 676 676 676 429 791 620 573 581 688 511 504 665 681\n" + "269 395 572 477 844 677 709 555 709 573 509 515 663 593 898 565\n" + "562 557 322 546 322 676 567 427 566 571 447 570 498 320 567 577\n" + "258 254 507 257 870 577 564 572 568 359 409 343 572 500 767 486\n" + "487 448 322 245 322 427 228 363 228 245 676 269 546 546 442 546\n" + "559 546 404 465 275 275 562 562 568 533 534 249 550 326 228 404\n" + "404 464 1136 1250 429 427 427 427 427 427 427 423 427 427 427 427\n" + "1136 835 396 492 709 923 388 781 258 270 567 858 592 677 765 677\n" + "443 361 677 358 354 573 343 840 840 840 620 620 620 620 620 620\n" + "581 511 511 511 511 269 269 269 269 700 677 709 709 709 709 709\n", + + "677 663 663 663 663 562 555 566 566 566 566 566 566 447 498 498\n" + "498 498 258 258 258 258 562 577 564 564 564 564 564 677 572 572\n" + "572 572 487 573 487 509 562 557 446 409 735 448 546 546 726 241\n" + "432 629 868 868 566 258 572 498 564 620 269 663 511 709 840 840\n" + "840 840 840 840 362 361 355 361 354 363 360 362 343 358 354 361\n" + "355 362 354 363 360 620 511 511 511 269 269 269 709 709 663 663\n" + "663 566 498 498 498 258 258 258 564 564 572 572 572]\n" + "9738 9757 250\n" + "9758 9778 333\n" + "12063 12087 500\n", + + + /*------------------------------------------------------------------------*/ + "KozMinProVI-Regular", + + "1[278 299 353 614 614 721 735 216 323 323 449 529 219 306 219\n" + "453]\n" + "17 26 614\n" + "27[219 219 529 529 529 486 744 646 604 617 681 567 537 647 738\n" + "320 433 637 566 904 710 716 605 716 623 517 601 690 668 990 681\n" + "634 578 316 614 316 529 500 387 509 566 478 565 503 337 549 580\n" + "275 266 544 276 854 579 550 578 566 410 444 340 575 512 760 503\n" + "529 453 326 380 326 387 216 453 216 380 529 299 614 614 265 614\n" + "475 614 353 451 291 291 588 589 500 476 476 219 494 452 216 353\n" + "353 451]\n" + "125[1075 486]\n" + "127 137 387\n" + "139[880 448 566 716 903 460 805 275 276 550 886 582 529 738 529\n" + "738 357 529 406 406 575 406 934 934 934 646 646 646 646 646 646\n" + "617 567 567 567 567 320 320 320 320 681 710 716 716 716 716 716\n" + "529 690 690 690 690 634 605 509 509 509 509 509 509 478 503 503\n" + "503 503 275 275 275 275 550 579 550 550 550 550 550 529 575 575\n" + "575 575 529 578 529 517 634 578 445 444 842 453 614]\n" + "231 632 500\n" + "8718[500 500]\n" + "9354[614 684 216 353 648 899 903 509 275 575 503 550 646 320 690\n" + "567 716 934 934 934 934 934 934]\n" + "9377 9384 426\n" + "9385[425 425 425 439 426 426 426 426 426 646 567 567 567 320 320\n" + "320 716 716 690 690 690 509 503 503 503 275 275 275 550 550 575\n" + "575 575 542 542 542 816 816 486 486 486 517 517 517 758 758 758\n" + "426 426 426 286 597 568 522 522 522 640 611 312 257 281 288 546\n" + "546 703 705 160 312 305 389 545 200 309 200 438]\n" + "9460 9469 546\n", + + "9470[200 200 545 545 545 471 744 607 572 563 650 550 516 622 696\n" + "312 314 603 524 848 665 644 561 645 583 491 566 643 581 872 616\n" + "537 516 312 546 312 472 464 400 548 530 447 558 460 301 486 564\n" + "283 258 509 265 834 578 521 554 551 390 410 335 565 476 717 525\n" + "464 456 312 339 312 400 179 422 177 339 545 281 546 546 248 546\n" + "491 570 310 440 278 279 556 563 586 403 403 207 500 440 170 307\n" + "310 440 786 1009 471 367 400 400 400 400 400 400 364 400 365 400\n" + "1012 849 394 544 644 889 377 744 283 285 521 808 545 504 703 545\n" + "703 324 504 397 397 557 397 859 859 859 607 607 607 607 607 607\n" + "562 550 550 550 550 312 312 312 312 662 665 644 644 644 644 644\n" + "497 643 643 643 643 537 576 548 548 548 548 548 548 446 460 460\n" + "460 460 283 283 283 283 522 578 521 521 521 521 521 545 565 565\n" + "565 565 464 540 464 491 537 516 418 410 842 456 546 563 627 196\n" + "289 560 828 835 548 283 565 460 521 607 312 643 550 644 859 859\n" + "859 859 859 859]\n" + "9697 9713 397\n" + "9714[607 550 550 550 312 312 312 644 644 643 643 643 548 460 460\n" + "460 283 283 283 521 521 565 565 565]\n" + "9738 9757 250\n" + "9758 9778 333\n" + "12063 12087 500\n" + "15449[670 810 640 760]\n" + "15455[980 529 529 529 619 529 891]\n" + "15464[529 529 529 529 534 534 566 566 530 529 529 529 529 581 529\n" + "529 533 533 738 853 676 533 882 882 882 716 716 600 529 589 688\n" + "529 529 559 559 594 619 522 529 468 721 529 529 529 525 529 529\n" + "661 529 660 564 684 500 790 940 870]\n" + "15521[630 740 740 900 840 980]\n" + "15529[900 940 710 870 970]\n" + "15535[820 930 840 940 850 850 960 960]\n" + "15545[960 980 940 970 910 950 870 980 980 910 930 820 850 980 950]\n" + "15562[970 980 980 980]\n" + "15575[980 990 990 880]\n" + "15581[960 850 860]\n", + + "15585[840 950 740 870 830 760 890 990 900 870 990 970 980 950 960]\n" + "15601[850 830 950 930 810 980 910 780 890 760 880 790 870 830 980\n" + "830 900 900 950 940 950 820 910 930 960 880 930 960 980 920 940\n" + "920 950 970 980 890 930 860 930 960 990 820 920 960 930 970 760\n" + "780 920 970 830 950 830 990 990 990 840 890 890 900 940 940 980\n" + "980 980 970 970 970 960 800 950 820 960 810 950 810 990 730 850\n" + "880 760 990 910 920 770 870 970 980 840 920 950 810 800 940 950\n" + "900 960 910 960 960 750 740 860 850 640 690 900 750 740 840 770\n" + "800 790 730 640 860 760 790]\n" + "15723[770 780 529 529 934 841 904 854 710 579 575 575 575 575 646\n" + "387 566 517 517 601 578 578 509 387 313 444 387 444 340 453 387\n" + "453 623 646 566 617 617 567 681 710 710 716 623 690 601 410 509\n" + "276 478 478 503 605 565 579 579 550 410 575 340 387 617 647 738\n" + "433 517 690 478 549 580 266 444 575 869 537 421 364 593 429 310\n" + "573 594 432 452 462 403 275 286 597 285 526 576 876 575 598 384\n" + "384 598 725 421 579 578 300 580 664 293 593 517 426 524 530 876\n" + "564 565 556 775 594 384 384 500 517 414 597 0 238 238 288 558\n" + "391]\n", + + "15851 15857 421\n" + "15858 15866 0\n" + "15867[393]\n" + "15868 15879 0\n" + "15880[468 624 624 541 484 367 580 738 635 555 505 546 598 500 447\n" + "290 474 310 331 220 466 632 976 529 529 882 882 882 446 526 544\n" + "431 627 500 859 848 834 665 578 565 565 565 565 607 524 491 491\n" + "566 516 516 548 265 410 410 335 456 456 583 607 524 563 563 550\n" + "650 665 665 644 583 643 566 390 548 265 447 447 460 558 558 578\n" + "578 521 390 565 335 563 622 696 314 491 643 447 486 564 258 410\n" + "565]\n" + "20317[386 386 458 446 807 677 734 739 563 692 598 514 538 302 575\n" + "337 616 564 645 645 645 314 314 630 563 563 709 618 689 689 689\n" + "689 689 990 633 476 499 546 546 546 270 538 272 272 575 405 570\n" + "757 526 903 669 723 589 589 589 400 400 373 390 732 657 691 613\n" + "521 628 563 534 505 272 574 331 560 546 619 619 619 306 306 597\n" + "521 521 662 576 641 641 641 641 641 867 531 445 457 483 483 483\n" + "279 505 262 262 574 385 561 714 460 1010 601 743 545 545 643]\n", + + + /*------------------------------------------------------------------------*/ + "AdobeMyungjoStd-Medium", + + "1[333 416 416 833 625 916 833 250 500 500 500 833 291 833 291\n" + "375]\n" + "17 26 625\n", + + "27[333 333 833 833 916 500]\n" + "34[791 708 708 750 708 666 750 791 375 500 791 666 916 791 750\n", + + "666 750 708 666 791 791 750]\n" + "57[708 708 666 500 375 500 500 500 333 541 583 541 583 583 375\n", + + "583 583 291 333 583 291 875 583 583 583 583 458 541 375 583 583\n" + "833 625 625 500 583 583 583 750]\n" + "97[500]\n" + "8094 8190 500\n", + + + /*------------------------------------------------------------------------*/ + "AdobeSongStd-Light", + + "1[207 270 342 467 462 797 710 239 374 374 423 605 238 375 238\n" + "334]\n" + "17 26 462\n", + + "27[238 238 605 605 605 344 748 684 560 695 739 563 511 729 793 \n" + "318 312 666 526 896 758 772 544 772 628 465 607 753 711 972 647\n", + + "620 607 374 333 374 606 500 239 417 503 427 529 415 264 444 518\n" + "241 230 495 228 793 527 524 524 504 338 336 277 517 450 652 466\n", + + "452 407 370 258 370 605]\n" + "814 939 500\n" + "7712[517 684 723]\n" + "7716[500]\n" + "22353[462 462 500 500 500]\n", + + + /*------------------------------------------------------------------------*/ + "AdobeMingStd-Light", + + "1[251 347 405 739 504 758 825 281 293 294 494 620 251 373 252\n" + "309 503 503 503 503 504 503 502 503 503 504 251 251 621 621 621\n", + + "405 1042 749 673 679 679 685 671 738 736 333 494 729 696 901 720\n" + "750 674 746 672 627 769 707 777 887 709 716 616 279 309 277 352\n", + + "575 294 500 511 502 549 494 356 516 550 321 321 510 317 738 533\n" + "535 545 533 376 443 361 529 526 742 534 576 439 447 262 446 472]\n", + + "13648 13742 500\n" + "17601[639]\n" + "17603[500]\n" +}; + +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ + +#endif /* FT_COREMETR_H */ diff --git a/src/pdflib/font/ft_font.c b/src/pdflib/font/ft_font.c new file mode 100644 index 0000000..53a39a9 --- /dev/null +++ b/src/pdflib/font/ft_font.c @@ -0,0 +1,532 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_font.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT basic font functions + * + */ + +#define FT_FONT_C + +#include "ft_font.h" + + +static pdc_error_info fnt_errors[] = +{ +#define fnt_genInfo 1 +#include "ft_generr.h" +}; + +#define N_FNT_ERRORS (sizeof fnt_errors / sizeof (pdc_error_info)) + +void +fnt_register_errtab(pdc_core *pdc) +{ + pdc_register_errtab(pdc, PDC_ET_FONT, fnt_errors, N_FNT_ERRORS); +} + +static void +fnt_init_font_metric(fnt_font_metric *metric) +{ + metric->name = NULL; + metric->flags = 0L; + metric->type = fnt_unknownType; + metric->charcoll = (int) cc_none; + + /* + * Fill in some reasonable default values in global font info in + * case they're missing from the metrics data. + */ + metric->italicAngle = 0; + metric->isFixedPitch = pdc_false; + metric->llx = FNT_MISSING_FONTVAL; + metric->lly = FNT_MISSING_FONTVAL; + metric->urx = FNT_MISSING_FONTVAL; + metric->ury = FNT_MISSING_FONTVAL; + metric->underlinePosition = -100; + metric->underlineThickness = FNT_DEFAULT_UNDERLINEWIDTH; + metric->ascender = FNT_MISSING_FONTVAL; + metric->descender = FNT_MISSING_FONTVAL; + metric->capHeight = FNT_MISSING_FONTVAL; + metric->xHeight = FNT_MISSING_FONTVAL; + metric->StdHW = 0; + metric->StdVW = 0; + + metric->defwidth = FNT_DEFAULT_WIDTH; + metric->numwidths = 0; + metric->widths = NULL; + metric->numinters = 0; + metric->ciw = NULL; + metric->numglwidths = 0; + metric->glw = NULL; + +} + +void +fnt_init_font(fnt_font *font) +{ + fnt_init_font_metric(&font->m); + + font->name = NULL; + font->utf8name = NULL; + font->filename = NULL; + font->isstdfont = pdc_false; + font->ishostfont = pdc_false; + font->issymbfont = pdc_true; + font->hasdescr = pdc_false; + font->vertical = pdc_false; + font->spacechar = 0; + font->spacewidth = 0; + font->linegap = FNT_MISSING_FONTVAL; + font->weight = 0; + font->vertical = pdc_false; + pdc_identity_matrix(&font->matrix); + font->bbox.llx = 0; + font->bbox.lly = 0; + font->bbox.urx = 0; + font->bbox.ury = 0; + font->fsscale = 1.0; + font->enc = pdc_invalidenc; + font->numglyphs = 0; + font->numcodes = 0; + font->gid2code = NULL; + font->code2gid = NULL; + font->embedded = pdc_false; + font->cmapname = NULL; + font->imgname = NULL; + font->filelen = 0; + font->img = NULL; +} + +static void +fnt_cleanup_font_metric(pdc_core *pdc, fnt_font_metric *metric) +{ + if (metric->name != NULL) + { + pdc_free(pdc, metric->name); + metric->name = NULL; + } + + if (metric->widths != NULL) + { + pdc_free(pdc, metric->widths); + metric->widths = NULL; + } + + if (metric->ciw != NULL) + { + pdc_free(pdc, metric->ciw); + metric->ciw = NULL; + } + + if (metric->glw != NULL) + { + pdc_free(pdc, metric->glw); + metric->glw = NULL; + } + + +} + +void +fnt_cleanup_fontimg(pdc_core *pdc, fnt_font *font) +{ + if (font->img != NULL && font->imgname == NULL) + { + pdc_free(pdc, font->img); + font->img = NULL; + } + + if (font->imgname != NULL) + { + pdc_free(pdc, font->imgname); + font->imgname = NULL; + } +} + +void +fnt_cleanup_font(pdc_core *pdc, fnt_font *font) +{ + int i = 0; + + (void) i; + + fnt_cleanup_font_metric(pdc, &font->m); + + if (font->name != NULL) + { + pdc_free(pdc, font->name); + font->name = NULL; + } + + if (font->utf8name != NULL) + { + pdc_free(pdc, font->utf8name); + font->utf8name = NULL; + } + + if (font->filename != NULL) + { + pdc_free(pdc, font->filename); + font->filename = NULL; + } + + /* delete font specific encoding vector */ + if (font->enc >= pdc_firstvarenc) + { + pdc_encodingvector *ev = pdc_get_encoding_vector(pdc, font->enc); + + if (ev != NULL && ev->flags & PDC_ENC_FONT) + pdc_remove_encoding_vector(pdc, (int) font->enc); + } + + if (font->gid2code != NULL) + { + pdc_free(pdc, font->gid2code); + font->gid2code = NULL; + } + + if (font->code2gid != NULL) + { + pdc_free(pdc, font->code2gid); + font->code2gid = NULL; + } + + + + if (font->cmapname != NULL) + { + pdc_free(pdc, font->cmapname); + font->cmapname = NULL; + } + + + fnt_cleanup_fontimg(pdc, font); +} + +/* + * we assume: + * code!=0 --> gid=0 --> gid=-1 or code=0 <--> gid=0 + * + */ +int +fnt_get_glyphid(int code, fnt_font *font) +{ + if (code >= 0 && code < font->numcodes) + { + if (font->code2gid != NULL) + { + int gid = font->code2gid[code]; + + if (gid) + return gid; + } + else + { + /* this is temporary. for Type1 fonts there is no information + * about glyphs at present. we assume identity code = glyph id. + */ + return code; + } + } + + if (!code) + return 0; + + return -1; +} + +/* + * we assume: + * gid!=0 --> code=0 --> code=-1 or gid=0 <--> code=0 + * + */ +int +fnt_get_code(int gid, fnt_font *font) +{ + if (gid >= 0 && gid < font->numglyphs) + { + if (font->gid2code != NULL) + { + int code = font->gid2code[gid]; + + if (code) + return code; + } + } + + if (!gid) + return 0; + + return -1; +} + +int +fnt_get_glyphwidth(int code, fnt_font *font) +{ + int i; + + if (font->m.widths != NULL) + { + if (code < font->m.numwidths) + return font->m.widths[code]; + } + else if (font->m.ciw != NULL) + { + fnt_interwidth *wd = font->m.ciw; + int lo = 0; + int hi = font->m.numinters - 1; + + while (lo < hi) + { + i = (lo + hi) / 2; + + if (code >= wd[i].startcode && code < wd[i+1].startcode) + return (int) wd[i].width; + + if (code < wd[i].startcode) + hi = i; + else + lo = i + 1; + } + } + else if (font->m.glw != NULL) + { + for (i = 0; i < font->m.numglwidths; i++) + { + if (font->m.glw[i].unicode == (pdc_ushort) code) + { + return font->m.glw[i].width; + } + } + } + + return FNT_MISSING_WIDTH; +} + +void +fnt_font_logg_widths(pdc_core *pdc, fnt_font *font) +{ + if (font != NULL && + pdc_logg_is_enabled(pdc, 2, trc_font)) + { + int code, width; + + for (code = 0; code < PDC_NUM_UNIVAL; code++) + { + width = fnt_get_glyphwidth(code, font); + if (width == FNT_MISSING_WIDTH) + break; + pdc_logg(pdc, + "\t\tWidth[%d]: %d\n", code, width); + } + } +} + +static const pdc_keyconn pdf_fonttype_pdfkeylist[] = +{ + {"Type0", fnt_Type0}, + {"Type1", fnt_Type1}, + {"MMType1", fnt_MMType1}, + {"TrueType", fnt_TrueType}, + {"CIDFontType2", fnt_CIDFontType2}, + {"Type1C", fnt_Type1C}, + {"CIDFontType0", fnt_CIDFontType0}, + {"CIDFontType0C", fnt_CIDFontType0C}, + {"OpenType", fnt_OpenType}, + {"OpenType", fnt_OpenTypeC}, + {"Type3", fnt_Type3}, + {"(unknown)", fnt_unknownType}, + {NULL, 0} +}; + +int +fnt_get_pdf_fonttype_code(const char *typenam) +{ + int type = pdc_get_keycode(typenam, pdf_fonttype_pdfkeylist); + return (type != PDC_KEY_NOTFOUND) ? type : fnt_unknownType; +} + +const char * +fnt_get_pdf_fonttype_name(int typecode) +{ + const char *name = pdc_get_keyword(typecode, pdf_fonttype_pdfkeylist); + return name ? name : ""; +} + +static const pdc_keyconn pdf_fonttype_descrkeylist[] = +{ + /* Acrobat 7 names for comparison */ + {"Composite", fnt_Type0}, /* - */ + {"Type 1", fnt_Type1}, /* Type 1 */ + {"Multiple Master", fnt_MMType1}, /* MM */ + {"TrueType", fnt_TrueType}, /* TrueType */ + {"TrueType (CID)", fnt_CIDFontType2}, /* TrueType (CID) */ + {"Type 1 CFF", fnt_Type1C}, /* Type 1 */ + {"Type 1 (CID)", fnt_CIDFontType0}, /* Type 1 (CID) */ + {"Type 1 CFF (CID)",fnt_CIDFontType0C}, /* Type 1 (CID) */ + {"OpenType", fnt_OpenType}, /* OpenType */ + {"OpenType", fnt_OpenTypeC}, + {"Type 3", fnt_Type3}, /* Type 3 */ + {"(unknown)", fnt_unknownType}, + {NULL, 0} +}; + +const char * +fnt_get_pdf_fonttype_desc(int typecode) +{ + const char *name = pdc_get_keyword(typecode, pdf_fonttype_descrkeylist); + return name ? name : ""; +} + +pdc_encodingvector * +fnt_create_font_ev(pdc_core *pdc, fnt_font *font) +{ + pdc_encodingvector *ev = NULL; + char encname[128]; + + pdc->uniqueno++; + sprintf(encname, "encoding_%s_%d", font->name, pdc->uniqueno); + ev = pdc_new_encoding(pdc, encname); + pdc_insert_encoding_vector(pdc, ev); + font->enc = pdc_find_encoding(pdc, encname); + ev->flags |= PDC_ENC_FONT; + + return ev; +} + +int +fnt_check_weight(int weight) +{ + if (weight == PDC_KEY_NOTFOUND) + weight = FNT_FW_NORMAL; + + if (weight > 1000) + weight = 1000; + + if (weight <= 10) + weight *= 100; + else + weight = 100 * (weight / 100); + + return weight; +} + +static const pdc_keyconn fnt_fontweight_keylist[] = +{ + {"none", FNT_FW_DONTCARE}, + {"thin", FNT_FW_THIN}, + {"extralight", FNT_FW_EXTRALIGHT}, + {"ultralight", FNT_FW_ULTRALIGHT}, + {"light", FNT_FW_LIGHT}, + {"normal", FNT_FW_NORMAL}, + {"regular", FNT_FW_REGULAR}, + {"", FNT_FW_REGULAR}, + {"medium", FNT_FW_MEDIUM}, + {"semibold", FNT_FW_SEMIBOLD}, + {"semi", FNT_FW_SEMIBOLD}, + {"demibold", FNT_FW_DEMIBOLD}, + {"bold", FNT_FW_BOLD}, + {"extrabold", FNT_FW_EXTRABOLD}, + {"extra", FNT_FW_EXTRABOLD}, + {"ultrabold", FNT_FW_ULTRABOLD}, + {"heavy", FNT_FW_HEAVY}, + {"black", FNT_FW_BLACK}, + {NULL, 0} +}; + +int +fnt_weightname2weight(const char *weightname) +{ + return pdc_get_keycode_ci(weightname, fnt_fontweight_keylist); +} + +const char * +fnt_weight2weightname(int weight) +{ + return pdc_get_keyword(weight, fnt_fontweight_keylist); +} + +int +fnt_macfontstyle2weight(int macfontstyle) +{ + return (macfontstyle & (1<<0)) ? FNT_FW_BOLD : FNT_FW_NORMAL; +} + +#define FNT_STEMV_WEIGHT 65.0 + +int +fnt_weight2stemv(int weight) +{ + double w = weight / FNT_STEMV_WEIGHT; + return (int) (FNT_STEMV_MIN + w * w + 0.5); +} + +int +fnt_stemv2weight(int stemv) +{ + double w; + int weight = 0; + + w = (double) (stemv - FNT_STEMV_MIN); + if (w > 0) + weight = (int) (FNT_STEMV_WEIGHT * sqrt(w) + 0.5); + + return weight; +} + +void +fnt_font_logg_protocol(pdc_core *pdc, fnt_font *font) +{ + if (font != NULL && + pdc_logg_is_enabled(pdc, 2, trc_font)) + { + const char *wname = fnt_weight2weightname(font->weight); + char dwname[16]; + + dwname[0] = 0; + if (wname && *wname) + sprintf(dwname, " (%s)", wname); + + pdc_logg(pdc, + "\n" + "\t\tFont type: %s\n" + "\t\tFlags: %d\n" + "\t\tFontBBox: %g,%g %g,%g\n" + "\t\titalicAngle: %g\n" + "\t\tisFixedPitch: %d\n" + "\t\tunderlinePosition: %d\n" + "\t\tunderlineThickness: %d\n" + "\t\tcapHeight: %d\n" + "\t\txHeight: %d\n" + "\t\tascender: %d\n" + "\t\tdescender: %d\n" + "\t\tlinegap: %d\n" + "\t\tweight: %d%s\n" + "\t\tStdVW: %d\n" + "\t\tStdHW: %d\n" + "\t\tdefWidth: %d\n", + fnt_get_pdf_fonttype_name(font->m.type), + font->m.flags, + font->m.llx, font->m.lly, font->m.urx, font->m.ury, + font->m.italicAngle, font->m.isFixedPitch, + font->m.underlinePosition, font->m.underlineThickness, + font->m.capHeight, font->m.xHeight, font->m.ascender, + font->m.descender, font->linegap, font->weight, + dwname, + font->m.StdVW, font->m.StdHW, + font->m.defwidth); + } +} + + diff --git a/src/pdflib/font/ft_font.h b/src/pdflib/font/ft_font.h new file mode 100644 index 0000000..34f2a0b --- /dev/null +++ b/src/pdflib/font/ft_font.h @@ -0,0 +1,267 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_font.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Header file for font handling + * + */ + +#ifndef FT_FONT_H +#define FT_FONT_H + +#include "pc_util.h" +#include "pc_geom.h" +#include "pc_file.h" +#include "ft_cid.h" + +#define FNT_DEFAULT_WIDTH 250 /* some reasonable default */ +#define FNT_DEFAULT_CIDWIDTH 1000 /* for CID fonts */ +#define FNT_MISSING_WIDTH -1234567890 /* missing width value */ + +#define FNT_DEFAULT_UNDERLINEWIDTH 50 /* default value of underlineThickness*/ + +#define FNT_MAX_METRICS 2048.0 /* maximal font metrics value */ + +/* + * these are the font weight values of Microsoft + * see LOGFONT structure member lfWeight + */ +#define FNT_FW_DONTCARE 0 +#define FNT_FW_THIN 100 +#define FNT_FW_EXTRALIGHT 200 +#define FNT_FW_ULTRALIGHT 200 +#define FNT_FW_LIGHT 300 +#define FNT_FW_NORMAL 400 +#define FNT_FW_REGULAR 400 +#define FNT_FW_MEDIUM 500 +#define FNT_FW_SEMIBOLD 600 +#define FNT_FW_DEMIBOLD 600 +#define FNT_FW_BOLD 700 +#define FNT_FW_EXTRABOLD 800 +#define FNT_FW_ULTRABOLD 800 +#define FNT_FW_HEAVY 900 +#define FNT_FW_BLACK 900 + +/* + * these defaults are used when the stem value + * must be derived from the name (unused) + */ +#define FNT_STEMV_MIN 50 /* minimum StemV value */ +#define FNT_STEMV_LIGHT 71 /* light StemV value */ +#define FNT_STEMV_NORMAL 109 /* normal StemV value */ +#define FNT_STEMV_MEDIUM 125 /* mediumbold StemV value */ +#define FNT_STEMV_SEMIBOLD 135 /* semibold StemV value */ +#define FNT_STEMV_BOLD 165 /* bold StemV value */ +#define FNT_STEMV_EXTRABOLD 201 /* extrabold StemV value */ +#define FNT_STEMV_BLACK 241 /* black StemV value */ + +/* + * Bit positions for the font descriptor flag + */ +#define FNT_FIXEDWIDTH (long) (1L<<0) +#define FNT_SERIF (long) (1L<<1) +#define FNT_SYMBOL (long) (1L<<2) +#define FNT_SCRIPT (long) (1L<<3) +#define FNT_ADOBESTANDARD (long) (1L<<5) +#define FNT_ITALIC (long) (1L<<6) +#define FNT_SMALLCAPS (long) (1L<<17) +#define FNT_FORCEBOLD (long) (1L<<18) + +#define FNT_DEF_ITALICANGLE -12 /* default italic angle */ +#define FNT_MISSING_FONTVAL PDC_SHRT_MIN /* missing font value */ + +/* start sequence of PFA files */ +#define FNT_PFA_STARTSEQU "%!PS" + +/* Font types */ +typedef enum +{ + fnt_Type0, /* Type0 fonts */ + fnt_Type1, /* Type1 fonts */ + fnt_MMType1, /* Multiple master fonts */ + fnt_TrueType, /* TrueType fonts for 1-byte encoding */ + fnt_CIDFontType2, /* TrueType fonts for 2-byte encoding */ + fnt_Type1C, /* CFF PostScript fonts for 1-byte encoding */ + fnt_CIDFontType0, /* OpenType fonts with CFF_ table for 2-byte encoding */ + fnt_CIDFontType0C, /* CFF PostScript fonts for 2-byte encoding */ + fnt_OpenType, /* OpenType fonts for 1-byte encoding */ + fnt_OpenTypeC, /* OpenType fonts for 2-byte encoding */ + fnt_Type3, /* Type3 fonts */ + fnt_unknownType /* for initialization only */ +} +fnt_fonttype; + +/* Font styles */ +typedef enum +{ + fnt_Normal, + fnt_Bold, + fnt_Italic, + fnt_BoldItalic +} +fnt_fontstyle; + +typedef struct fnt_interwidth_s fnt_interwidth; +typedef struct fnt_interwidth4_s fnt_interwidth4; +typedef struct fnt_glyphwidth_s fnt_glyphwidth; +typedef struct fnt_font_metric_s fnt_font_metric; +typedef struct fnt_font_s fnt_font; + +/* Code interval for glyph width */ +struct fnt_interwidth_s +{ + pdc_ushort startcode; /* start code of interval */ + pdc_short width; /* width of glyphs in the code interval */ +}; + +struct fnt_interwidth4_s +{ + int startcode; /* start UTF-32 Unicode of interval */ + pdc_short width; /* width of glyphs in the code interval */ +}; + +/* Code and Unicode for glyph width */ +struct fnt_glyphwidth_s +{ + pdc_ushort unicode; /* UTF-16 Unicode of glyph */ + pdc_short code; /* builtin 8-bit code */ + pdc_short width; /* glyph width */ +}; + + +/* Font metric exchange structure */ +struct fnt_font_metric_s +{ + char *name; /* font name (/FontName) */ + pdc_ulong flags; /* font flags of font descriptor */ + fnt_fonttype type; /* type of font */ + int charcoll; /* supported CID character collection */ + /* < 0: Halfwidth Latin-1 character */ + /* font metric */ + pdc_scalar italicAngle; /* AFM key: ItalicAngle */ + int isFixedPitch; /* AFM key: IsFixedPitch */ + pdc_scalar llx; /* AFM key: FontBBox */ + pdc_scalar lly; /* AFM key: FontBBox */ + pdc_scalar urx; /* AFM key: FontBBox */ + pdc_scalar ury; /* AFM key: FontBBox */ + int underlinePosition; /* AFM key: UnderlinePosition */ + int underlineThickness; /* AFM key: UnderlineThickness */ + int capHeight; /* AFM key: CapHeight */ + int xHeight; /* AFM key: XHeight */ + int ascender; /* AFM key: Ascender */ + int descender; /* AFM key: Descender */ + int StdVW; /* AFM key: StdVW */ + int StdHW; /* AFM key: StdHW */ + + /* glyph widths */ + int defwidth; /* default width */ + int numwidths; /* number of entries in widths */ + int *widths; /* ptr to glyph widths (enumerated by codes) */ + int numinters; /* number of entries in ciw */ + fnt_interwidth *ciw; /* ptr to code intervals for widths array */ + int numglwidths; /* number of entries in glw */ + fnt_glyphwidth *glw; /* ptr to glyph widths array */ + + +}; + +/* Font exchange structure */ +struct fnt_font_s +{ + char *name; /* font name (/BaseFont or /Name or 'font_#') */ + char *utf8name; /* UTF-8 encoded font name (maybe with BOM) */ + char *filename; /* font file name */ + + fnt_font_metric m; /* name, type, flags, charcoll and metric */ + pdc_bool isstdfont; /* is an incore font + * or standard CJK font in pdflib */ + pdc_bool ishostfont; /* is an host font */ + pdc_bool hasdescr; /* has font descriptor */ + pdc_bool vertical; /* vertical writing mode */ + + pdc_ushort spacechar; /* code of space character depending on enc */ + int spacewidth; /* width of space character */ + int linegap; /* OpenType lineGap */ + int weight; /* font weight value 0-1000 */ + + pdc_matrix matrix; /* Type3 font matrix */ + pdc_rectangle bbox; /* Type3 font bounding box */ + pdc_scalar fsscale; /* Type3 fontsize scaling */ + + pdc_bool issymbfont; /* is a symbol font */ + pdc_encoding enc; /* font encoding shortcut */ + + int numglyphs; /* number of glyphs */ + int numcodes; /* number of codes */ + + pdc_ushort *gid2code; /* mapping glyph ID -> [Uni]code or NULL */ + pdc_ushort *code2gid; /* mapping [Uni]code -> glyph ID or NULL */ + char *cmapname; /* CID CMap name */ + + + /* font in memory */ + pdc_bool embedded; /* embedded font */ + char *imgname; /* name of virtual file containing *img */ + size_t filelen; /* length of (uncompressed) font data */ + pdc_byte *img; /* font (or CFF table) data */ + +}; + +/* font error numbers. +*/ +enum +{ +#define fnt_genNames 1 +#include "ft_generr.h" + + FNT_E_dummy +}; + +/* ft_font.c */ +void fnt_register_errtab(pdc_core *pdc); +void fnt_init_font(fnt_font *font); +void fnt_cleanup_font(pdc_core *pdc, fnt_font *font); +void fnt_cleanup_fontimg(pdc_core *pdc, fnt_font *font); +int fnt_get_glyphid(int code, fnt_font *font); +int fnt_get_code(int gid, fnt_font *font); +int fnt_get_glyphwidth(int code, fnt_font *font); +int fnt_get_pdf_fonttype_code(const char *typenam); +const char *fnt_get_pdf_fonttype_name(int typecode); +const char *fnt_get_pdf_fonttype_desc(int typecode); +pdc_encodingvector *fnt_create_font_ev(pdc_core *pdc, fnt_font *font); +int fnt_check_weight(int weight); +int fnt_weightname2weight(const char *weightname); +int fnt_stemv2weight(int stemv); +const char *fnt_weight2weightname(int weight); +int fnt_macfontstyle2weight(int macfontstyle); +int fnt_weight2stemv(int weight); +void fnt_font_logg_widths(pdc_core *pdc, fnt_font *font); +void fnt_font_logg_protocol(pdc_core *pdc, fnt_font *font); + +/* ft_corefont.c */ +pdc_bool fnt_is_standard_font(const char *fontname); +const char *fnt_get_abb_std_fontname(const char *fontname); +void fnt_fill_font_metric(pdc_core *pdc, fnt_font *font, pdc_bool kerning, + const fnt_font_metric *metric); +const fnt_font_metric *fnt_get_core_metric(const char *fontname); +const char *fnt_get_abb_cjk_fontname(const char *fontname); +int fnt_get_preinstalled_cidfont(const char *fontname, + const fnt_font_metric **fontmetric); +const char **fnt_get_cid_widths_array(pdc_core *pdc, fnt_font *font); + + +/* ft_type1.c */ +pdc_bool fnt_test_type1_font(pdc_core *pdc, const pdc_byte *img); +pdc_bool fnt_get_type1_encoding(pdc_core *pdc, fnt_font *font, int glyphflags); + +#endif /* FT_FONT_H */ diff --git a/src/pdflib/font/ft_generr.h b/src/pdflib/font/ft_generr.h new file mode 100644 index 0000000..909596b --- /dev/null +++ b/src/pdflib/font/ft_generr.h @@ -0,0 +1,109 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_generr.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT error messages + * + */ + +#define FT_GENERR_H + +#if fnt_genNames +#define gen(n, num, nam, msg) FNT_E_##nam = num, +#elif fnt_genInfo +#define gen(n, num, nam, msg) { n, num, msg, (const char *) 0 }, + +#else +#error invalid inclusion of generator file +#endif + + +/* -------------------------------------------------------------------- */ +/* Font (70xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 7000, FONT_ILLFONTSTYLE, "Illegal fontstyle '$1' in font name") + +gen(1, 7001, FONT_PREFIX, "Font '$1': ") + +gen(0, 7002, FONT_HOSTNOTFOUND, "Host font not found") + +gen(1, 7004, FONT_UNSUPP_FORMAT, "Font format '$1' not supported") + +gen(0, 7006, FONT_TTHOSTNOTFOUND, "TrueType host font not found") + +gen(1, 7007, FONT_NAMETOOLONG, + "Font name too long (max. $1 characters)") + +gen(0, 7060, TT_BITMAP, "TrueType bitmap font not supported") + +gen(1, 7062, TT_NOFONT, "Font file '%s' is not a TrueType or OpenType font") + +gen(0, 7064, TT_BADCMAP, "Font contains unknown encodings (cmaps) only") + +gen(0, 7066, TT_SYMBOLOS2, "Symbol font does not contain OS/2 table") + +gen(0, 7068, TT_EMBED, + "Font cannot be embedded due to licensing restrictions in the font file") + +gen(0, 7070, TT_ASSERT1, "TrueType parser error") + +gen(0, 7071, TT_CORRUPT1, "Corrupt TrueType font") + +gen(1, 7072, TT_ASSERT2, "TrueType parser error in font file '$1'") + +gen(1, 7073, TT_CORRUPT2, "Corrupt TrueType font file '$1'") + +gen(1, 7074, TTC_NOTFOUND, + "Font not found in TrueType Collection file '$1'") + +gen(0, 7076, TT_NOGLYFDESC, + "TrueType font does not contain any character outlines") + +gen(1, 7077, TT_GLYPHIDNOTFOUND, + "Couldn't find glyph id for Unicode value U+$1") + +gen(0, 7078, TT_NONAME, + "TrueType font contains only unsupported records in 'name' table") + +gen(1, 7079, TT_BADPOST, + "TrueType 'post' table has unknown reserved character index $1") + +gen(1, 7080, OT_CHARSET, + "OpenType font with predefined charset '$1' in CFF table not supported") + +gen(0, 7081, OT_MULTIFONT, + "OpenType font with multiple font entries not supported") + +gen(0, 7082, OT_CHARSTRINGS, + "OpenType font has no CharStrings data in CFF table") + +gen(0, 7083, OT_TOPDICT, + "OpenType CID font has no Top DICT INDEX in CFF table") + +gen(0, 7085, OT_NO_ORDERING, + "OpenType CID font has no ordering string in CFF table") + +gen(1, 7086, OT_ILL_CHARCOLL, + "OpenType CID font has unknown character collection '$1'") + + + + + + + +#undef gen +#undef fnt_genNames +#undef fnt_genInfo + diff --git a/src/pdflib/font/ft_hostfont.c b/src/pdflib/font/ft_hostfont.c new file mode 100644 index 0000000..ec9411d --- /dev/null +++ b/src/pdflib/font/ft_hostfont.c @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_hostfont.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT host font handling routines for Windows and Mac + * + */ + +#include "pc_ctype.h" + +#include "ft_font.h" +#include "ft_truetype.h" + + diff --git a/src/pdflib/font/ft_pdffont.c b/src/pdflib/font/ft_pdffont.c new file mode 100644 index 0000000..0767d74 --- /dev/null +++ b/src/pdflib/font/ft_pdffont.c @@ -0,0 +1,18 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 2002-2006 PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_pdffont.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Routine for parsing font dictionaries in PDF files by pCOS + * + */ + +#include "ft_pdffont.h" +#include "ft_truetype.h" + + diff --git a/src/pdflib/font/ft_pdffont.h b/src/pdflib/font/ft_pdffont.h new file mode 100644 index 0000000..bb40cbc --- /dev/null +++ b/src/pdflib/font/ft_pdffont.h @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_pdffont.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Header file for parsing font dictionaries in PDF files + * + */ + +#ifndef FT_PDFFONT_H +#define FT_PDFFONT_H + +#include "ft_font.h" + + + +#endif /* FT_PDFFONT_H */ diff --git a/src/pdflib/font/ft_truetype.c b/src/pdflib/font/ft_truetype.c new file mode 100644 index 0000000..b4e33a6 --- /dev/null +++ b/src/pdflib/font/ft_truetype.c @@ -0,0 +1,2310 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_truetype.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT TrueType handling routines + * + */ + +#include "ft_font.h" +#include "ft_truetype.h" + +#ifdef PDF_TRUETYPE_SUPPORTED + +void +tt_assert(tt_file *ttf) +{ + pdc_core *pdc = ttf->pdc; + + if (ttf->filename) + pdc_error(pdc, FNT_E_TT_ASSERT2, ttf->filename, 0, 0, 0); + else + pdc_error(pdc, FNT_E_TT_ASSERT1, 0, 0, 0, 0); +} /* tt_assert */ + +void +tt_error(tt_file *ttf) +{ + pdc_core *pdc = ttf->pdc; + + if (ttf->filename) + pdc_error(pdc, FNT_E_TT_CORRUPT2, ttf->filename, 0, 0, 0); + else + pdc_error(pdc, FNT_E_TT_CORRUPT1, 0, 0, 0, 0); +} /* tt_error */ + +void +tt_seek(tt_file *ttf, long offset) +{ + if (ttf->incore) + { + TT_IOCHECK(ttf, ttf->img + (tt_ulong) offset <= ttf->end); + ttf->pos = ttf->img + (tt_ulong) offset; + } + else + TT_IOCHECK(ttf, pdc_fseek(ttf->fp, offset, SEEK_SET) == 0); +} + +void +tt_read(tt_file *ttf, void *buf, unsigned int nbytes) +{ + if (ttf->incore) + { + TT_IOCHECK(ttf, ttf->pos + (tt_ulong) nbytes <= ttf->end); + memcpy(buf, ttf->pos, (size_t) nbytes); + ttf->pos += (tt_ulong) nbytes; + } + else + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, nbytes)); +} + +long +tt_tell(tt_file *ttf) +{ + if (ttf->incore) + return (long) (ttf->pos - ttf->img); + else + return (long) pdc_ftell(ttf->fp); +} + +tt_ushort +tt_get_ushort(tt_file *ttf) +{ + tt_byte *pos, buf[2]; + + if (ttf->incore) + { + pos = ttf->pos; + TT_IOCHECK(ttf, (ttf->pos += 2) <= ttf->end); + } + else + { + pos = buf; + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 2)); + } + + return pdc_get_be_ushort(pos); +} + +tt_short +tt_get_short(tt_file *ttf) +{ + tt_byte *pos, buf[2]; + + if (ttf->incore) + { + pos = ttf->pos; + TT_IOCHECK(ttf, (ttf->pos += 2) <= ttf->end); + } + else + { + pos = buf; + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 2)); + } + + return pdc_get_be_short(pos); +} + +tt_ulong +tt_get_ulong3(tt_file *ttf) +{ + tt_byte *pos, buf[3]; + + if (ttf->incore) + { + pos = ttf->pos; + TT_IOCHECK(ttf, (ttf->pos += 3) <= ttf->end); + } + else + { + pos = buf; + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 3)); + } + + return pdc_get_be_ulong3(pos); +} + +tt_ulong +tt_get_ulong(tt_file *ttf) +{ + tt_byte *pos, buf[4]; + + if (ttf->incore) + { + pos = ttf->pos; + TT_IOCHECK(ttf, (ttf->pos += 4) <= ttf->end); + } + else + { + pos = buf; + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 4)); + } + + return pdc_get_be_ulong(pos); +} + +tt_long +tt_get_long(tt_file *ttf) +{ + tt_byte *pos, buf[4]; + + if (ttf->incore) + { + pos = ttf->pos; + TT_IOCHECK(ttf, (ttf->pos += 4) <= ttf->end); + } + else + { + pos = buf; + TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 4)); + } + + return pdc_get_be_long(pos); +} + +tt_ulong +tt_get_offset(tt_file *ttf, tt_byte offsize) +{ + tt_byte buf; + + switch (offsize) + { + case 1: + tt_read(ttf, &buf, 1); + return (tt_ulong) buf; + + case 2: + return (tt_ulong) tt_get_ushort(ttf); + + case 3: + return (tt_ulong) tt_get_ulong3(ttf); + + case 4: + return (tt_ulong) tt_get_ulong(ttf); + } + return 0; +} + +static void +tt_get_dirent(tt_dirent *dirent, tt_file *ttf) +{ + tt_read(ttf, dirent->tag, 4); + dirent->tag[4] = 0; + dirent->checksum = tt_get_ulong(ttf); + dirent->offset = tt_get_ulong(ttf); + dirent->length = tt_get_ulong(ttf); +} /* tt_get_dirent */ + + +int +tt_tag2idx(tt_file *ttf, char *tag) +{ + int i; + + for (i = 0; i < ttf->n_tables; ++i) + if (strcmp(ttf->dir[i].tag, tag) == 0) + return i; + + return -1; +} /* tt_tag2idx */ + +void * +tt_get_tab(tt_file *ttf, char *tag, size_t nbytes, pdc_bool tterror, + tt_ulong *offset) +{ + static const char *fn = "tt_get_tab"; + pdc_core *pdc = ttf->pdc; + int idx = tt_tag2idx(ttf, tag); + + if (idx == -1) + { + if (tterror) + tt_error(ttf); + return NULL; + } + + tt_seek(ttf, (long) ttf->dir[idx].offset); + + if (offset) + *offset = ttf->dir[idx].offset; + + return pdc_malloc(pdc, nbytes, fn); +} + +static void +tt_get_cmap0(tt_file *ttf, tt_cmap0_6 *cm0_6) +{ + static const char *fn = "tt_get_cmap0"; + pdc_core *pdc = ttf->pdc; + tt_ushort c; + tt_byte buf[256]; + + cm0_6->glyphIdArray = (tt_ushort *) 0; + + cm0_6->length = tt_get_ushort(ttf); + cm0_6->language = tt_get_ushort(ttf); + + /* These are not used in format 0 */ + cm0_6->firstCode = 0; + cm0_6->entryCount = 256; + + cm0_6->glyphIdArray = (tt_ushort *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * 256), fn); + + tt_read(ttf, buf, 256); + + for (c = 0; c < 256; c++) + cm0_6->glyphIdArray[c] = (tt_ushort) buf[c]; + +} /* tt_get_cmap0 */ + +static void +tt_get_cmap6(tt_file *ttf, tt_cmap0_6 *cm0_6) +{ + static const char *fn = "tt_get_cmap6"; + pdc_core *pdc = ttf->pdc; + tt_ushort c, last, cmax; + + cm0_6->glyphIdArray = (tt_ushort *) 0; + + cm0_6->length = tt_get_ushort(ttf); + cm0_6->language = tt_get_ushort(ttf); + cm0_6->firstCode = tt_get_ushort(ttf); + cm0_6->entryCount = tt_get_ushort(ttf); + + last = (tt_ushort) (cm0_6->firstCode + cm0_6->entryCount); + cmax = MAX(last, 256); + + cm0_6->glyphIdArray = (tt_ushort *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * cmax), fn); + + /* default for codes outside the range specified in this table */ + for (c = 0; c < cmax; c++) + cm0_6->glyphIdArray[c] = (tt_ushort) 0; + + for (c = cm0_6->firstCode; c < last; c++) + cm0_6->glyphIdArray[c] = tt_get_ushort(ttf); + +} /* tt_get_cmap6 */ + +static void +tt_get_cmap4(tt_file *ttf, tt_cmap4 *cm4) +{ + static const char *fn = "tt_get_cmap4"; + pdc_core *pdc = ttf->pdc; + int i, segs; + + /* the instruction order is critical for cleanup after exceptions! + */ + cm4->endCount = (tt_ushort *) 0; + cm4->startCount = (tt_ushort *) 0; + cm4->idDelta = (tt_short *) 0; + cm4->idRangeOffs = (tt_ushort *) 0; + cm4->glyphIdArray = (tt_ushort *) 0; + + cm4->length = tt_get_ushort(ttf); + cm4->version = tt_get_ushort(ttf); + cm4->segCountX2 = tt_get_ushort(ttf); + cm4->searchRange = tt_get_ushort(ttf); + cm4->entrySelector = tt_get_ushort(ttf); + cm4->rangeShift = tt_get_ushort(ttf); + + segs = cm4->segCountX2 / 2; + + cm4->numGlyphIds = (tt_ushort)( + ((cm4->length - ( 16L + 8L * segs )) & 0xFFFFU) / 2); + + TT_IOCHECK(ttf, 0 <= cm4->numGlyphIds); + + cm4->endCount = + (tt_ushort *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn); + cm4->startCount = + (tt_ushort *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn); + cm4->idDelta = + (tt_short *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn); + cm4->idRangeOffs = + (tt_ushort *) + pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn); + + if (cm4->numGlyphIds) + { + cm4->glyphIdArray = (tt_ushort *) + pdc_malloc(pdc, + (size_t) (sizeof (tt_ushort) * cm4->numGlyphIds), fn); + } + + for (i = 0; i < segs; ++i) + cm4->endCount[i] = tt_get_ushort(ttf); + + TT_IOCHECK(ttf, cm4->endCount[segs - 1] == 0xFFFF); + + (void) tt_get_ushort(ttf); /* padding */ + for (i = 0; i < segs; ++i) cm4->startCount[i] = tt_get_ushort(ttf); + for (i = 0; i < segs; ++i) cm4->idDelta[i] = tt_get_short(ttf); + for (i = 0; i < segs; ++i) cm4->idRangeOffs[i] = tt_get_ushort(ttf); + + for (i = 0; i < cm4->numGlyphIds; ++i) + cm4->glyphIdArray[i] = tt_get_ushort(ttf); + + /* empty cmap */ + if (segs == 1 && cm4->endCount[0] == cm4->startCount[0]) + { + cm4->segCountX2 = 0; + pdc_free(pdc, cm4->endCount); + cm4->endCount = (tt_ushort *) 0; + pdc_free(pdc, cm4->startCount); + cm4->startCount = (tt_ushort *) 0; + pdc_free(pdc, cm4->idDelta); + cm4->idDelta = (tt_short *) 0; + pdc_free(pdc, cm4->idRangeOffs); + cm4->idRangeOffs = (tt_ushort *) 0; + if (cm4->numGlyphIds) + { + pdc_free(pdc, cm4->glyphIdArray); + cm4->glyphIdArray = (tt_ushort *) 0; + } + } + +} /* tt_get_cmap4 */ + + +void +tt_get_tab_cmap(tt_file *ttf) +{ + static const char *fn = "tt_get_tab_cmap"; + pdc_core *pdc = ttf->pdc; + tt_tab_cmap *tp = NULL; + tt_ulong offset; + tt_ushort numEncTabs; + tt_ushort platformID = 0; + tt_ushort encodingID = 0; + tt_ushort tableFormat = 0; + tt_ulong offsetEncTab = 0; + tt_ulong offset_mac = 0; + tt_ulong offset_win = 0; + tt_ulong offset_ucs4 = 0; + tt_long pos = 0; + int i; + + tp = (tt_tab_cmap *) tt_get_tab(ttf, fnt_str_cmap, sizeof (tt_tab_cmap), + !ttf->fortet, &offset); + if (tp == NULL) + return; + ttf->tab_cmap = tp; + + tp->win = (tt_cmap4 *) 0; + tp->mac = (tt_cmap0_6 *) 0; + tp->ucs4 = (tt_cmap12 *) 0; + + tp->platform = 0; + tp->encoding = 0; + tp->format = 0; + tp->offset = 0; + tp->length = 0; + + (void) tt_get_ushort(ttf); /* version */ + numEncTabs = tt_get_ushort(ttf); + + pdc_logg_cond(pdc, 2, trc_font, + "\tSearching for cmap table entries:\n"); + for (i = 0; i < numEncTabs; ++i) + { + platformID = tt_get_ushort(ttf); + encodingID = tt_get_ushort(ttf); + offsetEncTab = tt_get_ulong(ttf); + pos = tt_tell(ttf); + + tt_seek(ttf, (long) (offset + offsetEncTab)); + tableFormat = tt_get_ushort(ttf); + + pdc_logg_cond(pdc, 2, trc_font, + "\t\tplatformID: %d, encodingID: %2d, " + "tableFormat: %2d, offsetEncTab: 0x%04X\n", + platformID, encodingID, tableFormat, offsetEncTab); + + /* + * platformID: 0 encodingID: 0 tableFormat: 0 + * platformID: 1 encodingID: 0 tableFormat: 0/6 + */ + if (((platformID == tt_pfid_uni && tableFormat == 0) || + platformID == tt_pfid_mac) && encodingID == tt_wenc_symbol) + { + /* we currently do not support cmaps + ** other than format 0 and 6 for Macintosh cmaps. + */ + + if (tableFormat == 0 && tp->mac == (tt_cmap0_6 *) 0) + { + tp->mac = (tt_cmap0_6 *) + pdc_malloc(pdc, sizeof (tt_cmap0_6), fn); + tp->mac->format = 0; + tt_get_cmap0(ttf, tp->mac); + } + else if (tableFormat == 6 && tp->mac == (tt_cmap0_6 *) 0) + { + tp->mac = (tt_cmap0_6 *) + pdc_malloc(pdc, sizeof (tt_cmap0_6), fn); + tp->mac->format = 6; + tt_get_cmap6(ttf, tp->mac); + } + offset_mac = offsetEncTab; + } + + /* + * platformID: 0 encodingID: 3 tableFormat: 4 (old mac) + * platformID: 3 encodingID: 0/1 tableFormat: 4 + */ + else if ((tp->win == (tt_cmap4 *) 0 && tableFormat == 4) && + ((platformID == tt_pfid_win && + (encodingID == tt_wenc_symbol || + encodingID == tt_wenc_text)) || + (platformID == tt_pfid_uni && + encodingID == tt_wenc_mtext))) + { + tp->win = (tt_cmap4 *) pdc_malloc(pdc, sizeof (tt_cmap4), fn); + tp->win->format = tableFormat; + + /* we suppose a windows platform (see old mac hostfont Times) */ + if (encodingID == tt_wenc_mtext) + { + encodingID = tt_wenc_text; + } + + tt_get_cmap4(ttf, tp->win); + + if (tp->win->segCountX2) + { + tp->win->encodingID = encodingID; + } + else + { + pdc_free(pdc, tp->win); + tp->win = (tt_cmap4 *) 0; + } + offset_win = offsetEncTab; + } + + + tt_seek(ttf, pos); + } /* for */ + + /* is symbol font */ + ttf->issymbol = (tp->win && tp->win->encodingID == tt_wenc_symbol) ? + pdc_true : pdc_false; + + /* has Unicode cmap */ + ttf->haswinuni = (!ttf->issymbol && (tp->win || tp->ucs4)) ? + pdc_true : pdc_false; + + /* has only Mac cmap */ + ttf->hasonlymac = (tp->mac && !tp->win && !tp->ucs4) ? + pdc_true : pdc_false; + + if (ttf->hasonlymac) + { + tp->platform = tt_pfid_mac; + tp->encoding = tt_wenc_symbol; + tp->format = tp->mac->format; + tp->offset = offset_mac; + tp->length = tp->mac->length; + } + else if (tp->win || tp->ucs4) + { + tp->platform = tt_pfid_win; + if (ttf->issymbol) + { + tp->encoding = tt_wenc_symbol; + tp->format = tp->win->format; + tp->offset = offset_win; + tp->length = tp->win->length; + } + else if (tp->ucs4) + { + tp->encoding = tt_wenc_utext; + tp->format = tp->ucs4->format; + tp->offset = offset_ucs4; + tp->length = tp->ucs4->length; + } + else + { + tp->encoding = tt_wenc_text; + tp->format = tp->win->format; + tp->offset = offset_win; + tp->length = tp->win->length; + } + } + + pdc_logg_cond(ttf->pdc, 1, trc_font, + "\tUsed cmap table entry:\n" + "\t\tplatformID: %d, encodingID: %2d, tableFormat: %2d (%s font)\n", + tp->platform, tp->encoding, tp->format, + ttf->issymbol ? "symbol" : "text"); + + /* for subsetting and symbolic font: + * tp->platform = tt_pfid_mac according PDF specification + * otherwise GS will emit an error message + */ + if (ttf->issymbol && offset_mac > 0) + { + tp->platform = tt_pfid_mac; + tp->encoding = tt_wenc_symbol; + tp->format = tp->mac->format; + tp->offset = offset_mac; + tp->length = tp->mac->length; + } + +} /* tt_get_tab_cmap */ + +void +tt_get_tab_head(tt_file *ttf) +{ + tt_tab_head *tp = NULL; + + tp = (tt_tab_head *) tt_get_tab(ttf, fnt_str_head, sizeof (tt_tab_head), + !ttf->fortet, NULL); + if (tp == NULL) + return; + ttf->tab_head = tp; + + tp->version = tt_get_fixed(ttf); + tp->fontRevision = tt_get_fixed(ttf); + tp->checkSumAdjustment = tt_get_ulong(ttf); + tp->magicNumber = tt_get_ulong(ttf); + tp->flags = tt_get_ushort(ttf); + tp->unitsPerEm = tt_get_ushort(ttf); + tp->created[1] = tt_get_ulong(ttf); + tp->created[0] = tt_get_ulong(ttf); + tp->modified[1] = tt_get_ulong(ttf); + tp->modified[0] = tt_get_ulong(ttf); + tp->xMin = tt_get_fword(ttf); + tp->yMin = tt_get_fword(ttf); + tp->xMax = tt_get_fword(ttf); + tp->yMax = tt_get_fword(ttf); + tp->macStyle = tt_get_ushort(ttf); + tp->lowestRecPPEM = tt_get_ushort(ttf); + tp->fontDirectionHint = tt_get_short(ttf); + tp->indexToLocFormat = tt_get_short(ttf); + tp->glyphDataFormat = tt_get_short(ttf); +} /* tt_get_tab_head */ + +static void +tt_get_tab_hhea(tt_file *ttf) +{ + tt_tab_hhea *tp = NULL; + + tp = (tt_tab_hhea *) tt_get_tab(ttf, fnt_str_hhea, sizeof (tt_tab_hhea), + !ttf->fortet, NULL); + if (tp == NULL) + return; + ttf->tab_hhea = tp; + + tp->version = tt_get_fixed(ttf); + tp->ascender = tt_get_fword(ttf); + tp->descender = tt_get_fword(ttf); + tp->lineGap = tt_get_fword(ttf); + tp->advanceWidthMax = tt_get_fword(ttf); + tp->minLeftSideBearing = tt_get_fword(ttf); + tp->minRightSideBearing = tt_get_fword(ttf); + tp->xMaxExtent = tt_get_fword(ttf); + tp->caretSlopeRise = tt_get_short(ttf); + tp->caretSlopeRun = tt_get_short(ttf); + tp->res1 = tt_get_short(ttf); + tp->res2 = tt_get_short(ttf); + tp->res3 = tt_get_short(ttf); + tp->res4 = tt_get_short(ttf); + tp->res5 = tt_get_short(ttf); + tp->metricDataFormat = tt_get_short(ttf); + tp->numberOfHMetrics = tt_get_ushort(ttf); +} /* tt_get_tab_hhea */ + +static void +tt_get_tab_hmtx(tt_file *ttf) +{ + static const char *fn = "tt_get_tab_hmtx"; + pdc_core *pdc = ttf->pdc; + tt_tab_hmtx *tp = NULL; + int n_metrics; + int n_lsbs; + int i; + + tp = (tt_tab_hmtx *) tt_get_tab(ttf, fnt_str_hmtx, sizeof (tt_tab_hmtx), + !ttf->fortet, NULL); + if (tp == NULL) + return; + ttf->tab_hmtx = tp; + + TT_ASSERT(ttf, ttf->tab_hhea != 0); + TT_ASSERT(ttf, ttf->tab_maxp != 0); + + tp->metrics = 0; + tp->lsbs = 0; + + n_metrics = ttf->tab_hhea->numberOfHMetrics; + n_lsbs = ttf->numGlyphs - n_metrics; + + TT_IOCHECK(ttf, n_metrics != 0); + TT_IOCHECK(ttf, n_lsbs >= 0); + tp->metrics = (tt_metric *) + pdc_malloc(pdc, n_metrics * sizeof (tt_metric), fn); + + for (i = 0; i < n_metrics; ++i) + { + tp->metrics[i].advanceWidth = tt_get_fword(ttf); + tp->metrics[i].lsb = tt_get_fword(ttf); + } + + if (n_lsbs == 0) + tp->lsbs = (tt_fword *) 0; + else + { + tp->lsbs = (tt_fword *) + pdc_malloc(pdc, n_lsbs * sizeof (tt_fword), fn); + for (i = 0; i < n_lsbs; ++i) + tp->lsbs[i] = tt_get_fword(ttf); + } +} /* tt_get_tab_hmtx */ + + + +pdc_bool +tt_get_tab_CFF_(tt_file *ttf) +{ + static const char *fn = "tt_get_tab_CFF_"; + pdc_core *pdc = ttf->pdc; + int idx = tt_tag2idx(ttf, fnt_str_CFF_); + + if (idx != -1) + { + /* CFF table found */ + ttf->tab_CFF_ = (tt_tab_CFF_ *) + pdc_malloc(pdc, sizeof (tt_tab_CFF_), fn); + ttf->tab_CFF_->offset = ttf->dir[idx].offset; + ttf->tab_CFF_->length = ttf->dir[idx].length; + } + else if (!ttf->fortet) + { + idx = tt_tag2idx(ttf, fnt_str_glyf); + if (idx == -1 || !ttf->dir[idx].length) + { + pdc_set_errmsg(pdc, FNT_E_TT_NOGLYFDESC, 0, 0, 0, 0); + return pdc_false; + } + idx = -1; + } + + + return pdc_true; + +} /* tt_get_tab_CFF_ */ + +void +tt_get_tab_maxp(tt_file *ttf) +{ + tt_tab_maxp *tp = NULL; + + tp = (tt_tab_maxp *) tt_get_tab(ttf, fnt_str_maxp, sizeof (tt_tab_maxp), + !ttf->fortet, NULL); + if (tp == NULL) + return; + ttf->tab_maxp = tp; + + tp->version = tt_get_fixed(ttf); + tp->numGlyphs = tt_get_ushort(ttf); + tp->maxPoints = tt_get_ushort(ttf); + tp->maxContours = tt_get_ushort(ttf); + tp->maxCompositePoints = tt_get_ushort(ttf); + tp->maxCompositeContours = tt_get_ushort(ttf); + tp->maxZones = tt_get_ushort(ttf); + tp->maxTwilightPoints = tt_get_ushort(ttf); + tp->maxStorage = tt_get_ushort(ttf); + tp->maxFunctionDefs = tt_get_ushort(ttf); + tp->maxInstructionDefs = tt_get_ushort(ttf); + tp->maxStackElements = tt_get_ushort(ttf); + tp->maxSizeOfInstructions = tt_get_ushort(ttf); + tp->maxComponentElements = tt_get_ushort(ttf); + tp->maxComponentDepth = tt_get_ushort(ttf); + + ttf->numGlyphs = tp->numGlyphs; + +} /* tt_get_tab_maxp */ + +pdc_bool +tt_get_tab_name(tt_file *ttf) +{ + static const char *fn = "tt_get_tab_name"; + pdc_core *pdc = ttf->pdc; + pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_font); + tt_tab_name *tp = NULL; + int i, j, k, namid, irec, irec4 = -1, irec6 = -1; + size_t len; + tt_nameref *namerec = NULL, lastnamerec; + char *localname = NULL; + tt_ulong offset, offs; + + tp = (tt_tab_name *) tt_get_tab(ttf, fnt_str_name, sizeof (tt_tab_name ), + pdc_false, &offset); + if (tp == NULL) + return pdc_false; + ttf->tab_name = tp; + + tp->namerecords = NULL; + tp->englishname4 = NULL; + tp->englishname6 = NULL; + tp->producer = NULL; + + tp->format = tt_get_ushort(ttf); + + /* Format 0 is the only document one, but some Apple fonts use 65535. + * This is very consequent since it follows Microsoft's lead in + * disregarding one's own published specifications. + */ + TT_IOCHECK(ttf, (tp->format == 0 || tp->format == 65535)); + + tp->numNameRecords = (tt_ushort) + tt_get_offset(ttf, sizeof(tt_ushort)); + tp->offsetStrings = tt_get_ushort(ttf); + offs = offset + tp->offsetStrings; + + pdc_logg_cond(pdc, 1, trc_font, + "\tRecords in name table of format %d: %d:\n", + tp->format, tp->numNameRecords); + + /* this was observed. we ignore it in TET */ + if (ttf->fortet && tp->numNameRecords == 0) + return pdc_true; + + TT_IOCHECK(ttf, (tp->numNameRecords > 0)); + + len = tp->numNameRecords * sizeof (tt_nameref); + tp->namerecords = (tt_nameref *) pdc_malloc(pdc, len, fn); + + for (i = 0; i < tp->numNameRecords; ++i) + { + tt_ushort platformID = tt_get_ushort(ttf); + tt_ushort encodingID = tt_get_ushort(ttf); + tt_ushort languageID = tt_get_ushort(ttf); + tt_ushort nameID = tt_get_ushort(ttf); + tt_ushort stringLength = tt_get_ushort(ttf); + tt_ushort stringOffset = tt_get_ushort(ttf); + + namerec = &tp->namerecords[i]; + namerec->platform = platformID; + namerec->encoding = encodingID; + namerec->language = languageID; + namerec->namid = nameID; + namerec->length = stringLength; + namerec->offset = stringOffset; + } + + namid = 4; + for (k = 0; k < 2; k++) + { + lastnamerec.platform = 0; + lastnamerec.language = 0; + lastnamerec.namid = 0; + lastnamerec.length = 0; + lastnamerec.offset = 0; + + for (i = 0; i < tp->numNameRecords; ++i) + { + localname = NULL; + namerec = &tp->namerecords[i]; + + if (logg5 && !k) + { + pdc_logg(pdc, "\t\t\t%2d. platformID: %d\n" + "\t\t\t encodingID: %d\n" + "\t\t\t languageID: %d\n" + "\t\t\t nameID: %d\n" + "\t\t\t length: %d\n" + "\t\t\t offset: %d\n", + i, + namerec->platform, namerec->encoding, + namerec->language, namerec->namid, + namerec->length, namerec->offset); + + /* read font name */ + if (namerec->length) + { + localname = + (char *) pdc_calloc(pdc, (size_t) namerec->length, fn); + tt_seek(ttf, (long) (offs + namerec->offset)); + tt_read(ttf, localname, (unsigned int) namerec->length); + + pdc_logg_hexdump(pdc, "data", "\t\t\t ", + localname, namerec->length); + } + pdc_logg(pdc, "\n"); + } + + if (tp->producer == NULL && + namerec->platform == tt_pfid_mac && + namerec->encoding == tt_wenc_symbol && + namerec->language == 0 && + namerec->namid == 0) + { + tp->producer = (char *) pdc_calloc(pdc, + (size_t) namerec->length + 1, fn); + tt_seek(ttf, (long) (offs + namerec->offset)); + tt_read(ttf, tp->producer, (unsigned int) namerec->length); + } + + if (namerec->length && namerec->namid == namid) + { + /* TTC font search */ + if (ttf->utf16fontname) + { + /* read font name */ + if (localname == NULL) + { + localname = (char *) pdc_calloc(pdc, + (size_t) namerec->length, fn); + tt_seek(ttf, (long) (offs + namerec->offset)); + tt_read(ttf, localname, (unsigned int) namerec->length); + } + + if (namerec->platform == tt_pfid_win) + { + pdc_logg_cond(pdc, 1, trc_font, + "\tUnicode fontname: \"%T\"\n", + localname, namerec->length); + + if (namerec->length == ttf->fnamelen && + !memcmp(localname, ttf->utf16fontname, + (size_t) ttf->fnamelen)) + { + /* font found */ + pdc_free(pdc, localname); + return pdc_true; + } + } + } + + /* search for the records with english names */ + else + { + /* we take the names from platformID 3 (Microsoft) or + * 1 (Macintosh). We favor Macintosh and then Microsoft + * with American English (LanguageID = 0x0409 = 1033) + */ + if ((lastnamerec.language != 0x0409 || + lastnamerec.platform != tt_pfid_win) && + (namerec->platform == tt_pfid_win || + (namerec->platform == tt_pfid_mac && + namerec->language == 0))) + { + lastnamerec = *namerec; + + /* We simulate always English */ + if (namerec->platform == tt_pfid_mac) + lastnamerec.language = 0x0409; + + if (namid == 4) irec4 = i; + if (namid == 6) irec6 = i; + } + } + } + + if (localname != NULL) + pdc_free(pdc, localname); + } + namid = 6; + } + + /* TTC font not found */ + if (ttf->utf16fontname) + return pdc_false; + + /* English font names */ + namid = 4; + irec = irec4; + for (k = 0; k < 2; k++) + { + if (irec == -1) + continue; + namerec = &tp->namerecords[irec]; + + /* read font name */ + len = (size_t) (namerec->length + 1); + localname = (char *) pdc_calloc(pdc, (size_t) len, fn); + tt_seek(ttf, (long) (offs + namerec->offset)); + tt_read(ttf, localname, (unsigned int) namerec->length); + + /* low byte picking */ + if (namerec->platform == tt_pfid_win) + { + for (j = 0; j < namerec->length / 2; j++) + { + /* We don't support wide character names */ + if (localname[2*j] != 0) + { + pdc_free(pdc, localname); + localname = NULL; + break; + } + localname[j] = localname[2*j + 1]; + } + if (localname) + localname[j] = 0; + } + + /* We observed this in EUDC fonts */ + if (localname && !strcmp(localname, "\060\060")) + { + pdc_free(pdc, localname); + localname = NULL; + } + + if (namid == 4 && localname) + tp->englishname4 = localname; + else if (namid == 6 && localname) + tp->englishname6 = localname; + + namid = 6; + irec = irec6; + } + + /* font name 4 (full font name) is required */ + if (tp->englishname6 == NULL && tp->englishname4 == NULL) + { + if (!ttf->fortet) + { + pdc_set_errmsg(pdc, FNT_E_TT_NONAME, 0, 0, 0, 0); + return pdc_false; + } + } + else + { + if (tp->englishname4 == NULL) + tp->englishname4 = pdc_strdup(pdc, tp->englishname6); + if (tp->englishname6 == NULL) + tp->englishname6 = pdc_strdup(pdc, tp->englishname4); + } + + return pdc_true; +} /* tt_get_tab_name */ + +static int tt_cpflag2cp[64] = +{ + 1252, 1250, 1251, 1253, 1254, 1255, 1256, 1257, + 1258, 0, 0, 0, 0, 0, 0, 0, + 874, 932, 936, 949, 950, 1361, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 869, 866, 865, 864, 863, 862, 861, 860, + 857, 855, 852, 775, 737, 708, 850, 437 +}; + +static int tt_cpflag2charcoll[4] = +{ + cc_japanese, cc_simplified_chinese, cc_korean, cc_traditional_chinese +}; + +void +tt_get_tab_OS_2(tt_file *ttf) +{ + pdc_bool logg3 = pdc_logg_is_enabled(ttf->pdc, 3, trc_font); + int i, j; + + tt_tab_OS_2 *tp = NULL; + + tp = (tt_tab_OS_2 *) tt_get_tab(ttf, fnt_str_OS_2, sizeof (tt_tab_OS_2), + pdc_false, NULL); + if (tp == NULL) + return; + ttf->tab_OS_2 = tp; + + tp->version = tt_get_ushort(ttf); + tp->xAvgCharWidth = tt_get_short(ttf); + tp->usWeightClass = tt_get_ushort(ttf); + tp->usWidthClass = tt_get_ushort(ttf); + tp->fsType = tt_get_ushort(ttf); + tp->ySubscriptXSize = tt_get_short(ttf); + tp->ySubscriptYSize = tt_get_short(ttf); + tp->ySubscriptXOffset = tt_get_short(ttf); + tp->ySubscriptYOffset = tt_get_short(ttf); + tp->ySuperscriptXSize = tt_get_short(ttf); + tp->ySuperscriptYSize = tt_get_short(ttf); + tp->ySuperscriptXOffset = tt_get_short(ttf); + tp->ySuperscriptYOffset = tt_get_short(ttf); + tp->yStrikeoutSize = tt_get_short(ttf); + tp->yStrikeoutPosition = tt_get_short(ttf); + tp->sFamilyClass = tt_get_ushort(ttf); + + tt_read(ttf, tp->panose, 10); + + tp->ulUnicodeRange1 = tt_get_ulong(ttf); + tp->ulUnicodeRange2 = tt_get_ulong(ttf); + tp->ulUnicodeRange3 = tt_get_ulong(ttf); + tp->ulUnicodeRange4 = tt_get_ulong(ttf); + + tt_read(ttf, tp->achVendID, 4); + + tp->fsSelection = tt_get_ushort(ttf); + tp->usFirstCharIndex = tt_get_ushort(ttf); + tp->usLastCharIndex = tt_get_ushort(ttf); + tp->sTypoAscender = tt_get_short(ttf); + tp->sTypoDescender = tt_get_short(ttf); + tp->sTypoLineGap = tt_get_short(ttf); + tp->usWinAscent = tt_get_ushort(ttf); + tp->usWinDescent = tt_get_ushort(ttf); + + if (tp->version >= 1) + { + tp->ulCodePageRange1 = tt_get_ulong(ttf); + tp->ulCodePageRange2 = tt_get_ulong(ttf); + } + else + { + tp->ulCodePageRange1 = 0; + tp->ulCodePageRange2 = 0; + } + + for (i = 0; i < PDC_NUMCHARCOLL; i++) + { + j = i + 17; + if (tp->ulCodePageRange1 & (1<<j)) + tp->charcolls[i] = tt_cpflag2charcoll[i]; + else + tp->charcolls[i] = cc_none; + } + + if (tp->version >= 2) + { + tp->sxHeight = tt_get_short(ttf); + tp->sCapHeight = tt_get_short(ttf); + tp->usDefaultChar = tt_get_ushort(ttf); + tp->usBreakChar = tt_get_ushort(ttf); + tp->usMaxContext = tt_get_ushort(ttf); + } + else + { + tp->sxHeight = FNT_MISSING_FONTVAL; + tp->sCapHeight = FNT_MISSING_FONTVAL; + tp->usDefaultChar = 0; + tp->usBreakChar = 0; + tp->usMaxContext = 0; + } + + /* there are fonts with inconsistent usFirstCharIndex */ + if (ttf->tab_cmap && ttf->tab_cmap->win && + tp->usFirstCharIndex != ttf->tab_cmap->win->startCount[0]) + ttf->tab_OS_2->usFirstCharIndex = ttf->tab_cmap->win->startCount[0]; + + if (logg3) + { + int nbit = 8 * sizeof(tt_ulong); + + pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange1 ", + (char *) &tp->ulUnicodeRange1, nbit); + pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange2 ", + (char *) &tp->ulUnicodeRange2, nbit); + pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange3 ", + (char *) &tp->ulUnicodeRange3, nbit); + pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange4 ", + (char *) &tp->ulUnicodeRange4, nbit); + + if (tp->version >= 1) + { + int n = 0; + + pdc_logg_bitarr(ttf->pdc, "\t\tulCodePageRange1", + (char *) &tp->ulCodePageRange1, nbit); + pdc_logg_bitarr(ttf->pdc, "\t\tulCodePageRange2", + (char *) &tp->ulCodePageRange2, nbit); + + for (i = 0; i < 32; i++) + { + if ((tp->ulCodePageRange1 & (1<<i)) && tt_cpflag2cp[i]) + { + pdc_logg(ttf->pdc, "%s%d", + (n ? ", " : "\t\tsupported code pages: "), + tt_cpflag2cp[i]); + n++; + } + } + for (i = 0; i < 32; i++) + { + j = i + 32; + if ((tp->ulCodePageRange1 & (1<<i)) && tt_cpflag2cp[j]) + { + pdc_logg(ttf->pdc, "%s%d", + (n ? ", " : "\t\tsupported code pages: "), + tt_cpflag2cp[j]); + n++; + } + } + + if (n) + pdc_logg(ttf->pdc, "\n"); + + n = 0; + for (i = 0; i < PDC_NUMCHARCOLL; i++) + { + if (tp->charcolls[i]) + { + pdc_logg(ttf->pdc, "%s%s", + (n ? ", " : "\t\tsupported character collections: "), + fnt_get_ordering_cid(tp->charcolls[i])); + n++; + } + } + if (n) + pdc_logg(ttf->pdc, "\n"); + } + } +} /* tt_get_tab_OS_2 */ + + +static void +tt_get_tab_post(tt_file *ttf) +{ + tt_tab_post *tp = NULL; + + + tp = (tt_tab_post *) tt_get_tab(ttf, fnt_str_post, sizeof (tt_tab_post), + !ttf->fortet, NULL); + if (tp == NULL) + return; + ttf->tab_post = tp; + + tp->formatType = tt_get_fixed(ttf); + tp->italicAngle = (tt_get_fixed(ttf) / 65536.0); + tp->underlinePosition = tt_get_fword(ttf); + tp->underlineThickness = tt_get_fword(ttf); + tp->isFixedPitch = tt_get_ulong(ttf); + tp->minMemType42 = tt_get_ulong(ttf); + tp->maxMemType42 = tt_get_ulong(ttf); + tp->minMemType1 = tt_get_ulong(ttf); + tp->maxMemType1 = tt_get_ulong(ttf); + + +} /* tt_get_tab_post */ + + + +/*--------------------------- general functions ------------------------------*/ + +#define FNT_O ((char) 0x4f) /* ASCII 'O' */ +#define FNT_T ((char) 0x54) /* ASCII 'T' */ + +#define FNT_t ((char) 0x74) /* ASCII 't' */ +#define FNT_r ((char) 0x72) /* ASCII 'r' */ +#define FNT_u ((char) 0x75) /* ASCII 'u' */ +#define FNT_e ((char) 0x65) /* ASCII 'e' */ + +#define FNT_c ((char) 0x63) /* ASCII 'c' */ +#define FNT_f ((char) 0x66) /* ASCII 'f' */ + +static const char *fnt_filetypes[4] = +{ + "TrueType", "OpenType", "Apple TrueType", "TrueType Collection" +}; + +pdc_bool +fnt_test_tt_font(pdc_core *pdc, tt_byte *img, tt_ulong *n_fonts, + pdc_bool requested) +{ + tt_ushort n_tables; + int ift = 0; + pdc_bool retval = requested ? pdc_false : pdc_undef; + + /* The TrueType (including OpenType/TT) "version" is always 0x00010000 */ + if (!(img[0] == 0x00 && img[1] == 0x01 && + img[2] == 0x00 && img[3] == 0x00)) + { + ift++; + + /* The OpenType/CFF version is always 'OTTO' */ + if (!(img[0] == FNT_O && img[1] == FNT_T && + img[2] == FNT_T && img[3] == FNT_O)) + { + ift++; + + /* Old Apple fonts have 'true' */ + if (!(img[0] == FNT_t && img[1] == FNT_r && + img[2] == FNT_u && img[3] == FNT_e)) + { + ift++; + + /* TrueType Collection */ + if (n_fonts == NULL || + !(img[0] == FNT_t && img[1] == FNT_t && + img[2] == FNT_c && img[3] == FNT_f)) + return retval; + + /* Version is always 0x00010000 or 0x00020000 */ + if (!(img[4] == 0x00 && (img[5] == 0x01 || img[5] == 0x02) && + img[6] == 0x00 && img[7] == 0x00)) + return retval; + + /* Number of fonts */ + *n_fonts = pdc_get_be_ulong(&img[8]); + + pdc_logg_cond(pdc, 1, trc_font, + "\t%s font with %d single fonts detected\n", + fnt_filetypes[ift], *n_fonts); + + return pdc_true; + } + } + } + + /* Number of tables */ + n_tables = pdc_get_be_ushort(&img[4]); + if (n_tables < 8 && n_tables > 64) /* max. 32 tables ? */ + return retval; + + /* Further check of the next 6 bytes not implemented */ + + if (n_fonts == NULL) + pdc_logg_cond(pdc, 1, trc_font, + "\t%s font with %d tables detected\n", + fnt_filetypes[ift], n_tables); + + return pdc_true; +} + +pdc_bool +fnt_is_opentype_font(tt_file *ttf) +{ + return (ttf->img[0] == FNT_O && + ttf->img[1] == FNT_T && + ttf->img[2] == FNT_T && + ttf->img[3] == FNT_O) ? pdc_true : pdc_false; +} + +pdc_bool +fnt_read_offset_tab(tt_file *ttf) +{ + static const char *fn = "fnt_get_tab_offset"; + pdc_core *pdc = ttf->pdc; + tt_byte img[TT_OFFSETTAB_SIZE]; + int i; + + /* Check */ + tt_read(ttf, img, TT_OFFSETTAB_SIZE); + if (fnt_test_tt_font(pdc, img, NULL, pdc_true) == pdc_false) + { + pdc_set_errmsg(pdc, FNT_E_TT_NOFONT, ttf->filename, 0, 0, 0); + return pdc_false; + } + + /* number of table directories */ + ttf->n_tables = pdc_get_be_ushort(&img[4]); + + /* set up table directory */ + ttf->dir = (tt_dirent *) pdc_malloc(pdc, + (size_t) (ttf->n_tables * sizeof (tt_dirent)), fn); + + tt_seek(ttf, (long) (ttf->offset + TT_OFFSETTAB_SIZE)); + + for (i = 0; i < ttf->n_tables; ++i) + { + tt_get_dirent(ttf->dir + i, ttf); + } + + /* make sure this isn't a bitmap-only Mac font */ + if (tt_tag2idx(ttf, fnt_str_bhed) != -1) + { + pdc_set_errmsg(pdc, FNT_E_TT_BITMAP, 0, 0, 0, 0); + return pdc_false; + } + + return pdc_true; + +} /* fnt_read_offset_tab */ + +pdc_bool +fnt_read_tt(tt_file *ttf) +{ + pdc_core *pdc = ttf->pdc; + + PDC_TRY(pdc) + { + if (fnt_read_offset_tab(ttf) == pdc_false) + { + PDC_EXIT_TRY(pdc); + return pdc_false; + } + + /* These are all required TrueType tables; + * optional tables are not read. + */ + tt_get_tab_cmap(ttf); + tt_get_tab_head(ttf); + tt_get_tab_hhea(ttf); + tt_get_tab_maxp(ttf); + if (!ttf->fortet) + tt_get_tab_hmtx(ttf); /* MUST be read AFTER hhea & maxp! */ + if (tt_get_tab_name(ttf) == pdc_false && !ttf->fortet) + { + PDC_EXIT_TRY(pdc); + return pdc_false; + } + tt_get_tab_post(ttf); + tt_get_tab_OS_2(ttf); /* may be missing from some Apple fonts */ + + /* this is an optional table, present only in OpenType fonts */ + if (tt_get_tab_CFF_(ttf) == pdc_false && !ttf->fortet) + { + PDC_EXIT_TRY(pdc); + return pdc_false; + } + + + PDC_EXIT_TRY(pdc); + return pdc_true; + } + PDC_CATCH(pdc) + { + } + + return pdc_false; +} /* fnt_read_tt */ + + + +/* convert Unicode scalar to glyph ID using cmap12 or cmap4. + */ +int +tt_unicode2gidx(tt_file *ttf, int usv, pdc_bool logg) +{ + pdc_core *pdc = ttf->pdc; + tt_cmap4 *cm4 = ttf->tab_cmap->win; + pdc_ushort uv; + int segs; + int gidx = 0; + int i; + + uv = (pdc_ushort) usv; + if (logg) pdc_logg(pdc, "\t\t\tU+%04X: ", uv); + segs = cm4->segCountX2 / 2; + + for (i = 0; i < segs; ++i) + if (uv <= cm4->endCount[i]) + break; + + if (logg) pdc_logg(pdc, "i=%d start=U+%04X ", i, cm4->startCount[i]); + + TT_IOCHECK(ttf, i != segs); + if (uv < cm4->startCount[i] || uv == 0xFFFF) + { + if (logg) pdc_logg(pdc, "==> gidx=0\n"); + return 0; + } + + if (logg) pdc_logg(pdc, "offs=%d ", cm4->idRangeOffs[i]); + + if (cm4->idRangeOffs[i] == 0) + { + if (logg) pdc_logg(pdc, "delta=%d ", cm4->idDelta[i]); + gidx = (int)((uv + cm4->idDelta[i]) & 0xFFFF); + } + else + { + int idx = (int) cm4->idRangeOffs[i] / 2 + + (int) (uv - cm4->startCount[i]) - (segs - i); + + if (idx < 0 || idx >= cm4->numGlyphIds) + { + pdc_warning(pdc, FNT_E_TT_GLYPHIDNOTFOUND, + pdc_errprintf(pdc, "%04X", uv), + 0, 0, 0); + return 0; + } + + if (logg) pdc_logg(pdc, "array[%d]=%d ", idx, gidx); + if (cm4->glyphIdArray[idx] == 0) + { + if (logg) pdc_logg(pdc, "==> gidx=0\n"); + return 0; + } + else + { + if (logg) pdc_logg(pdc, "delta=%d ", cm4->idDelta[i]); + gidx = (int)((cm4->glyphIdArray[idx] + cm4->idDelta[i]) & 0xFFFF); + } + } + + if (logg) pdc_logg(pdc, "gidx=%d ", gidx); + + /* this is necessary because of some Mac fonts (e.g. Hiragino) */ + if (gidx >= ttf->numGlyphs) + { + gidx = 0; + if (logg) pdc_logg(pdc, "==> gidx=0\n"); + } + else if (logg) + pdc_logg(pdc, "\n"); + + return gidx; +} + +int +tt_gidx2width(tt_file *ttf, int gidx) +{ + TT_ASSERT(ttf, ttf->tab_hmtx != (tt_tab_hmtx *) 0); + TT_ASSERT(ttf, ttf->tab_hhea != (tt_tab_hhea *) 0); + + { + int n_metrics = ttf->tab_hhea->numberOfHMetrics; + + if (gidx >= n_metrics) + gidx = n_metrics - 1; + if (ttf->monospace) + return ttf->monospace; + else + { + return FNT_TT2PDF(ttf->tab_hmtx->metrics[gidx].advanceWidth); + } + } +} /* tt_gidx2width */ + +void +fnt_set_tt_fontvalues(tt_file *ttf) +{ + fnt_font *font = ttf->font; + fnt_font_metric *ftm = &font->m; + + if (ttf->onlyCFF) + return; + + if (ttf->tab_head) + { + ftm->llx = FNT_TT2PDF(ttf->tab_head->xMin); + ftm->lly = FNT_TT2PDF(ttf->tab_head->yMin); + ftm->urx = FNT_TT2PDF(ttf->tab_head->xMax); + ftm->ury = FNT_TT2PDF(ttf->tab_head->yMax); + } + + if (ttf->tab_post) + { + ftm->italicAngle = ttf->tab_post->italicAngle; + ftm->isFixedPitch = (pdc_bool) ttf->tab_post->isFixedPitch; + ftm->underlinePosition = FNT_TT2PDF(ttf->tab_post->underlinePosition); + ftm->underlineThickness =FNT_TT2PDF(ttf->tab_post->underlineThickness); + } + + if (ttf->tab_OS_2) + { + + font->weight = fnt_check_weight(ttf->tab_OS_2->usWeightClass); + ftm->ascender = FNT_TT2PDF(ttf->tab_OS_2->sTypoAscender); + ftm->descender = FNT_TT2PDF(ttf->tab_OS_2->sTypoDescender); + + if (ttf->tab_OS_2->sCapHeight != FNT_MISSING_FONTVAL) + ftm->capHeight = FNT_TT2PDF(ttf->tab_OS_2->sCapHeight); + if (ttf->tab_OS_2->sxHeight != FNT_MISSING_FONTVAL) + ftm->xHeight = FNT_TT2PDF(ttf->tab_OS_2->sxHeight); + font->linegap = FNT_TT2PDF(ttf->tab_OS_2->sTypoLineGap); + } + + /* some fonts have no OS/2 table and + * some Apple fonts have zero values in the OS/2 table . + */ + if (ttf->tab_OS_2 == NULL || + (ttf->tab_OS_2->usWeightClass == 0 && + ttf->tab_OS_2->sTypoAscender == 0 && + ttf->tab_OS_2->sTypoDescender == 0 && + ttf->tab_OS_2->sTypoLineGap == 0)) + { + font->weight = fnt_macfontstyle2weight(ttf->tab_head->macStyle); + ftm->ascender = FNT_TT2PDF(ttf->tab_hhea->ascender); + ftm->descender = FNT_TT2PDF(ttf->tab_hhea->descender); + font->linegap = FNT_TT2PDF(ttf->tab_hhea->lineGap); + } + + /* default width */ + if (!ttf->fortet) + { + ftm->defwidth = tt_gidx2width(ttf, 0); + } +} + + +/* + * Create and fill some arrays in font structure. + * + * Before calling function the members 'encoding' and 'ev' + * of font struct have to been set: + * + * The desired arrays must be requested by following flags + * (enc == font->enc): + * + * TT_FONT_encvec: Encoding vector (enc == pdc_builtin) + * + * TT_FONT_gid2code: font->gid2code[font->numglyphs]: + * glyph ID -> 8-bit code (enc >= 0, == pdc_builtin) + * glyph ID -> Unicode otherwise. + * + * TT_FONT_code2gid: font->code2gid[font->numcodes]: + * 8-bit code -> glyph ID (enc >= 0, == pdc_builtin) + * Unicode -> glyph ID (enc == pdc_unicode) + * glyph ID -> glyph ID (enc == pdc_glyphid) + * + * TT_FONT_gid2name font->gdi2name[font->numglyphs]: + * glyph ID -> glyph name (enc == pdc_glyphid only) + * + * TT_FONT_name2unitab font->name2unitab[font->tabsize]: + * glyph name -> Unicode for unregistered names + * + * TT_FONT_m_ciw font->m.ciw[font->m.numinters] (Interval table) + * Unicode -> glyph width (enc == pdc_unicode only) + * + * TT_FONT_m_widths font->m.widths[font->numcodes] + * 8-bit code -> glyph width (enc >= 0, == pdc_builtin) + * glyph ID -> glyph width (enc == pdc_glyphid) + * + * TT_FONT_names font->m.name = englishname4 + * font->name = englishname6 + */ +int +fnt_set_tt_fontarrays(tt_file *ttf, int flags) +{ + static const char *fn = "pdc_set_tt_fontarrays"; + pdc_core *pdc = ttf->pdc; + fnt_font *font = ttf->font; + pdc_bool logg2 = pdc_logg_is_enabled(pdc, 2, trc_font); + pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_font); + pdc_bool logg7 = pdc_logg_is_enabled(pdc, 7, trc_font); + pdc_encoding enc = font->enc, encb = pdc_invalidenc; + pdc_encodingvector *ev = NULL, *evb = NULL; + const char *glyphname; + pdc_bool regorder, isencbyte = pdc_false; + pdc_ushort uc, uv; + int ncodes = 0, gidx = 0, width = 0, foundglyphs = 0, uvoffset = 0; + int ucoffset = 0; + int code; + + /* Unicode offset for symbol fonts */ + if (ttf->issymbol == pdc_true) + { + if (ttf->tab_OS_2) + { + /* e.g. WingDings has usFirstChar = 0xF020, but we must start + ** at 0xF000. I haven't seen non-symbol fonts with a usFirstChar + ** like that; perhaps we have to apply similar tricks then... + */ + uvoffset = (ttf->tab_OS_2->usFirstCharIndex & 0xFF00); + } + else + { + /* This would be an Apple font with an encoding different + * from macroman or a subset font withot OS_2 table. + */ + if (!ttf->fortet) + { + pdc_set_errmsg(pdc, FNT_E_TT_SYMBOLOS2, 0, 0, 0, 0); + return -1; + } + uvoffset = 0xF000; + } + + if (logg7) + pdc_logg(pdc, "\t\t\tuvoffset: U+%04X\n", uvoffset); + } + + /* font names */ + if (flags & TT_FONT_names && ttf->tab_name) + { + font->m.name = pdc_strdup(pdc, ttf->tab_name->englishname4); + font->name = pdc_strdup(pdc, ttf->tab_name->englishname6); + } + + /* is Standard Latin font */ + font->issymbfont = ttf->issymbol; + + /* number of glyphs */ + font->numglyphs = ttf->numGlyphs; + + /* number of codes */ + switch(enc) + { + case pdc_cid: + case pdc_unicode: + font->numcodes = ttf->numunicode; + break; + + case pdc_glyphid: + font->numcodes = font->numglyphs; + break; + + default: + font->numcodes = 256; + ev = pdc_get_encoding_vector(pdc, enc); + isencbyte = pdc_true; + break; + } + + + if (enc < 0 && ttf->hasonlymac) + { + encb = pdc_macroman; + evb = pdc_get_encoding_vector(pdc, encb); + } + else + { + encb = enc; + evb = ev; + + if (flags & TT_FONT_encvec && enc == pdc_builtin) + { + evb = fnt_create_font_ev(pdc, font); + ev = evb; + } + } + + if (flags & TT_FONT_code2gid) + { + if (ttf->numunicode <= PDC_NUM_BMPVAL || isencbyte || + enc == pdc_glyphid) + { + font->code2gid = (pdc_ushort *) pdc_calloc(pdc, + font->numcodes * sizeof (pdc_ushort), fn); + } + } + + if ((flags & TT_FONT_gid2code) || logg2) + { + if (ttf->numunicode <= PDC_NUM_BMPVAL || isencbyte) + { + font->gid2code = (pdc_ushort *) pdc_calloc(pdc, + font->numglyphs * sizeof (pdc_ushort), fn); + } + } + + + if (flags & TT_FONT_m_widths) + { + font->m.numwidths = font->numcodes; + font->m.widths = (int *) pdc_calloc(pdc, + font->m.numwidths * sizeof(int), fn); + } + + + /* + * Build the char width tables for the font, set mappings GID <-> Code, + * and count the characters. + */ + foundglyphs = 0; + regorder = pdc_true; + ncodes = (enc == pdc_glyphid) ? ttf->numunicode : font->numcodes; + for (code = 0; code < ncodes; code++) + { + uc = (pdc_ushort) code; + uv = 0; + gidx = 0; + + + if (encb == pdc_macroman && ttf->tab_cmap->mac) + { + tt_cmap0_6 *cm = ttf->tab_cmap->mac; + + if (code > -1 && code < (int) (cm->firstCode + cm->entryCount)) + gidx = cm->glyphIdArray[code]; + } + else if (ttf->issymbol == pdc_true) + { + switch (encb) + { + case pdc_unicode: + if (!ttf->fortet) + { + if (code < 0x00FF) + { + /* we map the lower Unicode values too */ + if (uvoffset > 0x00FF) + regorder = pdc_false; + uv = (pdc_ushort) (code + uvoffset); + break; + } + regorder = pdc_true; + } + + case pdc_glyphid: + uv = (pdc_ushort) code; + break; + + default: + { + uv = (pdc_ushort) (code + uvoffset); + } + if (evb != NULL) + evb->codes[code] = uv; + break; + } + + if (!gidx) + gidx = tt_unicode2gidx(ttf, (int) uv, logg7); + } + else + { + uv = evb->codes[code]; + if (uv) + { + gidx = tt_unicode2gidx(ttf, (int) uv, logg7); + } + } + + /* + * Mapping GID -> [Uni]code + * This is a 1:n relation (e.g. 1 -> SPACE, 1 -> NBSP) + * We prefer the first occurence (SPACE) (regorder), + * in the case of TT symbol fonts the second occurence. + */ + if (gidx && regorder && uc >= ucoffset) + { + /* mapping gid -> code */ + if (font->gid2code) + { + if (!font->gid2code[gidx]) + { + font->gid2code[gidx] = uc; + if (logg5) + pdc_logg(pdc, "\t\tGID: %d -> U+%04X\n", + gidx, font->gid2code[gidx]); + } + else if (logg2) + { + pdc_logg(pdc, "\t\tGID: %d: U+%04X vs. U+%04X\n", + gidx, font->gid2code[gidx], uc); + } + } + foundglyphs++; + + } + + switch (enc) + { + + default: + if (font->m.numwidths) + font->m.widths[code] = tt_gidx2width(ttf, gidx); + break; + } + + /* mapping code -> gid */ + if (font->code2gid) + { + font->code2gid[code] = (pdc_ushort) gidx; + if (logg5 && gidx) + pdc_logg(pdc, "\t\tU+%04X -> GID: %d\n", + code, font->code2gid[code]); + } + } + + + /* logging protocol and/or to check the completeness + * of the glyph names + */ + if (logg2 + ) + { + if (logg2) + pdc_logg(pdc, + "\n\t\tGlyph mapping for %d glyphs:\n", ttf->numGlyphs); + + width = -1; + for (gidx = 0; gidx < ttf->numGlyphs; gidx++) + { + pdc_bool fontspecific = pdc_false; + glyphname = NULL; + + + code = fnt_get_code(gidx, font); + if (!ttf->fortet) + width = tt_gidx2width(ttf, gidx); + + if (code >= 0 && glyphname == NULL) + { + if (enc >= 0 || (ttf->issymbol && ev != NULL)) + glyphname = ev->chars[code]; + else if (enc != pdc_builtin && code <= 0xFFFF) + glyphname = (char *) pdc_unicode2glyphname(pdc, + (pdc_ushort) code); + } + + pdc_logg(pdc, "\t\tGID%5d: ", gidx); + if (!ttf->fortet) + pdc_logg(pdc, "width=%4d ", width); + + switch (enc) + { + + default: + if (!gidx || code > 0) + { + if (enc >= 0 || (ttf->issymbol && ev != NULL)) + { + uv = ev->codes[code]; + pdc_logg(pdc, "code=%3d U+%04X ", code, uv); + } + else + { + if (ttf->fortet && enc == pdc_builtin) + pdc_logg(pdc, "U+%04X ", code); + else + pdc_logg(pdc, "code=%3d ", code); + } + } + break; + } + if (glyphname != NULL) + pdc_logg(pdc, "\"%s\"", glyphname); + if (fontspecific) + pdc_logg(pdc, " (specific)"); + pdc_logg(pdc, "\n"); + } + } + + if (!(flags & TT_FONT_gid2code)) + { + if (ttf->numunicode <= PDC_NUM_BMPVAL && font->gid2code != NULL) + { + pdc_free(pdc, font->gid2code); + font->gid2code = NULL; + } + } + + return foundglyphs; +} + +pdc_encoding +fnt_get_tt_encoding_key(tt_file *ttf, pdc_encoding inenc) +{ + pdc_encoding outenc = inenc; + + /* Symbol font */ + if (ttf->issymbol && inenc >= pdc_winansi) + outenc = pdc_builtin; + + /* MacRoman font */ + if (ttf->hasonlymac && inenc >= pdc_builtin) + outenc = pdc_macroman; + + if (!ttf->issymbol && !ttf->haswinuni && !ttf->hasonlymac) + { + outenc = pdc_invalidenc; + pdc_logg_cond(ttf->pdc, 1, trc_font, + "\tTrueType font contains %s cmap table\n", + ttf->tab_cmap ? "unsupported" : "no" ); + } + else + { + pdc_logg_cond(ttf->pdc, 1, trc_font, + "\tEncoding \"%s\" will be determined\n", + pdc_get_user_encoding(ttf->pdc, outenc)); + } + + return outenc; +} + +static pdc_bool +fnt_check_and_read_ttc(pdc_core *pdc, pdc_file *fp, + const char *filename, const char *fontname, + fnt_font *font, tt_ulong n_fonts) +{ + static const char *fn = "fnt_check_and_read_ttc"; + const char *sf; + tt_file *ttf; + pdc_byte *utf16fontname = NULL; + pdc_bool retval = pdc_false; + pdc_text_format textformat = PDC_UTF8; + pdc_text_format targettextformat = pdc_utf16be; + int i, inlen, outlen; + int ift = -1; + + /* initialize */ + ttf = fnt_new_tt(pdc, font); + ttf->filename = filename; + ttf->fontname = fontname; + ttf->check = pdc_true; + ttf->fp = fp; + ttf->verbose = pdc_false; + + /* searching for font index in font name */ + sf = strrchr(fontname, ':'); + if (sf != NULL) + { + sf++; + if (!*sf) + ift = 0; + else if (pdc_str2integer(sf, PDC_INT_UNSIGNED, &i)) + ift = i; + } + + /* create UTF-16-BE font name string for searching in font file */ + if (ift == -1) + { + inlen = (int) strlen(font->utf8name); + if (pdc_convert_string(pdc, textformat, 0, NULL, + (pdc_byte *) font->utf8name, inlen, + &targettextformat, NULL, + &utf16fontname, &outlen, + PDC_CONV_NOBOM | PDC_CONV_INFLATE, ttf->verbose)) + { + goto FNT_TRUETYPE_EXIT; + } + } + + /* search font */ + for (i = 0; i < (int)n_fonts; ++i) + { + if (i) fnt_delete_tt(ttf); + + tt_seek(ttf, (long) (TT_OFFSETTAB_SIZE + i * sizeof(tt_ulong))); + ttf->offset = tt_get_ulong(ttf); + tt_seek(ttf, (long) ttf->offset); + + pdc_logg_cond(pdc, 1, trc_font, "\tChecking font #%d \n", i+1); + + /* Offset Table */ + if (!fnt_read_offset_tab(ttf)) + goto FNT_TRUETYPE_EXIT; + + /* font name match in Naming Table */ + if (ift > -1) + { + if (ift == i) + break; + } + else + { + /* font name match in Naming Table */ + if (utf16fontname == NULL) + break; + ttf->utf16fontname = (char *) utf16fontname; + ttf->fnamelen = outlen; + if (tt_get_tab_name(ttf)) + break; + } + } + if (utf16fontname != NULL) + pdc_free(pdc, utf16fontname); + + /* font found */ + if (i < (int)n_fonts) + { + tt_byte *pos; + tt_ulong headlen, dirlen, tablen, length, offset; + + /* create file in memory */ + tablen = 0; + dirlen = 4 * sizeof(tt_ulong); + headlen = (tt_ulong) (TT_OFFSETTAB_SIZE + ttf->n_tables * dirlen); + font->filelen = headlen; + for (i = 0; i < ttf->n_tables; i++) + { + length = ttf->dir[i].length; + if (length > tablen) tablen = length; + font->filelen += length; + } + font->img = (pdc_byte *) pdc_malloc(pdc, font->filelen, fn); + + /* read font file */ + tt_seek( ttf, (long) ttf->offset); + tt_read( ttf, font->img, headlen); + pos = font->img + headlen; + for (i = 0; i < ttf->n_tables; i++) + { + length = ttf->dir[i].length; + tt_seek( ttf, (long) ttf->dir[i].offset); + tt_read( ttf, pos, length); + ttf->dir[i].offset = (unsigned int) (pos - font->img); + pos += length; + } + + /* correct offsets in Table Directory */ + pos = font->img + TT_OFFSETTAB_SIZE + 2 * sizeof(tt_ulong); + for (i = 0; i < ttf->n_tables; i++) + { + offset = ttf->dir[i].offset; + pos[0] = (tt_byte) (offset >> 24); + pos[1] = (tt_byte) (offset >> 16); + pos[2] = (tt_byte) (offset >> 8); + pos[3] = (tt_byte) (offset); + pos += dirlen; + } + retval = pdc_true; + } + else + { + pdc_set_errmsg(pdc, FNT_E_TTC_NOTFOUND, filename, 0, 0, 0); + goto FNT_TRUETYPE_EXIT; + } + + FNT_TRUETYPE_EXIT: + + ttf->check = pdc_false; + fnt_delete_tt(ttf); + + return retval; +} + +pdc_bool +fnt_check_tt_font(pdc_core *pdc, const char *filename, const char *fontname, + fnt_font *font, pdc_bool requested) +{ + pdc_file *fp; + char fullname[PDC_FILENAMELEN]; + tt_byte img[TT_OFFSETTAB_SIZE]; + pdc_bool ismem = pdc_false; + tt_ulong n_fonts = 0; + int retval = requested ? pdc_false : pdc_undef; + + fp = pdc_fsearch_fopen(pdc, filename, fullname, "font ",PDC_FILE_BINARY); + if (fp != NULL) + { + if (PDC_OK_FREAD(fp, img, TT_OFFSETTAB_SIZE)) + { + pdc_logg_cond(pdc, 1, trc_font, + "\tLoading TrueType fontfile \"%s\":\n", fullname); + + retval = fnt_test_tt_font(pdc, img, &n_fonts, requested); + if (retval == pdc_true) + { + ismem = pdc_file_isvirtual(fp); + + if (fontname != NULL) + { + if (n_fonts > 1) + { + retval = fnt_check_and_read_ttc(pdc, fp, filename, + fontname, font, n_fonts); + fp = NULL; + } + else + { + font->img = (pdc_byte *) + pdc_freadall(fp, &font->filelen, NULL); + } + + if (retval == pdc_true) + { + if (font->filelen == 0) + { + pdc_set_errmsg(pdc, + PDC_E_IO_READ, fullname, 0, 0, 0); + retval = pdc_false; + } + } + } + + if (retval == pdc_true) + { + if (fp != NULL && ismem) + { + font->imgname = pdc_strdup(pdc, filename); + pdc_lock_pvf(pdc, font->imgname); + } + + font->filename = pdc_strdup(pdc, fullname); + } + } + } + + if (fp != NULL) + pdc_fclose(fp); + } + else + { + retval = pdc_check_fopen_errmsg(pdc, requested); + } + + return retval; +} + + +/* + * After fnt_new_tt initialize following members + * (here with the opposite of default): + * + * ttf->filename = filename; + * ttf->fontname = fontname; + * + * ttf->verbose = pdc_false; + * ttf->kerning = pdc_true; + * ttf->vertical = pdc_true; + * ttf->fortet = pdc_true; + * + * ttf->check = pdc_true; + * ttf->incore = pdc_true; + * ttf->savecff = pdc_true; + * ttf->monospace = 1000; + * + * ttf->fp = fp; + * + */ +tt_file * +fnt_new_tt(pdc_core *pdc, fnt_font *font) +{ + static const char *fn = "fnt_new_tt"; + + tt_file *ttf = (tt_file *) + pdc_malloc(pdc, (size_t) sizeof (tt_file), fn); + + ttf->pdc = pdc; + ttf->font = font; + + ttf->img = (tt_byte *) font->img; + ttf->pos = ttf->img; + ttf->end = ttf->img + font->filelen; + + ttf->filename = NULL; + ttf->fontname = NULL; + ttf->verbose = pdc_true; + ttf->fortet = pdc_false; + ttf->check = pdc_false; + ttf->incore = pdc_false; + ttf->savecff = pdc_false; + ttf->monospace = 0; + ttf->fp = NULL; + + ttf->n_tables = 0; + ttf->offset = 0; + ttf->dir = (tt_dirent *) 0; + + ttf->tab_cmap = (tt_tab_cmap *) 0; + ttf->tab_head = (tt_tab_head *) 0; + ttf->tab_hhea = (tt_tab_hhea *) 0; + ttf->tab_hmtx = (tt_tab_hmtx *) 0; + ttf->tab_maxp = (tt_tab_maxp *) 0; + ttf->tab_name = (tt_tab_name *) 0; + ttf->tab_post = (tt_tab_post *) 0; + ttf->tab_OS_2 = (tt_tab_OS_2 *) 0; + ttf->tab_CFF_ = (tt_tab_CFF_ *) 0; + + ttf->numGlyphs = 0; + ttf->onlyCFF = 0; + ttf->hasGlyphNames = 0; + ttf->numunicode = PDC_NUM_BMPVAL; + ttf->builtinenc = pdc_stdenc; + ttf->regisadobe = pdc_false; + ttf->charcoll = cc_none; + ttf->supplement = 0; + + ttf->issymbol = pdc_false; + ttf->haswinuni = pdc_false; + ttf->hasonlymac = pdc_false; + + + ttf->utf16fontname = (char *) 0; + ttf->fnamelen = 0; + + return ttf; + +} /* fnt_new_tt */ + +void +fnt_delete_tt(tt_file *ttf) +{ + pdc_core *pdc = ttf->pdc; + int i; + + (void) i; + + if (ttf->check == pdc_false && ttf->fp != (pdc_file *) 0) + pdc_fclose(ttf->fp); + + if (ttf->dir != (tt_dirent *) 0) + pdc_free(pdc, ttf->dir); + ttf->dir = (tt_dirent *) 0; + + + if (ttf->tab_head != (tt_tab_head *) 0) + pdc_free(pdc, ttf->tab_head); + if (ttf->tab_hhea != (tt_tab_hhea *) 0) + pdc_free(pdc, ttf->tab_hhea); + if (ttf->tab_maxp != (tt_tab_maxp *) 0) + pdc_free(pdc, ttf->tab_maxp); + if (ttf->tab_OS_2 != (tt_tab_OS_2 *) 0) + pdc_free(pdc, ttf->tab_OS_2); + if (ttf->tab_CFF_ != (tt_tab_CFF_ *) 0) + pdc_free(pdc, ttf->tab_CFF_); + if (ttf->tab_post != (tt_tab_post *) 0) + { + pdc_free(pdc, ttf->tab_post); + } + + if (ttf->tab_cmap != (tt_tab_cmap *) 0) + { + if (ttf->tab_cmap->mac != (tt_cmap0_6 *) 0) { + if (ttf->tab_cmap->mac->glyphIdArray) + pdc_free(pdc, ttf->tab_cmap->mac->glyphIdArray); + pdc_free(pdc, ttf->tab_cmap->mac); + } + + if (ttf->tab_cmap->win != (tt_cmap4 *) 0) + { + tt_cmap4 *cm4 = (tt_cmap4 *) ttf->tab_cmap->win; + + if (cm4->endCount != 0) pdc_free(pdc, cm4->endCount); + if (cm4->startCount != 0) pdc_free(pdc, cm4->startCount); + if (cm4->idDelta != 0) pdc_free(pdc, cm4->idDelta); + if (cm4->idRangeOffs != 0) pdc_free(pdc, cm4->idRangeOffs); + if (cm4->glyphIdArray != 0) pdc_free(pdc, cm4->glyphIdArray); + + pdc_free(pdc, cm4); + } + + if (ttf->tab_cmap->ucs4 != (tt_cmap12 *) 0) + { + tt_cmap12 *cm12 = (tt_cmap12 *) ttf->tab_cmap->ucs4; + + if (cm12->grouptab != 0) pdc_free(pdc, cm12->grouptab); + + pdc_free(pdc, cm12); + } + + pdc_free(pdc, ttf->tab_cmap); + } + + if (ttf->tab_hmtx != (tt_tab_hmtx *) 0) + { + if (ttf->tab_hmtx->metrics != (tt_metric *) 0) + pdc_free(pdc, ttf->tab_hmtx->metrics); + if (ttf->tab_hmtx->lsbs != (tt_fword *) 0) + pdc_free(pdc, ttf->tab_hmtx->lsbs); + pdc_free(pdc, ttf->tab_hmtx); + } + + if (ttf->tab_name != (tt_tab_name *) 0) + { + if (ttf->tab_name->namerecords != (tt_nameref *) 0) + pdc_free(pdc, ttf->tab_name->namerecords); + if (ttf->tab_name->englishname4 != (char *) 0) + pdc_free(pdc, ttf->tab_name->englishname4); + if (ttf->tab_name->englishname6 != (char *) 0) + pdc_free(pdc, ttf->tab_name->englishname6); + if (ttf->tab_name->producer != (char *) 0) + pdc_free(pdc, ttf->tab_name->producer); + pdc_free(pdc, ttf->tab_name); + } + ttf->tab_name = (tt_tab_name *) 0; + + + /* Note: do not clean up ttf->img since the data belongs to font->img + */ + + if (ttf->check == pdc_false) + pdc_free(pdc, ttf); + +} /* fnt_delete_tt */ + + +#endif /* PDF_TRUETYPE_SUPPORTED */ diff --git a/src/pdflib/font/ft_truetype.h b/src/pdflib/font/ft_truetype.h new file mode 100644 index 0000000..89cd3fb --- /dev/null +++ b/src/pdflib/font/ft_truetype.h @@ -0,0 +1,558 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_truetype.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT TrueType typedefs, structures, and enums + * + */ + +#ifndef FT_TRUETYPE_H +#define FT_TRUETYPE_H + +typedef unsigned char tt_byte; +typedef char tt_char; +typedef unsigned short tt_ushort; +typedef short tt_short; +typedef unsigned int tt_ulong; +typedef int tt_long; + +typedef long tt_fixed; +typedef short tt_fword; +typedef unsigned short tt_ufword; + +#define tt_get_fixed tt_get_long +#define tt_get_fword tt_get_short +#define tt_get_ufword tt_get_ushort + +#define TT_XKERNPAIR_CHUNKSIZE 256 +#define TT_ACCGIDTAB_CHUNKSIZE 256 + +#define TT_OPERAND_STACKSIZE 48 + +#define TT_NUMSTDSTRINGS 391 +#define TT_NUMISOSTRINGS 229 +#define TT_NUMEXPSTRINGS 379 +#define TT_NUMEXPERTGIDS 166 + +#define TT_OFFSETTAB_SIZE 12 + +/* flags for fnt_set_tt_fontarrays */ +#define TT_FONT_encvec (1<<0) +#define TT_FONT_gid2code (1<<1) +#define TT_FONT_code2gid (1<<2) +#define TT_FONT_gid2name (1<<3) +#define TT_FONT_m_ciw (1<<4) +#define TT_FONT_m_widths (1<<5) +#define TT_FONT_names (1<<6) +#define TT_FONT_name2unitab (1<<7) + +typedef enum +{ + cff_version = 0, + cff_Notice = 1, + cff_FullName = 2, + cff_FamilyName = 3, + cff_Weight = 4, + cff_FontBBox = 5, + cff_BlueValues = 6, + cff_OtherBlues = 7, + cff_FamilyBlues = 8, + cff_FamilyOtherBlues = 9, + cff_StdHW = 10, + cff_StdVW = 11, + cff_Copyright = 0x100, /* 12 0 */ + cff_isFixedPitch = 0x101, /* 12 1 */ + cff_ItalicAngle = 0x102, /* 12 2 */ + cff_UnderlinePosition = 0x103, /* 12 3 */ + cff_UnderlineThickness = 0x104, /* 12 4 */ + cff_PaintType = 0x105, /* 12 5 */ + cff_CharstringType = 0x106, /* 12 6 */ + cff_FontMatrix = 0x107, /* 12 7 */ + cff_StrokeWidth = 0x108, /* 12 8 */ + cff_BlueScale = 0x109, /* 12 9 */ + cff_BlueShift = 0x10A, /* 12 10 */ + cff_BlueFuzz = 0x10B, /* 12 11 */ + cff_StemSnapH = 0x10C, /* 12 12 */ + cff_StemSnapV = 0x10D, /* 12 13 */ + cff_ForceBold = 0x10E, /* 12 14 */ + /* 0x10F, 12 15 */ + /* 0x110, 12 16 */ + cff_LanguageGroup = 0x111, /* 12 17 */ + cff_ExpansionFactor = 0x112, /* 12 18 */ + cff_initialRandomSeed = 0x113, /* 12 19 */ + cff_SyntheticBase = 0x114, /* 12 20 */ + cff_PostScript = 0x115, /* 12 21 */ + cff_BaseFontName = 0x116, /* 12 22 */ + cff_BaseFontBlend = 0x117, /* 12 23 */ + /* 0x118, 12 24 */ + /* 0x119, 12 25 */ + /* 0x11A, 12 26 */ + /* 0x11B, 12 27 */ + /* 0x11C, 12 28 */ + /* 0x11D, 12 29 */ + cff_ROS = 0x11E, /* 12 30 */ + cff_CIDFontVersion = 0x11F, /* 12 31 */ + cff_CIDFontRevision = 0x120, /* 12 32 */ + cff_CIDFontType = 0x121, /* 12 33 */ + cff_CIDCount = 0x122, /* 12 34 */ + cff_UIDBase = 0x123, /* 12 35 */ + cff_FDArray = 0x124, /* 12 36 */ + cff_FDSelect = 0x125, /* 12 37 */ + cff_FontName = 0x126, /* 12 38 */ + /* 0x127, 12 39 */ + cff_UniqueID = 13, + cff_XUID = 14, + cff_Charsets = 15, + cff_Encoding = 16, + cff_CharStrings = 17, + cff_Private = 18, + cff_Subrs = 19, + cff_defaultWidthX = 20, + cff_nominalWidthX = 21 +} +tt_cff_oper; + +typedef struct +{ + char tag[5]; + tt_ulong checksum; + tt_ulong offset; + tt_ulong length; +} tt_dirent; + +typedef enum +{ + tt_pfid_uni = 0, + tt_pfid_mac = 1, + tt_pfid_iso = 2, + tt_pfid_win = 3, + tt_pfid_custom = 4 +} tt_platform_id; + +typedef enum +{ + tt_wenc_symbol = 0, + tt_wenc_text = 1, + tt_wenc_mtext = 3, + tt_wenc_utext = 10 +} tt_win_encoding_id; + +/* format 4 cmap table: +*/ +typedef struct +{ + tt_ushort encodingID; + tt_ushort format; + tt_ushort length; + tt_ushort version; + tt_ushort segCountX2; /* segCount * 2 */ + tt_ushort searchRange; + tt_ushort entrySelector; + tt_ushort rangeShift; + tt_ushort * endCount; /* [segCount] */ + tt_ushort * startCount; /* [segCount] */ + tt_short * idDelta; /* [segCount] */ + tt_ushort * idRangeOffs; /* [segCount] */ + int numGlyphIds; + tt_ushort * glyphIdArray; +} tt_cmap4; + +/* combined data structure for format 0 and format 6 encoding tables: +*/ +typedef struct +{ + tt_ushort format; + tt_ushort length; + tt_ushort language; + tt_ushort firstCode; + tt_ushort entryCount; + tt_ushort *glyphIdArray; +} tt_cmap0_6; + +/* format 12 cmap table: +*/ +typedef struct +{ + tt_ulong startCharCode; + tt_ulong endCharCode; + tt_ulong startGlyphID; +} tt_grouptab; + +typedef struct +{ + tt_ushort format; + tt_ulong length; + tt_ulong language; + tt_ulong nGroups; + tt_grouptab *grouptab; /* [nGroups] */ +} tt_cmap12; + +typedef struct +{ + tt_ushort version; + tt_ushort numEncTabs; + + tt_cmap4 *win; + tt_cmap0_6 *mac; + tt_cmap12 *ucs4; + + /* picked table */ + tt_ushort platform; + tt_ushort encoding; + tt_ushort format; + tt_ulong offset; + tt_ulong length; +} tt_tab_cmap; + +typedef struct +{ + tt_fixed version; + tt_fixed fontRevision; + tt_ulong checkSumAdjustment; + tt_ulong magicNumber; + tt_ushort flags; + tt_ushort unitsPerEm; + tt_ulong created[2]; + tt_ulong modified[2]; + tt_fword xMin, yMin; + tt_fword xMax, yMax; + tt_ushort macStyle; + tt_ushort lowestRecPPEM; + tt_short fontDirectionHint; + tt_short indexToLocFormat; + tt_short glyphDataFormat; +} tt_tab_head; + +typedef struct +{ + tt_fixed version; + tt_fword ascender; + tt_fword descender; + tt_fword lineGap; + tt_fword advanceWidthMax; /* specification: tt_ufword */ + tt_fword minLeftSideBearing; + tt_fword minRightSideBearing; + tt_fword xMaxExtent; + tt_short caretSlopeRise; + tt_short caretSlopeRun; + tt_short res1; + tt_short res2; + tt_short res3; + tt_short res4; + tt_short res5; + tt_short metricDataFormat; + tt_ushort numberOfHMetrics; +} tt_tab_hhea; + +typedef struct +{ + tt_fword advanceWidth; /* specification: tt_ufword */ + tt_fword lsb; +} tt_metric; + +typedef struct +{ + tt_metric * metrics; + tt_fword * lsbs; +} tt_tab_hmtx; + +typedef struct +{ + tt_fixed version; + tt_ushort numGlyphs; + tt_ushort maxPoints; + tt_ushort maxContours; + tt_ushort maxCompositePoints; + tt_ushort maxCompositeContours; + tt_ushort maxZones; + tt_ushort maxTwilightPoints; + tt_ushort maxStorage; + tt_ushort maxFunctionDefs; + tt_ushort maxInstructionDefs; + tt_ushort maxStackElements; + tt_ushort maxSizeOfInstructions; + tt_ushort maxComponentElements; + tt_ushort maxComponentDepth; +} tt_tab_maxp; + +typedef struct +{ + tt_ushort platform; + tt_ushort encoding; + tt_ushort language; + tt_ushort namid; + tt_ushort length; + tt_ushort offset; +} tt_nameref; + +typedef struct +{ + tt_ushort format; + tt_ushort numNameRecords; + tt_ushort offsetStrings; + tt_nameref *namerecords; + char *englishname4; + char *englishname6; + char *producer; +} tt_tab_name; + +typedef struct +{ + tt_ushort version; + tt_short xAvgCharWidth; + tt_ushort usWeightClass; + tt_ushort usWidthClass; + tt_ushort fsType; /* tt_short? */ + tt_short ySubscriptXSize; + tt_short ySubscriptYSize; + tt_short ySubscriptXOffset; + tt_short ySubscriptYOffset; + tt_short ySuperscriptXSize; + tt_short ySuperscriptYSize; + tt_short ySuperscriptXOffset; + tt_short ySuperscriptYOffset; + tt_short yStrikeoutSize; + tt_short yStrikeoutPosition; + tt_ushort sFamilyClass; /* tt_short? */ + tt_byte panose[10]; + tt_ulong ulUnicodeRange1; + tt_ulong ulUnicodeRange2; + tt_ulong ulUnicodeRange3; + tt_ulong ulUnicodeRange4; + tt_char achVendID[4]; + tt_ushort fsSelection; + tt_ushort usFirstCharIndex; + tt_ushort usLastCharIndex; + + /* tt_ushort according to spec; obviously a spec bug. + */ + tt_short sTypoAscender; + tt_short sTypoDescender; + tt_short sTypoLineGap; + + tt_ushort usWinAscent; + tt_ushort usWinDescent; + + /* if version >= 1 + */ + tt_ulong ulCodePageRange1; + tt_ulong ulCodePageRange2; + + /* if version >= 2 (according to OpenType spec) + */ + tt_short sxHeight; + tt_short sCapHeight; + tt_ushort usDefaultChar; + tt_ushort usBreakChar; + tt_ushort usMaxContext; + + int charcolls[PDC_NUMCHARCOLL]; +} tt_tab_OS_2; + + +typedef struct +{ + tt_ulong offset; + tt_ulong length; +} +tt_tab_CFF_; + +typedef struct +{ + tt_fixed formatType; + double italicAngle; + tt_fword underlinePosition; + tt_fword underlineThickness; + tt_ulong isFixedPitch; + tt_ulong minMemType42; + tt_ulong maxMemType42; + tt_ulong minMemType1; + tt_ulong maxMemType1; + tt_ushort numberOfGlyphs; +} tt_tab_post; + +typedef struct +{ + tt_ushort start; + tt_ushort end; + tt_ushort cclass; +} tt_record_classrange; + +typedef struct +{ + tt_ushort left; + tt_ushort right; + tt_short value; + tt_short dominant; +} tt_xkern_pair; + +typedef struct +{ + tt_xkern_pair *pairs; + int capacity; + int number; +} tt_xkern_pair_list; + +typedef struct +{ + /* -------------------- input members -------------------- */ + + pdc_core *pdc; + fnt_font *font; /* corresponding font struct */ + + const char *filename; /* font file name */ + const char *fontname; /* font API name */ + + pdc_bool verbose; /* put warnings */ + pdc_bool fortet; /* for TET */ + + pdc_bool check; /* check for fontname */ + pdc_bool incore; /* whole font in-core */ + pdc_bool savecff; /* save results of CFF analyzing */ + int monospace; /* monospace amount */ + + tt_byte *img; /* in-core TT font file image */ + tt_byte *end; /* first byte above image buf */ + tt_byte *pos; /* current "file" position */ + pdc_file *fp; + + + /* ----------------- results from parsing ------------------- */ + + int n_tables; + tt_ulong offset; + tt_dirent * dir; + + /* table structs: */ + tt_tab_cmap *tab_cmap; + tt_tab_head *tab_head; + tt_tab_hhea *tab_hhea; + tt_tab_hmtx *tab_hmtx; + tt_tab_maxp *tab_maxp; + tt_tab_name *tab_name; + tt_tab_post *tab_post; + tt_tab_OS_2 *tab_OS_2; + tt_tab_CFF_ *tab_CFF_; + + + int numGlyphs; /* number of glyphs */ + int onlyCFF; /* only CFF_ table */ + int hasGlyphNames; /* CFF: has glyph names */ + int numunicode; /* number of Unicode values incl. 0 */ + int builtinenc; /* builtin encoding */ + pdc_bool regisadobe; /* registry is Adobe */ + int charcoll; /* character collection */ + int supplement; /* supplement number */ + + pdc_bool issymbol; /* symbol font */ + pdc_bool haswinuni; /* has a "Microsoft standard character + * to glyph index mapping table" + * cmap (3, 1) format 4 or + * cmap (3,10) format 12 or + * cmap (0, 3) format 4 (mac old case) */ + pdc_bool hasonlymac; /* has only macroman cmap (0,1) */ + + char *utf16fontname; /* UTF-16-BE font name for TTC fonts */ + int fnamelen; /* font name length */ + + +} tt_file; + +/* TrueType table names, defined as octal codes */ +#define fnt_str_ttcf "\164\164\143\146" +#define fnt_str_bhed "\142\150\145\144" +#define fnt_str_CFF_ "\103\106\106\040" +#define fnt_str_cvt_ "\143\166\164\040" +#define fnt_str_cmap "\143\155\141\160" +#define fnt_str_fpgm "\146\160\147\155" +#define fnt_str_glyf "\147\154\171\146" +#define fnt_str_GPOS "\107\120\117\123" +#define fnt_str_GSUB "\107\123\125\102" +#define fnt_str_head "\150\145\141\144" +#define fnt_str_hhea "\150\150\145\141" +#define fnt_str_hmtx "\150\155\164\170" +#define fnt_str_kern "\153\145\162\156" +#define fnt_str_loca "\154\157\143\141" +#define fnt_str_maxp "\155\141\170\160" +#define fnt_str_name "\156\141\155\145" +#define fnt_str_OS_2 "\117\123\057\062" /* OS/2 */ +#define fnt_str_post "\160\157\163\164" +#define fnt_str_prep "\160\162\145\160" + +#define fnt_str_vert "\166\145\162\164" + +/* Composite font flags. */ +/* See Reference of OpenType: glyf - Glyf Data */ +#define ARGS_ARE_WORDS 0x001 +#define ARGS_ARE_XY_VALUES 0x002 +#define ROUND_XY_TO_GRID 0x004 +#define WE_HAVE_A_SCALE 0x008 +/* reserved 0x010 */ +#define MORE_COMPONENTS 0x020 +#define WE_HAVE_AN_XY_SCALE 0x040 +#define WE_HAVE_A_2X2 0x080 +#define WE_HAVE_INSTR 0x100 +#define USE_MY_METRICS 0x200 + + +/* Functions */ + +#define FNT_TT2PDF(v) (int) PDC_ROUND(v * 1000.0 / ttf->tab_head->unitsPerEm) + +#define TT_ASSERT(ttf, cond) \ + ((cond) ? (void) 0 : tt_assert(ttf)) + +#define TT_IOCHECK(ttf, cond) \ + ((cond) ? (void) 0 : tt_error(ttf)) + +int tt_tag2idx(tt_file *ttf, char *tag); +void *tt_get_tab(tt_file *ttf, char *tag, size_t nbytes, pdc_bool tterror, + tt_ulong *offset); +void tt_get_tab_maxp(tt_file *ttf); +void tt_get_tab_head(tt_file *ttf); +void tt_get_tab_cmap(tt_file *ttf); +pdc_bool tt_get_tab_CFF_(tt_file *ttf); +void tt_get_tab_OS_2(tt_file *ttf); + +void tt_assert(tt_file *ttf); +void tt_error(tt_file *ttf); +void tt_seek(tt_file *ttf, long offset); +void tt_read(tt_file *ttf, void *buf, unsigned int nbytes); +long tt_tell(tt_file *ttf); +tt_ushort tt_get_ushort(tt_file *ttf); +tt_short tt_get_short(tt_file *ttf); +tt_ulong tt_get_ulong3(tt_file *ttf); +tt_ulong tt_get_ulong(tt_file *ttf); +tt_long tt_get_long(tt_file *ttf); +tt_ulong tt_get_offset(tt_file *ttf, tt_byte offsize); +pdc_bool tt_get_tab_name(tt_file *ttf); + +int tt_unicode2gidx(tt_file *ttf, int usv, pdc_bool logg); +int tt_gidx2width(tt_file *ttf, int gidx); + + +tt_file *fnt_new_tt(pdc_core *pdc, fnt_font *font); +void fnt_delete_tt(tt_file *ttf); +void fnt_set_tt_fontvalues(tt_file *ttf); +int fnt_set_tt_fontarrays(tt_file *ttf, int flags); +pdc_encoding fnt_get_tt_encoding_key(tt_file *ttf, pdc_encoding inenc); +pdc_bool fnt_read_tt(tt_file *ttf); +pdc_bool fnt_read_offset_tab(tt_file *ttf); +pdc_bool fnt_test_tt_font(pdc_core *pdc, tt_byte *img, tt_ulong *n_fonts, + pdc_bool requested); +pdc_bool fnt_is_opentype_font(tt_file *ttf); +pdc_bool fnt_check_tt_font(pdc_core *pdc, const char *filename, + const char *fontname, fnt_font *font, pdc_bool requested); + + +#endif /* FT_TRUETYPE_H */ diff --git a/src/pdflib/font/ft_type1.c b/src/pdflib/font/ft_type1.c new file mode 100644 index 0000000..2644284 --- /dev/null +++ b/src/pdflib/font/ft_type1.c @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: ft_type1.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * FONT Type1 font handling routines + * + */ + +#include "ft_font.h" + +pdc_bool +fnt_test_type1_font(pdc_core *pdc, const pdc_byte *img) +{ + char startsequ[5]; + + strcpy(startsequ, FNT_PFA_STARTSEQU); + + /* ASCII block sign and begin of text at byte 7 */ + if (img[0] == 0x80 && img[1] == 0x01 && + strncmp((const char *)&img[6], startsequ, 4) == 0) + { + pdc_logg_cond(pdc, 1, trc_font, + "\tPostScript Type1 font detected\n"); + return pdc_true; + } + return pdc_false; +} + + diff --git a/src/pdflib/pdcore/pc_aes.c b/src/pdflib/pdcore/pc_aes.c new file mode 100644 index 0000000..ddad480 --- /dev/null +++ b/src/pdflib/pdcore/pc_aes.c @@ -0,0 +1,32 @@ +/* crypto/aes/aes_core.c -*- mode:C; c-file-style: "eay" -*- */ +/** + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> + * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> + * @author Paulo Barreto <paulo.barreto@terra.com.br> + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Note: rewritten a little bit to provide error control and an OpenSSL- + compatible API */ + +#include "pc_util.h" + diff --git a/src/pdflib/pdcore/pc_aes.h b/src/pdflib/pdcore/pc_aes.h new file mode 100644 index 0000000..65ef4f4 --- /dev/null +++ b/src/pdflib/pdcore/pc_aes.h @@ -0,0 +1,53 @@ +/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#include "pc_core.h" + diff --git a/src/pdflib/pdcore/pc_aescbc.c b/src/pdflib/pdcore/pc_aescbc.c new file mode 100644 index 0000000..c9a5a42 --- /dev/null +++ b/src/pdflib/pdcore/pc_aescbc.c @@ -0,0 +1,53 @@ +/* crypto/aes/aes_cbc.c -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#include "pc_util.h" + diff --git a/src/pdflib/pdcore/pc_aeslocal.h b/src/pdflib/pdcore/pc_aeslocal.h new file mode 100644 index 0000000..65ef4f4 --- /dev/null +++ b/src/pdflib/pdcore/pc_aeslocal.h @@ -0,0 +1,53 @@ +/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#include "pc_core.h" + diff --git a/src/pdflib/pdcore/pc_arc4.c b/src/pdflib/pdcore/pc_arc4.c new file mode 100644 index 0000000..b48659e --- /dev/null +++ b/src/pdflib/pdcore/pc_arc4.c @@ -0,0 +1,61 @@ +/* crypto/arc4/arc4_enc.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the ARC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include "pc_util.h" +#include "pc_arc4.h" + diff --git a/src/pdflib/pdcore/pc_arc4.h b/src/pdflib/pdcore/pc_arc4.h new file mode 100644 index 0000000..9a474a7 --- /dev/null +++ b/src/pdflib/pdcore/pc_arc4.h @@ -0,0 +1,60 @@ +/* crypto/arc4/arc4.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the ARC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include "pc_core.h" + diff --git a/src/pdflib/pdcore/pc_chartabs.c b/src/pdflib/pdcore/pc_chartabs.c new file mode 100644 index 0000000..3799d45 --- /dev/null +++ b/src/pdflib/pdcore/pc_chartabs.c @@ -0,0 +1,613 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_chartabs.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib routines for converting glyph or character names to Unicode + * and vice versa + * + */ + +#define PC_CHARTABS_C + +#include "pc_util.h" +#include "pc_chartabs.h" +#include "pc_ctype.h" + + +/* ---------------- general character search functions ------------------- */ + +/* + * Binary search for list of codes in a pdc_glyph_tab array sorted by glyphname + */ +int +pdc_glyphname2codelist(const char *glyphname, const pdc_glyph_tab *glyphtab, + int tabsize, pdc_ushort *codelist) +{ + int lo = 0; + int hi = glyphname ? tabsize : lo; + int nv = 0; + + while (lo < hi) + { + int i = (lo + hi) / 2; + int cmp = strcmp(glyphname, glyphtab[i].name); + + if (cmp == 0) + { + for (; i >= 1; i--) + { + if (strcmp(glyphname, glyphtab[i-1].name)) + break; + } + for (; i < tabsize; i++) + { + if (strcmp(glyphname, glyphtab[i].name)) + break; + codelist[nv] = glyphtab[i].code; + nv++; + } + return nv; + } + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + + return nv; +} + +/* + * Binary search for code in a pdc_glyph_tab array sorted by glyphname + */ +int +pdc_glyphname2code(const char *glyphname, const pdc_glyph_tab *glyphtab, + int tabsize) +{ + int lo = 0; + int hi = glyphname ? tabsize : lo; + + while (lo < hi) + { + int i = (lo + hi) / 2; + int cmp = strcmp(glyphname, glyphtab[i].name); + + if (cmp == 0) + return (int) glyphtab[i].code; + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + + return -1; +} + +/* + * Binary search for glyphname in a pdc_glyph_tab array sorted by code + */ +const char * +pdc_code2glyphname(pdc_ushort code, const pdc_glyph_tab *glyphtab, int tabsize) +{ + int lo = 0; + int hi = tabsize; + + while (lo < hi) + { + int i = (lo + hi) / 2; + + if (code == glyphtab[i].code) + return glyphtab[i].name; + + if (code < glyphtab[i].code) + hi = i; + else + lo = i + 1; + } + + return NULL; +} + +/* + * Binary search for list of codes in a pdc_code_map array sorted by source code + */ +int +pdc_code2codelist(pdc_core *pdc, pdc_ushort code, + const pdc_code_map *codemap, int tabsize, + pdc_ushort *codelist, int listsize) +{ + int lo = 0; + int hi = tabsize; + int nv = 0; + + while (lo < hi) + { + int i = (lo + hi) / 2; + + if (codemap[i].src == code) + { + for (; i >= 1; i--) + { + if (codemap[i-1].src != code) + break; + } + + for (; i < tabsize; i++) + { + if (codemap[i].src != code) + break; + + if (nv >= listsize) + pdc_error(pdc, PDC_E_CONV_LIST_MEMOVERFLOW, 0, 0, 0, 0); + + codelist[nv] = codemap[i].dst; + nv++; + } + + return nv; + } + if (codemap[i].src > code) + hi = i; + else + lo = i + 1; + } + + return nv; +} + +/* + * Binary search for glyphname in a pdc_glyph_tab array sorted by glyphname + * to get the static pointer for the glyphname. + */ +const char * +pdc_glyphname2glyphname(const char *glyphname, + const pdc_glyph_tab *glyphtab, int tabsize) +{ + int lo = 0; + int hi = tabsize; + + while (lo < hi) + { + int i = (lo + hi) / 2; + int cmp = strcmp(glyphname, glyphtab[i].name); + + if (cmp == 0) + return glyphtab[i].name; + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + + return NULL; +} + + +/* ---------------- special character search functions ------------------- */ + +/* + * Returns the Unicode value of a glyph name in Adobe Glyph List 1.2'. + * If the name is not contained in AGL, -1 will be returned. + */ +int +pdc_adobe2unicode(const char *glyphname) +{ + return pdc_glyphname2code(glyphname, tab_agl2uni, + (sizeof (tab_agl2uni)) / (sizeof (pdc_glyph_tab))); +} + +/* + * Returns the name in AGL 1.2' or ZapfDingbats font, + * which corresponds to the supplied Unicode value. + * If the value doesn't have a corresponding glyph name, + * NULL will be returned. + * For control codes ".notdef" will be returned. + * But this is not compatibel with AGL 2.0! + */ +const char * +pdc_unicode2adobe(pdc_ushort uv) +{ + const char *glyphname; + + /* AGL 1.2' glyphname */ + glyphname = pdc_code2glyphname(uv, tab_uni2agl, + (sizeof tab_uni2agl) / (sizeof (pdc_glyph_tab))); + if (glyphname != NULL) + return glyphname; + + /* C0 and C1 control characters. + * They have never a graphical representation but are defined. + */ + if (uv < PDC_UNICODE_SPACE || + (uv >= PDC_UNICODE_DELETE && uv < PDC_UNICODE_NBSP)) + return glyph__notdef; + + return NULL; +} + +const char * +pdc_get_notdef_glyphname(void) +{ + return (char *) glyph__notdef; +} + +/* + * Returns the Unicode value of a ZapfDingbats glyph name. + * If the name is not contained in the ZapfDingbats list + * -1 will be returned. + */ +int +pdc_zadb2unicode(const char *glyphname) +{ + return pdc_glyphname2code(glyphname, tab_zadb2uni, + (sizeof (tab_zadb2uni)) / (sizeof (pdc_glyph_tab))); +} + +/* + * Returns the glyph name in the ZapfDingbats font which corresponds + * to the supplied Unicode value. If the value doesn't have a + * corresponding glyph name NULL will be returned. + */ +const char * +pdc_unicode2zadb(pdc_ushort uv) +{ + return pdc_code2glyphname(uv, tab_uni2zadb, + (sizeof tab_uni2zadb) / (sizeof (pdc_glyph_tab))); +} + +/* + * Returns the Unicode values of a glyph name in Adobe Glyph List 2.0 + * which is not contained in AGL-1.2'. + * + * The function presupposes that uvlist is an array of PDC_MAX_UVLIST. + * + * Return value is the number of Unicodes. + */ +int +pdc_newadobe2unicodelist(const char *glyphname, pdc_ushort *uvlist) +{ + return pdc_glyphname2codelist(glyphname, tab_diffagl2uni, + (sizeof tab_diffagl2uni) / (sizeof (pdc_glyph_tab)), + uvlist); +} + +/* + * Returns the glyph name in Adobe Glyph List 2.0 + * which is not contained in AGL-1.2' corresponding + * to the supplied Unicode value. Ambiguous Unicode + * values or glyph names are not supported! + * If the value doesn't have a corresponding glyph name + * NULL will be returned. + */ +const char * +pdc_unicode2newadobe(pdc_ushort uv) +{ + return pdc_code2glyphname(uv, tab_uni2diffagl, + (sizeof tab_uni2diffagl) / (sizeof (pdc_glyph_tab))); +} + +/* + * Returns the glyph name in Adobe Glyph List 2.0 + * which is not contained in AGL-1.2' and which matches + * the supplied glyph name. + * If no match is found NULL will be returned. + */ +const char * +pdc_get_newadobe_glyphname(const char *glyphname) +{ + return pdc_glyphname2glyphname(glyphname, tab_diffagl2uni, + (sizeof tab_diffagl2uni) / (sizeof (pdc_glyph_tab))); +} + + +/* + * Returns the alternative Unicode value of a double-mapped + * AGL-1.2 glyph name. If the name is not double-mapped, + * -1 will be returned. + */ +int +pdc_glyphname2altunicode(const char *glyphname) +{ + return pdc_glyphname2code(glyphname, tab_double_mappping, + (sizeof (tab_double_mappping)) / (sizeof (pdc_glyph_tab))); +} + +/* + * Returns true if a character name is contained in pc_standard_latin_charset. + * Otherwise false will be returned. + */ +pdc_bool +pdc_is_std_charname(const char *glyphname) +{ + int lo = 0; + int hi = ((sizeof pc_standard_latin_charset) / (sizeof (char *))); + + if (glyphname) + { + while (lo < hi) + { + int i = (lo + hi) / 2; + int cmp = strcmp(glyphname, pc_standard_latin_charset[i]); + + if (cmp == 0) + return pdc_true; + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + } + + return pdc_false; +} + + + +/* -------------- special character mapping for Type1 fonts --------------- */ + +/* + * Deletes a bit in a bit mask. The bit indicates that + * the respective glyph name of AGL 2.0 is not available + * in a PostScript font. The glyph name is used to avoid + * ambiguities (see comment in pc_chartabs.h) + * + */ + +#define PDC_BIT_NBSP (1L<<0) +#define PDC_BIT_SHY (1L<<1) +#define PDC_BIT_MODMACRON (1L<<2) +#define PDC_BIT_CAPDELTA (1L<<3) +#define PDC_BIT_CAPOMEGA (1L<<4) +#define PDC_BIT_DIVSLASH (1L<<5) +#define PDC_BIT_BULLETOP (1L<<6) +#define PDC_BIT_SMALLMU (1L<<7) + +void +pdc_delete_missingglyph_bit(pdc_ushort uv, pdc_ulong *bmask) +{ + switch(uv) + { + case PDC_UNICODE_NBSP: + *bmask &= ~PDC_BIT_NBSP; + return; + + case PDC_UNICODE_SHY: + *bmask &= ~PDC_BIT_SHY; + return; + + case PDC_UNICODE_MODMACRON: + *bmask &= ~PDC_BIT_MODMACRON; + return; + + case PDC_UNICODE_CAPDELTA: + *bmask &= ~PDC_BIT_CAPDELTA; + return; + + case PDC_UNICODE_CAPOMEGA: + *bmask &= ~PDC_BIT_CAPOMEGA; + return; + + case PDC_UNICODE_DIVSLASH: + *bmask &= ~PDC_BIT_DIVSLASH; + return; + + case PDC_UNICODE_BULLETOP: + *bmask &= ~PDC_BIT_BULLETOP; + return; + + case PDC_UNICODE_SMALLMU: + *bmask &= ~PDC_BIT_SMALLMU; + return; + + default: + return; + } +} + +/* + * Returnes an alternative Unicode value and/or glyph name for an + * AGL 2.0 glyph name which is not available in a PostScript font. + * + */ + +pdc_ushort +pdc_get_alter_glyphname(pdc_ushort uv, pdc_ulong bmask, char **glyphname) +{ + switch(uv) + { + case PDC_UNICODE_NBSP: + if (bmask & PDC_BIT_NBSP) + { + if (glyphname) + *glyphname = (char *) glyph_space; + return PDC_UNICODE_SPACE; + } + break; + + case PDC_UNICODE_SHY: + if (bmask & PDC_BIT_SHY) + { + if (glyphname) + *glyphname = (char *) glyph_hyphen; + return PDC_UNICODE_HYPHEN; + } + break; + + case PDC_UNICODE_MODMACRON: + if (bmask & PDC_BIT_MODMACRON) + { + if (glyphname) + *glyphname = (char *) glyph_macron; + return PDC_UNICODE_MACRON; + } + break; + + case PDC_UNICODE_CAPDELTA: + if (bmask & PDC_BIT_CAPDELTA) + { + if (glyphname) + *glyphname = (char *) glyph_Delta; + return PDC_UNICODE_INCREMENT; + } + break; + + case PDC_UNICODE_CAPOMEGA: + if (bmask & PDC_BIT_CAPOMEGA) + { + if (glyphname) + *glyphname = (char *) glyph_Omega; + return PDC_UNICODE_OHMSIGN; + } + break; + + case PDC_UNICODE_DIVSLASH: + if (bmask & PDC_BIT_DIVSLASH) + { + if (glyphname) + *glyphname = (char *) glyph_fraction; + return PDC_UNICODE_FRACSLASH; + } + + case PDC_UNICODE_BULLETOP: + if (bmask & PDC_BIT_BULLETOP) + { + if (glyphname) + *glyphname = (char *) glyph_periodcentered; + return PDC_UNICODE_MIDDLEDOT; + } + + case PDC_UNICODE_SMALLMU: + if (bmask & PDC_BIT_SMALLMU) + { + if (glyphname) + *glyphname = (char *) glyph_mu; + return PDC_UNICODE_MICRO; + } + + default: + if (glyphname) + { + if (*glyphname == NULL) + *glyphname = (char *) pdc_get_notdef_glyphname(); + return 0; + } + } + + return uv; +} + +/* + * Returns the Unicode value for a given string Unicode expression: + * + * - Byte 1...255 -> U0001...U00FF + * - U+XXXXX + * - 0xXXXXX + * - HTML character reference without frame syntax &...; + * + * If no conversion is possible -1 will be returned. + */ +int +pdc_string2unicode(pdc_core *pdc, const char *text, int i_flags, + const pdc_keyconn *keyconn, pdc_bool verbose) +{ + int iz = PDC_KEY_NOTFOUND, usv = -1; + pdc_bool seterr = pdc_false; + int flags = PDC_INT_UNSIGNED; + int i = 0; + + (void) verbose; + + /* single byte as Unicode value */ + if (strlen(text) == 1) + { + char c = text[0]; + usv = (pdc_byte) c; + } + else + { + /* keyword */ + if (keyconn) + { + if (i_flags & PDC_INT_CASESENS) + iz = pdc_get_keycode(text, keyconn); + else + iz = pdc_get_keycode_ci(text, keyconn); + } + if (iz != PDC_KEY_NOTFOUND) + { + usv = iz; + } + else + { + /* Unicode value */ + if (!pdc_strincmp(text, "U+", 2)) + { + flags |= PDC_INT_HEXADEC; + i = 2; + } + if (!pdc_str2integer(&text[i], flags, &iz)) + { + seterr = pdc_true; + } + else if (iz >= PDC_NUM_UNIVAL || + (iz >= PDC_UNICODE_MINHIGHSUR && + iz <= PDC_UNICODE_MAXLOWSUR)) + { + seterr = pdc_true; + } + else + { + usv = iz; + } + } + } + + if (seterr) + { + pdc_set_errmsg(pdc, PDC_E_CONV_ILLUTF32, &text[i], 0, 0, 0); + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + } + + return usv; +} + +/* + * Returns true if Unicode character is a character relevant for line breaking + * + */ +pdc_bool +pdc_is_linebreaking_relchar(pdc_ushort uv) +{ + switch (uv) + { + case PDC_UNICODE_HT: + case PDC_UNICODE_LF: + case PDC_UNICODE_VT: + case PDC_UNICODE_FF: + case PDC_UNICODE_CR: + case PDC_UNICODE_NEL: + case PDC_UNICODE_SHY: + case PDC_UNICODE_LS: + case PDC_UNICODE_PS: + return pdc_true; + } + + return pdc_false; +} + + diff --git a/src/pdflib/pdcore/pc_chartabs.h b/src/pdflib/pdcore/pc_chartabs.h new file mode 100644 index 0000000..cd6970b --- /dev/null +++ b/src/pdflib/pdcore/pc_chartabs.h @@ -0,0 +1,13851 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_chartabs.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * This file contains Adobe Glyph Names, HTML character reference names and + * some special glyph names. + * + */ + +#ifndef PC_CHARTABS_H +#define PC_CHARTABS_H + +/* + * All glyph names of Adobe Glyph List (AGL) version 2.0 + * + */ + +static const char glyph__notdef[] = ".notdef"; + +static const char glyph_A[] = "A"; +static const char glyph_AE[] = "AE"; +static const char glyph_AEacute[] = "AEacute"; +static const char glyph_AEmacron[] = "AEmacron"; +static const char glyph_AEsmall[] = "AEsmall"; +static const char glyph_Aacute[] = "Aacute"; +static const char glyph_Aacutesmall[] = "Aacutesmall"; +static const char glyph_Abreve[] = "Abreve"; +static const char glyph_Abreveacute[] = "Abreveacute"; +static const char glyph_Abrevecyrillic[] = "Abrevecyrillic"; +static const char glyph_Abrevedotbelow[] = "Abrevedotbelow"; +static const char glyph_Abrevegrave[] = "Abrevegrave"; +static const char glyph_Abrevehookabove[] = "Abrevehookabove"; +static const char glyph_Abrevetilde[] = "Abrevetilde"; +static const char glyph_Acaron[] = "Acaron"; +static const char glyph_Acircle[] = "Acircle"; +static const char glyph_Acircumflex[] = "Acircumflex"; +static const char glyph_Acircumflexacute[] = "Acircumflexacute"; +static const char glyph_Acircumflexdotbelow[] = "Acircumflexdotbelow"; +static const char glyph_Acircumflexgrave[] = "Acircumflexgrave"; +static const char glyph_Acircumflexhookabove[] = "Acircumflexhookabove"; +static const char glyph_Acircumflexsmall[] = "Acircumflexsmall"; +static const char glyph_Acircumflextilde[] = "Acircumflextilde"; +static const char glyph_Acute[] = "Acute"; +static const char glyph_Acutesmall[] = "Acutesmall"; +static const char glyph_Acyrillic[] = "Acyrillic"; +static const char glyph_Adblgrave[] = "Adblgrave"; +static const char glyph_Adieresis[] = "Adieresis"; +static const char glyph_Adieresiscyrillic[] = "Adieresiscyrillic"; +static const char glyph_Adieresismacron[] = "Adieresismacron"; +static const char glyph_Adieresissmall[] = "Adieresissmall"; +static const char glyph_Adotbelow[] = "Adotbelow"; +static const char glyph_Adotmacron[] = "Adotmacron"; +static const char glyph_Agrave[] = "Agrave"; +static const char glyph_Agravesmall[] = "Agravesmall"; +static const char glyph_Ahookabove[] = "Ahookabove"; +static const char glyph_Aiecyrillic[] = "Aiecyrillic"; +static const char glyph_Ainvertedbreve[] = "Ainvertedbreve"; +static const char glyph_Alpha[] = "Alpha"; +static const char glyph_Alphatonos[] = "Alphatonos"; +static const char glyph_Amacron[] = "Amacron"; +static const char glyph_Amonospace[] = "Amonospace"; +static const char glyph_Aogonek[] = "Aogonek"; +static const char glyph_Aring[] = "Aring"; +static const char glyph_Aringacute[] = "Aringacute"; +static const char glyph_Aringbelow[] = "Aringbelow"; +static const char glyph_Aringsmall[] = "Aringsmall"; +static const char glyph_Asmall[] = "Asmall"; +static const char glyph_Atilde[] = "Atilde"; +static const char glyph_Atildesmall[] = "Atildesmall"; +static const char glyph_Aybarmenian[] = "Aybarmenian"; +static const char glyph_B[] = "B"; +static const char glyph_Bcircle[] = "Bcircle"; +static const char glyph_Bdotaccent[] = "Bdotaccent"; +static const char glyph_Bdotbelow[] = "Bdotbelow"; +static const char glyph_Becyrillic[] = "Becyrillic"; +static const char glyph_Benarmenian[] = "Benarmenian"; +static const char glyph_Beta[] = "Beta"; +static const char glyph_Bhook[] = "Bhook"; +static const char glyph_Blinebelow[] = "Blinebelow"; +static const char glyph_Bmonospace[] = "Bmonospace"; +static const char glyph_Brevesmall[] = "Brevesmall"; +static const char glyph_Bsmall[] = "Bsmall"; +static const char glyph_Btopbar[] = "Btopbar"; +static const char glyph_C[] = "C"; +static const char glyph_Caarmenian[] = "Caarmenian"; +static const char glyph_Cacute[] = "Cacute"; +static const char glyph_Caron[] = "Caron"; +static const char glyph_Caronsmall[] = "Caronsmall"; +static const char glyph_Ccaron[] = "Ccaron"; +static const char glyph_Ccedilla[] = "Ccedilla"; +static const char glyph_Ccedillaacute[] = "Ccedillaacute"; +static const char glyph_Ccedillasmall[] = "Ccedillasmall"; +static const char glyph_Ccircle[] = "Ccircle"; +static const char glyph_Ccircumflex[] = "Ccircumflex"; +static const char glyph_Cdot[] = "Cdot"; +static const char glyph_Cdotaccent[] = "Cdotaccent"; +static const char glyph_Cedillasmall[] = "Cedillasmall"; +static const char glyph_Chaarmenian[] = "Chaarmenian"; +static const char glyph_Cheabkhasiancyrillic[] = "Cheabkhasiancyrillic"; +static const char glyph_Checyrillic[] = "Checyrillic"; +static const char glyph_Chedescenderabkhasiancyrillic[] = +"Chedescenderabkhasiancyrillic"; +static const char glyph_Chedescendercyrillic[] = "Chedescendercyrillic"; +static const char glyph_Chedieresiscyrillic[] = "Chedieresiscyrillic"; +static const char glyph_Cheharmenian[] = "Cheharmenian"; +static const char glyph_Chekhakassiancyrillic[] = "Chekhakassiancyrillic"; +static const char glyph_Cheverticalstrokecyrillic[] = +"Cheverticalstrokecyrillic"; +static const char glyph_Chi[] = "Chi"; +static const char glyph_Chook[] = "Chook"; +static const char glyph_Circumflexsmall[] = "Circumflexsmall"; +static const char glyph_Cmonospace[] = "Cmonospace"; +static const char glyph_Coarmenian[] = "Coarmenian"; +static const char glyph_Csmall[] = "Csmall"; +static const char glyph_D[] = "D"; +static const char glyph_DZ[] = "DZ"; +static const char glyph_DZcaron[] = "DZcaron"; +static const char glyph_Daarmenian[] = "Daarmenian"; +static const char glyph_Dafrican[] = "Dafrican"; +static const char glyph_Dcaron[] = "Dcaron"; +static const char glyph_Dcedilla[] = "Dcedilla"; +static const char glyph_Dcircle[] = "Dcircle"; +static const char glyph_Dcircumflexbelow[] = "Dcircumflexbelow"; +static const char glyph_Dcroat[] = "Dcroat"; +static const char glyph_Ddotaccent[] = "Ddotaccent"; +static const char glyph_Ddotbelow[] = "Ddotbelow"; +static const char glyph_Decyrillic[] = "Decyrillic"; +static const char glyph_Deicoptic[] = "Deicoptic"; +static const char glyph_Delta[] = "Delta"; +static const char glyph_Deltagreek[] = "Deltagreek"; +static const char glyph_Dhook[] = "Dhook"; +static const char glyph_Dieresis[] = "Dieresis"; +static const char glyph_DieresisAcute[] = "DieresisAcute"; +static const char glyph_DieresisGrave[] = "DieresisGrave"; +static const char glyph_Dieresissmall[] = "Dieresissmall"; +static const char glyph_Digammagreek[] = "Digammagreek"; +static const char glyph_Djecyrillic[] = "Djecyrillic"; +static const char glyph_Dlinebelow[] = "Dlinebelow"; +static const char glyph_Dmonospace[] = "Dmonospace"; +static const char glyph_Dotaccentsmall[] = "Dotaccentsmall"; +static const char glyph_Dslash[] = "Dslash"; +static const char glyph_Dsmall[] = "Dsmall"; +static const char glyph_Dtopbar[] = "Dtopbar"; +static const char glyph_Dz[] = "Dz"; +static const char glyph_Dzcaron[] = "Dzcaron"; +static const char glyph_Dzeabkhasiancyrillic[] = "Dzeabkhasiancyrillic"; +static const char glyph_Dzecyrillic[] = "Dzecyrillic"; +static const char glyph_Dzhecyrillic[] = "Dzhecyrillic"; +static const char glyph_E[] = "E"; +static const char glyph_Eacute[] = "Eacute"; +static const char glyph_Eacutesmall[] = "Eacutesmall"; +static const char glyph_Ebreve[] = "Ebreve"; +static const char glyph_Ecaron[] = "Ecaron"; +static const char glyph_Ecedillabreve[] = "Ecedillabreve"; +static const char glyph_Echarmenian[] = "Echarmenian"; +static const char glyph_Ecircle[] = "Ecircle"; +static const char glyph_Ecircumflex[] = "Ecircumflex"; +static const char glyph_Ecircumflexacute[] = "Ecircumflexacute"; +static const char glyph_Ecircumflexbelow[] = "Ecircumflexbelow"; +static const char glyph_Ecircumflexdotbelow[] = "Ecircumflexdotbelow"; +static const char glyph_Ecircumflexgrave[] = "Ecircumflexgrave"; +static const char glyph_Ecircumflexhookabove[] = "Ecircumflexhookabove"; +static const char glyph_Ecircumflexsmall[] = "Ecircumflexsmall"; +static const char glyph_Ecircumflextilde[] = "Ecircumflextilde"; +static const char glyph_Ecyrillic[] = "Ecyrillic"; +static const char glyph_Edblgrave[] = "Edblgrave"; +static const char glyph_Edieresis[] = "Edieresis"; +static const char glyph_Edieresissmall[] = "Edieresissmall"; +static const char glyph_Edot[] = "Edot"; +static const char glyph_Edotaccent[] = "Edotaccent"; +static const char glyph_Edotbelow[] = "Edotbelow"; +static const char glyph_Efcyrillic[] = "Efcyrillic"; +static const char glyph_Egrave[] = "Egrave"; +static const char glyph_Egravesmall[] = "Egravesmall"; +static const char glyph_Eharmenian[] = "Eharmenian"; +static const char glyph_Ehookabove[] = "Ehookabove"; +static const char glyph_Eightroman[] = "Eightroman"; +static const char glyph_Einvertedbreve[] = "Einvertedbreve"; +static const char glyph_Eiotifiedcyrillic[] = "Eiotifiedcyrillic"; +static const char glyph_Elcyrillic[] = "Elcyrillic"; +static const char glyph_Elevenroman[] = "Elevenroman"; +static const char glyph_Emacron[] = "Emacron"; +static const char glyph_Emacronacute[] = "Emacronacute"; +static const char glyph_Emacrongrave[] = "Emacrongrave"; +static const char glyph_Emcyrillic[] = "Emcyrillic"; +static const char glyph_Emonospace[] = "Emonospace"; +static const char glyph_Encyrillic[] = "Encyrillic"; +static const char glyph_Endescendercyrillic[] = "Endescendercyrillic"; +static const char glyph_Eng[] = "Eng"; +static const char glyph_Enghecyrillic[] = "Enghecyrillic"; +static const char glyph_Enhookcyrillic[] = "Enhookcyrillic"; +static const char glyph_Eogonek[] = "Eogonek"; +static const char glyph_Eopen[] = "Eopen"; +static const char glyph_Epsilon[] = "Epsilon"; +static const char glyph_Epsilontonos[] = "Epsilontonos"; +static const char glyph_Ercyrillic[] = "Ercyrillic"; +static const char glyph_Ereversed[] = "Ereversed"; +static const char glyph_Ereversedcyrillic[] = "Ereversedcyrillic"; +static const char glyph_Escyrillic[] = "Escyrillic"; +static const char glyph_Esdescendercyrillic[] = "Esdescendercyrillic"; +static const char glyph_Esh[] = "Esh"; +static const char glyph_Esmall[] = "Esmall"; +static const char glyph_Eta[] = "Eta"; +static const char glyph_Etarmenian[] = "Etarmenian"; +static const char glyph_Etatonos[] = "Etatonos"; +static const char glyph_Eth[] = "Eth"; +static const char glyph_Ethsmall[] = "Ethsmall"; +static const char glyph_Etilde[] = "Etilde"; +static const char glyph_Etildebelow[] = "Etildebelow"; +static const char glyph_Euro[] = "Euro"; +static const char glyph_Ezh[] = "Ezh"; +static const char glyph_Ezhcaron[] = "Ezhcaron"; +static const char glyph_Ezhreversed[] = "Ezhreversed"; +static const char glyph_F[] = "F"; +static const char glyph_Fcircle[] = "Fcircle"; +static const char glyph_Fdotaccent[] = "Fdotaccent"; +static const char glyph_Feharmenian[] = "Feharmenian"; +static const char glyph_Feicoptic[] = "Feicoptic"; +static const char glyph_Fhook[] = "Fhook"; +static const char glyph_Fitacyrillic[] = "Fitacyrillic"; +static const char glyph_Fiveroman[] = "Fiveroman"; +static const char glyph_Fmonospace[] = "Fmonospace"; +static const char glyph_Fourroman[] = "Fourroman"; +static const char glyph_Fsmall[] = "Fsmall"; +static const char glyph_G[] = "G"; +static const char glyph_GBsquare[] = "GBsquare"; +static const char glyph_Gacute[] = "Gacute"; +static const char glyph_Gamma[] = "Gamma"; +static const char glyph_Gammaafrican[] = "Gammaafrican"; +static const char glyph_Gangiacoptic[] = "Gangiacoptic"; +static const char glyph_Gbreve[] = "Gbreve"; +static const char glyph_Gcaron[] = "Gcaron"; +static const char glyph_Gcedilla[] = "Gcedilla"; +static const char glyph_Gcircle[] = "Gcircle"; +static const char glyph_Gcircumflex[] = "Gcircumflex"; +static const char glyph_Gcommaaccent[] = "Gcommaaccent"; +static const char glyph_Gdot[] = "Gdot"; +static const char glyph_Gdotaccent[] = "Gdotaccent"; +static const char glyph_Gecyrillic[] = "Gecyrillic"; +static const char glyph_Ghadarmenian[] = "Ghadarmenian"; +static const char glyph_Ghemiddlehookcyrillic[] = "Ghemiddlehookcyrillic"; +static const char glyph_Ghestrokecyrillic[] = "Ghestrokecyrillic"; +static const char glyph_Gheupturncyrillic[] = "Gheupturncyrillic"; +static const char glyph_Ghook[] = "Ghook"; +static const char glyph_Gimarmenian[] = "Gimarmenian"; +static const char glyph_Gjecyrillic[] = "Gjecyrillic"; +static const char glyph_Gmacron[] = "Gmacron"; +static const char glyph_Gmonospace[] = "Gmonospace"; +static const char glyph_Grave[] = "Grave"; +static const char glyph_Gravesmall[] = "Gravesmall"; +static const char glyph_Gsmall[] = "Gsmall"; +static const char glyph_Gsmallhook[] = "Gsmallhook"; +static const char glyph_Gstroke[] = "Gstroke"; +static const char glyph_H[] = "H"; +static const char glyph_H18533[] = "H18533"; +static const char glyph_H18543[] = "H18543"; +static const char glyph_H18551[] = "H18551"; +static const char glyph_H22073[] = "H22073"; +static const char glyph_HPsquare[] = "HPsquare"; +static const char glyph_Haabkhasiancyrillic[] = "Haabkhasiancyrillic"; +static const char glyph_Hadescendercyrillic[] = "Hadescendercyrillic"; +static const char glyph_Hardsigncyrillic[] = "Hardsigncyrillic"; +static const char glyph_Hbar[] = "Hbar"; +static const char glyph_Hbrevebelow[] = "Hbrevebelow"; +static const char glyph_Hcedilla[] = "Hcedilla"; +static const char glyph_Hcircle[] = "Hcircle"; +static const char glyph_Hcircumflex[] = "Hcircumflex"; +static const char glyph_Hdieresis[] = "Hdieresis"; +static const char glyph_Hdotaccent[] = "Hdotaccent"; +static const char glyph_Hdotbelow[] = "Hdotbelow"; +static const char glyph_Hmonospace[] = "Hmonospace"; +static const char glyph_Hoarmenian[] = "Hoarmenian"; +static const char glyph_Horicoptic[] = "Horicoptic"; +static const char glyph_Hsmall[] = "Hsmall"; +static const char glyph_Hungarumlaut[] = "Hungarumlaut"; +static const char glyph_Hungarumlautsmall[] = "Hungarumlautsmall"; +static const char glyph_Hzsquare[] = "Hzsquare"; +static const char glyph_I[] = "I"; +static const char glyph_IAcyrillic[] = "IAcyrillic"; +static const char glyph_IJ[] = "IJ"; +static const char glyph_IUcyrillic[] = "IUcyrillic"; +static const char glyph_Iacute[] = "Iacute"; +static const char glyph_Iacutesmall[] = "Iacutesmall"; +static const char glyph_Ibreve[] = "Ibreve"; +static const char glyph_Icaron[] = "Icaron"; +static const char glyph_Icircle[] = "Icircle"; +static const char glyph_Icircumflex[] = "Icircumflex"; +static const char glyph_Icircumflexsmall[] = "Icircumflexsmall"; +static const char glyph_Icyrillic[] = "Icyrillic"; +static const char glyph_Idblgrave[] = "Idblgrave"; +static const char glyph_Idieresis[] = "Idieresis"; +static const char glyph_Idieresisacute[] = "Idieresisacute"; +static const char glyph_Idieresiscyrillic[] = "Idieresiscyrillic"; +static const char glyph_Idieresissmall[] = "Idieresissmall"; +static const char glyph_Idot[] = "Idot"; +static const char glyph_Idotaccent[] = "Idotaccent"; +static const char glyph_Idotbelow[] = "Idotbelow"; +static const char glyph_Iebrevecyrillic[] = "Iebrevecyrillic"; +static const char glyph_Iecyrillic[] = "Iecyrillic"; +static const char glyph_Ifraktur[] = "Ifraktur"; +static const char glyph_Igrave[] = "Igrave"; +static const char glyph_Igravesmall[] = "Igravesmall"; +static const char glyph_Ihookabove[] = "Ihookabove"; +static const char glyph_Iicyrillic[] = "Iicyrillic"; +static const char glyph_Iinvertedbreve[] = "Iinvertedbreve"; +static const char glyph_Iishortcyrillic[] = "Iishortcyrillic"; +static const char glyph_Imacron[] = "Imacron"; +static const char glyph_Imacroncyrillic[] = "Imacroncyrillic"; +static const char glyph_Imonospace[] = "Imonospace"; +static const char glyph_Iniarmenian[] = "Iniarmenian"; +static const char glyph_Iocyrillic[] = "Iocyrillic"; +static const char glyph_Iogonek[] = "Iogonek"; +static const char glyph_Iota[] = "Iota"; +static const char glyph_Iotaafrican[] = "Iotaafrican"; +static const char glyph_Iotadieresis[] = "Iotadieresis"; +static const char glyph_Iotatonos[] = "Iotatonos"; +static const char glyph_Ismall[] = "Ismall"; +static const char glyph_Istroke[] = "Istroke"; +static const char glyph_Itilde[] = "Itilde"; +static const char glyph_Itildebelow[] = "Itildebelow"; +static const char glyph_Izhitsacyrillic[] = "Izhitsacyrillic"; +static const char glyph_Izhitsadblgravecyrillic[] = "Izhitsadblgravecyrillic"; +static const char glyph_J[] = "J"; +static const char glyph_Jaarmenian[] = "Jaarmenian"; +static const char glyph_Jcircle[] = "Jcircle"; +static const char glyph_Jcircumflex[] = "Jcircumflex"; +static const char glyph_Jecyrillic[] = "Jecyrillic"; +static const char glyph_Jheharmenian[] = "Jheharmenian"; +static const char glyph_Jmonospace[] = "Jmonospace"; +static const char glyph_Jsmall[] = "Jsmall"; +static const char glyph_K[] = "K"; +static const char glyph_KBsquare[] = "KBsquare"; +static const char glyph_KKsquare[] = "KKsquare"; +static const char glyph_Kabashkircyrillic[] = "Kabashkircyrillic"; +static const char glyph_Kacute[] = "Kacute"; +static const char glyph_Kacyrillic[] = "Kacyrillic"; +static const char glyph_Kadescendercyrillic[] = "Kadescendercyrillic"; +static const char glyph_Kahookcyrillic[] = "Kahookcyrillic"; +static const char glyph_Kappa[] = "Kappa"; +static const char glyph_Kastrokecyrillic[] = "Kastrokecyrillic"; +static const char glyph_Kaverticalstrokecyrillic[] = "Kaverticalstrokecyrillic"; +static const char glyph_Kcaron[] = "Kcaron"; +static const char glyph_Kcedilla[] = "Kcedilla"; +static const char glyph_Kcircle[] = "Kcircle"; +static const char glyph_Kcommaaccent[] = "Kcommaaccent"; +static const char glyph_Kdotbelow[] = "Kdotbelow"; +static const char glyph_Keharmenian[] = "Keharmenian"; +static const char glyph_Kenarmenian[] = "Kenarmenian"; +static const char glyph_Khacyrillic[] = "Khacyrillic"; +static const char glyph_Kheicoptic[] = "Kheicoptic"; +static const char glyph_Khook[] = "Khook"; +static const char glyph_Kjecyrillic[] = "Kjecyrillic"; +static const char glyph_Klinebelow[] = "Klinebelow"; +static const char glyph_Kmonospace[] = "Kmonospace"; +static const char glyph_Koppacyrillic[] = "Koppacyrillic"; +static const char glyph_Koppagreek[] = "Koppagreek"; +static const char glyph_Ksicyrillic[] = "Ksicyrillic"; +static const char glyph_Ksmall[] = "Ksmall"; +static const char glyph_L[] = "L"; +static const char glyph_LJ[] = "LJ"; +static const char glyph_LL[] = "LL"; +static const char glyph_Lacute[] = "Lacute"; +static const char glyph_Lambda[] = "Lambda"; +static const char glyph_Lcaron[] = "Lcaron"; +static const char glyph_Lcedilla[] = "Lcedilla"; +static const char glyph_Lcircle[] = "Lcircle"; +static const char glyph_Lcircumflexbelow[] = "Lcircumflexbelow"; +static const char glyph_Lcommaaccent[] = "Lcommaaccent"; +static const char glyph_Ldot[] = "Ldot"; +static const char glyph_Ldotaccent[] = "Ldotaccent"; +static const char glyph_Ldotbelow[] = "Ldotbelow"; +static const char glyph_Ldotbelowmacron[] = "Ldotbelowmacron"; +static const char glyph_Liwnarmenian[] = "Liwnarmenian"; +static const char glyph_Lj[] = "Lj"; +static const char glyph_Ljecyrillic[] = "Ljecyrillic"; +static const char glyph_Llinebelow[] = "Llinebelow"; +static const char glyph_Lmonospace[] = "Lmonospace"; +static const char glyph_Lslash[] = "Lslash"; +static const char glyph_Lslashsmall[] = "Lslashsmall"; +static const char glyph_Lsmall[] = "Lsmall"; +static const char glyph_M[] = "M"; +static const char glyph_MBsquare[] = "MBsquare"; +static const char glyph_Macron[] = "Macron"; +static const char glyph_Macronsmall[] = "Macronsmall"; +static const char glyph_Macute[] = "Macute"; +static const char glyph_Mcircle[] = "Mcircle"; +static const char glyph_Mdotaccent[] = "Mdotaccent"; +static const char glyph_Mdotbelow[] = "Mdotbelow"; +static const char glyph_Menarmenian[] = "Menarmenian"; +static const char glyph_Mmonospace[] = "Mmonospace"; +static const char glyph_Msmall[] = "Msmall"; +static const char glyph_Mturned[] = "Mturned"; +static const char glyph_Mu[] = "Mu"; +static const char glyph_N[] = "N"; +static const char glyph_NJ[] = "NJ"; +static const char glyph_Nacute[] = "Nacute"; +static const char glyph_Ncaron[] = "Ncaron"; +static const char glyph_Ncedilla[] = "Ncedilla"; +static const char glyph_Ncircle[] = "Ncircle"; +static const char glyph_Ncircumflexbelow[] = "Ncircumflexbelow"; +static const char glyph_Ncommaaccent[] = "Ncommaaccent"; +static const char glyph_Ndotaccent[] = "Ndotaccent"; +static const char glyph_Ndotbelow[] = "Ndotbelow"; +static const char glyph_Nhookleft[] = "Nhookleft"; +static const char glyph_Nineroman[] = "Nineroman"; +static const char glyph_Nj[] = "Nj"; +static const char glyph_Njecyrillic[] = "Njecyrillic"; +static const char glyph_Nlinebelow[] = "Nlinebelow"; +static const char glyph_Nmonospace[] = "Nmonospace"; +static const char glyph_Nowarmenian[] = "Nowarmenian"; +static const char glyph_Nsmall[] = "Nsmall"; +static const char glyph_Ntilde[] = "Ntilde"; +static const char glyph_Ntildesmall[] = "Ntildesmall"; +static const char glyph_Nu[] = "Nu"; +static const char glyph_O[] = "O"; +static const char glyph_OE[] = "OE"; +static const char glyph_OEsmall[] = "OEsmall"; +static const char glyph_Oacute[] = "Oacute"; +static const char glyph_Oacutesmall[] = "Oacutesmall"; +static const char glyph_Obarredcyrillic[] = "Obarredcyrillic"; +static const char glyph_Obarreddieresiscyrillic[] = "Obarreddieresiscyrillic"; +static const char glyph_Obreve[] = "Obreve"; +static const char glyph_Ocaron[] = "Ocaron"; +static const char glyph_Ocenteredtilde[] = "Ocenteredtilde"; +static const char glyph_Ocircle[] = "Ocircle"; +static const char glyph_Ocircumflex[] = "Ocircumflex"; +static const char glyph_Ocircumflexacute[] = "Ocircumflexacute"; +static const char glyph_Ocircumflexdotbelow[] = "Ocircumflexdotbelow"; +static const char glyph_Ocircumflexgrave[] = "Ocircumflexgrave"; +static const char glyph_Ocircumflexhookabove[] = "Ocircumflexhookabove"; +static const char glyph_Ocircumflexsmall[] = "Ocircumflexsmall"; +static const char glyph_Ocircumflextilde[] = "Ocircumflextilde"; +static const char glyph_Ocyrillic[] = "Ocyrillic"; +static const char glyph_Odblacute[] = "Odblacute"; +static const char glyph_Odblgrave[] = "Odblgrave"; +static const char glyph_Odieresis[] = "Odieresis"; +static const char glyph_Odieresiscyrillic[] = "Odieresiscyrillic"; +static const char glyph_Odieresissmall[] = "Odieresissmall"; +static const char glyph_Odotbelow[] = "Odotbelow"; +static const char glyph_Ogoneksmall[] = "Ogoneksmall"; +static const char glyph_Ograve[] = "Ograve"; +static const char glyph_Ogravesmall[] = "Ogravesmall"; +static const char glyph_Oharmenian[] = "Oharmenian"; +static const char glyph_Ohm[] = "Ohm"; +static const char glyph_Ohookabove[] = "Ohookabove"; +static const char glyph_Ohorn[] = "Ohorn"; +static const char glyph_Ohornacute[] = "Ohornacute"; +static const char glyph_Ohorndotbelow[] = "Ohorndotbelow"; +static const char glyph_Ohorngrave[] = "Ohorngrave"; +static const char glyph_Ohornhookabove[] = "Ohornhookabove"; +static const char glyph_Ohorntilde[] = "Ohorntilde"; +static const char glyph_Ohungarumlaut[] = "Ohungarumlaut"; +static const char glyph_Oi[] = "Oi"; +static const char glyph_Oinvertedbreve[] = "Oinvertedbreve"; +static const char glyph_Omacron[] = "Omacron"; +static const char glyph_Omacronacute[] = "Omacronacute"; +static const char glyph_Omacrongrave[] = "Omacrongrave"; +static const char glyph_Omega[] = "Omega"; +static const char glyph_Omegacyrillic[] = "Omegacyrillic"; +static const char glyph_Omegagreek[] = "Omegagreek"; +static const char glyph_Omegaroundcyrillic[] = "Omegaroundcyrillic"; +static const char glyph_Omegatitlocyrillic[] = "Omegatitlocyrillic"; +static const char glyph_Omegatonos[] = "Omegatonos"; +static const char glyph_Omicron[] = "Omicron"; +static const char glyph_Omicrontonos[] = "Omicrontonos"; +static const char glyph_Omonospace[] = "Omonospace"; +static const char glyph_Oneroman[] = "Oneroman"; +static const char glyph_Oogonek[] = "Oogonek"; +static const char glyph_Oogonekmacron[] = "Oogonekmacron"; +static const char glyph_Oopen[] = "Oopen"; +static const char glyph_Oslash[] = "Oslash"; +static const char glyph_Oslashacute[] = "Oslashacute"; +static const char glyph_Oslashsmall[] = "Oslashsmall"; +static const char glyph_Osmall[] = "Osmall"; +static const char glyph_Ostrokeacute[] = "Ostrokeacute"; +static const char glyph_Otcyrillic[] = "Otcyrillic"; +static const char glyph_Otilde[] = "Otilde"; +static const char glyph_Otildeacute[] = "Otildeacute"; +static const char glyph_Otildedieresis[] = "Otildedieresis"; +static const char glyph_Otildesmall[] = "Otildesmall"; +static const char glyph_P[] = "P"; +static const char glyph_Pacute[] = "Pacute"; +static const char glyph_Pcircle[] = "Pcircle"; +static const char glyph_Pdotaccent[] = "Pdotaccent"; +static const char glyph_Pecyrillic[] = "Pecyrillic"; +static const char glyph_Peharmenian[] = "Peharmenian"; +static const char glyph_Pemiddlehookcyrillic[] = "Pemiddlehookcyrillic"; +static const char glyph_Phi[] = "Phi"; +static const char glyph_Phook[] = "Phook"; +static const char glyph_Pi[] = "Pi"; +static const char glyph_Piwrarmenian[] = "Piwrarmenian"; +static const char glyph_Pmonospace[] = "Pmonospace"; +static const char glyph_Psi[] = "Psi"; +static const char glyph_Psicyrillic[] = "Psicyrillic"; +static const char glyph_Psmall[] = "Psmall"; +static const char glyph_Q[] = "Q"; +static const char glyph_Qcircle[] = "Qcircle"; +static const char glyph_Qmonospace[] = "Qmonospace"; +static const char glyph_Qsmall[] = "Qsmall"; +static const char glyph_R[] = "R"; +static const char glyph_Raarmenian[] = "Raarmenian"; +static const char glyph_Racute[] = "Racute"; +static const char glyph_Rcaron[] = "Rcaron"; +static const char glyph_Rcedilla[] = "Rcedilla"; +static const char glyph_Rcircle[] = "Rcircle"; +static const char glyph_Rcommaaccent[] = "Rcommaaccent"; +static const char glyph_Rdblgrave[] = "Rdblgrave"; +static const char glyph_Rdotaccent[] = "Rdotaccent"; +static const char glyph_Rdotbelow[] = "Rdotbelow"; +static const char glyph_Rdotbelowmacron[] = "Rdotbelowmacron"; +static const char glyph_Reharmenian[] = "Reharmenian"; +static const char glyph_Rfraktur[] = "Rfraktur"; +static const char glyph_Rho[] = "Rho"; +static const char glyph_Ringsmall[] = "Ringsmall"; +static const char glyph_Rinvertedbreve[] = "Rinvertedbreve"; +static const char glyph_Rlinebelow[] = "Rlinebelow"; +static const char glyph_Rmonospace[] = "Rmonospace"; +static const char glyph_Rsmall[] = "Rsmall"; +static const char glyph_Rsmallinverted[] = "Rsmallinverted"; +static const char glyph_Rsmallinvertedsuperior[] = "Rsmallinvertedsuperior"; +static const char glyph_S[] = "S"; +static const char glyph_SF010000[] = "SF010000"; +static const char glyph_SF020000[] = "SF020000"; +static const char glyph_SF030000[] = "SF030000"; +static const char glyph_SF040000[] = "SF040000"; +static const char glyph_SF050000[] = "SF050000"; +static const char glyph_SF060000[] = "SF060000"; +static const char glyph_SF070000[] = "SF070000"; +static const char glyph_SF080000[] = "SF080000"; +static const char glyph_SF090000[] = "SF090000"; +static const char glyph_SF100000[] = "SF100000"; +static const char glyph_SF110000[] = "SF110000"; +static const char glyph_SF190000[] = "SF190000"; +static const char glyph_SF200000[] = "SF200000"; +static const char glyph_SF210000[] = "SF210000"; +static const char glyph_SF220000[] = "SF220000"; +static const char glyph_SF230000[] = "SF230000"; +static const char glyph_SF240000[] = "SF240000"; +static const char glyph_SF250000[] = "SF250000"; +static const char glyph_SF260000[] = "SF260000"; +static const char glyph_SF270000[] = "SF270000"; +static const char glyph_SF280000[] = "SF280000"; +static const char glyph_SF360000[] = "SF360000"; +static const char glyph_SF370000[] = "SF370000"; +static const char glyph_SF380000[] = "SF380000"; +static const char glyph_SF390000[] = "SF390000"; +static const char glyph_SF400000[] = "SF400000"; +static const char glyph_SF410000[] = "SF410000"; +static const char glyph_SF420000[] = "SF420000"; +static const char glyph_SF430000[] = "SF430000"; +static const char glyph_SF440000[] = "SF440000"; +static const char glyph_SF450000[] = "SF450000"; +static const char glyph_SF460000[] = "SF460000"; +static const char glyph_SF470000[] = "SF470000"; +static const char glyph_SF480000[] = "SF480000"; +static const char glyph_SF490000[] = "SF490000"; +static const char glyph_SF500000[] = "SF500000"; +static const char glyph_SF510000[] = "SF510000"; +static const char glyph_SF520000[] = "SF520000"; +static const char glyph_SF530000[] = "SF530000"; +static const char glyph_SF540000[] = "SF540000"; +static const char glyph_Sacute[] = "Sacute"; +static const char glyph_Sacutedotaccent[] = "Sacutedotaccent"; +static const char glyph_Sampigreek[] = "Sampigreek"; +static const char glyph_Scaron[] = "Scaron"; +static const char glyph_Scarondotaccent[] = "Scarondotaccent"; +static const char glyph_Scaronsmall[] = "Scaronsmall"; +static const char glyph_Scedilla[] = "Scedilla"; +static const char glyph_Schwa[] = "Schwa"; +static const char glyph_Schwacyrillic[] = "Schwacyrillic"; +static const char glyph_Schwadieresiscyrillic[] = "Schwadieresiscyrillic"; +static const char glyph_Scircle[] = "Scircle"; +static const char glyph_Scircumflex[] = "Scircumflex"; +static const char glyph_Scommaaccent[] = "Scommaaccent"; +static const char glyph_Sdotaccent[] = "Sdotaccent"; +static const char glyph_Sdotbelow[] = "Sdotbelow"; +static const char glyph_Sdotbelowdotaccent[] = "Sdotbelowdotaccent"; +static const char glyph_Seharmenian[] = "Seharmenian"; +static const char glyph_Sevenroman[] = "Sevenroman"; +static const char glyph_Shaarmenian[] = "Shaarmenian"; +static const char glyph_Shacyrillic[] = "Shacyrillic"; +static const char glyph_Shchacyrillic[] = "Shchacyrillic"; +static const char glyph_Sheicoptic[] = "Sheicoptic"; +static const char glyph_Shhacyrillic[] = "Shhacyrillic"; +static const char glyph_Shimacoptic[] = "Shimacoptic"; +static const char glyph_Sigma[] = "Sigma"; +static const char glyph_Sixroman[] = "Sixroman"; +static const char glyph_Smonospace[] = "Smonospace"; +static const char glyph_Softsigncyrillic[] = "Softsigncyrillic"; +static const char glyph_Ssmall[] = "Ssmall"; +static const char glyph_Stigmagreek[] = "Stigmagreek"; +static const char glyph_T[] = "T"; +static const char glyph_Tau[] = "Tau"; +static const char glyph_Tbar[] = "Tbar"; +static const char glyph_Tcaron[] = "Tcaron"; +static const char glyph_Tcedilla[] = "Tcedilla"; +static const char glyph_Tcircle[] = "Tcircle"; +static const char glyph_Tcircumflexbelow[] = "Tcircumflexbelow"; +static const char glyph_Tcommaaccent[] = "Tcommaaccent"; +static const char glyph_Tdotaccent[] = "Tdotaccent"; +static const char glyph_Tdotbelow[] = "Tdotbelow"; +static const char glyph_Tecyrillic[] = "Tecyrillic"; +static const char glyph_Tedescendercyrillic[] = "Tedescendercyrillic"; +static const char glyph_Tenroman[] = "Tenroman"; +static const char glyph_Tetsecyrillic[] = "Tetsecyrillic"; +static const char glyph_Theta[] = "Theta"; +static const char glyph_Thook[] = "Thook"; +static const char glyph_Thorn[] = "Thorn"; +static const char glyph_Thornsmall[] = "Thornsmall"; +static const char glyph_Threeroman[] = "Threeroman"; +static const char glyph_Tildesmall[] = "Tildesmall"; +static const char glyph_Tiwnarmenian[] = "Tiwnarmenian"; +static const char glyph_Tlinebelow[] = "Tlinebelow"; +static const char glyph_Tmonospace[] = "Tmonospace"; +static const char glyph_Toarmenian[] = "Toarmenian"; +static const char glyph_Tonefive[] = "Tonefive"; +static const char glyph_Tonesix[] = "Tonesix"; +static const char glyph_Tonetwo[] = "Tonetwo"; +static const char glyph_Tretroflexhook[] = "Tretroflexhook"; +static const char glyph_Tsecyrillic[] = "Tsecyrillic"; +static const char glyph_Tshecyrillic[] = "Tshecyrillic"; +static const char glyph_Tsmall[] = "Tsmall"; +static const char glyph_Twelveroman[] = "Twelveroman"; +static const char glyph_Tworoman[] = "Tworoman"; +static const char glyph_U[] = "U"; +static const char glyph_Uacute[] = "Uacute"; +static const char glyph_Uacutesmall[] = "Uacutesmall"; +static const char glyph_Ubreve[] = "Ubreve"; +static const char glyph_Ucaron[] = "Ucaron"; +static const char glyph_Ucircle[] = "Ucircle"; +static const char glyph_Ucircumflex[] = "Ucircumflex"; +static const char glyph_Ucircumflexbelow[] = "Ucircumflexbelow"; +static const char glyph_Ucircumflexsmall[] = "Ucircumflexsmall"; +static const char glyph_Ucyrillic[] = "Ucyrillic"; +static const char glyph_Udblacute[] = "Udblacute"; +static const char glyph_Udblgrave[] = "Udblgrave"; +static const char glyph_Udieresis[] = "Udieresis"; +static const char glyph_Udieresisacute[] = "Udieresisacute"; +static const char glyph_Udieresisbelow[] = "Udieresisbelow"; +static const char glyph_Udieresiscaron[] = "Udieresiscaron"; +static const char glyph_Udieresiscyrillic[] = "Udieresiscyrillic"; +static const char glyph_Udieresisgrave[] = "Udieresisgrave"; +static const char glyph_Udieresismacron[] = "Udieresismacron"; +static const char glyph_Udieresissmall[] = "Udieresissmall"; +static const char glyph_Udotbelow[] = "Udotbelow"; +static const char glyph_Ugrave[] = "Ugrave"; +static const char glyph_Ugravesmall[] = "Ugravesmall"; +static const char glyph_Uhookabove[] = "Uhookabove"; +static const char glyph_Uhorn[] = "Uhorn"; +static const char glyph_Uhornacute[] = "Uhornacute"; +static const char glyph_Uhorndotbelow[] = "Uhorndotbelow"; +static const char glyph_Uhorngrave[] = "Uhorngrave"; +static const char glyph_Uhornhookabove[] = "Uhornhookabove"; +static const char glyph_Uhorntilde[] = "Uhorntilde"; +static const char glyph_Uhungarumlaut[] = "Uhungarumlaut"; +static const char glyph_Uhungarumlautcyrillic[] = "Uhungarumlautcyrillic"; +static const char glyph_Uinvertedbreve[] = "Uinvertedbreve"; +static const char glyph_Ukcyrillic[] = "Ukcyrillic"; +static const char glyph_Umacron[] = "Umacron"; +static const char glyph_Umacroncyrillic[] = "Umacroncyrillic"; +static const char glyph_Umacrondieresis[] = "Umacrondieresis"; +static const char glyph_Umonospace[] = "Umonospace"; +static const char glyph_Uogonek[] = "Uogonek"; +static const char glyph_Upsilon[] = "Upsilon"; +static const char glyph_Upsilon1[] = "Upsilon1"; +static const char glyph_Upsilonacutehooksymbolgreek[] = +"Upsilonacutehooksymbolgreek"; +static const char glyph_Upsilonafrican[] = "Upsilonafrican"; +static const char glyph_Upsilondieresis[] = "Upsilondieresis"; +static const char glyph_Upsilondieresishooksymbolgreek[] = +"Upsilondieresishooksymbolgreek"; +static const char glyph_Upsilonhooksymbol[] = "Upsilonhooksymbol"; +static const char glyph_Upsilontonos[] = "Upsilontonos"; +static const char glyph_Uring[] = "Uring"; +static const char glyph_Ushortcyrillic[] = "Ushortcyrillic"; +static const char glyph_Usmall[] = "Usmall"; +static const char glyph_Ustraightcyrillic[] = "Ustraightcyrillic"; +static const char glyph_Ustraightstrokecyrillic[] = "Ustraightstrokecyrillic"; +static const char glyph_Utilde[] = "Utilde"; +static const char glyph_Utildeacute[] = "Utildeacute"; +static const char glyph_Utildebelow[] = "Utildebelow"; +static const char glyph_V[] = "V"; +static const char glyph_Vcircle[] = "Vcircle"; +static const char glyph_Vdotbelow[] = "Vdotbelow"; +static const char glyph_Vecyrillic[] = "Vecyrillic"; +static const char glyph_Vewarmenian[] = "Vewarmenian"; +static const char glyph_Vhook[] = "Vhook"; +static const char glyph_Vmonospace[] = "Vmonospace"; +static const char glyph_Voarmenian[] = "Voarmenian"; +static const char glyph_Vsmall[] = "Vsmall"; +static const char glyph_Vtilde[] = "Vtilde"; +static const char glyph_W[] = "W"; +static const char glyph_Wacute[] = "Wacute"; +static const char glyph_Wcircle[] = "Wcircle"; +static const char glyph_Wcircumflex[] = "Wcircumflex"; +static const char glyph_Wdieresis[] = "Wdieresis"; +static const char glyph_Wdotaccent[] = "Wdotaccent"; +static const char glyph_Wdotbelow[] = "Wdotbelow"; +static const char glyph_Wgrave[] = "Wgrave"; +static const char glyph_Wmonospace[] = "Wmonospace"; +static const char glyph_Wsmall[] = "Wsmall"; +static const char glyph_X[] = "X"; +static const char glyph_Xcircle[] = "Xcircle"; +static const char glyph_Xdieresis[] = "Xdieresis"; +static const char glyph_Xdotaccent[] = "Xdotaccent"; +static const char glyph_Xeharmenian[] = "Xeharmenian"; +static const char glyph_Xi[] = "Xi"; +static const char glyph_Xmonospace[] = "Xmonospace"; +static const char glyph_Xsmall[] = "Xsmall"; +static const char glyph_Y[] = "Y"; +static const char glyph_Yacute[] = "Yacute"; +static const char glyph_Yacutesmall[] = "Yacutesmall"; +static const char glyph_Yatcyrillic[] = "Yatcyrillic"; +static const char glyph_Ycircle[] = "Ycircle"; +static const char glyph_Ycircumflex[] = "Ycircumflex"; +static const char glyph_Ydieresis[] = "Ydieresis"; +static const char glyph_Ydieresissmall[] = "Ydieresissmall"; +static const char glyph_Ydotaccent[] = "Ydotaccent"; +static const char glyph_Ydotbelow[] = "Ydotbelow"; +static const char glyph_Yericyrillic[] = "Yericyrillic"; +static const char glyph_Yerudieresiscyrillic[] = "Yerudieresiscyrillic"; +static const char glyph_Ygrave[] = "Ygrave"; +static const char glyph_Yhook[] = "Yhook"; +static const char glyph_Yhookabove[] = "Yhookabove"; +static const char glyph_Yiarmenian[] = "Yiarmenian"; +static const char glyph_Yicyrillic[] = "Yicyrillic"; +static const char glyph_Yiwnarmenian[] = "Yiwnarmenian"; +static const char glyph_Ymonospace[] = "Ymonospace"; +static const char glyph_Ysmall[] = "Ysmall"; +static const char glyph_Ytilde[] = "Ytilde"; +static const char glyph_Yusbigcyrillic[] = "Yusbigcyrillic"; +static const char glyph_Yusbigiotifiedcyrillic[] = "Yusbigiotifiedcyrillic"; +static const char glyph_Yuslittlecyrillic[] = "Yuslittlecyrillic"; +static const char glyph_Yuslittleiotifiedcyrillic[] = +"Yuslittleiotifiedcyrillic"; +static const char glyph_Z[] = "Z"; +static const char glyph_Zaarmenian[] = "Zaarmenian"; +static const char glyph_Zacute[] = "Zacute"; +static const char glyph_Zcaron[] = "Zcaron"; +static const char glyph_Zcaronsmall[] = "Zcaronsmall"; +static const char glyph_Zcircle[] = "Zcircle"; +static const char glyph_Zcircumflex[] = "Zcircumflex"; +static const char glyph_Zdot[] = "Zdot"; +static const char glyph_Zdotaccent[] = "Zdotaccent"; +static const char glyph_Zdotbelow[] = "Zdotbelow"; +static const char glyph_Zecyrillic[] = "Zecyrillic"; +static const char glyph_Zedescendercyrillic[] = "Zedescendercyrillic"; +static const char glyph_Zedieresiscyrillic[] = "Zedieresiscyrillic"; +static const char glyph_Zeta[] = "Zeta"; +static const char glyph_Zhearmenian[] = "Zhearmenian"; +static const char glyph_Zhebrevecyrillic[] = "Zhebrevecyrillic"; +static const char glyph_Zhecyrillic[] = "Zhecyrillic"; +static const char glyph_Zhedescendercyrillic[] = "Zhedescendercyrillic"; +static const char glyph_Zhedieresiscyrillic[] = "Zhedieresiscyrillic"; +static const char glyph_Zlinebelow[] = "Zlinebelow"; +static const char glyph_Zmonospace[] = "Zmonospace"; +static const char glyph_Zsmall[] = "Zsmall"; +static const char glyph_Zstroke[] = "Zstroke"; +static const char glyph_a[] = "a"; +static const char glyph_aabengali[] = "aabengali"; +static const char glyph_aacute[] = "aacute"; +static const char glyph_aadeva[] = "aadeva"; +static const char glyph_aagujarati[] = "aagujarati"; +static const char glyph_aagurmukhi[] = "aagurmukhi"; +static const char glyph_aamatragurmukhi[] = "aamatragurmukhi"; +static const char glyph_aarusquare[] = "aarusquare"; +static const char glyph_aavowelsignbengali[] = "aavowelsignbengali"; +static const char glyph_aavowelsigndeva[] = "aavowelsigndeva"; +static const char glyph_aavowelsigngujarati[] = "aavowelsigngujarati"; +static const char glyph_abbreviationmarkarmenian[] = +"abbreviationmarkarmenian"; +static const char glyph_abbreviationsigndeva[] = "abbreviationsigndeva"; +static const char glyph_abengali[] = "abengali"; +static const char glyph_abopomofo[] = "abopomofo"; +static const char glyph_abreve[] = "abreve"; +static const char glyph_abreveacute[] = "abreveacute"; +static const char glyph_abrevecyrillic[] = "abrevecyrillic"; +static const char glyph_abrevedotbelow[] = "abrevedotbelow"; +static const char glyph_abrevegrave[] = "abrevegrave"; +static const char glyph_abrevehookabove[] = "abrevehookabove"; +static const char glyph_abrevetilde[] = "abrevetilde"; +static const char glyph_acaron[] = "acaron"; +static const char glyph_acircle[] = "acircle"; +static const char glyph_acircumflex[] = "acircumflex"; +static const char glyph_acircumflexacute[] = "acircumflexacute"; +static const char glyph_acircumflexdotbelow[] = "acircumflexdotbelow"; +static const char glyph_acircumflexgrave[] = "acircumflexgrave"; +static const char glyph_acircumflexhookabove[] = "acircumflexhookabove"; +static const char glyph_acircumflextilde[] = "acircumflextilde"; +static const char glyph_acute[] = "acute"; +static const char glyph_acutebelowcmb[] = "acutebelowcmb"; +static const char glyph_acutecmb[] = "acutecmb"; +static const char glyph_acutecomb[] = "acutecomb"; +static const char glyph_acutedeva[] = "acutedeva"; +static const char glyph_acutelowmod[] = "acutelowmod"; +static const char glyph_acutetonecmb[] = "acutetonecmb"; +static const char glyph_acyrillic[] = "acyrillic"; +static const char glyph_adblgrave[] = "adblgrave"; +static const char glyph_addakgurmukhi[] = "addakgurmukhi"; +static const char glyph_adeva[] = "adeva"; +static const char glyph_adieresis[] = "adieresis"; +static const char glyph_adieresiscyrillic[] = "adieresiscyrillic"; +static const char glyph_adieresismacron[] = "adieresismacron"; +static const char glyph_adotbelow[] = "adotbelow"; +static const char glyph_adotmacron[] = "adotmacron"; +static const char glyph_ae[] = "ae"; +static const char glyph_aeacute[] = "aeacute"; +static const char glyph_aekorean[] = "aekorean"; +static const char glyph_aemacron[] = "aemacron"; +static const char glyph_afii00208[] = "afii00208"; +static const char glyph_afii08941[] = "afii08941"; +static const char glyph_afii10017[] = "afii10017"; +static const char glyph_afii10018[] = "afii10018"; +static const char glyph_afii10019[] = "afii10019"; +static const char glyph_afii10020[] = "afii10020"; +static const char glyph_afii10021[] = "afii10021"; +static const char glyph_afii10022[] = "afii10022"; +static const char glyph_afii10023[] = "afii10023"; +static const char glyph_afii10024[] = "afii10024"; +static const char glyph_afii10025[] = "afii10025"; +static const char glyph_afii10026[] = "afii10026"; +static const char glyph_afii10027[] = "afii10027"; +static const char glyph_afii10028[] = "afii10028"; +static const char glyph_afii10029[] = "afii10029"; +static const char glyph_afii10030[] = "afii10030"; +static const char glyph_afii10031[] = "afii10031"; +static const char glyph_afii10032[] = "afii10032"; +static const char glyph_afii10033[] = "afii10033"; +static const char glyph_afii10034[] = "afii10034"; +static const char glyph_afii10035[] = "afii10035"; +static const char glyph_afii10036[] = "afii10036"; +static const char glyph_afii10037[] = "afii10037"; +static const char glyph_afii10038[] = "afii10038"; +static const char glyph_afii10039[] = "afii10039"; +static const char glyph_afii10040[] = "afii10040"; +static const char glyph_afii10041[] = "afii10041"; +static const char glyph_afii10042[] = "afii10042"; +static const char glyph_afii10043[] = "afii10043"; +static const char glyph_afii10044[] = "afii10044"; +static const char glyph_afii10045[] = "afii10045"; +static const char glyph_afii10046[] = "afii10046"; +static const char glyph_afii10047[] = "afii10047"; +static const char glyph_afii10048[] = "afii10048"; +static const char glyph_afii10049[] = "afii10049"; +static const char glyph_afii10050[] = "afii10050"; +static const char glyph_afii10051[] = "afii10051"; +static const char glyph_afii10052[] = "afii10052"; +static const char glyph_afii10053[] = "afii10053"; +static const char glyph_afii10054[] = "afii10054"; +static const char glyph_afii10055[] = "afii10055"; +static const char glyph_afii10056[] = "afii10056"; +static const char glyph_afii10057[] = "afii10057"; +static const char glyph_afii10058[] = "afii10058"; +static const char glyph_afii10059[] = "afii10059"; +static const char glyph_afii10060[] = "afii10060"; +static const char glyph_afii10061[] = "afii10061"; +static const char glyph_afii10062[] = "afii10062"; +static const char glyph_afii10063[] = "afii10063"; +static const char glyph_afii10064[] = "afii10064"; +static const char glyph_afii10065[] = "afii10065"; +static const char glyph_afii10066[] = "afii10066"; +static const char glyph_afii10067[] = "afii10067"; +static const char glyph_afii10068[] = "afii10068"; +static const char glyph_afii10069[] = "afii10069"; +static const char glyph_afii10070[] = "afii10070"; +static const char glyph_afii10071[] = "afii10071"; +static const char glyph_afii10072[] = "afii10072"; +static const char glyph_afii10073[] = "afii10073"; +static const char glyph_afii10074[] = "afii10074"; +static const char glyph_afii10075[] = "afii10075"; +static const char glyph_afii10076[] = "afii10076"; +static const char glyph_afii10077[] = "afii10077"; +static const char glyph_afii10078[] = "afii10078"; +static const char glyph_afii10079[] = "afii10079"; +static const char glyph_afii10080[] = "afii10080"; +static const char glyph_afii10081[] = "afii10081"; +static const char glyph_afii10082[] = "afii10082"; +static const char glyph_afii10083[] = "afii10083"; +static const char glyph_afii10084[] = "afii10084"; +static const char glyph_afii10085[] = "afii10085"; +static const char glyph_afii10086[] = "afii10086"; +static const char glyph_afii10087[] = "afii10087"; +static const char glyph_afii10088[] = "afii10088"; +static const char glyph_afii10089[] = "afii10089"; +static const char glyph_afii10090[] = "afii10090"; +static const char glyph_afii10091[] = "afii10091"; +static const char glyph_afii10092[] = "afii10092"; +static const char glyph_afii10093[] = "afii10093"; +static const char glyph_afii10094[] = "afii10094"; +static const char glyph_afii10095[] = "afii10095"; +static const char glyph_afii10096[] = "afii10096"; +static const char glyph_afii10097[] = "afii10097"; +static const char glyph_afii10098[] = "afii10098"; +static const char glyph_afii10099[] = "afii10099"; +static const char glyph_afii10100[] = "afii10100"; +static const char glyph_afii10101[] = "afii10101"; +static const char glyph_afii10102[] = "afii10102"; +static const char glyph_afii10103[] = "afii10103"; +static const char glyph_afii10104[] = "afii10104"; +static const char glyph_afii10105[] = "afii10105"; +static const char glyph_afii10106[] = "afii10106"; +static const char glyph_afii10107[] = "afii10107"; +static const char glyph_afii10108[] = "afii10108"; +static const char glyph_afii10109[] = "afii10109"; +static const char glyph_afii10110[] = "afii10110"; +static const char glyph_afii10145[] = "afii10145"; +static const char glyph_afii10146[] = "afii10146"; +static const char glyph_afii10147[] = "afii10147"; +static const char glyph_afii10148[] = "afii10148"; +static const char glyph_afii10192[] = "afii10192"; +static const char glyph_afii10193[] = "afii10193"; +static const char glyph_afii10194[] = "afii10194"; +static const char glyph_afii10195[] = "afii10195"; +static const char glyph_afii10196[] = "afii10196"; +static const char glyph_afii10831[] = "afii10831"; +static const char glyph_afii10832[] = "afii10832"; +static const char glyph_afii10846[] = "afii10846"; +static const char glyph_afii299[] = "afii299"; +static const char glyph_afii300[] = "afii300"; +static const char glyph_afii301[] = "afii301"; +static const char glyph_afii57381[] = "afii57381"; +static const char glyph_afii57388[] = "afii57388"; +static const char glyph_afii57392[] = "afii57392"; +static const char glyph_afii57393[] = "afii57393"; +static const char glyph_afii57394[] = "afii57394"; +static const char glyph_afii57395[] = "afii57395"; +static const char glyph_afii57396[] = "afii57396"; +static const char glyph_afii57397[] = "afii57397"; +static const char glyph_afii57398[] = "afii57398"; +static const char glyph_afii57399[] = "afii57399"; +static const char glyph_afii57400[] = "afii57400"; +static const char glyph_afii57401[] = "afii57401"; +static const char glyph_afii57403[] = "afii57403"; +static const char glyph_afii57407[] = "afii57407"; +static const char glyph_afii57409[] = "afii57409"; +static const char glyph_afii57410[] = "afii57410"; +static const char glyph_afii57411[] = "afii57411"; +static const char glyph_afii57412[] = "afii57412"; +static const char glyph_afii57413[] = "afii57413"; +static const char glyph_afii57414[] = "afii57414"; +static const char glyph_afii57415[] = "afii57415"; +static const char glyph_afii57416[] = "afii57416"; +static const char glyph_afii57417[] = "afii57417"; +static const char glyph_afii57418[] = "afii57418"; +static const char glyph_afii57419[] = "afii57419"; +static const char glyph_afii57420[] = "afii57420"; +static const char glyph_afii57421[] = "afii57421"; +static const char glyph_afii57422[] = "afii57422"; +static const char glyph_afii57423[] = "afii57423"; +static const char glyph_afii57424[] = "afii57424"; +static const char glyph_afii57425[] = "afii57425"; +static const char glyph_afii57426[] = "afii57426"; +static const char glyph_afii57427[] = "afii57427"; +static const char glyph_afii57428[] = "afii57428"; +static const char glyph_afii57429[] = "afii57429"; +static const char glyph_afii57430[] = "afii57430"; +static const char glyph_afii57431[] = "afii57431"; +static const char glyph_afii57432[] = "afii57432"; +static const char glyph_afii57433[] = "afii57433"; +static const char glyph_afii57434[] = "afii57434"; +static const char glyph_afii57440[] = "afii57440"; +static const char glyph_afii57441[] = "afii57441"; +static const char glyph_afii57442[] = "afii57442"; +static const char glyph_afii57443[] = "afii57443"; +static const char glyph_afii57444[] = "afii57444"; +static const char glyph_afii57445[] = "afii57445"; +static const char glyph_afii57446[] = "afii57446"; +static const char glyph_afii57448[] = "afii57448"; +static const char glyph_afii57449[] = "afii57449"; +static const char glyph_afii57450[] = "afii57450"; +static const char glyph_afii57451[] = "afii57451"; +static const char glyph_afii57452[] = "afii57452"; +static const char glyph_afii57453[] = "afii57453"; +static const char glyph_afii57454[] = "afii57454"; +static const char glyph_afii57455[] = "afii57455"; +static const char glyph_afii57456[] = "afii57456"; +static const char glyph_afii57457[] = "afii57457"; +static const char glyph_afii57458[] = "afii57458"; +static const char glyph_afii57470[] = "afii57470"; +static const char glyph_afii57505[] = "afii57505"; +static const char glyph_afii57506[] = "afii57506"; +static const char glyph_afii57507[] = "afii57507"; +static const char glyph_afii57508[] = "afii57508"; +static const char glyph_afii57509[] = "afii57509"; +static const char glyph_afii57511[] = "afii57511"; +static const char glyph_afii57512[] = "afii57512"; +static const char glyph_afii57513[] = "afii57513"; +static const char glyph_afii57514[] = "afii57514"; +static const char glyph_afii57519[] = "afii57519"; +static const char glyph_afii57534[] = "afii57534"; +static const char glyph_afii57636[] = "afii57636"; +static const char glyph_afii57645[] = "afii57645"; +static const char glyph_afii57658[] = "afii57658"; +static const char glyph_afii57664[] = "afii57664"; +static const char glyph_afii57665[] = "afii57665"; +static const char glyph_afii57666[] = "afii57666"; +static const char glyph_afii57667[] = "afii57667"; +static const char glyph_afii57668[] = "afii57668"; +static const char glyph_afii57669[] = "afii57669"; +static const char glyph_afii57670[] = "afii57670"; +static const char glyph_afii57671[] = "afii57671"; +static const char glyph_afii57672[] = "afii57672"; +static const char glyph_afii57673[] = "afii57673"; +static const char glyph_afii57674[] = "afii57674"; +static const char glyph_afii57675[] = "afii57675"; +static const char glyph_afii57676[] = "afii57676"; +static const char glyph_afii57677[] = "afii57677"; +static const char glyph_afii57678[] = "afii57678"; +static const char glyph_afii57679[] = "afii57679"; +static const char glyph_afii57680[] = "afii57680"; +static const char glyph_afii57681[] = "afii57681"; +static const char glyph_afii57682[] = "afii57682"; +static const char glyph_afii57683[] = "afii57683"; +static const char glyph_afii57684[] = "afii57684"; +static const char glyph_afii57685[] = "afii57685"; +static const char glyph_afii57686[] = "afii57686"; +static const char glyph_afii57687[] = "afii57687"; +static const char glyph_afii57688[] = "afii57688"; +static const char glyph_afii57689[] = "afii57689"; +static const char glyph_afii57690[] = "afii57690"; +static const char glyph_afii57694[] = "afii57694"; +static const char glyph_afii57695[] = "afii57695"; +static const char glyph_afii57700[] = "afii57700"; +static const char glyph_afii57705[] = "afii57705"; +static const char glyph_afii57716[] = "afii57716"; +static const char glyph_afii57717[] = "afii57717"; +static const char glyph_afii57718[] = "afii57718"; +static const char glyph_afii57723[] = "afii57723"; +static const char glyph_afii57793[] = "afii57793"; +static const char glyph_afii57794[] = "afii57794"; +static const char glyph_afii57795[] = "afii57795"; +static const char glyph_afii57796[] = "afii57796"; +static const char glyph_afii57797[] = "afii57797"; +static const char glyph_afii57798[] = "afii57798"; +static const char glyph_afii57799[] = "afii57799"; +static const char glyph_afii57800[] = "afii57800"; +static const char glyph_afii57801[] = "afii57801"; +static const char glyph_afii57802[] = "afii57802"; +static const char glyph_afii57803[] = "afii57803"; +static const char glyph_afii57804[] = "afii57804"; +static const char glyph_afii57806[] = "afii57806"; +static const char glyph_afii57807[] = "afii57807"; +static const char glyph_afii57839[] = "afii57839"; +static const char glyph_afii57841[] = "afii57841"; +static const char glyph_afii57842[] = "afii57842"; +static const char glyph_afii57929[] = "afii57929"; +static const char glyph_afii61248[] = "afii61248"; +static const char glyph_afii61289[] = "afii61289"; +static const char glyph_afii61352[] = "afii61352"; +static const char glyph_afii61573[] = "afii61573"; +static const char glyph_afii61574[] = "afii61574"; +static const char glyph_afii61575[] = "afii61575"; +static const char glyph_afii61664[] = "afii61664"; +static const char glyph_afii63167[] = "afii63167"; +static const char glyph_afii64937[] = "afii64937"; +static const char glyph_agrave[] = "agrave"; +static const char glyph_agujarati[] = "agujarati"; +static const char glyph_agurmukhi[] = "agurmukhi"; +static const char glyph_ahiragana[] = "ahiragana"; +static const char glyph_ahookabove[] = "ahookabove"; +static const char glyph_aibengali[] = "aibengali"; +static const char glyph_aibopomofo[] = "aibopomofo"; +static const char glyph_aideva[] = "aideva"; +static const char glyph_aiecyrillic[] = "aiecyrillic"; +static const char glyph_aigujarati[] = "aigujarati"; +static const char glyph_aigurmukhi[] = "aigurmukhi"; +static const char glyph_aimatragurmukhi[] = "aimatragurmukhi"; +static const char glyph_ainarabic[] = "ainarabic"; +static const char glyph_ainfinalarabic[] = "ainfinalarabic"; +static const char glyph_aininitialarabic[] = "aininitialarabic"; +static const char glyph_ainmedialarabic[] = "ainmedialarabic"; +static const char glyph_ainvertedbreve[] = "ainvertedbreve"; +static const char glyph_aivowelsignbengali[] = "aivowelsignbengali"; +static const char glyph_aivowelsigndeva[] = "aivowelsigndeva"; +static const char glyph_aivowelsigngujarati[] = "aivowelsigngujarati"; +static const char glyph_akatakana[] = "akatakana"; +static const char glyph_akatakanahalfwidth[] = "akatakanahalfwidth"; +static const char glyph_akorean[] = "akorean"; +static const char glyph_alef[] = "alef"; +static const char glyph_alefarabic[] = "alefarabic"; +static const char glyph_alefdageshhebrew[] = "alefdageshhebrew"; +static const char glyph_aleffinalarabic[] = "aleffinalarabic"; +static const char glyph_alefhamzaabovearabic[] = "alefhamzaabovearabic"; +static const char glyph_alefhamzaabovefinalarabic[] = +"alefhamzaabovefinalarabic"; +static const char glyph_alefhamzabelowarabic[] = "alefhamzabelowarabic"; +static const char glyph_alefhamzabelowfinalarabic[] = +"alefhamzabelowfinalarabic"; +static const char glyph_alefhebrew[] = "alefhebrew"; +static const char glyph_aleflamedhebrew[] = "aleflamedhebrew"; +static const char glyph_alefmaddaabovearabic[] = "alefmaddaabovearabic"; +static const char glyph_alefmaddaabovefinalarabic[] = +"alefmaddaabovefinalarabic"; +static const char glyph_alefmaksuraarabic[] = "alefmaksuraarabic"; +static const char glyph_alefmaksurafinalarabic[] = "alefmaksurafinalarabic"; +static const char glyph_alefmaksurainitialarabic[] = +"alefmaksurainitialarabic"; +static const char glyph_alefmaksuramedialarabic[] = "alefmaksuramedialarabic"; +static const char glyph_alefpatahhebrew[] = "alefpatahhebrew"; +static const char glyph_alefqamatshebrew[] = "alefqamatshebrew"; +static const char glyph_aleph[] = "aleph"; +static const char glyph_allequal[] = "allequal"; +static const char glyph_alpha[] = "alpha"; +static const char glyph_alphatonos[] = "alphatonos"; +static const char glyph_amacron[] = "amacron"; +static const char glyph_amonospace[] = "amonospace"; +static const char glyph_ampersand[] = "ampersand"; +static const char glyph_ampersandmonospace[] = "ampersandmonospace"; +static const char glyph_ampersandsmall[] = "ampersandsmall"; +static const char glyph_amsquare[] = "amsquare"; +static const char glyph_anbopomofo[] = "anbopomofo"; +static const char glyph_angbopomofo[] = "angbopomofo"; +static const char glyph_angkhankhuthai[] = "angkhankhuthai"; +static const char glyph_angle[] = "angle"; +static const char glyph_anglebracketleft[] = "anglebracketleft"; +static const char glyph_anglebracketleftvertical[] = +"anglebracketleftvertical"; +static const char glyph_anglebracketright[] = "anglebracketright"; +static const char glyph_anglebracketrightvertical[] = +"anglebracketrightvertical"; +static const char glyph_angleleft[] = "angleleft"; +static const char glyph_angleright[] = "angleright"; +static const char glyph_angstrom[] = "angstrom"; +static const char glyph_anoteleia[] = "anoteleia"; +static const char glyph_anudattadeva[] = "anudattadeva"; +static const char glyph_anusvarabengali[] = "anusvarabengali"; +static const char glyph_anusvaradeva[] = "anusvaradeva"; +static const char glyph_anusvaragujarati[] = "anusvaragujarati"; +static const char glyph_aogonek[] = "aogonek"; +static const char glyph_apaatosquare[] = "apaatosquare"; +static const char glyph_aparen[] = "aparen"; +static const char glyph_apostrophearmenian[] = "apostrophearmenian"; +static const char glyph_apostrophemod[] = "apostrophemod"; +static const char glyph_apple[] = "apple"; +static const char glyph_approaches[] = "approaches"; +static const char glyph_approxequal[] = "approxequal"; +static const char glyph_approxequalorimage[] = "approxequalorimage"; +static const char glyph_approximatelyequal[] = "approximatelyequal"; +static const char glyph_araeaekorean[] = "araeaekorean"; +static const char glyph_araeakorean[] = "araeakorean"; +static const char glyph_arc[] = "arc"; +static const char glyph_arighthalfring[] = "arighthalfring"; +static const char glyph_aring[] = "aring"; +static const char glyph_aringacute[] = "aringacute"; +static const char glyph_aringbelow[] = "aringbelow"; +static const char glyph_arrowboth[] = "arrowboth"; +static const char glyph_arrowdashdown[] = "arrowdashdown"; +static const char glyph_arrowdashleft[] = "arrowdashleft"; +static const char glyph_arrowdashright[] = "arrowdashright"; +static const char glyph_arrowdashup[] = "arrowdashup"; +static const char glyph_arrowdblboth[] = "arrowdblboth"; +static const char glyph_arrowdbldown[] = "arrowdbldown"; +static const char glyph_arrowdblleft[] = "arrowdblleft"; +static const char glyph_arrowdblright[] = "arrowdblright"; +static const char glyph_arrowdblup[] = "arrowdblup"; +static const char glyph_arrowdown[] = "arrowdown"; +static const char glyph_arrowdownleft[] = "arrowdownleft"; +static const char glyph_arrowdownright[] = "arrowdownright"; +static const char glyph_arrowdownwhite[] = "arrowdownwhite"; +static const char glyph_arrowheaddownmod[] = "arrowheaddownmod"; +static const char glyph_arrowheadleftmod[] = "arrowheadleftmod"; +static const char glyph_arrowheadrightmod[] = "arrowheadrightmod"; +static const char glyph_arrowheadupmod[] = "arrowheadupmod"; +static const char glyph_arrowhorizex[] = "arrowhorizex"; +static const char glyph_arrowleft[] = "arrowleft"; +static const char glyph_arrowleftdbl[] = "arrowleftdbl"; +static const char glyph_arrowleftdblstroke[] = "arrowleftdblstroke"; +static const char glyph_arrowleftoverright[] = "arrowleftoverright"; +static const char glyph_arrowleftwhite[] = "arrowleftwhite"; +static const char glyph_arrowright[] = "arrowright"; +static const char glyph_arrowrightdblstroke[] = "arrowrightdblstroke"; +static const char glyph_arrowrightheavy[] = "arrowrightheavy"; +static const char glyph_arrowrightoverleft[] = "arrowrightoverleft"; +static const char glyph_arrowrightwhite[] = "arrowrightwhite"; +static const char glyph_arrowtableft[] = "arrowtableft"; +static const char glyph_arrowtabright[] = "arrowtabright"; +static const char glyph_arrowup[] = "arrowup"; +static const char glyph_arrowupdn[] = "arrowupdn"; +static const char glyph_arrowupdnbse[] = "arrowupdnbse"; +static const char glyph_arrowupdownbase[] = "arrowupdownbase"; +static const char glyph_arrowupleft[] = "arrowupleft"; +static const char glyph_arrowupleftofdown[] = "arrowupleftofdown"; +static const char glyph_arrowupright[] = "arrowupright"; +static const char glyph_arrowupwhite[] = "arrowupwhite"; +static const char glyph_arrowvertex[] = "arrowvertex"; +static const char glyph_asciicircum[] = "asciicircum"; +static const char glyph_asciicircummonospace[] = "asciicircummonospace"; +static const char glyph_asciitilde[] = "asciitilde"; +static const char glyph_asciitildemonospace[] = "asciitildemonospace"; +static const char glyph_ascript[] = "ascript"; +static const char glyph_ascriptturned[] = "ascriptturned"; +static const char glyph_asmallhiragana[] = "asmallhiragana"; +static const char glyph_asmallkatakana[] = "asmallkatakana"; +static const char glyph_asmallkatakanahalfwidth[] = "asmallkatakanahalfwidth"; +static const char glyph_asterisk[] = "asterisk"; +static const char glyph_asteriskaltonearabic[] = "asteriskaltonearabic"; +static const char glyph_asteriskarabic[] = "asteriskarabic"; +static const char glyph_asteriskmath[] = "asteriskmath"; +static const char glyph_asteriskmonospace[] = "asteriskmonospace"; +static const char glyph_asterisksmall[] = "asterisksmall"; +static const char glyph_asterism[] = "asterism"; +static const char glyph_asuperior[] = "asuperior"; +static const char glyph_asymptoticallyequal[] = "asymptoticallyequal"; +static const char glyph_at[] = "at"; +static const char glyph_atilde[] = "atilde"; +static const char glyph_atmonospace[] = "atmonospace"; +static const char glyph_atsmall[] = "atsmall"; +static const char glyph_aturned[] = "aturned"; +static const char glyph_aubengali[] = "aubengali"; +static const char glyph_aubopomofo[] = "aubopomofo"; +static const char glyph_audeva[] = "audeva"; +static const char glyph_augujarati[] = "augujarati"; +static const char glyph_augurmukhi[] = "augurmukhi"; +static const char glyph_aulengthmarkbengali[] = "aulengthmarkbengali"; +static const char glyph_aumatragurmukhi[] = "aumatragurmukhi"; +static const char glyph_auvowelsignbengali[] = "auvowelsignbengali"; +static const char glyph_auvowelsigndeva[] = "auvowelsigndeva"; +static const char glyph_auvowelsigngujarati[] = "auvowelsigngujarati"; +static const char glyph_avagrahadeva[] = "avagrahadeva"; +static const char glyph_aybarmenian[] = "aybarmenian"; +static const char glyph_ayin[] = "ayin"; +static const char glyph_ayinaltonehebrew[] = "ayinaltonehebrew"; +static const char glyph_ayinhebrew[] = "ayinhebrew"; +static const char glyph_b[] = "b"; +static const char glyph_babengali[] = "babengali"; +static const char glyph_backslash[] = "backslash"; +static const char glyph_backslashmonospace[] = "backslashmonospace"; +static const char glyph_badeva[] = "badeva"; +static const char glyph_bagujarati[] = "bagujarati"; +static const char glyph_bagurmukhi[] = "bagurmukhi"; +static const char glyph_bahiragana[] = "bahiragana"; +static const char glyph_bahtthai[] = "bahtthai"; +static const char glyph_bakatakana[] = "bakatakana"; +static const char glyph_bar[] = "bar"; +static const char glyph_barmonospace[] = "barmonospace"; +static const char glyph_bbopomofo[] = "bbopomofo"; +static const char glyph_bcircle[] = "bcircle"; +static const char glyph_bdotaccent[] = "bdotaccent"; +static const char glyph_bdotbelow[] = "bdotbelow"; +static const char glyph_beamedsixteenthnotes[] = "beamedsixteenthnotes"; +static const char glyph_because[] = "because"; +static const char glyph_becyrillic[] = "becyrillic"; +static const char glyph_beharabic[] = "beharabic"; +static const char glyph_behfinalarabic[] = "behfinalarabic"; +static const char glyph_behinitialarabic[] = "behinitialarabic"; +static const char glyph_behiragana[] = "behiragana"; +static const char glyph_behmedialarabic[] = "behmedialarabic"; +static const char glyph_behmeeminitialarabic[] = "behmeeminitialarabic"; +static const char glyph_behmeemisolatedarabic[] = "behmeemisolatedarabic"; +static const char glyph_behnoonfinalarabic[] = "behnoonfinalarabic"; +static const char glyph_bekatakana[] = "bekatakana"; +static const char glyph_benarmenian[] = "benarmenian"; +static const char glyph_bet[] = "bet"; +static const char glyph_beta[] = "beta"; +static const char glyph_betasymbolgreek[] = "betasymbolgreek"; +static const char glyph_betdagesh[] = "betdagesh"; +static const char glyph_betdageshhebrew[] = "betdageshhebrew"; +static const char glyph_bethebrew[] = "bethebrew"; +static const char glyph_betrafehebrew[] = "betrafehebrew"; +static const char glyph_bhabengali[] = "bhabengali"; +static const char glyph_bhadeva[] = "bhadeva"; +static const char glyph_bhagujarati[] = "bhagujarati"; +static const char glyph_bhagurmukhi[] = "bhagurmukhi"; +static const char glyph_bhook[] = "bhook"; +static const char glyph_bihiragana[] = "bihiragana"; +static const char glyph_bikatakana[] = "bikatakana"; +static const char glyph_bilabialclick[] = "bilabialclick"; +static const char glyph_bindigurmukhi[] = "bindigurmukhi"; +static const char glyph_birusquare[] = "birusquare"; +static const char glyph_blackcircle[] = "blackcircle"; +static const char glyph_blackdiamond[] = "blackdiamond"; +static const char glyph_blackdownpointingtriangle[] = +"blackdownpointingtriangle"; +static const char glyph_blackleftpointingpointer[] = +"blackleftpointingpointer"; +static const char glyph_blackleftpointingtriangle[] = +"blackleftpointingtriangle"; +static const char glyph_blacklenticularbracketleft[] = +"blacklenticularbracketleft"; +static const char glyph_blacklenticularbracketleftvertical[] = +"blacklenticularbracketleftvertical"; +static const char glyph_blacklenticularbracketright[] = +"blacklenticularbracketright"; +static const char glyph_blacklenticularbracketrightvertical[] = +"blacklenticularbracketrightvertical"; +static const char glyph_blacklowerlefttriangle[] = +"blacklowerlefttriangle"; +static const char glyph_blacklowerrighttriangle[] = "blacklowerrighttriangle"; +static const char glyph_blackrectangle[] = "blackrectangle"; +static const char glyph_blackrightpointingpointer[] = +"blackrightpointingpointer"; +static const char glyph_blackrightpointingtriangle[] = +"blackrightpointingtriangle"; +static const char glyph_blacksmallsquare[] = "blacksmallsquare"; +static const char glyph_blacksmilingface[] = "blacksmilingface"; +static const char glyph_blacksquare[] = "blacksquare"; +static const char glyph_blackstar[] = "blackstar"; +static const char glyph_blackupperlefttriangle[] = "blackupperlefttriangle"; +static const char glyph_blackupperrighttriangle[] = "blackupperrighttriangle"; +static const char glyph_blackuppointingsmalltriangle[] = +"blackuppointingsmalltriangle"; +static const char glyph_blackuppointingtriangle[] = "blackuppointingtriangle"; +static const char glyph_blank[] = "blank"; +static const char glyph_blinebelow[] = "blinebelow"; +static const char glyph_block[] = "block"; +static const char glyph_bmonospace[] = "bmonospace"; +static const char glyph_bobaimaithai[] = "bobaimaithai"; +static const char glyph_bohiragana[] = "bohiragana"; +static const char glyph_bokatakana[] = "bokatakana"; +static const char glyph_bparen[] = "bparen"; +static const char glyph_bqsquare[] = "bqsquare"; +static const char glyph_braceex[] = "braceex"; +static const char glyph_braceleft[] = "braceleft"; +static const char glyph_braceleftbt[] = "braceleftbt"; +static const char glyph_braceleftmid[] = "braceleftmid"; +static const char glyph_braceleftmonospace[] = "braceleftmonospace"; +static const char glyph_braceleftsmall[] = "braceleftsmall"; +static const char glyph_bracelefttp[] = "bracelefttp"; +static const char glyph_braceleftvertical[] = "braceleftvertical"; +static const char glyph_braceright[] = "braceright"; +static const char glyph_bracerightbt[] = "bracerightbt"; +static const char glyph_bracerightmid[] = "bracerightmid"; +static const char glyph_bracerightmonospace[] = "bracerightmonospace"; +static const char glyph_bracerightsmall[] = "bracerightsmall"; +static const char glyph_bracerighttp[] = "bracerighttp"; +static const char glyph_bracerightvertical[] = "bracerightvertical"; +static const char glyph_bracketleft[] = "bracketleft"; +static const char glyph_bracketleftbt[] = "bracketleftbt"; +static const char glyph_bracketleftex[] = "bracketleftex"; +static const char glyph_bracketleftmonospace[] = "bracketleftmonospace"; +static const char glyph_bracketlefttp[] = "bracketlefttp"; +static const char glyph_bracketright[] = "bracketright"; +static const char glyph_bracketrightbt[] = "bracketrightbt"; +static const char glyph_bracketrightex[] = "bracketrightex"; +static const char glyph_bracketrightmonospace[] = "bracketrightmonospace"; +static const char glyph_bracketrighttp[] = "bracketrighttp"; +static const char glyph_breve[] = "breve"; +static const char glyph_brevebelowcmb[] = "brevebelowcmb"; +static const char glyph_brevecmb[] = "brevecmb"; +static const char glyph_breveinvertedbelowcmb[] = "breveinvertedbelowcmb"; +static const char glyph_breveinvertedcmb[] = "breveinvertedcmb"; +static const char glyph_breveinverteddoublecmb[] = "breveinverteddoublecmb"; +static const char glyph_bridgebelowcmb[] = "bridgebelowcmb"; +static const char glyph_bridgeinvertedbelowcmb[] = "bridgeinvertedbelowcmb"; +static const char glyph_brokenbar[] = "brokenbar"; +static const char glyph_bstroke[] = "bstroke"; +static const char glyph_bsuperior[] = "bsuperior"; +static const char glyph_btopbar[] = "btopbar"; +static const char glyph_buhiragana[] = "buhiragana"; +static const char glyph_bukatakana[] = "bukatakana"; +static const char glyph_bullet[] = "bullet"; +static const char glyph_bulletinverse[] = "bulletinverse"; +static const char glyph_bulletoperator[] = "bulletoperator"; +static const char glyph_bullseye[] = "bullseye"; +static const char glyph_c[] = "c"; +static const char glyph_caarmenian[] = "caarmenian"; +static const char glyph_cabengali[] = "cabengali"; +static const char glyph_cacute[] = "cacute"; +static const char glyph_cadeva[] = "cadeva"; +static const char glyph_cagujarati[] = "cagujarati"; +static const char glyph_cagurmukhi[] = "cagurmukhi"; +static const char glyph_calsquare[] = "calsquare"; +static const char glyph_candrabindubengali[] = "candrabindubengali"; +static const char glyph_candrabinducmb[] = "candrabinducmb"; +static const char glyph_candrabindudeva[] = "candrabindudeva"; +static const char glyph_candrabindugujarati[] = "candrabindugujarati"; +static const char glyph_capslock[] = "capslock"; +static const char glyph_careof[] = "careof"; +static const char glyph_caron[] = "caron"; +static const char glyph_caronbelowcmb[] = "caronbelowcmb"; +static const char glyph_caroncmb[] = "caroncmb"; +static const char glyph_carriagereturn[] = "carriagereturn"; +static const char glyph_cbopomofo[] = "cbopomofo"; +static const char glyph_ccaron[] = "ccaron"; +static const char glyph_ccedilla[] = "ccedilla"; +static const char glyph_ccedillaacute[] = "ccedillaacute"; +static const char glyph_ccircle[] = "ccircle"; +static const char glyph_ccircumflex[] = "ccircumflex"; +static const char glyph_ccurl[] = "ccurl"; +static const char glyph_cdot[] = "cdot"; +static const char glyph_cdotaccent[] = "cdotaccent"; +static const char glyph_cdsquare[] = "cdsquare"; +static const char glyph_cedilla[] = "cedilla"; +static const char glyph_cedillacmb[] = "cedillacmb"; +static const char glyph_cent[] = "cent"; +static const char glyph_centigrade[] = "centigrade"; +static const char glyph_centinferior[] = "centinferior"; +static const char glyph_centmonospace[] = "centmonospace"; +static const char glyph_centoldstyle[] = "centoldstyle"; +static const char glyph_centsuperior[] = "centsuperior"; +static const char glyph_chaarmenian[] = "chaarmenian"; +static const char glyph_chabengali[] = "chabengali"; +static const char glyph_chadeva[] = "chadeva"; +static const char glyph_chagujarati[] = "chagujarati"; +static const char glyph_chagurmukhi[] = "chagurmukhi"; +static const char glyph_chbopomofo[] = "chbopomofo"; +static const char glyph_cheabkhasiancyrillic[] = "cheabkhasiancyrillic"; +static const char glyph_checkmark[] = "checkmark"; +static const char glyph_checyrillic[] = "checyrillic"; +static const char glyph_chedescenderabkhasiancyrillic[] = +"chedescenderabkhasiancyrillic"; +static const char glyph_chedescendercyrillic[] = "chedescendercyrillic"; +static const char glyph_chedieresiscyrillic[] = "chedieresiscyrillic"; +static const char glyph_cheharmenian[] = "cheharmenian"; +static const char glyph_chekhakassiancyrillic[] = "chekhakassiancyrillic"; +static const char glyph_cheverticalstrokecyrillic[] = +"cheverticalstrokecyrillic"; +static const char glyph_chi[] = "chi"; +static const char glyph_chieuchacirclekorean[] = "chieuchacirclekorean"; +static const char glyph_chieuchaparenkorean[] = "chieuchaparenkorean"; +static const char glyph_chieuchcirclekorean[] = "chieuchcirclekorean"; +static const char glyph_chieuchkorean[] = "chieuchkorean"; +static const char glyph_chieuchparenkorean[] = "chieuchparenkorean"; +static const char glyph_chochangthai[] = "chochangthai"; +static const char glyph_chochanthai[] = "chochanthai"; +static const char glyph_chochingthai[] = "chochingthai"; +static const char glyph_chochoethai[] = "chochoethai"; +static const char glyph_chook[] = "chook"; +static const char glyph_cieucacirclekorean[] = "cieucacirclekorean"; +static const char glyph_cieucaparenkorean[] = "cieucaparenkorean"; +static const char glyph_cieuccirclekorean[] = "cieuccirclekorean"; +static const char glyph_cieuckorean[] = "cieuckorean"; +static const char glyph_cieucparenkorean[] = "cieucparenkorean"; +static const char glyph_cieucuparenkorean[] = "cieucuparenkorean"; +static const char glyph_circle[] = "circle"; +static const char glyph_circlemultiply[] = "circlemultiply"; +static const char glyph_circleot[] = "circleot"; +static const char glyph_circleplus[] = "circleplus"; +static const char glyph_circlepostalmark[] = "circlepostalmark"; +static const char glyph_circlewithlefthalfblack[] = "circlewithlefthalfblack"; +static const char glyph_circlewithrighthalfblack[] = +"circlewithrighthalfblack"; +static const char glyph_circumflex[] = "circumflex"; +static const char glyph_circumflexbelowcmb[] = "circumflexbelowcmb"; +static const char glyph_circumflexcmb[] = "circumflexcmb"; +static const char glyph_clear[] = "clear"; +static const char glyph_clickalveolar[] = "clickalveolar"; +static const char glyph_clickdental[] = "clickdental"; +static const char glyph_clicklateral[] = "clicklateral"; +static const char glyph_clickretroflex[] = "clickretroflex"; +static const char glyph_club[] = "club"; +static const char glyph_clubsuitblack[] = "clubsuitblack"; +static const char glyph_clubsuitwhite[] = "clubsuitwhite"; +static const char glyph_cmcubedsquare[] = "cmcubedsquare"; +static const char glyph_cmonospace[] = "cmonospace"; +static const char glyph_cmsquaredsquare[] = "cmsquaredsquare"; +static const char glyph_coarmenian[] = "coarmenian"; +static const char glyph_colon[] = "colon"; +static const char glyph_colonmonetary[] = "colonmonetary"; +static const char glyph_colonmonospace[] = "colonmonospace"; +static const char glyph_colonsign[] = "colonsign"; +static const char glyph_colonsmall[] = "colonsmall"; +static const char glyph_colontriangularhalfmod[] = "colontriangularhalfmod"; +static const char glyph_colontriangularmod[] = "colontriangularmod"; +static const char glyph_comma[] = "comma"; +static const char glyph_commaabovecmb[] = "commaabovecmb"; +static const char glyph_commaaboverightcmb[] = "commaaboverightcmb"; +static const char glyph_commaaccent[] = "commaaccent"; +static const char glyph_commaarabic[] = "commaarabic"; +static const char glyph_commaarmenian[] = "commaarmenian"; +static const char glyph_commainferior[] = "commainferior"; +static const char glyph_commamonospace[] = "commamonospace"; +static const char glyph_commareversedabovecmb[] = "commareversedabovecmb"; +static const char glyph_commareversedmod[] = "commareversedmod"; +static const char glyph_commasmall[] = "commasmall"; +static const char glyph_commasuperior[] = "commasuperior"; +static const char glyph_commaturnedabovecmb[] = "commaturnedabovecmb"; +static const char glyph_commaturnedmod[] = "commaturnedmod"; +static const char glyph_compass[] = "compass"; +static const char glyph_congruent[] = "congruent"; +static const char glyph_contourintegral[] = "contourintegral"; +static const char glyph_control[] = "control"; +static const char glyph_controlACK[] = "controlACK"; +static const char glyph_controlBEL[] = "controlBEL"; +static const char glyph_controlBS[] = "controlBS"; +static const char glyph_controlCAN[] = "controlCAN"; +static const char glyph_controlCR[] = "controlCR"; +static const char glyph_controlDC1[] = "controlDC1"; +static const char glyph_controlDC2[] = "controlDC2"; +static const char glyph_controlDC3[] = "controlDC3"; +static const char glyph_controlDC4[] = "controlDC4"; +static const char glyph_controlDEL[] = "controlDEL"; +static const char glyph_controlDLE[] = "controlDLE"; +static const char glyph_controlEM[] = "controlEM"; +static const char glyph_controlENQ[] = "controlENQ"; +static const char glyph_controlEOT[] = "controlEOT"; +static const char glyph_controlESC[] = "controlESC"; +static const char glyph_controlETB[] = "controlETB"; +static const char glyph_controlETX[] = "controlETX"; +static const char glyph_controlFF[] = "controlFF"; +static const char glyph_controlFS[] = "controlFS"; +static const char glyph_controlGS[] = "controlGS"; +static const char glyph_controlHT[] = "controlHT"; +static const char glyph_controlLF[] = "controlLF"; +static const char glyph_controlNAK[] = "controlNAK"; +static const char glyph_controlRS[] = "controlRS"; +static const char glyph_controlSI[] = "controlSI"; +static const char glyph_controlSO[] = "controlSO"; +static const char glyph_controlSOT[] = "controlSOT"; +static const char glyph_controlSTX[] = "controlSTX"; +static const char glyph_controlSUB[] = "controlSUB"; +static const char glyph_controlSYN[] = "controlSYN"; +static const char glyph_controlUS[] = "controlUS"; +static const char glyph_controlVT[] = "controlVT"; +static const char glyph_copyright[] = "copyright"; +static const char glyph_copyrightsans[] = "copyrightsans"; +static const char glyph_copyrightserif[] = "copyrightserif"; +static const char glyph_cornerbracketleft[] = "cornerbracketleft"; +static const char glyph_cornerbracketlefthalfwidth[] = +"cornerbracketlefthalfwidth"; +static const char glyph_cornerbracketleftvertical[] = +"cornerbracketleftvertical"; +static const char glyph_cornerbracketright[] = "cornerbracketright"; +static const char glyph_cornerbracketrighthalfwidth[] = +"cornerbracketrighthalfwidth"; +static const char glyph_cornerbracketrightvertical[] = +"cornerbracketrightvertical"; +static const char glyph_corporationsquare[] = "corporationsquare"; +static const char glyph_cosquare[] = "cosquare"; +static const char glyph_coverkgsquare[] = "coverkgsquare"; +static const char glyph_cparen[] = "cparen"; +static const char glyph_cruzeiro[] = "cruzeiro"; +static const char glyph_cstretched[] = "cstretched"; +static const char glyph_curlyand[] = "curlyand"; +static const char glyph_curlyor[] = "curlyor"; +static const char glyph_currency[] = "currency"; +static const char glyph_cyrBreve[] = "cyrBreve"; +static const char glyph_cyrFlex[] = "cyrFlex"; +static const char glyph_cyrbreve[] = "cyrbreve"; +static const char glyph_cyrflex[] = "cyrflex"; +static const char glyph_d[] = "d"; +static const char glyph_daarmenian[] = "daarmenian"; +static const char glyph_dabengali[] = "dabengali"; +static const char glyph_dadarabic[] = "dadarabic"; +static const char glyph_dadeva[] = "dadeva"; +static const char glyph_dadfinalarabic[] = "dadfinalarabic"; +static const char glyph_dadinitialarabic[] = "dadinitialarabic"; +static const char glyph_dadmedialarabic[] = "dadmedialarabic"; +static const char glyph_dagesh[] = "dagesh"; +static const char glyph_dageshhebrew[] = "dageshhebrew"; +static const char glyph_dagger[] = "dagger"; +static const char glyph_daggerdbl[] = "daggerdbl"; +static const char glyph_dagujarati[] = "dagujarati"; +static const char glyph_dagurmukhi[] = "dagurmukhi"; +static const char glyph_dahiragana[] = "dahiragana"; +static const char glyph_dakatakana[] = "dakatakana"; +static const char glyph_dalarabic[] = "dalarabic"; +static const char glyph_dalet[] = "dalet"; +static const char glyph_daletdagesh[] = "daletdagesh"; +static const char glyph_daletdageshhebrew[] = "daletdageshhebrew"; +static const char glyph_dalethatafpatah[] = "dalethatafpatah"; +static const char glyph_dalethatafpatahhebrew[] = "dalethatafpatahhebrew"; +static const char glyph_dalethatafsegol[] = "dalethatafsegol"; +static const char glyph_dalethatafsegolhebrew[] = "dalethatafsegolhebrew"; +static const char glyph_dalethebrew[] = "dalethebrew"; +static const char glyph_dalethiriq[] = "dalethiriq"; +static const char glyph_dalethiriqhebrew[] = "dalethiriqhebrew"; +static const char glyph_daletholam[] = "daletholam"; +static const char glyph_daletholamhebrew[] = "daletholamhebrew"; +static const char glyph_daletpatah[] = "daletpatah"; +static const char glyph_daletpatahhebrew[] = "daletpatahhebrew"; +static const char glyph_daletqamats[] = "daletqamats"; +static const char glyph_daletqamatshebrew[] = "daletqamatshebrew"; +static const char glyph_daletqubuts[] = "daletqubuts"; +static const char glyph_daletqubutshebrew[] = "daletqubutshebrew"; +static const char glyph_daletsegol[] = "daletsegol"; +static const char glyph_daletsegolhebrew[] = "daletsegolhebrew"; +static const char glyph_daletsheva[] = "daletsheva"; +static const char glyph_daletshevahebrew[] = "daletshevahebrew"; +static const char glyph_dalettsere[] = "dalettsere"; +static const char glyph_dalettserehebrew[] = "dalettserehebrew"; +static const char glyph_dalfinalarabic[] = "dalfinalarabic"; +static const char glyph_dammaarabic[] = "dammaarabic"; +static const char glyph_dammalowarabic[] = "dammalowarabic"; +static const char glyph_dammatanaltonearabic[] = "dammatanaltonearabic"; +static const char glyph_dammatanarabic[] = "dammatanarabic"; +static const char glyph_danda[] = "danda"; +static const char glyph_dargahebrew[] = "dargahebrew"; +static const char glyph_dargalefthebrew[] = "dargalefthebrew"; +static const char glyph_dasiapneumatacyrilliccmb[] = +"dasiapneumatacyrilliccmb"; +static const char glyph_dblGrave[] = "dblGrave"; +static const char glyph_dblanglebracketleft[] = "dblanglebracketleft"; +static const char glyph_dblanglebracketleftvertical[] = +"dblanglebracketleftvertical"; +static const char glyph_dblanglebracketright[] = "dblanglebracketright"; +static const char glyph_dblanglebracketrightvertical[] = +"dblanglebracketrightvertical"; +static const char glyph_dblarchinvertedbelowcmb[] = "dblarchinvertedbelowcmb"; +static const char glyph_dblarrowleft[] = "dblarrowleft"; +static const char glyph_dblarrowright[] = "dblarrowright"; +static const char glyph_dbldanda[] = "dbldanda"; +static const char glyph_dblgrave[] = "dblgrave"; +static const char glyph_dblgravecmb[] = "dblgravecmb"; +static const char glyph_dblintegral[] = "dblintegral"; +static const char glyph_dbllowline[] = "dbllowline"; +static const char glyph_dbllowlinecmb[] = "dbllowlinecmb"; +static const char glyph_dbloverlinecmb[] = "dbloverlinecmb"; +static const char glyph_dblprimemod[] = "dblprimemod"; +static const char glyph_dblverticalbar[] = "dblverticalbar"; +static const char glyph_dblverticallineabovecmb[] = "dblverticallineabovecmb"; +static const char glyph_dbopomofo[] = "dbopomofo"; +static const char glyph_dbsquare[] = "dbsquare"; +static const char glyph_dcaron[] = "dcaron"; +static const char glyph_dcedilla[] = "dcedilla"; +static const char glyph_dcircle[] = "dcircle"; +static const char glyph_dcircumflexbelow[] = "dcircumflexbelow"; +static const char glyph_dcroat[] = "dcroat"; +static const char glyph_ddabengali[] = "ddabengali"; +static const char glyph_ddadeva[] = "ddadeva"; +static const char glyph_ddagujarati[] = "ddagujarati"; +static const char glyph_ddagurmukhi[] = "ddagurmukhi"; +static const char glyph_ddalarabic[] = "ddalarabic"; +static const char glyph_ddalfinalarabic[] = "ddalfinalarabic"; +static const char glyph_dddhadeva[] = "dddhadeva"; +static const char glyph_ddhabengali[] = "ddhabengali"; +static const char glyph_ddhadeva[] = "ddhadeva"; +static const char glyph_ddhagujarati[] = "ddhagujarati"; +static const char glyph_ddhagurmukhi[] = "ddhagurmukhi"; +static const char glyph_ddotaccent[] = "ddotaccent"; +static const char glyph_ddotbelow[] = "ddotbelow"; +static const char glyph_decimalseparatorarabic[] = "decimalseparatorarabic"; +static const char glyph_decimalseparatorpersian[] = "decimalseparatorpersian"; +static const char glyph_decyrillic[] = "decyrillic"; +static const char glyph_degree[] = "degree"; +static const char glyph_dehihebrew[] = "dehihebrew"; +static const char glyph_dehiragana[] = "dehiragana"; +static const char glyph_deicoptic[] = "deicoptic"; +static const char glyph_dekatakana[] = "dekatakana"; +static const char glyph_deleteleft[] = "deleteleft"; +static const char glyph_deleteright[] = "deleteright"; +static const char glyph_delta[] = "delta"; +static const char glyph_deltaturned[] = "deltaturned"; +static const char glyph_denominatorminusonenumeratorbengali[] = +"denominatorminusonenumeratorbengali"; +static const char glyph_dezh[] = "dezh"; +static const char glyph_dhabengali[] = "dhabengali"; +static const char glyph_dhadeva[] = "dhadeva"; +static const char glyph_dhagujarati[] = "dhagujarati"; +static const char glyph_dhagurmukhi[] = "dhagurmukhi"; +static const char glyph_dhook[] = "dhook"; +static const char glyph_dialytikatonos[] = "dialytikatonos"; +static const char glyph_dialytikatonoscmb[] = "dialytikatonoscmb"; +static const char glyph_diamond[] = "diamond"; +static const char glyph_diamondsuitwhite[] = "diamondsuitwhite"; +static const char glyph_dieresis[] = "dieresis"; +static const char glyph_dieresisacute[] = "dieresisacute"; +static const char glyph_dieresisbelowcmb[] = "dieresisbelowcmb"; +static const char glyph_dieresiscmb[] = "dieresiscmb"; +static const char glyph_dieresisgrave[] = "dieresisgrave"; +static const char glyph_dieresistonos[] = "dieresistonos"; +static const char glyph_dihiragana[] = "dihiragana"; +static const char glyph_dikatakana[] = "dikatakana"; +static const char glyph_dittomark[] = "dittomark"; +static const char glyph_divide[] = "divide"; +static const char glyph_divides[] = "divides"; +static const char glyph_divisionslash[] = "divisionslash"; +static const char glyph_djecyrillic[] = "djecyrillic"; +static const char glyph_dkshade[] = "dkshade"; +static const char glyph_dlinebelow[] = "dlinebelow"; +static const char glyph_dlsquare[] = "dlsquare"; +static const char glyph_dmacron[] = "dmacron"; +static const char glyph_dmonospace[] = "dmonospace"; +static const char glyph_dnblock[] = "dnblock"; +static const char glyph_dochadathai[] = "dochadathai"; +static const char glyph_dodekthai[] = "dodekthai"; +static const char glyph_dohiragana[] = "dohiragana"; +static const char glyph_dokatakana[] = "dokatakana"; +static const char glyph_dollar[] = "dollar"; +static const char glyph_dollarinferior[] = "dollarinferior"; +static const char glyph_dollarmonospace[] = "dollarmonospace"; +static const char glyph_dollaroldstyle[] = "dollaroldstyle"; +static const char glyph_dollarsmall[] = "dollarsmall"; +static const char glyph_dollarsuperior[] = "dollarsuperior"; +static const char glyph_dong[] = "dong"; +static const char glyph_dorusquare[] = "dorusquare"; +static const char glyph_dotaccent[] = "dotaccent"; +static const char glyph_dotaccentcmb[] = "dotaccentcmb"; +static const char glyph_dotbelowcmb[] = "dotbelowcmb"; +static const char glyph_dotbelowcomb[] = "dotbelowcomb"; +static const char glyph_dotkatakana[] = "dotkatakana"; +static const char glyph_dotlessi[] = "dotlessi"; +static const char glyph_dotlessj[] = "dotlessj"; +static const char glyph_dotlessjstrokehook[] = "dotlessjstrokehook"; +static const char glyph_dotmath[] = "dotmath"; +static const char glyph_dottedcircle[] = "dottedcircle"; +static const char glyph_doubleyodpatah[] = "doubleyodpatah"; +static const char glyph_doubleyodpatahhebrew[] = "doubleyodpatahhebrew"; +static const char glyph_downtackbelowcmb[] = "downtackbelowcmb"; +static const char glyph_downtackmod[] = "downtackmod"; +static const char glyph_dparen[] = "dparen"; +static const char glyph_dsuperior[] = "dsuperior"; +static const char glyph_dtail[] = "dtail"; +static const char glyph_dtopbar[] = "dtopbar"; +static const char glyph_duhiragana[] = "duhiragana"; +static const char glyph_dukatakana[] = "dukatakana"; +static const char glyph_dz[] = "dz"; +static const char glyph_dzaltone[] = "dzaltone"; +static const char glyph_dzcaron[] = "dzcaron"; +static const char glyph_dzcurl[] = "dzcurl"; +static const char glyph_dzeabkhasiancyrillic[] = "dzeabkhasiancyrillic"; +static const char glyph_dzecyrillic[] = "dzecyrillic"; +static const char glyph_dzhecyrillic[] = "dzhecyrillic"; +static const char glyph_e[] = "e"; +static const char glyph_eacute[] = "eacute"; +static const char glyph_earth[] = "earth"; +static const char glyph_ebengali[] = "ebengali"; +static const char glyph_ebopomofo[] = "ebopomofo"; +static const char glyph_ebreve[] = "ebreve"; +static const char glyph_ecandradeva[] = "ecandradeva"; +static const char glyph_ecandragujarati[] = "ecandragujarati"; +static const char glyph_ecandravowelsigndeva[] = "ecandravowelsigndeva"; +static const char glyph_ecandravowelsigngujarati[] = +"ecandravowelsigngujarati"; +static const char glyph_ecaron[] = "ecaron"; +static const char glyph_ecedillabreve[] = "ecedillabreve"; +static const char glyph_echarmenian[] = "echarmenian"; +static const char glyph_echyiwnarmenian[] = "echyiwnarmenian"; +static const char glyph_ecircle[] = "ecircle"; +static const char glyph_ecircumflex[] = "ecircumflex"; +static const char glyph_ecircumflexacute[] = "ecircumflexacute"; +static const char glyph_ecircumflexbelow[] = "ecircumflexbelow"; +static const char glyph_ecircumflexdotbelow[] = "ecircumflexdotbelow"; +static const char glyph_ecircumflexgrave[] = "ecircumflexgrave"; +static const char glyph_ecircumflexhookabove[] = "ecircumflexhookabove"; +static const char glyph_ecircumflextilde[] = "ecircumflextilde"; +static const char glyph_ecyrillic[] = "ecyrillic"; +static const char glyph_edblgrave[] = "edblgrave"; +static const char glyph_edeva[] = "edeva"; +static const char glyph_edieresis[] = "edieresis"; +static const char glyph_edot[] = "edot"; +static const char glyph_edotaccent[] = "edotaccent"; +static const char glyph_edotbelow[] = "edotbelow"; +static const char glyph_eegurmukhi[] = "eegurmukhi"; +static const char glyph_eematragurmukhi[] = "eematragurmukhi"; +static const char glyph_efcyrillic[] = "efcyrillic"; +static const char glyph_egrave[] = "egrave"; +static const char glyph_egujarati[] = "egujarati"; +static const char glyph_eharmenian[] = "eharmenian"; +static const char glyph_ehbopomofo[] = "ehbopomofo"; +static const char glyph_ehiragana[] = "ehiragana"; +static const char glyph_ehookabove[] = "ehookabove"; +static const char glyph_eibopomofo[] = "eibopomofo"; +static const char glyph_eight[] = "eight"; +static const char glyph_eightarabic[] = "eightarabic"; +static const char glyph_eightbengali[] = "eightbengali"; +static const char glyph_eightcircle[] = "eightcircle"; +static const char glyph_eightcircleinversesansserif[] = +"eightcircleinversesansserif"; +static const char glyph_eightdeva[] = "eightdeva"; +static const char glyph_eighteencircle[] = "eighteencircle"; +static const char glyph_eighteenparen[] = "eighteenparen"; +static const char glyph_eighteenperiod[] = "eighteenperiod"; +static const char glyph_eightgujarati[] = "eightgujarati"; +static const char glyph_eightgurmukhi[] = "eightgurmukhi"; +static const char glyph_eighthackarabic[] = "eighthackarabic"; +static const char glyph_eighthangzhou[] = "eighthangzhou"; +static const char glyph_eighthnotebeamed[] = "eighthnotebeamed"; +static const char glyph_eightideographicparen[] = "eightideographicparen"; +static const char glyph_eightinferior[] = "eightinferior"; +static const char glyph_eightmonospace[] = "eightmonospace"; +static const char glyph_eightoldstyle[] = "eightoldstyle"; +static const char glyph_eightparen[] = "eightparen"; +static const char glyph_eightperiod[] = "eightperiod"; +static const char glyph_eightpersian[] = "eightpersian"; +static const char glyph_eightroman[] = "eightroman"; +static const char glyph_eightsuperior[] = "eightsuperior"; +static const char glyph_eightthai[] = "eightthai"; +static const char glyph_einvertedbreve[] = "einvertedbreve"; +static const char glyph_eiotifiedcyrillic[] = "eiotifiedcyrillic"; +static const char glyph_ekatakana[] = "ekatakana"; +static const char glyph_ekatakanahalfwidth[] = "ekatakanahalfwidth"; +static const char glyph_ekonkargurmukhi[] = "ekonkargurmukhi"; +static const char glyph_ekorean[] = "ekorean"; +static const char glyph_elcyrillic[] = "elcyrillic"; +static const char glyph_element[] = "element"; +static const char glyph_elevencircle[] = "elevencircle"; +static const char glyph_elevenparen[] = "elevenparen"; +static const char glyph_elevenperiod[] = "elevenperiod"; +static const char glyph_elevenroman[] = "elevenroman"; +static const char glyph_ellipsis[] = "ellipsis"; +static const char glyph_ellipsisvertical[] = "ellipsisvertical"; +static const char glyph_emacron[] = "emacron"; +static const char glyph_emacronacute[] = "emacronacute"; +static const char glyph_emacrongrave[] = "emacrongrave"; +static const char glyph_emcyrillic[] = "emcyrillic"; +static const char glyph_emdash[] = "emdash"; +static const char glyph_emdashvertical[] = "emdashvertical"; +static const char glyph_emonospace[] = "emonospace"; +static const char glyph_emphasismarkarmenian[] = "emphasismarkarmenian"; +static const char glyph_emptyset[] = "emptyset"; +static const char glyph_enbopomofo[] = "enbopomofo"; +static const char glyph_encyrillic[] = "encyrillic"; +static const char glyph_endash[] = "endash"; +static const char glyph_endashvertical[] = "endashvertical"; +static const char glyph_endescendercyrillic[] = "endescendercyrillic"; +static const char glyph_eng[] = "eng"; +static const char glyph_engbopomofo[] = "engbopomofo"; +static const char glyph_enghecyrillic[] = "enghecyrillic"; +static const char glyph_enhookcyrillic[] = "enhookcyrillic"; +static const char glyph_enspace[] = "enspace"; +static const char glyph_eogonek[] = "eogonek"; +static const char glyph_eokorean[] = "eokorean"; +static const char glyph_eopen[] = "eopen"; +static const char glyph_eopenclosed[] = "eopenclosed"; +static const char glyph_eopenreversed[] = "eopenreversed"; +static const char glyph_eopenreversedclosed[] = "eopenreversedclosed"; +static const char glyph_eopenreversedhook[] = "eopenreversedhook"; +static const char glyph_eparen[] = "eparen"; +static const char glyph_epsilon[] = "epsilon"; +static const char glyph_epsilontonos[] = "epsilontonos"; +static const char glyph_equal[] = "equal"; +static const char glyph_equalmonospace[] = "equalmonospace"; +static const char glyph_equalsmall[] = "equalsmall"; +static const char glyph_equalsuperior[] = "equalsuperior"; +static const char glyph_equivalence[] = "equivalence"; +static const char glyph_erbopomofo[] = "erbopomofo"; +static const char glyph_ercyrillic[] = "ercyrillic"; +static const char glyph_ereversed[] = "ereversed"; +static const char glyph_ereversedcyrillic[] = "ereversedcyrillic"; +static const char glyph_escyrillic[] = "escyrillic"; +static const char glyph_esdescendercyrillic[] = "esdescendercyrillic"; +static const char glyph_esh[] = "esh"; +static const char glyph_eshcurl[] = "eshcurl"; +static const char glyph_eshortdeva[] = "eshortdeva"; +static const char glyph_eshortvowelsigndeva[] = "eshortvowelsigndeva"; +static const char glyph_eshreversedloop[] = "eshreversedloop"; +static const char glyph_eshsquatreversed[] = "eshsquatreversed"; +static const char glyph_esmallhiragana[] = "esmallhiragana"; +static const char glyph_esmallkatakana[] = "esmallkatakana"; +static const char glyph_esmallkatakanahalfwidth[] = "esmallkatakanahalfwidth"; +static const char glyph_estimated[] = "estimated"; +static const char glyph_esuperior[] = "esuperior"; +static const char glyph_eta[] = "eta"; +static const char glyph_etarmenian[] = "etarmenian"; +static const char glyph_etatonos[] = "etatonos"; +static const char glyph_eth[] = "eth"; +static const char glyph_etilde[] = "etilde"; +static const char glyph_etildebelow[] = "etildebelow"; +static const char glyph_etnahtafoukhhebrew[] = "etnahtafoukhhebrew"; +static const char glyph_etnahtafoukhlefthebrew[] = "etnahtafoukhlefthebrew"; +static const char glyph_etnahtahebrew[] = "etnahtahebrew"; +static const char glyph_etnahtalefthebrew[] = "etnahtalefthebrew"; +static const char glyph_eturned[] = "eturned"; +static const char glyph_eukorean[] = "eukorean"; +static const char glyph_euro[] = "euro"; +static const char glyph_evowelsignbengali[] = "evowelsignbengali"; +static const char glyph_evowelsigndeva[] = "evowelsigndeva"; +static const char glyph_evowelsigngujarati[] = "evowelsigngujarati"; +static const char glyph_exclam[] = "exclam"; +static const char glyph_exclamarmenian[] = "exclamarmenian"; +static const char glyph_exclamdbl[] = "exclamdbl"; +static const char glyph_exclamdown[] = "exclamdown"; +static const char glyph_exclamdownsmall[] = "exclamdownsmall"; +static const char glyph_exclammonospace[] = "exclammonospace"; +static const char glyph_exclamsmall[] = "exclamsmall"; +static const char glyph_existential[] = "existential"; +static const char glyph_ezh[] = "ezh"; +static const char glyph_ezhcaron[] = "ezhcaron"; +static const char glyph_ezhcurl[] = "ezhcurl"; +static const char glyph_ezhreversed[] = "ezhreversed"; +static const char glyph_ezhtail[] = "ezhtail"; +static const char glyph_f[] = "f"; +static const char glyph_fadeva[] = "fadeva"; +static const char glyph_fagurmukhi[] = "fagurmukhi"; +static const char glyph_fahrenheit[] = "fahrenheit"; +static const char glyph_fathaarabic[] = "fathaarabic"; +static const char glyph_fathalowarabic[] = "fathalowarabic"; +static const char glyph_fathatanarabic[] = "fathatanarabic"; +static const char glyph_fbopomofo[] = "fbopomofo"; +static const char glyph_fcircle[] = "fcircle"; +static const char glyph_fdotaccent[] = "fdotaccent"; +static const char glyph_feharabic[] = "feharabic"; +static const char glyph_feharmenian[] = "feharmenian"; +static const char glyph_fehfinalarabic[] = "fehfinalarabic"; +static const char glyph_fehinitialarabic[] = "fehinitialarabic"; +static const char glyph_fehmedialarabic[] = "fehmedialarabic"; +static const char glyph_feicoptic[] = "feicoptic"; +static const char glyph_female[] = "female"; +static const char glyph_ff[] = "ff"; +static const char glyph_ffi[] = "ffi"; +static const char glyph_ffl[] = "ffl"; +static const char glyph_fi[] = "fi"; +static const char glyph_fifteencircle[] = "fifteencircle"; +static const char glyph_fifteenparen[] = "fifteenparen"; +static const char glyph_fifteenperiod[] = "fifteenperiod"; +static const char glyph_figuredash[] = "figuredash"; +static const char glyph_filledbox[] = "filledbox"; +static const char glyph_filledrect[] = "filledrect"; +static const char glyph_finalkaf[] = "finalkaf"; +static const char glyph_finalkafdagesh[] = "finalkafdagesh"; +static const char glyph_finalkafdageshhebrew[] = "finalkafdageshhebrew"; +static const char glyph_finalkafhebrew[] = "finalkafhebrew"; +static const char glyph_finalkafqamats[] = "finalkafqamats"; +static const char glyph_finalkafqamatshebrew[] = "finalkafqamatshebrew"; +static const char glyph_finalkafsheva[] = "finalkafsheva"; +static const char glyph_finalkafshevahebrew[] = "finalkafshevahebrew"; +static const char glyph_finalmem[] = "finalmem"; +static const char glyph_finalmemhebrew[] = "finalmemhebrew"; +static const char glyph_finalnun[] = "finalnun"; +static const char glyph_finalnunhebrew[] = "finalnunhebrew"; +static const char glyph_finalpe[] = "finalpe"; +static const char glyph_finalpehebrew[] = "finalpehebrew"; +static const char glyph_finaltsadi[] = "finaltsadi"; +static const char glyph_finaltsadihebrew[] = "finaltsadihebrew"; +static const char glyph_firsttonechinese[] = "firsttonechinese"; +static const char glyph_fisheye[] = "fisheye"; +static const char glyph_fitacyrillic[] = "fitacyrillic"; +static const char glyph_five[] = "five"; +static const char glyph_fivearabic[] = "fivearabic"; +static const char glyph_fivebengali[] = "fivebengali"; +static const char glyph_fivecircle[] = "fivecircle"; +static const char glyph_fivecircleinversesansserif[] = +"fivecircleinversesansserif"; +static const char glyph_fivedeva[] = "fivedeva"; +static const char glyph_fiveeighths[] = "fiveeighths"; +static const char glyph_fivegujarati[] = "fivegujarati"; +static const char glyph_fivegurmukhi[] = "fivegurmukhi"; +static const char glyph_fivehackarabic[] = "fivehackarabic"; +static const char glyph_fivehangzhou[] = "fivehangzhou"; +static const char glyph_fiveideographicparen[] = "fiveideographicparen"; +static const char glyph_fiveinferior[] = "fiveinferior"; +static const char glyph_fivemonospace[] = "fivemonospace"; +static const char glyph_fiveoldstyle[] = "fiveoldstyle"; +static const char glyph_fiveparen[] = "fiveparen"; +static const char glyph_fiveperiod[] = "fiveperiod"; +static const char glyph_fivepersian[] = "fivepersian"; +static const char glyph_fiveroman[] = "fiveroman"; +static const char glyph_fivesuperior[] = "fivesuperior"; +static const char glyph_fivethai[] = "fivethai"; +static const char glyph_fl[] = "fl"; +static const char glyph_florin[] = "florin"; +static const char glyph_fmonospace[] = "fmonospace"; +static const char glyph_fmsquare[] = "fmsquare"; +static const char glyph_fofanthai[] = "fofanthai"; +static const char glyph_fofathai[] = "fofathai"; +static const char glyph_fongmanthai[] = "fongmanthai"; +static const char glyph_forall[] = "forall"; +static const char glyph_four[] = "four"; +static const char glyph_fourarabic[] = "fourarabic"; +static const char glyph_fourbengali[] = "fourbengali"; +static const char glyph_fourcircle[] = "fourcircle"; +static const char glyph_fourcircleinversesansserif[] = +"fourcircleinversesansserif"; +static const char glyph_fourdeva[] = "fourdeva"; +static const char glyph_fourgujarati[] = "fourgujarati"; +static const char glyph_fourgurmukhi[] = "fourgurmukhi"; +static const char glyph_fourhackarabic[] = "fourhackarabic"; +static const char glyph_fourhangzhou[] = "fourhangzhou"; +static const char glyph_fourideographicparen[] = "fourideographicparen"; +static const char glyph_fourinferior[] = "fourinferior"; +static const char glyph_fourmonospace[] = "fourmonospace"; +static const char glyph_fournumeratorbengali[] = "fournumeratorbengali"; +static const char glyph_fouroldstyle[] = "fouroldstyle"; +static const char glyph_fourparen[] = "fourparen"; +static const char glyph_fourperiod[] = "fourperiod"; +static const char glyph_fourpersian[] = "fourpersian"; +static const char glyph_fourroman[] = "fourroman"; +static const char glyph_foursuperior[] = "foursuperior"; +static const char glyph_fourteencircle[] = "fourteencircle"; +static const char glyph_fourteenparen[] = "fourteenparen"; +static const char glyph_fourteenperiod[] = "fourteenperiod"; +static const char glyph_fourthai[] = "fourthai"; +static const char glyph_fourthtonechinese[] = "fourthtonechinese"; +static const char glyph_fparen[] = "fparen"; +static const char glyph_fraction[] = "fraction"; +static const char glyph_franc[] = "franc"; +static const char glyph_g[] = "g"; +static const char glyph_gabengali[] = "gabengali"; +static const char glyph_gacute[] = "gacute"; +static const char glyph_gadeva[] = "gadeva"; +static const char glyph_gafarabic[] = "gafarabic"; +static const char glyph_gaffinalarabic[] = "gaffinalarabic"; +static const char glyph_gafinitialarabic[] = "gafinitialarabic"; +static const char glyph_gafmedialarabic[] = "gafmedialarabic"; +static const char glyph_gagujarati[] = "gagujarati"; +static const char glyph_gagurmukhi[] = "gagurmukhi"; +static const char glyph_gahiragana[] = "gahiragana"; +static const char glyph_gakatakana[] = "gakatakana"; +static const char glyph_gamma[] = "gamma"; +static const char glyph_gammalatinsmall[] = "gammalatinsmall"; +static const char glyph_gammasuperior[] = "gammasuperior"; +static const char glyph_gangiacoptic[] = "gangiacoptic"; +static const char glyph_gbopomofo[] = "gbopomofo"; +static const char glyph_gbreve[] = "gbreve"; +static const char glyph_gcaron[] = "gcaron"; +static const char glyph_gcedilla[] = "gcedilla"; +static const char glyph_gcircle[] = "gcircle"; +static const char glyph_gcircumflex[] = "gcircumflex"; +static const char glyph_gcommaaccent[] = "gcommaaccent"; +static const char glyph_gdot[] = "gdot"; +static const char glyph_gdotaccent[] = "gdotaccent"; +static const char glyph_gecyrillic[] = "gecyrillic"; +static const char glyph_gehiragana[] = "gehiragana"; +static const char glyph_gekatakana[] = "gekatakana"; +static const char glyph_geometricallyequal[] = "geometricallyequal"; +static const char glyph_gereshaccenthebrew[] = "gereshaccenthebrew"; +static const char glyph_gereshhebrew[] = "gereshhebrew"; +static const char glyph_gereshmuqdamhebrew[] = "gereshmuqdamhebrew"; +static const char glyph_germandbls[] = "germandbls"; +static const char glyph_gershayimaccenthebrew[] = "gershayimaccenthebrew"; +static const char glyph_gershayimhebrew[] = "gershayimhebrew"; +static const char glyph_getamark[] = "getamark"; +static const char glyph_ghabengali[] = "ghabengali"; +static const char glyph_ghadarmenian[] = "ghadarmenian"; +static const char glyph_ghadeva[] = "ghadeva"; +static const char glyph_ghagujarati[] = "ghagujarati"; +static const char glyph_ghagurmukhi[] = "ghagurmukhi"; +static const char glyph_ghainarabic[] = "ghainarabic"; +static const char glyph_ghainfinalarabic[] = "ghainfinalarabic"; +static const char glyph_ghaininitialarabic[] = "ghaininitialarabic"; +static const char glyph_ghainmedialarabic[] = "ghainmedialarabic"; +static const char glyph_ghemiddlehookcyrillic[] = "ghemiddlehookcyrillic"; +static const char glyph_ghestrokecyrillic[] = "ghestrokecyrillic"; +static const char glyph_gheupturncyrillic[] = "gheupturncyrillic"; +static const char glyph_ghhadeva[] = "ghhadeva"; +static const char glyph_ghhagurmukhi[] = "ghhagurmukhi"; +static const char glyph_ghook[] = "ghook"; +static const char glyph_ghzsquare[] = "ghzsquare"; +static const char glyph_gihiragana[] = "gihiragana"; +static const char glyph_gikatakana[] = "gikatakana"; +static const char glyph_gimarmenian[] = "gimarmenian"; +static const char glyph_gimel[] = "gimel"; +static const char glyph_gimeldagesh[] = "gimeldagesh"; +static const char glyph_gimeldageshhebrew[] = "gimeldageshhebrew"; +static const char glyph_gimelhebrew[] = "gimelhebrew"; +static const char glyph_gjecyrillic[] = "gjecyrillic"; +static const char glyph_glottalinvertedstroke[] = "glottalinvertedstroke"; +static const char glyph_glottalstop[] = "glottalstop"; +static const char glyph_glottalstopinverted[] = "glottalstopinverted"; +static const char glyph_glottalstopmod[] = "glottalstopmod"; +static const char glyph_glottalstopreversed[] = "glottalstopreversed"; +static const char glyph_glottalstopreversedmod[] = "glottalstopreversedmod"; +static const char glyph_glottalstopreversedsuperior[] = +"glottalstopreversedsuperior"; +static const char glyph_glottalstopstroke[] = "glottalstopstroke"; +static const char glyph_glottalstopstrokereversed[] = +"glottalstopstrokereversed"; +static const char glyph_gmacron[] = "gmacron"; +static const char glyph_gmonospace[] = "gmonospace"; +static const char glyph_gohiragana[] = "gohiragana"; +static const char glyph_gokatakana[] = "gokatakana"; +static const char glyph_gparen[] = "gparen"; +static const char glyph_gpasquare[] = "gpasquare"; +static const char glyph_gradient[] = "gradient"; +static const char glyph_grave[] = "grave"; +static const char glyph_gravebelowcmb[] = "gravebelowcmb"; +static const char glyph_gravecmb[] = "gravecmb"; +static const char glyph_gravecomb[] = "gravecomb"; +static const char glyph_gravedeva[] = "gravedeva"; +static const char glyph_gravelowmod[] = "gravelowmod"; +static const char glyph_gravemonospace[] = "gravemonospace"; +static const char glyph_gravetonecmb[] = "gravetonecmb"; +static const char glyph_greater[] = "greater"; +static const char glyph_greaterequal[] = "greaterequal"; +static const char glyph_greaterequalorless[] = "greaterequalorless"; +static const char glyph_greatermonospace[] = "greatermonospace"; +static const char glyph_greaterorequivalent[] = "greaterorequivalent"; +static const char glyph_greaterorless[] = "greaterorless"; +static const char glyph_greateroverequal[] = "greateroverequal"; +static const char glyph_greatersmall[] = "greatersmall"; +static const char glyph_gscript[] = "gscript"; +static const char glyph_gstroke[] = "gstroke"; +static const char glyph_guhiragana[] = "guhiragana"; +static const char glyph_guillemotleft[] = "guillemotleft"; +static const char glyph_guillemotright[] = "guillemotright"; +static const char glyph_guilsinglleft[] = "guilsinglleft"; +static const char glyph_guilsinglright[] = "guilsinglright"; +static const char glyph_gukatakana[] = "gukatakana"; +static const char glyph_guramusquare[] = "guramusquare"; +static const char glyph_gysquare[] = "gysquare"; +static const char glyph_h[] = "h"; +static const char glyph_haabkhasiancyrillic[] = "haabkhasiancyrillic"; +static const char glyph_haaltonearabic[] = "haaltonearabic"; +static const char glyph_habengali[] = "habengali"; +static const char glyph_hadescendercyrillic[] = "hadescendercyrillic"; +static const char glyph_hadeva[] = "hadeva"; +static const char glyph_hagujarati[] = "hagujarati"; +static const char glyph_hagurmukhi[] = "hagurmukhi"; +static const char glyph_haharabic[] = "haharabic"; +static const char glyph_hahfinalarabic[] = "hahfinalarabic"; +static const char glyph_hahinitialarabic[] = "hahinitialarabic"; +static const char glyph_hahiragana[] = "hahiragana"; +static const char glyph_hahmedialarabic[] = "hahmedialarabic"; +static const char glyph_haitusquare[] = "haitusquare"; +static const char glyph_hakatakana[] = "hakatakana"; +static const char glyph_hakatakanahalfwidth[] = "hakatakanahalfwidth"; +static const char glyph_halantgurmukhi[] = "halantgurmukhi"; +static const char glyph_hamzaarabic[] = "hamzaarabic"; +static const char glyph_hamzadammaarabic[] = "hamzadammaarabic"; +static const char glyph_hamzadammatanarabic[] = "hamzadammatanarabic"; +static const char glyph_hamzafathaarabic[] = "hamzafathaarabic"; +static const char glyph_hamzafathatanarabic[] = "hamzafathatanarabic"; +static const char glyph_hamzalowarabic[] = "hamzalowarabic"; +static const char glyph_hamzalowkasraarabic[] = "hamzalowkasraarabic"; +static const char glyph_hamzalowkasratanarabic[] = "hamzalowkasratanarabic"; +static const char glyph_hamzasukunarabic[] = "hamzasukunarabic"; +static const char glyph_hangulfiller[] = "hangulfiller"; +static const char glyph_hardsigncyrillic[] = "hardsigncyrillic"; +static const char glyph_harpoonleftbarbup[] = "harpoonleftbarbup"; +static const char glyph_harpoonrightbarbup[] = "harpoonrightbarbup"; +static const char glyph_hasquare[] = "hasquare"; +static const char glyph_hatafpatah[] = "hatafpatah"; +static const char glyph_hatafpatah16[] = "hatafpatah16"; +static const char glyph_hatafpatah23[] = "hatafpatah23"; +static const char glyph_hatafpatah2f[] = "hatafpatah2f"; +static const char glyph_hatafpatahhebrew[] = "hatafpatahhebrew"; +static const char glyph_hatafpatahnarrowhebrew[] = "hatafpatahnarrowhebrew"; +static const char glyph_hatafpatahquarterhebrew[] = "hatafpatahquarterhebrew"; +static const char glyph_hatafpatahwidehebrew[] = "hatafpatahwidehebrew"; +static const char glyph_hatafqamats[] = "hatafqamats"; +static const char glyph_hatafqamats1b[] = "hatafqamats1b"; +static const char glyph_hatafqamats28[] = "hatafqamats28"; +static const char glyph_hatafqamats34[] = "hatafqamats34"; +static const char glyph_hatafqamatshebrew[] = "hatafqamatshebrew"; +static const char glyph_hatafqamatsnarrowhebrew[] = "hatafqamatsnarrowhebrew"; +static const char glyph_hatafqamatsquarterhebrew[] = +"hatafqamatsquarterhebrew"; +static const char glyph_hatafqamatswidehebrew[] = "hatafqamatswidehebrew"; +static const char glyph_hatafsegol[] = "hatafsegol"; +static const char glyph_hatafsegol17[] = "hatafsegol17"; +static const char glyph_hatafsegol24[] = "hatafsegol24"; +static const char glyph_hatafsegol30[] = "hatafsegol30"; +static const char glyph_hatafsegolhebrew[] = "hatafsegolhebrew"; +static const char glyph_hatafsegolnarrowhebrew[] = "hatafsegolnarrowhebrew"; +static const char glyph_hatafsegolquarterhebrew[] = "hatafsegolquarterhebrew"; +static const char glyph_hatafsegolwidehebrew[] = "hatafsegolwidehebrew"; +static const char glyph_hbar[] = "hbar"; +static const char glyph_hbopomofo[] = "hbopomofo"; +static const char glyph_hbrevebelow[] = "hbrevebelow"; +static const char glyph_hcedilla[] = "hcedilla"; +static const char glyph_hcircle[] = "hcircle"; +static const char glyph_hcircumflex[] = "hcircumflex"; +static const char glyph_hdieresis[] = "hdieresis"; +static const char glyph_hdotaccent[] = "hdotaccent"; +static const char glyph_hdotbelow[] = "hdotbelow"; +static const char glyph_he[] = "he"; +static const char glyph_heart[] = "heart"; +static const char glyph_heartsuitblack[] = "heartsuitblack"; +static const char glyph_heartsuitwhite[] = "heartsuitwhite"; +static const char glyph_hedagesh[] = "hedagesh"; +static const char glyph_hedageshhebrew[] = "hedageshhebrew"; +static const char glyph_hehaltonearabic[] = "hehaltonearabic"; +static const char glyph_heharabic[] = "heharabic"; +static const char glyph_hehebrew[] = "hehebrew"; +static const char glyph_hehfinalaltonearabic[] = "hehfinalaltonearabic"; +static const char glyph_hehfinalalttwoarabic[] = "hehfinalalttwoarabic"; +static const char glyph_hehfinalarabic[] = "hehfinalarabic"; +static const char glyph_hehhamzaabovefinalarabic[] = +"hehhamzaabovefinalarabic"; +static const char glyph_hehhamzaaboveisolatedarabic[] = +"hehhamzaaboveisolatedarabic"; +static const char glyph_hehinitialaltonearabic[] = "hehinitialaltonearabic"; +static const char glyph_hehinitialarabic[] = "hehinitialarabic"; +static const char glyph_hehiragana[] = "hehiragana"; +static const char glyph_hehmedialaltonearabic[] = "hehmedialaltonearabic"; +static const char glyph_hehmedialarabic[] = "hehmedialarabic"; +static const char glyph_heiseierasquare[] = "heiseierasquare"; +static const char glyph_hekatakana[] = "hekatakana"; +static const char glyph_hekatakanahalfwidth[] = "hekatakanahalfwidth"; +static const char glyph_hekutaarusquare[] = "hekutaarusquare"; +static const char glyph_henghook[] = "henghook"; +static const char glyph_herutusquare[] = "herutusquare"; +static const char glyph_het[] = "het"; +static const char glyph_hethebrew[] = "hethebrew"; +static const char glyph_hhook[] = "hhook"; +static const char glyph_hhooksuperior[] = "hhooksuperior"; +static const char glyph_hieuhacirclekorean[] = "hieuhacirclekorean"; +static const char glyph_hieuhaparenkorean[] = "hieuhaparenkorean"; +static const char glyph_hieuhcirclekorean[] = "hieuhcirclekorean"; +static const char glyph_hieuhkorean[] = "hieuhkorean"; +static const char glyph_hieuhparenkorean[] = "hieuhparenkorean"; +static const char glyph_hihiragana[] = "hihiragana"; +static const char glyph_hikatakana[] = "hikatakana"; +static const char glyph_hikatakanahalfwidth[] = "hikatakanahalfwidth"; +static const char glyph_hiriq[] = "hiriq"; +static const char glyph_hiriq14[] = "hiriq14"; +static const char glyph_hiriq21[] = "hiriq21"; +static const char glyph_hiriq2d[] = "hiriq2d"; +static const char glyph_hiriqhebrew[] = "hiriqhebrew"; +static const char glyph_hiriqnarrowhebrew[] = "hiriqnarrowhebrew"; +static const char glyph_hiriqquarterhebrew[] = "hiriqquarterhebrew"; +static const char glyph_hiriqwidehebrew[] = "hiriqwidehebrew"; +static const char glyph_hlinebelow[] = "hlinebelow"; +static const char glyph_hmonospace[] = "hmonospace"; +static const char glyph_hoarmenian[] = "hoarmenian"; +static const char glyph_hohipthai[] = "hohipthai"; +static const char glyph_hohiragana[] = "hohiragana"; +static const char glyph_hokatakana[] = "hokatakana"; +static const char glyph_hokatakanahalfwidth[] = "hokatakanahalfwidth"; +static const char glyph_holam[] = "holam"; +static const char glyph_holam19[] = "holam19"; +static const char glyph_holam26[] = "holam26"; +static const char glyph_holam32[] = "holam32"; +static const char glyph_holamhebrew[] = "holamhebrew"; +static const char glyph_holamnarrowhebrew[] = "holamnarrowhebrew"; +static const char glyph_holamquarterhebrew[] = "holamquarterhebrew"; +static const char glyph_holamwidehebrew[] = "holamwidehebrew"; +static const char glyph_honokhukthai[] = "honokhukthai"; +static const char glyph_hookabovecomb[] = "hookabovecomb"; +static const char glyph_hookcmb[] = "hookcmb"; +static const char glyph_hookpalatalizedbelowcmb[] = "hookpalatalizedbelowcmb"; +static const char glyph_hookretroflexbelowcmb[] = "hookretroflexbelowcmb"; +static const char glyph_hoonsquare[] = "hoonsquare"; +static const char glyph_horicoptic[] = "horicoptic"; +static const char glyph_horizontalbar[] = "horizontalbar"; +static const char glyph_horncmb[] = "horncmb"; +static const char glyph_hotsprings[] = "hotsprings"; +static const char glyph_house[] = "house"; +static const char glyph_hparen[] = "hparen"; +static const char glyph_hsuperior[] = "hsuperior"; +static const char glyph_hturned[] = "hturned"; +static const char glyph_huhiragana[] = "huhiragana"; +static const char glyph_huiitosquare[] = "huiitosquare"; +static const char glyph_hukatakana[] = "hukatakana"; +static const char glyph_hukatakanahalfwidth[] = "hukatakanahalfwidth"; +static const char glyph_hungarumlaut[] = "hungarumlaut"; +static const char glyph_hungarumlautcmb[] = "hungarumlautcmb"; +static const char glyph_hv[] = "hv"; +static const char glyph_hyphen[] = "hyphen"; +static const char glyph_hypheninferior[] = "hypheninferior"; +static const char glyph_hyphenmonospace[] = "hyphenmonospace"; +static const char glyph_hyphensmall[] = "hyphensmall"; +static const char glyph_hyphensuperior[] = "hyphensuperior"; +static const char glyph_hyphentwo[] = "hyphentwo"; +static const char glyph_i[] = "i"; +static const char glyph_iacute[] = "iacute"; +static const char glyph_iacyrillic[] = "iacyrillic"; +static const char glyph_ibengali[] = "ibengali"; +static const char glyph_ibopomofo[] = "ibopomofo"; +static const char glyph_ibreve[] = "ibreve"; +static const char glyph_icaron[] = "icaron"; +static const char glyph_icircle[] = "icircle"; +static const char glyph_icircumflex[] = "icircumflex"; +static const char glyph_icyrillic[] = "icyrillic"; +static const char glyph_idblgrave[] = "idblgrave"; +static const char glyph_ideographearthcircle[] = "ideographearthcircle"; +static const char glyph_ideographfirecircle[] = "ideographfirecircle"; +static const char glyph_ideographicallianceparen[] = +"ideographicallianceparen"; +static const char glyph_ideographiccallparen[] = "ideographiccallparen"; +static const char glyph_ideographiccentrecircle[] = "ideographiccentrecircle"; +static const char glyph_ideographicclose[] = "ideographicclose"; +static const char glyph_ideographiccomma[] = "ideographiccomma"; +static const char glyph_ideographiccommaleft[] = "ideographiccommaleft"; +static const char glyph_ideographiccongratulationparen[] = +"ideographiccongratulationparen"; +static const char glyph_ideographiccorrectcircle[] = +"ideographiccorrectcircle"; +static const char glyph_ideographicearthparen[] = +"ideographicearthparen"; +static const char glyph_ideographicenterpriseparen[] = +"ideographicenterpriseparen"; +static const char glyph_ideographicexcellentcircle[] = +"ideographicexcellentcircle"; +static const char glyph_ideographicfestivalparen[] = +"ideographicfestivalparen"; +static const char glyph_ideographicfinancialcircle[] = +"ideographicfinancialcircle"; +static const char glyph_ideographicfinancialparen[] = +"ideographicfinancialparen"; +static const char glyph_ideographicfireparen[] = "ideographicfireparen"; +static const char glyph_ideographichaveparen[] = "ideographichaveparen"; +static const char glyph_ideographichighcircle[] = "ideographichighcircle"; +static const char glyph_ideographiciterationmark[] = +"ideographiciterationmark"; +static const char glyph_ideographiclaborcircle[] = "ideographiclaborcircle"; +static const char glyph_ideographiclaborparen[] = "ideographiclaborparen"; +static const char glyph_ideographicleftcircle[] = "ideographicleftcircle"; +static const char glyph_ideographiclowcircle[] = "ideographiclowcircle"; +static const char glyph_ideographicmedicinecircle[] = +"ideographicmedicinecircle"; +static const char glyph_ideographicmetalparen[] = "ideographicmetalparen"; +static const char glyph_ideographicmoonparen[] = "ideographicmoonparen"; +static const char glyph_ideographicnameparen[] = "ideographicnameparen"; +static const char glyph_ideographicperiod[] = "ideographicperiod"; +static const char glyph_ideographicprintcircle[] = "ideographicprintcircle"; +static const char glyph_ideographicreachparen[] = "ideographicreachparen"; +static const char glyph_ideographicrepresentparen[] = +"ideographicrepresentparen"; +static const char glyph_ideographicresourceparen[] = +"ideographicresourceparen"; +static const char glyph_ideographicrightcircle[] = "ideographicrightcircle"; +static const char glyph_ideographicsecretcircle[] = "ideographicsecretcircle"; +static const char glyph_ideographicselfparen[] = "ideographicselfparen"; +static const char glyph_ideographicsocietyparen[] = "ideographicsocietyparen"; +static const char glyph_ideographicspace[] = "ideographicspace"; +static const char glyph_ideographicspecialparen[] = "ideographicspecialparen"; +static const char glyph_ideographicstockparen[] = "ideographicstockparen"; +static const char glyph_ideographicstudyparen[] = "ideographicstudyparen"; +static const char glyph_ideographicsunparen[] = "ideographicsunparen"; +static const char glyph_ideographicsuperviseparen[] = +"ideographicsuperviseparen"; +static const char glyph_ideographicwaterparen[] = "ideographicwaterparen"; +static const char glyph_ideographicwoodparen[] = "ideographicwoodparen"; +static const char glyph_ideographiczero[] = "ideographiczero"; +static const char glyph_ideographmetalcircle[] = "ideographmetalcircle"; +static const char glyph_ideographmooncircle[] = "ideographmooncircle"; +static const char glyph_ideographnamecircle[] = "ideographnamecircle"; +static const char glyph_ideographsuncircle[] = "ideographsuncircle"; +static const char glyph_ideographwatercircle[] = "ideographwatercircle"; +static const char glyph_ideographwoodcircle[] = "ideographwoodcircle"; +static const char glyph_ideva[] = "ideva"; +static const char glyph_idieresis[] = "idieresis"; +static const char glyph_idieresisacute[] = "idieresisacute"; +static const char glyph_idieresiscyrillic[] = "idieresiscyrillic"; +static const char glyph_idotbelow[] = "idotbelow"; +static const char glyph_iebrevecyrillic[] = "iebrevecyrillic"; +static const char glyph_iecyrillic[] = "iecyrillic"; +static const char glyph_ieungacirclekorean[] = "ieungacirclekorean"; +static const char glyph_ieungaparenkorean[] = "ieungaparenkorean"; +static const char glyph_ieungcirclekorean[] = "ieungcirclekorean"; +static const char glyph_ieungkorean[] = "ieungkorean"; +static const char glyph_ieungparenkorean[] = "ieungparenkorean"; +static const char glyph_igrave[] = "igrave"; +static const char glyph_igujarati[] = "igujarati"; +static const char glyph_igurmukhi[] = "igurmukhi"; +static const char glyph_ihiragana[] = "ihiragana"; +static const char glyph_ihookabove[] = "ihookabove"; +static const char glyph_iibengali[] = "iibengali"; +static const char glyph_iicyrillic[] = "iicyrillic"; +static const char glyph_iideva[] = "iideva"; +static const char glyph_iigujarati[] = "iigujarati"; +static const char glyph_iigurmukhi[] = "iigurmukhi"; +static const char glyph_iimatragurmukhi[] = "iimatragurmukhi"; +static const char glyph_iinvertedbreve[] = "iinvertedbreve"; +static const char glyph_iishortcyrillic[] = "iishortcyrillic"; +static const char glyph_iivowelsignbengali[] = "iivowelsignbengali"; +static const char glyph_iivowelsigndeva[] = "iivowelsigndeva"; +static const char glyph_iivowelsigngujarati[] = "iivowelsigngujarati"; +static const char glyph_ij[] = "ij"; +static const char glyph_ikatakana[] = "ikatakana"; +static const char glyph_ikatakanahalfwidth[] = "ikatakanahalfwidth"; +static const char glyph_ikorean[] = "ikorean"; +static const char glyph_ilde[] = "ilde"; +static const char glyph_iluyhebrew[] = "iluyhebrew"; +static const char glyph_imacron[] = "imacron"; +static const char glyph_imacroncyrillic[] = "imacroncyrillic"; +static const char glyph_imageorapproximatelyequal[] = +"imageorapproximatelyequal"; +static const char glyph_imatragurmukhi[] = "imatragurmukhi"; +static const char glyph_imonospace[] = "imonospace"; +static const char glyph_increment[] = "increment"; +static const char glyph_infinity[] = "infinity"; +static const char glyph_iniarmenian[] = "iniarmenian"; +static const char glyph_integral[] = "integral"; +static const char glyph_integralbottom[] = "integralbottom"; +static const char glyph_integralbt[] = "integralbt"; +static const char glyph_integralex[] = "integralex"; +static const char glyph_integraltop[] = "integraltop"; +static const char glyph_integraltp[] = "integraltp"; +static const char glyph_intersection[] = "intersection"; +static const char glyph_intisquare[] = "intisquare"; +static const char glyph_invbullet[] = "invbullet"; +static const char glyph_invcircle[] = "invcircle"; +static const char glyph_invsmileface[] = "invsmileface"; +static const char glyph_iocyrillic[] = "iocyrillic"; +static const char glyph_iogonek[] = "iogonek"; +static const char glyph_iota[] = "iota"; +static const char glyph_iotadieresis[] = "iotadieresis"; +static const char glyph_iotadieresistonos[] = "iotadieresistonos"; +static const char glyph_iotalatin[] = "iotalatin"; +static const char glyph_iotatonos[] = "iotatonos"; +static const char glyph_iparen[] = "iparen"; +static const char glyph_irigurmukhi[] = "irigurmukhi"; +static const char glyph_ismallhiragana[] = "ismallhiragana"; +static const char glyph_ismallkatakana[] = "ismallkatakana"; +static const char glyph_ismallkatakanahalfwidth[] = "ismallkatakanahalfwidth"; +static const char glyph_issharbengali[] = "issharbengali"; +static const char glyph_istroke[] = "istroke"; +static const char glyph_isuperior[] = "isuperior"; +static const char glyph_iterationhiragana[] = "iterationhiragana"; +static const char glyph_iterationkatakana[] = "iterationkatakana"; +static const char glyph_itilde[] = "itilde"; +static const char glyph_itildebelow[] = "itildebelow"; +static const char glyph_iubopomofo[] = "iubopomofo"; +static const char glyph_iucyrillic[] = "iucyrillic"; +static const char glyph_ivowelsignbengali[] = "ivowelsignbengali"; +static const char glyph_ivowelsigndeva[] = "ivowelsigndeva"; +static const char glyph_ivowelsigngujarati[] = "ivowelsigngujarati"; +static const char glyph_izhitsacyrillic[] = "izhitsacyrillic"; +static const char glyph_izhitsadblgravecyrillic[] = "izhitsadblgravecyrillic"; +static const char glyph_j[] = "j"; +static const char glyph_jaarmenian[] = "jaarmenian"; +static const char glyph_jabengali[] = "jabengali"; +static const char glyph_jadeva[] = "jadeva"; +static const char glyph_jagujarati[] = "jagujarati"; +static const char glyph_jagurmukhi[] = "jagurmukhi"; +static const char glyph_jbopomofo[] = "jbopomofo"; +static const char glyph_jcaron[] = "jcaron"; +static const char glyph_jcircle[] = "jcircle"; +static const char glyph_jcircumflex[] = "jcircumflex"; +static const char glyph_jcrossedtail[] = "jcrossedtail"; +static const char glyph_jdotlessstroke[] = "jdotlessstroke"; +static const char glyph_jecyrillic[] = "jecyrillic"; +static const char glyph_jeemarabic[] = "jeemarabic"; +static const char glyph_jeemfinalarabic[] = "jeemfinalarabic"; +static const char glyph_jeeminitialarabic[] = "jeeminitialarabic"; +static const char glyph_jeemmedialarabic[] = "jeemmedialarabic"; +static const char glyph_jeharabic[] = "jeharabic"; +static const char glyph_jehfinalarabic[] = "jehfinalarabic"; +static const char glyph_jhabengali[] = "jhabengali"; +static const char glyph_jhadeva[] = "jhadeva"; +static const char glyph_jhagujarati[] = "jhagujarati"; +static const char glyph_jhagurmukhi[] = "jhagurmukhi"; +static const char glyph_jheharmenian[] = "jheharmenian"; +static const char glyph_jis[] = "jis"; +static const char glyph_jmonospace[] = "jmonospace"; +static const char glyph_jparen[] = "jparen"; +static const char glyph_jsuperior[] = "jsuperior"; +static const char glyph_k[] = "k"; +static const char glyph_kabashkircyrillic[] = "kabashkircyrillic"; +static const char glyph_kabengali[] = "kabengali"; +static const char glyph_kacute[] = "kacute"; +static const char glyph_kacyrillic[] = "kacyrillic"; +static const char glyph_kadescendercyrillic[] = "kadescendercyrillic"; +static const char glyph_kadeva[] = "kadeva"; +static const char glyph_kaf[] = "kaf"; +static const char glyph_kafarabic[] = "kafarabic"; +static const char glyph_kafdagesh[] = "kafdagesh"; +static const char glyph_kafdageshhebrew[] = "kafdageshhebrew"; +static const char glyph_kaffinalarabic[] = "kaffinalarabic"; +static const char glyph_kafhebrew[] = "kafhebrew"; +static const char glyph_kafinitialarabic[] = "kafinitialarabic"; +static const char glyph_kafmedialarabic[] = "kafmedialarabic"; +static const char glyph_kafrafehebrew[] = "kafrafehebrew"; +static const char glyph_kagujarati[] = "kagujarati"; +static const char glyph_kagurmukhi[] = "kagurmukhi"; +static const char glyph_kahiragana[] = "kahiragana"; +static const char glyph_kahookcyrillic[] = "kahookcyrillic"; +static const char glyph_kakatakana[] = "kakatakana"; +static const char glyph_kakatakanahalfwidth[] = "kakatakanahalfwidth"; +static const char glyph_kappa[] = "kappa"; +static const char glyph_kappasymbolgreek[] = "kappasymbolgreek"; +static const char glyph_kapyeounmieumkorean[] = "kapyeounmieumkorean"; +static const char glyph_kapyeounphieuphkorean[] = "kapyeounphieuphkorean"; +static const char glyph_kapyeounpieupkorean[] = "kapyeounpieupkorean"; +static const char glyph_kapyeounssangpieupkorean[] = +"kapyeounssangpieupkorean"; +static const char glyph_karoriisquare[] = "karoriisquare"; +static const char glyph_kashidaautoarabic[] = "kashidaautoarabic"; +static const char glyph_kashidaautonosidebearingarabic[] = +"kashidaautonosidebearingarabic"; +static const char glyph_kasmallkatakana[] = "kasmallkatakana"; +static const char glyph_kasquare[] = "kasquare"; +static const char glyph_kasraarabic[] = "kasraarabic"; +static const char glyph_kasratanarabic[] = "kasratanarabic"; +static const char glyph_kastrokecyrillic[] = "kastrokecyrillic"; +static const char glyph_katahiraprolongmarkhalfwidth[] = +"katahiraprolongmarkhalfwidth"; +static const char glyph_kaverticalstrokecyrillic[] = +"kaverticalstrokecyrillic"; +static const char glyph_kbopomofo[] = "kbopomofo"; +static const char glyph_kcalsquare[] = "kcalsquare"; +static const char glyph_kcaron[] = "kcaron"; +static const char glyph_kcedilla[] = "kcedilla"; +static const char glyph_kcircle[] = "kcircle"; +static const char glyph_kcommaaccent[] = "kcommaaccent"; +static const char glyph_kdotbelow[] = "kdotbelow"; +static const char glyph_keharmenian[] = "keharmenian"; +static const char glyph_kehiragana[] = "kehiragana"; +static const char glyph_kekatakana[] = "kekatakana"; +static const char glyph_kekatakanahalfwidth[] = "kekatakanahalfwidth"; +static const char glyph_kenarmenian[] = "kenarmenian"; +static const char glyph_kesmallkatakana[] = "kesmallkatakana"; +static const char glyph_kgreenlandic[] = "kgreenlandic"; +static const char glyph_khabengali[] = "khabengali"; +static const char glyph_khacyrillic[] = "khacyrillic"; +static const char glyph_khadeva[] = "khadeva"; +static const char glyph_khagujarati[] = "khagujarati"; +static const char glyph_khagurmukhi[] = "khagurmukhi"; +static const char glyph_khaharabic[] = "khaharabic"; +static const char glyph_khahfinalarabic[] = "khahfinalarabic"; +static const char glyph_khahinitialarabic[] = "khahinitialarabic"; +static const char glyph_khahmedialarabic[] = "khahmedialarabic"; +static const char glyph_kheicoptic[] = "kheicoptic"; +static const char glyph_khhadeva[] = "khhadeva"; +static const char glyph_khhagurmukhi[] = "khhagurmukhi"; +static const char glyph_khieukhacirclekorean[] = "khieukhacirclekorean"; +static const char glyph_khieukhaparenkorean[] = "khieukhaparenkorean"; +static const char glyph_khieukhcirclekorean[] = "khieukhcirclekorean"; +static const char glyph_khieukhkorean[] = "khieukhkorean"; +static const char glyph_khieukhparenkorean[] = "khieukhparenkorean"; +static const char glyph_khokhaithai[] = "khokhaithai"; +static const char glyph_khokhonthai[] = "khokhonthai"; +static const char glyph_khokhuatthai[] = "khokhuatthai"; +static const char glyph_khokhwaithai[] = "khokhwaithai"; +static const char glyph_khomutthai[] = "khomutthai"; +static const char glyph_khook[] = "khook"; +static const char glyph_khorakhangthai[] = "khorakhangthai"; +static const char glyph_khzsquare[] = "khzsquare"; +static const char glyph_kihiragana[] = "kihiragana"; +static const char glyph_kikatakana[] = "kikatakana"; +static const char glyph_kikatakanahalfwidth[] = "kikatakanahalfwidth"; +static const char glyph_kiroguramusquare[] = "kiroguramusquare"; +static const char glyph_kiromeetorusquare[] = "kiromeetorusquare"; +static const char glyph_kirosquare[] = "kirosquare"; +static const char glyph_kiyeokacirclekorean[] = "kiyeokacirclekorean"; +static const char glyph_kiyeokaparenkorean[] = "kiyeokaparenkorean"; +static const char glyph_kiyeokcirclekorean[] = "kiyeokcirclekorean"; +static const char glyph_kiyeokkorean[] = "kiyeokkorean"; +static const char glyph_kiyeokparenkorean[] = "kiyeokparenkorean"; +static const char glyph_kiyeoksioskorean[] = "kiyeoksioskorean"; +static const char glyph_kjecyrillic[] = "kjecyrillic"; +static const char glyph_klinebelow[] = "klinebelow"; +static const char glyph_klsquare[] = "klsquare"; +static const char glyph_kmcubedsquare[] = "kmcubedsquare"; +static const char glyph_kmonospace[] = "kmonospace"; +static const char glyph_kmsquaredsquare[] = "kmsquaredsquare"; +static const char glyph_kohiragana[] = "kohiragana"; +static const char glyph_kohmsquare[] = "kohmsquare"; +static const char glyph_kokaithai[] = "kokaithai"; +static const char glyph_kokatakana[] = "kokatakana"; +static const char glyph_kokatakanahalfwidth[] = "kokatakanahalfwidth"; +static const char glyph_kooposquare[] = "kooposquare"; +static const char glyph_koppacyrillic[] = "koppacyrillic"; +static const char glyph_koreanstandardsymbol[] = "koreanstandardsymbol"; +static const char glyph_koroniscmb[] = "koroniscmb"; +static const char glyph_kparen[] = "kparen"; +static const char glyph_kpasquare[] = "kpasquare"; +static const char glyph_ksicyrillic[] = "ksicyrillic"; +static const char glyph_ktsquare[] = "ktsquare"; +static const char glyph_kturned[] = "kturned"; +static const char glyph_kuhiragana[] = "kuhiragana"; +static const char glyph_kukatakana[] = "kukatakana"; +static const char glyph_kukatakanahalfwidth[] = "kukatakanahalfwidth"; +static const char glyph_kvsquare[] = "kvsquare"; +static const char glyph_kwsquare[] = "kwsquare"; +static const char glyph_l[] = "l"; +static const char glyph_labengali[] = "labengali"; +static const char glyph_lacute[] = "lacute"; +static const char glyph_ladeva[] = "ladeva"; +static const char glyph_lagujarati[] = "lagujarati"; +static const char glyph_lagurmukhi[] = "lagurmukhi"; +static const char glyph_lakkhangyaothai[] = "lakkhangyaothai"; +static const char glyph_lamaleffinalarabic[] = "lamaleffinalarabic"; +static const char glyph_lamalefhamzaabovefinalarabic[] = +"lamalefhamzaabovefinalarabic"; +static const char glyph_lamalefhamzaaboveisolatedarabic[] = +"lamalefhamzaaboveisolatedarabic"; +static const char glyph_lamalefhamzabelowfinalarabic[] = +"lamalefhamzabelowfinalarabic"; +static const char glyph_lamalefhamzabelowisolatedarabic[] = +"lamalefhamzabelowisolatedarabic"; +static const char glyph_lamalefisolatedarabic[] = +"lamalefisolatedarabic"; +static const char glyph_lamalefmaddaabovefinalarabic[] = +"lamalefmaddaabovefinalarabic"; +static const char glyph_lamalefmaddaaboveisolatedarabic[] = +"lamalefmaddaaboveisolatedarabic"; +static const char glyph_lamarabic[] = "lamarabic"; +static const char glyph_lambda[] = "lambda"; +static const char glyph_lambdastroke[] = "lambdastroke"; +static const char glyph_lamed[] = "lamed"; +static const char glyph_lameddagesh[] = "lameddagesh"; +static const char glyph_lameddageshhebrew[] = "lameddageshhebrew"; +static const char glyph_lamedhebrew[] = "lamedhebrew"; +static const char glyph_lamedholam[] = "lamedholam"; +static const char glyph_lamedholamdagesh[] = "lamedholamdagesh"; +static const char glyph_lamedholamdageshhebrew[] = "lamedholamdageshhebrew"; +static const char glyph_lamedholamhebrew[] = "lamedholamhebrew"; +static const char glyph_lamfinalarabic[] = "lamfinalarabic"; +static const char glyph_lamhahinitialarabic[] = "lamhahinitialarabic"; +static const char glyph_laminitialarabic[] = "laminitialarabic"; +static const char glyph_lamjeeminitialarabic[] = "lamjeeminitialarabic"; +static const char glyph_lamkhahinitialarabic[] = "lamkhahinitialarabic"; +static const char glyph_lamlamhehisolatedarabic[] = "lamlamhehisolatedarabic"; +static const char glyph_lammedialarabic[] = "lammedialarabic"; +static const char glyph_lammeemhahinitialarabic[] = "lammeemhahinitialarabic"; +static const char glyph_lammeeminitialarabic[] = "lammeeminitialarabic"; +static const char glyph_lammeemjeeminitialarabic[] = +"lammeemjeeminitialarabic"; +static const char glyph_lammeemkhahinitialarabic[] = +"lammeemkhahinitialarabic"; +static const char glyph_largecircle[] = "largecircle"; +static const char glyph_lbar[] = "lbar"; +static const char glyph_lbelt[] = "lbelt"; +static const char glyph_lbopomofo[] = "lbopomofo"; +static const char glyph_lcaron[] = "lcaron"; +static const char glyph_lcedilla[] = "lcedilla"; +static const char glyph_lcircle[] = "lcircle"; +static const char glyph_lcircumflexbelow[] = "lcircumflexbelow"; +static const char glyph_lcommaaccent[] = "lcommaaccent"; +static const char glyph_ldot[] = "ldot"; +static const char glyph_ldotaccent[] = "ldotaccent"; +static const char glyph_ldotbelow[] = "ldotbelow"; +static const char glyph_ldotbelowmacron[] = "ldotbelowmacron"; +static const char glyph_leftangleabovecmb[] = "leftangleabovecmb"; +static const char glyph_lefttackbelowcmb[] = "lefttackbelowcmb"; +static const char glyph_less[] = "less"; +static const char glyph_lessequal[] = "lessequal"; +static const char glyph_lessequalorgreater[] = "lessequalorgreater"; +static const char glyph_lessmonospace[] = "lessmonospace"; +static const char glyph_lessorequivalent[] = "lessorequivalent"; +static const char glyph_lessorgreater[] = "lessorgreater"; +static const char glyph_lessoverequal[] = "lessoverequal"; +static const char glyph_lesssmall[] = "lesssmall"; +static const char glyph_lezh[] = "lezh"; +static const char glyph_lfblock[] = "lfblock"; +static const char glyph_lhookretroflex[] = "lhookretroflex"; +static const char glyph_lira[] = "lira"; +static const char glyph_liwnarmenian[] = "liwnarmenian"; +static const char glyph_lj[] = "lj"; +static const char glyph_ljecyrillic[] = "ljecyrillic"; +static const char glyph_ll[] = "ll"; +static const char glyph_lladeva[] = "lladeva"; +static const char glyph_llagujarati[] = "llagujarati"; +static const char glyph_llinebelow[] = "llinebelow"; +static const char glyph_llladeva[] = "llladeva"; +static const char glyph_llvocalicbengali[] = "llvocalicbengali"; +static const char glyph_llvocalicdeva[] = "llvocalicdeva"; +static const char glyph_llvocalicvowelsignbengali[] = +"llvocalicvowelsignbengali"; +static const char glyph_llvocalicvowelsigndeva[] = "llvocalicvowelsigndeva"; +static const char glyph_lmiddletilde[] = "lmiddletilde"; +static const char glyph_lmonospace[] = "lmonospace"; +static const char glyph_lmsquare[] = "lmsquare"; +static const char glyph_lochulathai[] = "lochulathai"; +static const char glyph_logicaland[] = "logicaland"; +static const char glyph_logicalnot[] = "logicalnot"; +static const char glyph_logicalnotreversed[] = "logicalnotreversed"; +static const char glyph_logicalor[] = "logicalor"; +static const char glyph_lolingthai[] = "lolingthai"; +static const char glyph_longs[] = "longs"; +static const char glyph_lowlinecenterline[] = "lowlinecenterline"; +static const char glyph_lowlinecmb[] = "lowlinecmb"; +static const char glyph_lowlinedashed[] = "lowlinedashed"; +static const char glyph_lozenge[] = "lozenge"; +static const char glyph_lparen[] = "lparen"; +static const char glyph_lslash[] = "lslash"; +static const char glyph_lsquare[] = "lsquare"; +static const char glyph_lsuperior[] = "lsuperior"; +static const char glyph_ltshade[] = "ltshade"; +static const char glyph_luthai[] = "luthai"; +static const char glyph_lvocalicbengali[] = "lvocalicbengali"; +static const char glyph_lvocalicdeva[] = "lvocalicdeva"; +static const char glyph_lvocalicvowelsignbengali[] = +"lvocalicvowelsignbengali"; +static const char glyph_lvocalicvowelsigndeva[] = "lvocalicvowelsigndeva"; +static const char glyph_lxsquare[] = "lxsquare"; +static const char glyph_m[] = "m"; +static const char glyph_mabengali[] = "mabengali"; +static const char glyph_macron[] = "macron"; +static const char glyph_macronbelowcmb[] = "macronbelowcmb"; +static const char glyph_macroncmb[] = "macroncmb"; +static const char glyph_macronlowmod[] = "macronlowmod"; +static const char glyph_macronmonospace[] = "macronmonospace"; +static const char glyph_macute[] = "macute"; +static const char glyph_madeva[] = "madeva"; +static const char glyph_magujarati[] = "magujarati"; +static const char glyph_magurmukhi[] = "magurmukhi"; +static const char glyph_mahapakhhebrew[] = "mahapakhhebrew"; +static const char glyph_mahapakhlefthebrew[] = "mahapakhlefthebrew"; +static const char glyph_mahiragana[] = "mahiragana"; +static const char glyph_maichattawalowleftthai[] = "maichattawalowleftthai"; +static const char glyph_maichattawalowrightthai[] = "maichattawalowrightthai"; +static const char glyph_maichattawathai[] = "maichattawathai"; +static const char glyph_maichattawaupperleftthai[] = +"maichattawaupperleftthai"; +static const char glyph_maieklowleftthai[] = "maieklowleftthai"; +static const char glyph_maieklowrightthai[] = "maieklowrightthai"; +static const char glyph_maiekthai[] = "maiekthai"; +static const char glyph_maiekupperleftthai[] = "maiekupperleftthai"; +static const char glyph_maihanakatleftthai[] = "maihanakatleftthai"; +static const char glyph_maihanakatthai[] = "maihanakatthai"; +static const char glyph_maitaikhuleftthai[] = "maitaikhuleftthai"; +static const char glyph_maitaikhuthai[] = "maitaikhuthai"; +static const char glyph_maitholowleftthai[] = "maitholowleftthai"; +static const char glyph_maitholowrightthai[] = "maitholowrightthai"; +static const char glyph_maithothai[] = "maithothai"; +static const char glyph_maithoupperleftthai[] = "maithoupperleftthai"; +static const char glyph_maitrilowleftthai[] = "maitrilowleftthai"; +static const char glyph_maitrilowrightthai[] = "maitrilowrightthai"; +static const char glyph_maitrithai[] = "maitrithai"; +static const char glyph_maitriupperleftthai[] = "maitriupperleftthai"; +static const char glyph_maiyamokthai[] = "maiyamokthai"; +static const char glyph_makatakana[] = "makatakana"; +static const char glyph_makatakanahalfwidth[] = "makatakanahalfwidth"; +static const char glyph_male[] = "male"; +static const char glyph_mansyonsquare[] = "mansyonsquare"; +static const char glyph_maqafhebrew[] = "maqafhebrew"; +static const char glyph_mars[] = "mars"; +static const char glyph_masoracirclehebrew[] = "masoracirclehebrew"; +static const char glyph_masquare[] = "masquare"; +static const char glyph_mbopomofo[] = "mbopomofo"; +static const char glyph_mbsquare[] = "mbsquare"; +static const char glyph_mcircle[] = "mcircle"; +static const char glyph_mcubedsquare[] = "mcubedsquare"; +static const char glyph_mdotaccent[] = "mdotaccent"; +static const char glyph_mdotbelow[] = "mdotbelow"; +static const char glyph_meemarabic[] = "meemarabic"; +static const char glyph_meemfinalarabic[] = "meemfinalarabic"; +static const char glyph_meeminitialarabic[] = "meeminitialarabic"; +static const char glyph_meemmedialarabic[] = "meemmedialarabic"; +static const char glyph_meemmeeminitialarabic[] = "meemmeeminitialarabic"; +static const char glyph_meemmeemisolatedarabic[] = "meemmeemisolatedarabic"; +static const char glyph_meetorusquare[] = "meetorusquare"; +static const char glyph_mehiragana[] = "mehiragana"; +static const char glyph_meizierasquare[] = "meizierasquare"; +static const char glyph_mekatakana[] = "mekatakana"; +static const char glyph_mekatakanahalfwidth[] = "mekatakanahalfwidth"; +static const char glyph_mem[] = "mem"; +static const char glyph_memdagesh[] = "memdagesh"; +static const char glyph_memdageshhebrew[] = "memdageshhebrew"; +static const char glyph_memhebrew[] = "memhebrew"; +static const char glyph_menarmenian[] = "menarmenian"; +static const char glyph_merkhahebrew[] = "merkhahebrew"; +static const char glyph_merkhakefulahebrew[] = "merkhakefulahebrew"; +static const char glyph_merkhakefulalefthebrew[] = "merkhakefulalefthebrew"; +static const char glyph_merkhalefthebrew[] = "merkhalefthebrew"; +static const char glyph_mhook[] = "mhook"; +static const char glyph_mhzsquare[] = "mhzsquare"; +static const char glyph_middledotkatakanahalfwidth[] = +"middledotkatakanahalfwidth"; +static const char glyph_middot[] = "middot"; +static const char glyph_mieumacirclekorean[] = "mieumacirclekorean"; +static const char glyph_mieumaparenkorean[] = "mieumaparenkorean"; +static const char glyph_mieumcirclekorean[] = "mieumcirclekorean"; +static const char glyph_mieumkorean[] = "mieumkorean"; +static const char glyph_mieumpansioskorean[] = "mieumpansioskorean"; +static const char glyph_mieumparenkorean[] = "mieumparenkorean"; +static const char glyph_mieumpieupkorean[] = "mieumpieupkorean"; +static const char glyph_mieumsioskorean[] = "mieumsioskorean"; +static const char glyph_mihiragana[] = "mihiragana"; +static const char glyph_mikatakana[] = "mikatakana"; +static const char glyph_mikatakanahalfwidth[] = "mikatakanahalfwidth"; +static const char glyph_minus[] = "minus"; +static const char glyph_minusbelowcmb[] = "minusbelowcmb"; +static const char glyph_minuscircle[] = "minuscircle"; +static const char glyph_minusmod[] = "minusmod"; +static const char glyph_minusplus[] = "minusplus"; +static const char glyph_minute[] = "minute"; +static const char glyph_miribaarusquare[] = "miribaarusquare"; +static const char glyph_mirisquare[] = "mirisquare"; +static const char glyph_mlonglegturned[] = "mlonglegturned"; +static const char glyph_mlsquare[] = "mlsquare"; +static const char glyph_mmcubedsquare[] = "mmcubedsquare"; +static const char glyph_mmonospace[] = "mmonospace"; +static const char glyph_mmsquaredsquare[] = "mmsquaredsquare"; +static const char glyph_mohiragana[] = "mohiragana"; +static const char glyph_mohmsquare[] = "mohmsquare"; +static const char glyph_mokatakana[] = "mokatakana"; +static const char glyph_mokatakanahalfwidth[] = "mokatakanahalfwidth"; +static const char glyph_molsquare[] = "molsquare"; +static const char glyph_momathai[] = "momathai"; +static const char glyph_moverssquare[] = "moverssquare"; +static const char glyph_moverssquaredsquare[] = "moverssquaredsquare"; +static const char glyph_mparen[] = "mparen"; +static const char glyph_mpasquare[] = "mpasquare"; +static const char glyph_mssquare[] = "mssquare"; +static const char glyph_msuperior[] = "msuperior"; +static const char glyph_mturned[] = "mturned"; +static const char glyph_mu[] = "mu"; +static const char glyph_mu1[] = "mu1"; +static const char glyph_muasquare[] = "muasquare"; +static const char glyph_muchgreater[] = "muchgreater"; +static const char glyph_muchless[] = "muchless"; +static const char glyph_mufsquare[] = "mufsquare"; +static const char glyph_mugreek[] = "mugreek"; +static const char glyph_mugsquare[] = "mugsquare"; +static const char glyph_muhiragana[] = "muhiragana"; +static const char glyph_mukatakana[] = "mukatakana"; +static const char glyph_mukatakanahalfwidth[] = "mukatakanahalfwidth"; +static const char glyph_mulsquare[] = "mulsquare"; +static const char glyph_multiply[] = "multiply"; +static const char glyph_mumsquare[] = "mumsquare"; +static const char glyph_munahhebrew[] = "munahhebrew"; +static const char glyph_munahlefthebrew[] = "munahlefthebrew"; +static const char glyph_musicalnote[] = "musicalnote"; +static const char glyph_musicalnotedbl[] = "musicalnotedbl"; +static const char glyph_musicflatsign[] = "musicflatsign"; +static const char glyph_musicsharpsign[] = "musicsharpsign"; +static const char glyph_mussquare[] = "mussquare"; +static const char glyph_muvsquare[] = "muvsquare"; +static const char glyph_muwsquare[] = "muwsquare"; +static const char glyph_mvmegasquare[] = "mvmegasquare"; +static const char glyph_mvsquare[] = "mvsquare"; +static const char glyph_mwmegasquare[] = "mwmegasquare"; +static const char glyph_mwsquare[] = "mwsquare"; +static const char glyph_n[] = "n"; +static const char glyph_nabengali[] = "nabengali"; +static const char glyph_nabla[] = "nabla"; +static const char glyph_nacute[] = "nacute"; +static const char glyph_nadeva[] = "nadeva"; +static const char glyph_nagujarati[] = "nagujarati"; +static const char glyph_nagurmukhi[] = "nagurmukhi"; +static const char glyph_nahiragana[] = "nahiragana"; +static const char glyph_nakatakana[] = "nakatakana"; +static const char glyph_nakatakanahalfwidth[] = "nakatakanahalfwidth"; +static const char glyph_napostrophe[] = "napostrophe"; +static const char glyph_nasquare[] = "nasquare"; +static const char glyph_nbopomofo[] = "nbopomofo"; +static const char glyph_nbspace[] = "nbspace"; +static const char glyph_ncaron[] = "ncaron"; +static const char glyph_ncedilla[] = "ncedilla"; +static const char glyph_ncircle[] = "ncircle"; +static const char glyph_ncircumflexbelow[] = "ncircumflexbelow"; +static const char glyph_ncommaaccent[] = "ncommaaccent"; +static const char glyph_ndotaccent[] = "ndotaccent"; +static const char glyph_ndotbelow[] = "ndotbelow"; +static const char glyph_nehiragana[] = "nehiragana"; +static const char glyph_nekatakana[] = "nekatakana"; +static const char glyph_nekatakanahalfwidth[] = "nekatakanahalfwidth"; +static const char glyph_newsheqelsign[] = "newsheqelsign"; +static const char glyph_nfsquare[] = "nfsquare"; +static const char glyph_ngabengali[] = "ngabengali"; +static const char glyph_ngadeva[] = "ngadeva"; +static const char glyph_ngagujarati[] = "ngagujarati"; +static const char glyph_ngagurmukhi[] = "ngagurmukhi"; +static const char glyph_ngonguthai[] = "ngonguthai"; +static const char glyph_nhiragana[] = "nhiragana"; +static const char glyph_nhookleft[] = "nhookleft"; +static const char glyph_nhookretroflex[] = "nhookretroflex"; +static const char glyph_nieunacirclekorean[] = "nieunacirclekorean"; +static const char glyph_nieunaparenkorean[] = "nieunaparenkorean"; +static const char glyph_nieuncieuckorean[] = "nieuncieuckorean"; +static const char glyph_nieuncirclekorean[] = "nieuncirclekorean"; +static const char glyph_nieunhieuhkorean[] = "nieunhieuhkorean"; +static const char glyph_nieunkorean[] = "nieunkorean"; +static const char glyph_nieunpansioskorean[] = "nieunpansioskorean"; +static const char glyph_nieunparenkorean[] = "nieunparenkorean"; +static const char glyph_nieunsioskorean[] = "nieunsioskorean"; +static const char glyph_nieuntikeutkorean[] = "nieuntikeutkorean"; +static const char glyph_nihiragana[] = "nihiragana"; +static const char glyph_nikatakana[] = "nikatakana"; +static const char glyph_nikatakanahalfwidth[] = "nikatakanahalfwidth"; +static const char glyph_nikhahitleftthai[] = "nikhahitleftthai"; +static const char glyph_nikhahitthai[] = "nikhahitthai"; +static const char glyph_nine[] = "nine"; +static const char glyph_ninearabic[] = "ninearabic"; +static const char glyph_ninebengali[] = "ninebengali"; +static const char glyph_ninecircle[] = "ninecircle"; +static const char glyph_ninecircleinversesansserif[] = +"ninecircleinversesansserif"; +static const char glyph_ninedeva[] = "ninedeva"; +static const char glyph_ninegujarati[] = "ninegujarati"; +static const char glyph_ninegurmukhi[] = "ninegurmukhi"; +static const char glyph_ninehackarabic[] = "ninehackarabic"; +static const char glyph_ninehangzhou[] = "ninehangzhou"; +static const char glyph_nineideographicparen[] = "nineideographicparen"; +static const char glyph_nineinferior[] = "nineinferior"; +static const char glyph_ninemonospace[] = "ninemonospace"; +static const char glyph_nineoldstyle[] = "nineoldstyle"; +static const char glyph_nineparen[] = "nineparen"; +static const char glyph_nineperiod[] = "nineperiod"; +static const char glyph_ninepersian[] = "ninepersian"; +static const char glyph_nineroman[] = "nineroman"; +static const char glyph_ninesuperior[] = "ninesuperior"; +static const char glyph_nineteencircle[] = "nineteencircle"; +static const char glyph_nineteenparen[] = "nineteenparen"; +static const char glyph_nineteenperiod[] = "nineteenperiod"; +static const char glyph_ninethai[] = "ninethai"; +static const char glyph_nj[] = "nj"; +static const char glyph_njecyrillic[] = "njecyrillic"; +static const char glyph_nkatakana[] = "nkatakana"; +static const char glyph_nkatakanahalfwidth[] = "nkatakanahalfwidth"; +static const char glyph_nlegrightlong[] = "nlegrightlong"; +static const char glyph_nlinebelow[] = "nlinebelow"; +static const char glyph_nmonospace[] = "nmonospace"; +static const char glyph_nmsquare[] = "nmsquare"; +static const char glyph_nnabengali[] = "nnabengali"; +static const char glyph_nnadeva[] = "nnadeva"; +static const char glyph_nnagujarati[] = "nnagujarati"; +static const char glyph_nnagurmukhi[] = "nnagurmukhi"; +static const char glyph_nnnadeva[] = "nnnadeva"; +static const char glyph_nohiragana[] = "nohiragana"; +static const char glyph_nokatakana[] = "nokatakana"; +static const char glyph_nokatakanahalfwidth[] = "nokatakanahalfwidth"; +static const char glyph_nonbreakingspace[] = "nonbreakingspace"; +static const char glyph_nonenthai[] = "nonenthai"; +static const char glyph_nonuthai[] = "nonuthai"; +static const char glyph_noonarabic[] = "noonarabic"; +static const char glyph_noonfinalarabic[] = "noonfinalarabic"; +static const char glyph_noonghunnaarabic[] = "noonghunnaarabic"; +static const char glyph_noonghunnafinalarabic[] = "noonghunnafinalarabic"; +static const char glyph_noonhehinitialarabic[] = "noonhehinitialarabic"; +static const char glyph_nooninitialarabic[] = "nooninitialarabic"; +static const char glyph_noonjeeminitialarabic[] = "noonjeeminitialarabic"; +static const char glyph_noonjeemisolatedarabic[] = "noonjeemisolatedarabic"; +static const char glyph_noonmedialarabic[] = "noonmedialarabic"; +static const char glyph_noonmeeminitialarabic[] = "noonmeeminitialarabic"; +static const char glyph_noonmeemisolatedarabic[] = "noonmeemisolatedarabic"; +static const char glyph_noonnoonfinalarabic[] = "noonnoonfinalarabic"; +static const char glyph_notcontains[] = "notcontains"; +static const char glyph_notelement[] = "notelement"; +static const char glyph_notelementof[] = "notelementof"; +static const char glyph_notequal[] = "notequal"; +static const char glyph_notgreater[] = "notgreater"; +static const char glyph_notgreaternorequal[] = "notgreaternorequal"; +static const char glyph_notgreaternorless[] = "notgreaternorless"; +static const char glyph_notidentical[] = "notidentical"; +static const char glyph_notless[] = "notless"; +static const char glyph_notlessnorequal[] = "notlessnorequal"; +static const char glyph_notparallel[] = "notparallel"; +static const char glyph_notprecedes[] = "notprecedes"; +static const char glyph_notsubset[] = "notsubset"; +static const char glyph_notsucceeds[] = "notsucceeds"; +static const char glyph_notsuperset[] = "notsuperset"; +static const char glyph_nowarmenian[] = "nowarmenian"; +static const char glyph_nparen[] = "nparen"; +static const char glyph_nssquare[] = "nssquare"; +static const char glyph_nsuperior[] = "nsuperior"; +static const char glyph_ntilde[] = "ntilde"; +static const char glyph_nu[] = "nu"; +static const char glyph_nuhiragana[] = "nuhiragana"; +static const char glyph_nukatakana[] = "nukatakana"; +static const char glyph_nukatakanahalfwidth[] = "nukatakanahalfwidth"; +static const char glyph_nuktabengali[] = "nuktabengali"; +static const char glyph_nuktadeva[] = "nuktadeva"; +static const char glyph_nuktagujarati[] = "nuktagujarati"; +static const char glyph_nuktagurmukhi[] = "nuktagurmukhi"; +static const char glyph_numbersign[] = "numbersign"; +static const char glyph_numbersignmonospace[] = "numbersignmonospace"; +static const char glyph_numbersignsmall[] = "numbersignsmall"; +static const char glyph_numeralsigngreek[] = "numeralsigngreek"; +static const char glyph_numeralsignlowergreek[] = "numeralsignlowergreek"; +static const char glyph_numero[] = "numero"; +static const char glyph_nun[] = "nun"; +static const char glyph_nundagesh[] = "nundagesh"; +static const char glyph_nundageshhebrew[] = "nundageshhebrew"; +static const char glyph_nunhebrew[] = "nunhebrew"; +static const char glyph_nvsquare[] = "nvsquare"; +static const char glyph_nwsquare[] = "nwsquare"; +static const char glyph_nyabengali[] = "nyabengali"; +static const char glyph_nyadeva[] = "nyadeva"; +static const char glyph_nyagujarati[] = "nyagujarati"; +static const char glyph_nyagurmukhi[] = "nyagurmukhi"; +static const char glyph_o[] = "o"; +static const char glyph_oacute[] = "oacute"; +static const char glyph_oangthai[] = "oangthai"; +static const char glyph_obarred[] = "obarred"; +static const char glyph_obarredcyrillic[] = "obarredcyrillic"; +static const char glyph_obarreddieresiscyrillic[] = "obarreddieresiscyrillic"; +static const char glyph_obengali[] = "obengali"; +static const char glyph_obopomofo[] = "obopomofo"; +static const char glyph_obreve[] = "obreve"; +static const char glyph_ocandradeva[] = "ocandradeva"; +static const char glyph_ocandragujarati[] = "ocandragujarati"; +static const char glyph_ocandravowelsigndeva[] = "ocandravowelsigndeva"; +static const char glyph_ocandravowelsigngujarati[] = +"ocandravowelsigngujarati"; +static const char glyph_ocaron[] = "ocaron"; +static const char glyph_ocircle[] = "ocircle"; +static const char glyph_ocircumflex[] = "ocircumflex"; +static const char glyph_ocircumflexacute[] = "ocircumflexacute"; +static const char glyph_ocircumflexdotbelow[] = "ocircumflexdotbelow"; +static const char glyph_ocircumflexgrave[] = "ocircumflexgrave"; +static const char glyph_ocircumflexhookabove[] = "ocircumflexhookabove"; +static const char glyph_ocircumflextilde[] = "ocircumflextilde"; +static const char glyph_ocyrillic[] = "ocyrillic"; +static const char glyph_odblacute[] = "odblacute"; +static const char glyph_odblgrave[] = "odblgrave"; +static const char glyph_odeva[] = "odeva"; +static const char glyph_odieresis[] = "odieresis"; +static const char glyph_odieresiscyrillic[] = "odieresiscyrillic"; +static const char glyph_odotbelow[] = "odotbelow"; +static const char glyph_oe[] = "oe"; +static const char glyph_oekorean[] = "oekorean"; +static const char glyph_ogonek[] = "ogonek"; +static const char glyph_ogonekcmb[] = "ogonekcmb"; +static const char glyph_ograve[] = "ograve"; +static const char glyph_ogujarati[] = "ogujarati"; +static const char glyph_oharmenian[] = "oharmenian"; +static const char glyph_ohiragana[] = "ohiragana"; +static const char glyph_ohookabove[] = "ohookabove"; +static const char glyph_ohorn[] = "ohorn"; +static const char glyph_ohornacute[] = "ohornacute"; +static const char glyph_ohorndotbelow[] = "ohorndotbelow"; +static const char glyph_ohorngrave[] = "ohorngrave"; +static const char glyph_ohornhookabove[] = "ohornhookabove"; +static const char glyph_ohorntilde[] = "ohorntilde"; +static const char glyph_ohungarumlaut[] = "ohungarumlaut"; +static const char glyph_oi[] = "oi"; +static const char glyph_oinvertedbreve[] = "oinvertedbreve"; +static const char glyph_okatakana[] = "okatakana"; +static const char glyph_okatakanahalfwidth[] = "okatakanahalfwidth"; +static const char glyph_okorean[] = "okorean"; +static const char glyph_olehebrew[] = "olehebrew"; +static const char glyph_omacron[] = "omacron"; +static const char glyph_omacronacute[] = "omacronacute"; +static const char glyph_omacrongrave[] = "omacrongrave"; +static const char glyph_omdeva[] = "omdeva"; +static const char glyph_omega[] = "omega"; +static const char glyph_omega1[] = "omega1"; +static const char glyph_omegacyrillic[] = "omegacyrillic"; +static const char glyph_omegalatinclosed[] = "omegalatinclosed"; +static const char glyph_omegaroundcyrillic[] = "omegaroundcyrillic"; +static const char glyph_omegatitlocyrillic[] = "omegatitlocyrillic"; +static const char glyph_omegatonos[] = "omegatonos"; +static const char glyph_omgujarati[] = "omgujarati"; +static const char glyph_omicron[] = "omicron"; +static const char glyph_omicrontonos[] = "omicrontonos"; +static const char glyph_omonospace[] = "omonospace"; +static const char glyph_one[] = "one"; +static const char glyph_onearabic[] = "onearabic"; +static const char glyph_onebengali[] = "onebengali"; +static const char glyph_onecircle[] = "onecircle"; +static const char glyph_onecircleinversesansserif[] = +"onecircleinversesansserif"; +static const char glyph_onedeva[] = "onedeva"; +static const char glyph_onedotenleader[] = "onedotenleader"; +static const char glyph_oneeighth[] = "oneeighth"; +static const char glyph_onefitted[] = "onefitted"; +static const char glyph_onegujarati[] = "onegujarati"; +static const char glyph_onegurmukhi[] = "onegurmukhi"; +static const char glyph_onehackarabic[] = "onehackarabic"; +static const char glyph_onehalf[] = "onehalf"; +static const char glyph_onehangzhou[] = "onehangzhou"; +static const char glyph_oneideographicparen[] = "oneideographicparen"; +static const char glyph_oneinferior[] = "oneinferior"; +static const char glyph_onemonospace[] = "onemonospace"; +static const char glyph_onenumeratorbengali[] = "onenumeratorbengali"; +static const char glyph_oneoldstyle[] = "oneoldstyle"; +static const char glyph_oneparen[] = "oneparen"; +static const char glyph_oneperiod[] = "oneperiod"; +static const char glyph_onepersian[] = "onepersian"; +static const char glyph_onequarter[] = "onequarter"; +static const char glyph_oneroman[] = "oneroman"; +static const char glyph_onesuperior[] = "onesuperior"; +static const char glyph_onethai[] = "onethai"; +static const char glyph_onethird[] = "onethird"; +static const char glyph_oogonek[] = "oogonek"; +static const char glyph_oogonekmacron[] = "oogonekmacron"; +static const char glyph_oogurmukhi[] = "oogurmukhi"; +static const char glyph_oomatragurmukhi[] = "oomatragurmukhi"; +static const char glyph_oopen[] = "oopen"; +static const char glyph_oparen[] = "oparen"; +static const char glyph_openbullet[] = "openbullet"; +static const char glyph_option[] = "option"; +static const char glyph_ordfeminine[] = "ordfeminine"; +static const char glyph_ordmasculine[] = "ordmasculine"; +static const char glyph_orthogonal[] = "orthogonal"; +static const char glyph_oshortdeva[] = "oshortdeva"; +static const char glyph_oshortvowelsigndeva[] = "oshortvowelsigndeva"; +static const char glyph_oslash[] = "oslash"; +static const char glyph_oslashacute[] = "oslashacute"; +static const char glyph_osmallhiragana[] = "osmallhiragana"; +static const char glyph_osmallkatakana[] = "osmallkatakana"; +static const char glyph_osmallkatakanahalfwidth[] = "osmallkatakanahalfwidth"; +static const char glyph_ostrokeacute[] = "ostrokeacute"; +static const char glyph_osuperior[] = "osuperior"; +static const char glyph_otcyrillic[] = "otcyrillic"; +static const char glyph_otilde[] = "otilde"; +static const char glyph_otildeacute[] = "otildeacute"; +static const char glyph_otildedieresis[] = "otildedieresis"; +static const char glyph_oubopomofo[] = "oubopomofo"; +static const char glyph_overline[] = "overline"; +static const char glyph_overlinecenterline[] = "overlinecenterline"; +static const char glyph_overlinecmb[] = "overlinecmb"; +static const char glyph_overlinedashed[] = "overlinedashed"; +static const char glyph_overlinedblwavy[] = "overlinedblwavy"; +static const char glyph_overlinewavy[] = "overlinewavy"; +static const char glyph_overscore[] = "overscore"; +static const char glyph_ovowelsignbengali[] = "ovowelsignbengali"; +static const char glyph_ovowelsigndeva[] = "ovowelsigndeva"; +static const char glyph_ovowelsigngujarati[] = "ovowelsigngujarati"; +static const char glyph_p[] = "p"; +static const char glyph_paampssquare[] = "paampssquare"; +static const char glyph_paasentosquare[] = "paasentosquare"; +static const char glyph_pabengali[] = "pabengali"; +static const char glyph_pacute[] = "pacute"; +static const char glyph_padeva[] = "padeva"; +static const char glyph_pagedown[] = "pagedown"; +static const char glyph_pageup[] = "pageup"; +static const char glyph_pagujarati[] = "pagujarati"; +static const char glyph_pagurmukhi[] = "pagurmukhi"; +static const char glyph_pahiragana[] = "pahiragana"; +static const char glyph_paiyannoithai[] = "paiyannoithai"; +static const char glyph_pakatakana[] = "pakatakana"; +static const char glyph_palatalizationcyrilliccmb[] = +"palatalizationcyrilliccmb"; +static const char glyph_palochkacyrillic[] = "palochkacyrillic"; +static const char glyph_pansioskorean[] = "pansioskorean"; +static const char glyph_paragraph[] = "paragraph"; +static const char glyph_parallel[] = "parallel"; +static const char glyph_parenleft[] = "parenleft"; +static const char glyph_parenleftaltonearabic[] = "parenleftaltonearabic"; +static const char glyph_parenleftbt[] = "parenleftbt"; +static const char glyph_parenleftex[] = "parenleftex"; +static const char glyph_parenleftinferior[] = "parenleftinferior"; +static const char glyph_parenleftmonospace[] = "parenleftmonospace"; +static const char glyph_parenleftsmall[] = "parenleftsmall"; +static const char glyph_parenleftsuperior[] = "parenleftsuperior"; +static const char glyph_parenlefttp[] = "parenlefttp"; +static const char glyph_parenleftvertical[] = "parenleftvertical"; +static const char glyph_parenright[] = "parenright"; +static const char glyph_parenrightaltonearabic[] = "parenrightaltonearabic"; +static const char glyph_parenrightbt[] = "parenrightbt"; +static const char glyph_parenrightex[] = "parenrightex"; +static const char glyph_parenrightinferior[] = "parenrightinferior"; +static const char glyph_parenrightmonospace[] = "parenrightmonospace"; +static const char glyph_parenrightsmall[] = "parenrightsmall"; +static const char glyph_parenrightsuperior[] = "parenrightsuperior"; +static const char glyph_parenrighttp[] = "parenrighttp"; +static const char glyph_parenrightvertical[] = "parenrightvertical"; +static const char glyph_partialdiff[] = "partialdiff"; +static const char glyph_paseqhebrew[] = "paseqhebrew"; +static const char glyph_pashtahebrew[] = "pashtahebrew"; +static const char glyph_pasquare[] = "pasquare"; +static const char glyph_patah[] = "patah"; +static const char glyph_patah11[] = "patah11"; +static const char glyph_patah1d[] = "patah1d"; +static const char glyph_patah2a[] = "patah2a"; +static const char glyph_patahhebrew[] = "patahhebrew"; +static const char glyph_patahnarrowhebrew[] = "patahnarrowhebrew"; +static const char glyph_patahquarterhebrew[] = "patahquarterhebrew"; +static const char glyph_patahwidehebrew[] = "patahwidehebrew"; +static const char glyph_pazerhebrew[] = "pazerhebrew"; +static const char glyph_pbopomofo[] = "pbopomofo"; +static const char glyph_pcircle[] = "pcircle"; +static const char glyph_pdotaccent[] = "pdotaccent"; +static const char glyph_pe[] = "pe"; +static const char glyph_pecyrillic[] = "pecyrillic"; +static const char glyph_pedagesh[] = "pedagesh"; +static const char glyph_pedageshhebrew[] = "pedageshhebrew"; +static const char glyph_peezisquare[] = "peezisquare"; +static const char glyph_pefinaldageshhebrew[] = "pefinaldageshhebrew"; +static const char glyph_peharabic[] = "peharabic"; +static const char glyph_peharmenian[] = "peharmenian"; +static const char glyph_pehebrew[] = "pehebrew"; +static const char glyph_pehfinalarabic[] = "pehfinalarabic"; +static const char glyph_pehinitialarabic[] = "pehinitialarabic"; +static const char glyph_pehiragana[] = "pehiragana"; +static const char glyph_pehmedialarabic[] = "pehmedialarabic"; +static const char glyph_pekatakana[] = "pekatakana"; +static const char glyph_pemiddlehookcyrillic[] = "pemiddlehookcyrillic"; +static const char glyph_perafehebrew[] = "perafehebrew"; +static const char glyph_percent[] = "percent"; +static const char glyph_percentarabic[] = "percentarabic"; +static const char glyph_percentmonospace[] = "percentmonospace"; +static const char glyph_percentsmall[] = "percentsmall"; +static const char glyph_period[] = "period"; +static const char glyph_periodarmenian[] = "periodarmenian"; +static const char glyph_periodcentered[] = "periodcentered"; +static const char glyph_periodhalfwidth[] = "periodhalfwidth"; +static const char glyph_periodinferior[] = "periodinferior"; +static const char glyph_periodmonospace[] = "periodmonospace"; +static const char glyph_periodsmall[] = "periodsmall"; +static const char glyph_periodsuperior[] = "periodsuperior"; +static const char glyph_perispomenigreekcmb[] = "perispomenigreekcmb"; +static const char glyph_perpendicular[] = "perpendicular"; +static const char glyph_perthousand[] = "perthousand"; +static const char glyph_peseta[] = "peseta"; +static const char glyph_pfsquare[] = "pfsquare"; +static const char glyph_phabengali[] = "phabengali"; +static const char glyph_phadeva[] = "phadeva"; +static const char glyph_phagujarati[] = "phagujarati"; +static const char glyph_phagurmukhi[] = "phagurmukhi"; +static const char glyph_phi[] = "phi"; +static const char glyph_phi1[] = "phi1"; +static const char glyph_phieuphacirclekorean[] = "phieuphacirclekorean"; +static const char glyph_phieuphaparenkorean[] = "phieuphaparenkorean"; +static const char glyph_phieuphcirclekorean[] = "phieuphcirclekorean"; +static const char glyph_phieuphkorean[] = "phieuphkorean"; +static const char glyph_phieuphparenkorean[] = "phieuphparenkorean"; +static const char glyph_philatin[] = "philatin"; +static const char glyph_phinthuthai[] = "phinthuthai"; +static const char glyph_phisymbolgreek[] = "phisymbolgreek"; +static const char glyph_phook[] = "phook"; +static const char glyph_phophanthai[] = "phophanthai"; +static const char glyph_phophungthai[] = "phophungthai"; +static const char glyph_phosamphaothai[] = "phosamphaothai"; +static const char glyph_pi[] = "pi"; +static const char glyph_pieupacirclekorean[] = "pieupacirclekorean"; +static const char glyph_pieupaparenkorean[] = "pieupaparenkorean"; +static const char glyph_pieupcieuckorean[] = "pieupcieuckorean"; +static const char glyph_pieupcirclekorean[] = "pieupcirclekorean"; +static const char glyph_pieupkiyeokkorean[] = "pieupkiyeokkorean"; +static const char glyph_pieupkorean[] = "pieupkorean"; +static const char glyph_pieupparenkorean[] = "pieupparenkorean"; +static const char glyph_pieupsioskiyeokkorean[] = "pieupsioskiyeokkorean"; +static const char glyph_pieupsioskorean[] = "pieupsioskorean"; +static const char glyph_pieupsiostikeutkorean[] = "pieupsiostikeutkorean"; +static const char glyph_pieupthieuthkorean[] = "pieupthieuthkorean"; +static const char glyph_pieuptikeutkorean[] = "pieuptikeutkorean"; +static const char glyph_pihiragana[] = "pihiragana"; +static const char glyph_pikatakana[] = "pikatakana"; +static const char glyph_pisymbolgreek[] = "pisymbolgreek"; +static const char glyph_piwrarmenian[] = "piwrarmenian"; +static const char glyph_plus[] = "plus"; +static const char glyph_plusbelowcmb[] = "plusbelowcmb"; +static const char glyph_pluscircle[] = "pluscircle"; +static const char glyph_plusminus[] = "plusminus"; +static const char glyph_plusmod[] = "plusmod"; +static const char glyph_plusmonospace[] = "plusmonospace"; +static const char glyph_plussmall[] = "plussmall"; +static const char glyph_plussuperior[] = "plussuperior"; +static const char glyph_pmonospace[] = "pmonospace"; +static const char glyph_pmsquare[] = "pmsquare"; +static const char glyph_pohiragana[] = "pohiragana"; +static const char glyph_pointingindexdownwhite[] = "pointingindexdownwhite"; +static const char glyph_pointingindexleftwhite[] = "pointingindexleftwhite"; +static const char glyph_pointingindexrightwhite[] = "pointingindexrightwhite"; +static const char glyph_pointingindexupwhite[] = "pointingindexupwhite"; +static const char glyph_pokatakana[] = "pokatakana"; +static const char glyph_poplathai[] = "poplathai"; +static const char glyph_postalmark[] = "postalmark"; +static const char glyph_postalmarkface[] = "postalmarkface"; +static const char glyph_pparen[] = "pparen"; +static const char glyph_precedes[] = "precedes"; +static const char glyph_prescription[] = "prescription"; +static const char glyph_primemod[] = "primemod"; +static const char glyph_primereversed[] = "primereversed"; +static const char glyph_product[] = "product"; +static const char glyph_projective[] = "projective"; +static const char glyph_prolongedkana[] = "prolongedkana"; +static const char glyph_propellor[] = "propellor"; +static const char glyph_propersubset[] = "propersubset"; +static const char glyph_propersuperset[] = "propersuperset"; +static const char glyph_proportion[] = "proportion"; +static const char glyph_proportional[] = "proportional"; +static const char glyph_psi[] = "psi"; +static const char glyph_psicyrillic[] = "psicyrillic"; +static const char glyph_psilipneumatacyrilliccmb[] = +"psilipneumatacyrilliccmb"; +static const char glyph_pssquare[] = "pssquare"; +static const char glyph_puhiragana[] = "puhiragana"; +static const char glyph_pukatakana[] = "pukatakana"; +static const char glyph_pvsquare[] = "pvsquare"; +static const char glyph_pwsquare[] = "pwsquare"; +static const char glyph_q[] = "q"; +static const char glyph_qadeva[] = "qadeva"; +static const char glyph_qadmahebrew[] = "qadmahebrew"; +static const char glyph_qafarabic[] = "qafarabic"; +static const char glyph_qaffinalarabic[] = "qaffinalarabic"; +static const char glyph_qafinitialarabic[] = "qafinitialarabic"; +static const char glyph_qafmedialarabic[] = "qafmedialarabic"; +static const char glyph_qamats[] = "qamats"; +static const char glyph_qamats10[] = "qamats10"; +static const char glyph_qamats1a[] = "qamats1a"; +static const char glyph_qamats1c[] = "qamats1c"; +static const char glyph_qamats27[] = "qamats27"; +static const char glyph_qamats29[] = "qamats29"; +static const char glyph_qamats33[] = "qamats33"; +static const char glyph_qamatsde[] = "qamatsde"; +static const char glyph_qamatshebrew[] = "qamatshebrew"; +static const char glyph_qamatsnarrowhebrew[] = "qamatsnarrowhebrew"; +static const char glyph_qamatsqatanhebrew[] = "qamatsqatanhebrew"; +static const char glyph_qamatsqatannarrowhebrew[] = "qamatsqatannarrowhebrew"; +static const char glyph_qamatsqatanquarterhebrew[] = +"qamatsqatanquarterhebrew"; +static const char glyph_qamatsqatanwidehebrew[] = "qamatsqatanwidehebrew"; +static const char glyph_qamatsquarterhebrew[] = "qamatsquarterhebrew"; +static const char glyph_qamatswidehebrew[] = "qamatswidehebrew"; +static const char glyph_qarneyparahebrew[] = "qarneyparahebrew"; +static const char glyph_qbopomofo[] = "qbopomofo"; +static const char glyph_qcircle[] = "qcircle"; +static const char glyph_qhook[] = "qhook"; +static const char glyph_qmonospace[] = "qmonospace"; +static const char glyph_qof[] = "qof"; +static const char glyph_qofdagesh[] = "qofdagesh"; +static const char glyph_qofdageshhebrew[] = "qofdageshhebrew"; +static const char glyph_qofhatafpatah[] = "qofhatafpatah"; +static const char glyph_qofhatafpatahhebrew[] = "qofhatafpatahhebrew"; +static const char glyph_qofhatafsegol[] = "qofhatafsegol"; +static const char glyph_qofhatafsegolhebrew[] = "qofhatafsegolhebrew"; +static const char glyph_qofhebrew[] = "qofhebrew"; +static const char glyph_qofhiriq[] = "qofhiriq"; +static const char glyph_qofhiriqhebrew[] = "qofhiriqhebrew"; +static const char glyph_qofholam[] = "qofholam"; +static const char glyph_qofholamhebrew[] = "qofholamhebrew"; +static const char glyph_qofpatah[] = "qofpatah"; +static const char glyph_qofpatahhebrew[] = "qofpatahhebrew"; +static const char glyph_qofqamats[] = "qofqamats"; +static const char glyph_qofqamatshebrew[] = "qofqamatshebrew"; +static const char glyph_qofqubuts[] = "qofqubuts"; +static const char glyph_qofqubutshebrew[] = "qofqubutshebrew"; +static const char glyph_qofsegol[] = "qofsegol"; +static const char glyph_qofsegolhebrew[] = "qofsegolhebrew"; +static const char glyph_qofsheva[] = "qofsheva"; +static const char glyph_qofshevahebrew[] = "qofshevahebrew"; +static const char glyph_qoftsere[] = "qoftsere"; +static const char glyph_qoftserehebrew[] = "qoftserehebrew"; +static const char glyph_qparen[] = "qparen"; +static const char glyph_quarternote[] = "quarternote"; +static const char glyph_qubuts[] = "qubuts"; +static const char glyph_qubuts18[] = "qubuts18"; +static const char glyph_qubuts25[] = "qubuts25"; +static const char glyph_qubuts31[] = "qubuts31"; +static const char glyph_qubutshebrew[] = "qubutshebrew"; +static const char glyph_qubutsnarrowhebrew[] = "qubutsnarrowhebrew"; +static const char glyph_qubutsquarterhebrew[] = "qubutsquarterhebrew"; +static const char glyph_qubutswidehebrew[] = "qubutswidehebrew"; +static const char glyph_question[] = "question"; +static const char glyph_questionarabic[] = "questionarabic"; +static const char glyph_questionarmenian[] = "questionarmenian"; +static const char glyph_questiondown[] = "questiondown"; +static const char glyph_questiondownsmall[] = "questiondownsmall"; +static const char glyph_questiongreek[] = "questiongreek"; +static const char glyph_questionmonospace[] = "questionmonospace"; +static const char glyph_questionsmall[] = "questionsmall"; +static const char glyph_quotedbl[] = "quotedbl"; +static const char glyph_quotedblbase[] = "quotedblbase"; +static const char glyph_quotedblleft[] = "quotedblleft"; +static const char glyph_quotedblmonospace[] = "quotedblmonospace"; +static const char glyph_quotedblprime[] = "quotedblprime"; +static const char glyph_quotedblprimereversed[] = "quotedblprimereversed"; +static const char glyph_quotedblright[] = "quotedblright"; +static const char glyph_quoteleft[] = "quoteleft"; +static const char glyph_quoteleftreversed[] = "quoteleftreversed"; +static const char glyph_quotereversed[] = "quotereversed"; +static const char glyph_quoteright[] = "quoteright"; +static const char glyph_quoterightn[] = "quoterightn"; +static const char glyph_quotesinglbase[] = "quotesinglbase"; +static const char glyph_quotesingle[] = "quotesingle"; +static const char glyph_quotesinglemonospace[] = "quotesinglemonospace"; +static const char glyph_r[] = "r"; +static const char glyph_raarmenian[] = "raarmenian"; +static const char glyph_rabengali[] = "rabengali"; +static const char glyph_racute[] = "racute"; +static const char glyph_radeva[] = "radeva"; +static const char glyph_radical[] = "radical"; +static const char glyph_radicalex[] = "radicalex"; +static const char glyph_radoverssquare[] = "radoverssquare"; +static const char glyph_radoverssquaredsquare[] = "radoverssquaredsquare"; +static const char glyph_radsquare[] = "radsquare"; +static const char glyph_rafe[] = "rafe"; +static const char glyph_rafehebrew[] = "rafehebrew"; +static const char glyph_ragujarati[] = "ragujarati"; +static const char glyph_ragurmukhi[] = "ragurmukhi"; +static const char glyph_rahiragana[] = "rahiragana"; +static const char glyph_rakatakana[] = "rakatakana"; +static const char glyph_rakatakanahalfwidth[] = "rakatakanahalfwidth"; +static const char glyph_ralowerdiagonalbengali[] = "ralowerdiagonalbengali"; +static const char glyph_ramiddlediagonalbengali[] = "ramiddlediagonalbengali"; +static const char glyph_ramshorn[] = "ramshorn"; +static const char glyph_ratio[] = "ratio"; +static const char glyph_rbopomofo[] = "rbopomofo"; +static const char glyph_rcaron[] = "rcaron"; +static const char glyph_rcedilla[] = "rcedilla"; +static const char glyph_rcircle[] = "rcircle"; +static const char glyph_rcommaaccent[] = "rcommaaccent"; +static const char glyph_rdblgrave[] = "rdblgrave"; +static const char glyph_rdotaccent[] = "rdotaccent"; +static const char glyph_rdotbelow[] = "rdotbelow"; +static const char glyph_rdotbelowmacron[] = "rdotbelowmacron"; +static const char glyph_referencemark[] = "referencemark"; +static const char glyph_reflexsubset[] = "reflexsubset"; +static const char glyph_reflexsuperset[] = "reflexsuperset"; +static const char glyph_registered[] = "registered"; +static const char glyph_registersans[] = "registersans"; +static const char glyph_registerserif[] = "registerserif"; +static const char glyph_reharabic[] = "reharabic"; +static const char glyph_reharmenian[] = "reharmenian"; +static const char glyph_rehfinalarabic[] = "rehfinalarabic"; +static const char glyph_rehiragana[] = "rehiragana"; +static const char glyph_rehyehaleflamarabic[] = "rehyehaleflamarabic"; +static const char glyph_rekatakana[] = "rekatakana"; +static const char glyph_rekatakanahalfwidth[] = "rekatakanahalfwidth"; +static const char glyph_resh[] = "resh"; +static const char glyph_reshdageshhebrew[] = "reshdageshhebrew"; +static const char glyph_reshhatafpatah[] = "reshhatafpatah"; +static const char glyph_reshhatafpatahhebrew[] = "reshhatafpatahhebrew"; +static const char glyph_reshhatafsegol[] = "reshhatafsegol"; +static const char glyph_reshhatafsegolhebrew[] = "reshhatafsegolhebrew"; +static const char glyph_reshhebrew[] = "reshhebrew"; +static const char glyph_reshhiriq[] = "reshhiriq"; +static const char glyph_reshhiriqhebrew[] = "reshhiriqhebrew"; +static const char glyph_reshholam[] = "reshholam"; +static const char glyph_reshholamhebrew[] = "reshholamhebrew"; +static const char glyph_reshpatah[] = "reshpatah"; +static const char glyph_reshpatahhebrew[] = "reshpatahhebrew"; +static const char glyph_reshqamats[] = "reshqamats"; +static const char glyph_reshqamatshebrew[] = "reshqamatshebrew"; +static const char glyph_reshqubuts[] = "reshqubuts"; +static const char glyph_reshqubutshebrew[] = "reshqubutshebrew"; +static const char glyph_reshsegol[] = "reshsegol"; +static const char glyph_reshsegolhebrew[] = "reshsegolhebrew"; +static const char glyph_reshsheva[] = "reshsheva"; +static const char glyph_reshshevahebrew[] = "reshshevahebrew"; +static const char glyph_reshtsere[] = "reshtsere"; +static const char glyph_reshtserehebrew[] = "reshtserehebrew"; +static const char glyph_reversedtilde[] = "reversedtilde"; +static const char glyph_reviahebrew[] = "reviahebrew"; +static const char glyph_reviamugrashhebrew[] = "reviamugrashhebrew"; +static const char glyph_revlogicalnot[] = "revlogicalnot"; +static const char glyph_rfishhook[] = "rfishhook"; +static const char glyph_rfishhookreversed[] = "rfishhookreversed"; +static const char glyph_rhabengali[] = "rhabengali"; +static const char glyph_rhadeva[] = "rhadeva"; +static const char glyph_rho[] = "rho"; +static const char glyph_rhook[] = "rhook"; +static const char glyph_rhookturned[] = "rhookturned"; +static const char glyph_rhookturnedsuperior[] = "rhookturnedsuperior"; +static const char glyph_rhosymbolgreek[] = "rhosymbolgreek"; +static const char glyph_rhotichookmod[] = "rhotichookmod"; +static const char glyph_rieulacirclekorean[] = "rieulacirclekorean"; +static const char glyph_rieulaparenkorean[] = "rieulaparenkorean"; +static const char glyph_rieulcirclekorean[] = "rieulcirclekorean"; +static const char glyph_rieulhieuhkorean[] = "rieulhieuhkorean"; +static const char glyph_rieulkiyeokkorean[] = "rieulkiyeokkorean"; +static const char glyph_rieulkiyeoksioskorean[] = "rieulkiyeoksioskorean"; +static const char glyph_rieulkorean[] = "rieulkorean"; +static const char glyph_rieulmieumkorean[] = "rieulmieumkorean"; +static const char glyph_rieulpansioskorean[] = "rieulpansioskorean"; +static const char glyph_rieulparenkorean[] = "rieulparenkorean"; +static const char glyph_rieulphieuphkorean[] = "rieulphieuphkorean"; +static const char glyph_rieulpieupkorean[] = "rieulpieupkorean"; +static const char glyph_rieulpieupsioskorean[] = "rieulpieupsioskorean"; +static const char glyph_rieulsioskorean[] = "rieulsioskorean"; +static const char glyph_rieulthieuthkorean[] = "rieulthieuthkorean"; +static const char glyph_rieultikeutkorean[] = "rieultikeutkorean"; +static const char glyph_rieulyeorinhieuhkorean[] = "rieulyeorinhieuhkorean"; +static const char glyph_rightangle[] = "rightangle"; +static const char glyph_righttackbelowcmb[] = "righttackbelowcmb"; +static const char glyph_righttriangle[] = "righttriangle"; +static const char glyph_rihiragana[] = "rihiragana"; +static const char glyph_rikatakana[] = "rikatakana"; +static const char glyph_rikatakanahalfwidth[] = "rikatakanahalfwidth"; +static const char glyph_ring[] = "ring"; +static const char glyph_ringbelowcmb[] = "ringbelowcmb"; +static const char glyph_ringcmb[] = "ringcmb"; +static const char glyph_ringhalfleft[] = "ringhalfleft"; +static const char glyph_ringhalfleftarmenian[] = "ringhalfleftarmenian"; +static const char glyph_ringhalfleftbelowcmb[] = "ringhalfleftbelowcmb"; +static const char glyph_ringhalfleftcentered[] = "ringhalfleftcentered"; +static const char glyph_ringhalfright[] = "ringhalfright"; +static const char glyph_ringhalfrightbelowcmb[] = "ringhalfrightbelowcmb"; +static const char glyph_ringhalfrightcentered[] = "ringhalfrightcentered"; +static const char glyph_rinvertedbreve[] = "rinvertedbreve"; +static const char glyph_rittorusquare[] = "rittorusquare"; +static const char glyph_rlinebelow[] = "rlinebelow"; +static const char glyph_rlongleg[] = "rlongleg"; +static const char glyph_rlonglegturned[] = "rlonglegturned"; +static const char glyph_rmonospace[] = "rmonospace"; +static const char glyph_rohiragana[] = "rohiragana"; +static const char glyph_rokatakana[] = "rokatakana"; +static const char glyph_rokatakanahalfwidth[] = "rokatakanahalfwidth"; +static const char glyph_roruathai[] = "roruathai"; +static const char glyph_rparen[] = "rparen"; +static const char glyph_rrabengali[] = "rrabengali"; +static const char glyph_rradeva[] = "rradeva"; +static const char glyph_rragurmukhi[] = "rragurmukhi"; +static const char glyph_rreharabic[] = "rreharabic"; +static const char glyph_rrehfinalarabic[] = "rrehfinalarabic"; +static const char glyph_rrvocalicbengali[] = "rrvocalicbengali"; +static const char glyph_rrvocalicdeva[] = "rrvocalicdeva"; +static const char glyph_rrvocalicgujarati[] = "rrvocalicgujarati"; +static const char glyph_rrvocalicvowelsignbengali[] = +"rrvocalicvowelsignbengali"; +static const char glyph_rrvocalicvowelsigndeva[] = "rrvocalicvowelsigndeva"; +static const char glyph_rrvocalicvowelsigngujarati[] = +"rrvocalicvowelsigngujarati"; +static const char glyph_rsuperior[] = "rsuperior"; +static const char glyph_rtblock[] = "rtblock"; +static const char glyph_rturned[] = "rturned"; +static const char glyph_rturnedsuperior[] = "rturnedsuperior"; +static const char glyph_ruhiragana[] = "ruhiragana"; +static const char glyph_rukatakana[] = "rukatakana"; +static const char glyph_rukatakanahalfwidth[] = "rukatakanahalfwidth"; +static const char glyph_rupeemarkbengali[] = "rupeemarkbengali"; +static const char glyph_rupeesignbengali[] = "rupeesignbengali"; +static const char glyph_rupiah[] = "rupiah"; +static const char glyph_ruthai[] = "ruthai"; +static const char glyph_rvocalicbengali[] = "rvocalicbengali"; +static const char glyph_rvocalicdeva[] = "rvocalicdeva"; +static const char glyph_rvocalicgujarati[] = "rvocalicgujarati"; +static const char glyph_rvocalicvowelsignbengali[] = +"rvocalicvowelsignbengali"; +static const char glyph_rvocalicvowelsigndeva[] = "rvocalicvowelsigndeva"; +static const char glyph_rvocalicvowelsigngujarati[] = +"rvocalicvowelsigngujarati"; +static const char glyph_s[] = "s"; +static const char glyph_sabengali[] = "sabengali"; +static const char glyph_sacute[] = "sacute"; +static const char glyph_sacutedotaccent[] = "sacutedotaccent"; +static const char glyph_sadarabic[] = "sadarabic"; +static const char glyph_sadeva[] = "sadeva"; +static const char glyph_sadfinalarabic[] = "sadfinalarabic"; +static const char glyph_sadinitialarabic[] = "sadinitialarabic"; +static const char glyph_sadmedialarabic[] = "sadmedialarabic"; +static const char glyph_sagujarati[] = "sagujarati"; +static const char glyph_sagurmukhi[] = "sagurmukhi"; +static const char glyph_sahiragana[] = "sahiragana"; +static const char glyph_sakatakana[] = "sakatakana"; +static const char glyph_sakatakanahalfwidth[] = "sakatakanahalfwidth"; +static const char glyph_sallallahoualayhewasallamarabic[] = +"sallallahoualayhewasallamarabic"; +static const char glyph_samekh[] = "samekh"; +static const char glyph_samekhdagesh[] = "samekhdagesh"; +static const char glyph_samekhdageshhebrew[] = "samekhdageshhebrew"; +static const char glyph_samekhhebrew[] = "samekhhebrew"; +static const char glyph_saraaathai[] = "saraaathai"; +static const char glyph_saraaethai[] = "saraaethai"; +static const char glyph_saraaimaimalaithai[] = "saraaimaimalaithai"; +static const char glyph_saraaimaimuanthai[] = "saraaimaimuanthai"; +static const char glyph_saraamthai[] = "saraamthai"; +static const char glyph_saraathai[] = "saraathai"; +static const char glyph_saraethai[] = "saraethai"; +static const char glyph_saraiileftthai[] = "saraiileftthai"; +static const char glyph_saraiithai[] = "saraiithai"; +static const char glyph_saraileftthai[] = "saraileftthai"; +static const char glyph_saraithai[] = "saraithai"; +static const char glyph_saraothai[] = "saraothai"; +static const char glyph_saraueeleftthai[] = "saraueeleftthai"; +static const char glyph_saraueethai[] = "saraueethai"; +static const char glyph_saraueleftthai[] = "saraueleftthai"; +static const char glyph_sarauethai[] = "sarauethai"; +static const char glyph_sarauthai[] = "sarauthai"; +static const char glyph_sarauuthai[] = "sarauuthai"; +static const char glyph_sbopomofo[] = "sbopomofo"; +static const char glyph_scaron[] = "scaron"; +static const char glyph_scarondotaccent[] = "scarondotaccent"; +static const char glyph_scedilla[] = "scedilla"; +static const char glyph_schwa[] = "schwa"; +static const char glyph_schwacyrillic[] = "schwacyrillic"; +static const char glyph_schwadieresiscyrillic[] = "schwadieresiscyrillic"; +static const char glyph_schwahook[] = "schwahook"; +static const char glyph_scircle[] = "scircle"; +static const char glyph_scircumflex[] = "scircumflex"; +static const char glyph_scommaaccent[] = "scommaaccent"; +static const char glyph_sdotaccent[] = "sdotaccent"; +static const char glyph_sdotbelow[] = "sdotbelow"; +static const char glyph_sdotbelowdotaccent[] = "sdotbelowdotaccent"; +static const char glyph_seagullbelowcmb[] = "seagullbelowcmb"; +static const char glyph_second[] = "second"; +static const char glyph_secondtonechinese[] = "secondtonechinese"; +static const char glyph_section[] = "section"; +static const char glyph_seenarabic[] = "seenarabic"; +static const char glyph_seenfinalarabic[] = "seenfinalarabic"; +static const char glyph_seeninitialarabic[] = "seeninitialarabic"; +static const char glyph_seenmedialarabic[] = "seenmedialarabic"; +static const char glyph_segol[] = "segol"; +static const char glyph_segol13[] = "segol13"; +static const char glyph_segol1f[] = "segol1f"; +static const char glyph_segol2c[] = "segol2c"; +static const char glyph_segolhebrew[] = "segolhebrew"; +static const char glyph_segolnarrowhebrew[] = "segolnarrowhebrew"; +static const char glyph_segolquarterhebrew[] = "segolquarterhebrew"; +static const char glyph_segoltahebrew[] = "segoltahebrew"; +static const char glyph_segolwidehebrew[] = "segolwidehebrew"; +static const char glyph_seharmenian[] = "seharmenian"; +static const char glyph_sehiragana[] = "sehiragana"; +static const char glyph_sekatakana[] = "sekatakana"; +static const char glyph_sekatakanahalfwidth[] = "sekatakanahalfwidth"; +static const char glyph_semicolon[] = "semicolon"; +static const char glyph_semicolonarabic[] = "semicolonarabic"; +static const char glyph_semicolonmonospace[] = "semicolonmonospace"; +static const char glyph_semicolonsmall[] = "semicolonsmall"; +static const char glyph_semivoicedmarkkana[] = "semivoicedmarkkana"; +static const char glyph_semivoicedmarkkanahalfwidth[] = +"semivoicedmarkkanahalfwidth"; +static const char glyph_sentisquare[] = "sentisquare"; +static const char glyph_sentosquare[] = "sentosquare"; +static const char glyph_seven[] = "seven"; +static const char glyph_sevenarabic[] = "sevenarabic"; +static const char glyph_sevenbengali[] = "sevenbengali"; +static const char glyph_sevencircle[] = "sevencircle"; +static const char glyph_sevencircleinversesansserif[] = +"sevencircleinversesansserif"; +static const char glyph_sevendeva[] = "sevendeva"; +static const char glyph_seveneighths[] = "seveneighths"; +static const char glyph_sevengujarati[] = "sevengujarati"; +static const char glyph_sevengurmukhi[] = "sevengurmukhi"; +static const char glyph_sevenhackarabic[] = "sevenhackarabic"; +static const char glyph_sevenhangzhou[] = "sevenhangzhou"; +static const char glyph_sevenideographicparen[] = "sevenideographicparen"; +static const char glyph_seveninferior[] = "seveninferior"; +static const char glyph_sevenmonospace[] = "sevenmonospace"; +static const char glyph_sevenoldstyle[] = "sevenoldstyle"; +static const char glyph_sevenparen[] = "sevenparen"; +static const char glyph_sevenperiod[] = "sevenperiod"; +static const char glyph_sevenpersian[] = "sevenpersian"; +static const char glyph_sevenroman[] = "sevenroman"; +static const char glyph_sevensuperior[] = "sevensuperior"; +static const char glyph_seventeencircle[] = "seventeencircle"; +static const char glyph_seventeenparen[] = "seventeenparen"; +static const char glyph_seventeenperiod[] = "seventeenperiod"; +static const char glyph_seventhai[] = "seventhai"; +static const char glyph_sfthyphen[] = "sfthyphen"; +static const char glyph_shaarmenian[] = "shaarmenian"; +static const char glyph_shabengali[] = "shabengali"; +static const char glyph_shacyrillic[] = "shacyrillic"; +static const char glyph_shaddaarabic[] = "shaddaarabic"; +static const char glyph_shaddadammaarabic[] = "shaddadammaarabic"; +static const char glyph_shaddadammatanarabic[] = "shaddadammatanarabic"; +static const char glyph_shaddafathaarabic[] = "shaddafathaarabic"; +static const char glyph_shaddafathatanarabic[] = "shaddafathatanarabic"; +static const char glyph_shaddakasraarabic[] = "shaddakasraarabic"; +static const char glyph_shaddakasratanarabic[] = "shaddakasratanarabic"; +static const char glyph_shade[] = "shade"; +static const char glyph_shadedark[] = "shadedark"; +static const char glyph_shadelight[] = "shadelight"; +static const char glyph_shademedium[] = "shademedium"; +static const char glyph_shadeva[] = "shadeva"; +static const char glyph_shagujarati[] = "shagujarati"; +static const char glyph_shagurmukhi[] = "shagurmukhi"; +static const char glyph_shalshelethebrew[] = "shalshelethebrew"; +static const char glyph_shbopomofo[] = "shbopomofo"; +static const char glyph_shchacyrillic[] = "shchacyrillic"; +static const char glyph_sheenarabic[] = "sheenarabic"; +static const char glyph_sheenfinalarabic[] = "sheenfinalarabic"; +static const char glyph_sheeninitialarabic[] = "sheeninitialarabic"; +static const char glyph_sheenmedialarabic[] = "sheenmedialarabic"; +static const char glyph_sheicoptic[] = "sheicoptic"; +static const char glyph_sheqel[] = "sheqel"; +static const char glyph_sheqelhebrew[] = "sheqelhebrew"; +static const char glyph_sheva[] = "sheva"; +static const char glyph_sheva115[] = "sheva115"; +static const char glyph_sheva15[] = "sheva15"; +static const char glyph_sheva22[] = "sheva22"; +static const char glyph_sheva2e[] = "sheva2e"; +static const char glyph_shevahebrew[] = "shevahebrew"; +static const char glyph_shevanarrowhebrew[] = "shevanarrowhebrew"; +static const char glyph_shevaquarterhebrew[] = "shevaquarterhebrew"; +static const char glyph_shevawidehebrew[] = "shevawidehebrew"; +static const char glyph_shhacyrillic[] = "shhacyrillic"; +static const char glyph_shimacoptic[] = "shimacoptic"; +static const char glyph_shin[] = "shin"; +static const char glyph_shindagesh[] = "shindagesh"; +static const char glyph_shindageshhebrew[] = "shindageshhebrew"; +static const char glyph_shindageshshindot[] = "shindageshshindot"; +static const char glyph_shindageshshindothebrew[] = "shindageshshindothebrew"; +static const char glyph_shindageshsindot[] = "shindageshsindot"; +static const char glyph_shindageshsindothebrew[] = "shindageshsindothebrew"; +static const char glyph_shindothebrew[] = "shindothebrew"; +static const char glyph_shinhebrew[] = "shinhebrew"; +static const char glyph_shinshindot[] = "shinshindot"; +static const char glyph_shinshindothebrew[] = "shinshindothebrew"; +static const char glyph_shinsindot[] = "shinsindot"; +static const char glyph_shinsindothebrew[] = "shinsindothebrew"; +static const char glyph_shook[] = "shook"; +static const char glyph_sigma[] = "sigma"; +static const char glyph_sigma1[] = "sigma1"; +static const char glyph_sigmafinal[] = "sigmafinal"; +static const char glyph_sigmalunatesymbolgreek[] = "sigmalunatesymbolgreek"; +static const char glyph_sihiragana[] = "sihiragana"; +static const char glyph_sikatakana[] = "sikatakana"; +static const char glyph_sikatakanahalfwidth[] = "sikatakanahalfwidth"; +static const char glyph_siluqhebrew[] = "siluqhebrew"; +static const char glyph_siluqlefthebrew[] = "siluqlefthebrew"; +static const char glyph_similar[] = "similar"; +static const char glyph_sindothebrew[] = "sindothebrew"; +static const char glyph_siosacirclekorean[] = "siosacirclekorean"; +static const char glyph_siosaparenkorean[] = "siosaparenkorean"; +static const char glyph_sioscieuckorean[] = "sioscieuckorean"; +static const char glyph_sioscirclekorean[] = "sioscirclekorean"; +static const char glyph_sioskiyeokkorean[] = "sioskiyeokkorean"; +static const char glyph_sioskorean[] = "sioskorean"; +static const char glyph_siosnieunkorean[] = "siosnieunkorean"; +static const char glyph_siosparenkorean[] = "siosparenkorean"; +static const char glyph_siospieupkorean[] = "siospieupkorean"; +static const char glyph_siostikeutkorean[] = "siostikeutkorean"; +static const char glyph_six[] = "six"; +static const char glyph_sixarabic[] = "sixarabic"; +static const char glyph_sixbengali[] = "sixbengali"; +static const char glyph_sixcircle[] = "sixcircle"; +static const char glyph_sixcircleinversesansserif[] = +"sixcircleinversesansserif"; +static const char glyph_sixdeva[] = "sixdeva"; +static const char glyph_sixgujarati[] = "sixgujarati"; +static const char glyph_sixgurmukhi[] = "sixgurmukhi"; +static const char glyph_sixhackarabic[] = "sixhackarabic"; +static const char glyph_sixhangzhou[] = "sixhangzhou"; +static const char glyph_sixideographicparen[] = "sixideographicparen"; +static const char glyph_sixinferior[] = "sixinferior"; +static const char glyph_sixmonospace[] = "sixmonospace"; +static const char glyph_sixoldstyle[] = "sixoldstyle"; +static const char glyph_sixparen[] = "sixparen"; +static const char glyph_sixperiod[] = "sixperiod"; +static const char glyph_sixpersian[] = "sixpersian"; +static const char glyph_sixroman[] = "sixroman"; +static const char glyph_sixsuperior[] = "sixsuperior"; +static const char glyph_sixteencircle[] = "sixteencircle"; +static const char glyph_sixteencurrencydenominatorbengali[] = +"sixteencurrencydenominatorbengali"; +static const char glyph_sixteenparen[] = "sixteenparen"; +static const char glyph_sixteenperiod[] = "sixteenperiod"; +static const char glyph_sixthai[] = "sixthai"; +static const char glyph_slash[] = "slash"; +static const char glyph_slashmonospace[] = "slashmonospace"; +static const char glyph_slong[] = "slong"; +static const char glyph_slongdotaccent[] = "slongdotaccent"; +static const char glyph_smileface[] = "smileface"; +static const char glyph_smonospace[] = "smonospace"; +static const char glyph_sofpasuqhebrew[] = "sofpasuqhebrew"; +static const char glyph_softhyphen[] = "softhyphen"; +static const char glyph_softsigncyrillic[] = "softsigncyrillic"; +static const char glyph_sohiragana[] = "sohiragana"; +static const char glyph_sokatakana[] = "sokatakana"; +static const char glyph_sokatakanahalfwidth[] = "sokatakanahalfwidth"; +static const char glyph_soliduslongoverlaycmb[] = "soliduslongoverlaycmb"; +static const char glyph_solidusshortoverlaycmb[] = "solidusshortoverlaycmb"; +static const char glyph_sorusithai[] = "sorusithai"; +static const char glyph_sosalathai[] = "sosalathai"; +static const char glyph_sosothai[] = "sosothai"; +static const char glyph_sosuathai[] = "sosuathai"; +static const char glyph_space[] = "space"; +static const char glyph_spacehackarabic[] = "spacehackarabic"; +static const char glyph_spade[] = "spade"; +static const char glyph_spadesuitblack[] = "spadesuitblack"; +static const char glyph_spadesuitwhite[] = "spadesuitwhite"; +static const char glyph_sparen[] = "sparen"; +static const char glyph_squarebelowcmb[] = "squarebelowcmb"; +static const char glyph_squarecc[] = "squarecc"; +static const char glyph_squarecm[] = "squarecm"; +static const char glyph_squarediagonalcrosshatchfill[] = +"squarediagonalcrosshatchfill"; +static const char glyph_squarehorizontalfill[] = "squarehorizontalfill"; +static const char glyph_squarekg[] = "squarekg"; +static const char glyph_squarekm[] = "squarekm"; +static const char glyph_squarekmcapital[] = "squarekmcapital"; +static const char glyph_squareln[] = "squareln"; +static const char glyph_squarelog[] = "squarelog"; +static const char glyph_squaremg[] = "squaremg"; +static const char glyph_squaremil[] = "squaremil"; +static const char glyph_squaremm[] = "squaremm"; +static const char glyph_squaremsquared[] = "squaremsquared"; +static const char glyph_squareorthogonalcrosshatchfill[] = +"squareorthogonalcrosshatchfill"; +static const char glyph_squareupperlefttolowerrightfill[] = +"squareupperlefttolowerrightfill"; +static const char glyph_squareupperrighttolowerleftfill[] = +"squareupperrighttolowerleftfill"; +static const char glyph_squareverticalfill[] = "squareverticalfill"; +static const char glyph_squarewhitewithsmallblack[] = +"squarewhitewithsmallblack"; +static const char glyph_srsquare[] = "srsquare"; +static const char glyph_ssabengali[] = "ssabengali"; +static const char glyph_ssadeva[] = "ssadeva"; +static const char glyph_ssagujarati[] = "ssagujarati"; +static const char glyph_ssangcieuckorean[] = "ssangcieuckorean"; +static const char glyph_ssanghieuhkorean[] = "ssanghieuhkorean"; +static const char glyph_ssangieungkorean[] = "ssangieungkorean"; +static const char glyph_ssangkiyeokkorean[] = "ssangkiyeokkorean"; +static const char glyph_ssangnieunkorean[] = "ssangnieunkorean"; +static const char glyph_ssangpieupkorean[] = "ssangpieupkorean"; +static const char glyph_ssangsioskorean[] = "ssangsioskorean"; +static const char glyph_ssangtikeutkorean[] = "ssangtikeutkorean"; +static const char glyph_ssuperior[] = "ssuperior"; +static const char glyph_sterling[] = "sterling"; +static const char glyph_sterlingmonospace[] = "sterlingmonospace"; +static const char glyph_strokelongoverlaycmb[] = "strokelongoverlaycmb"; +static const char glyph_strokeshortoverlaycmb[] = "strokeshortoverlaycmb"; +static const char glyph_subset[] = "subset"; +static const char glyph_subsetnotequal[] = "subsetnotequal"; +static const char glyph_subsetorequal[] = "subsetorequal"; +static const char glyph_succeeds[] = "succeeds"; +static const char glyph_suchthat[] = "suchthat"; +static const char glyph_suhiragana[] = "suhiragana"; +static const char glyph_sukatakana[] = "sukatakana"; +static const char glyph_sukatakanahalfwidth[] = "sukatakanahalfwidth"; +static const char glyph_sukunarabic[] = "sukunarabic"; +static const char glyph_summation[] = "summation"; +static const char glyph_sun[] = "sun"; +static const char glyph_superset[] = "superset"; +static const char glyph_supersetnotequal[] = "supersetnotequal"; +static const char glyph_supersetorequal[] = "supersetorequal"; +static const char glyph_svsquare[] = "svsquare"; +static const char glyph_syouwaerasquare[] = "syouwaerasquare"; +static const char glyph_t[] = "t"; +static const char glyph_tabengali[] = "tabengali"; +static const char glyph_tackdown[] = "tackdown"; +static const char glyph_tackleft[] = "tackleft"; +static const char glyph_tadeva[] = "tadeva"; +static const char glyph_tagujarati[] = "tagujarati"; +static const char glyph_tagurmukhi[] = "tagurmukhi"; +static const char glyph_taharabic[] = "taharabic"; +static const char glyph_tahfinalarabic[] = "tahfinalarabic"; +static const char glyph_tahinitialarabic[] = "tahinitialarabic"; +static const char glyph_tahiragana[] = "tahiragana"; +static const char glyph_tahmedialarabic[] = "tahmedialarabic"; +static const char glyph_taisyouerasquare[] = "taisyouerasquare"; +static const char glyph_takatakana[] = "takatakana"; +static const char glyph_takatakanahalfwidth[] = "takatakanahalfwidth"; +static const char glyph_tatweelarabic[] = "tatweelarabic"; +static const char glyph_tau[] = "tau"; +static const char glyph_tav[] = "tav"; +static const char glyph_tavdages[] = "tavdages"; +static const char glyph_tavdagesh[] = "tavdagesh"; +static const char glyph_tavdageshhebrew[] = "tavdageshhebrew"; +static const char glyph_tavhebrew[] = "tavhebrew"; +static const char glyph_tbar[] = "tbar"; +static const char glyph_tbopomofo[] = "tbopomofo"; +static const char glyph_tcaron[] = "tcaron"; +static const char glyph_tccurl[] = "tccurl"; +static const char glyph_tcedilla[] = "tcedilla"; +static const char glyph_tcheharabic[] = "tcheharabic"; +static const char glyph_tchehfinalarabic[] = "tchehfinalarabic"; +static const char glyph_tchehinitialarabic[] = "tchehinitialarabic"; +static const char glyph_tchehmedialarabic[] = "tchehmedialarabic"; +static const char glyph_tchehmeeminitialarabic[] = "tchehmeeminitialarabic"; +static const char glyph_tcircle[] = "tcircle"; +static const char glyph_tcircumflexbelow[] = "tcircumflexbelow"; +static const char glyph_tcommaaccent[] = "tcommaaccent"; +static const char glyph_tdieresis[] = "tdieresis"; +static const char glyph_tdotaccent[] = "tdotaccent"; +static const char glyph_tdotbelow[] = "tdotbelow"; +static const char glyph_tecyrillic[] = "tecyrillic"; +static const char glyph_tedescendercyrillic[] = "tedescendercyrillic"; +static const char glyph_teharabic[] = "teharabic"; +static const char glyph_tehfinalarabic[] = "tehfinalarabic"; +static const char glyph_tehhahinitialarabic[] = "tehhahinitialarabic"; +static const char glyph_tehhahisolatedarabic[] = "tehhahisolatedarabic"; +static const char glyph_tehinitialarabic[] = "tehinitialarabic"; +static const char glyph_tehiragana[] = "tehiragana"; +static const char glyph_tehjeeminitialarabic[] = "tehjeeminitialarabic"; +static const char glyph_tehjeemisolatedarabic[] = "tehjeemisolatedarabic"; +static const char glyph_tehmarbutaarabic[] = "tehmarbutaarabic"; +static const char glyph_tehmarbutafinalarabic[] = "tehmarbutafinalarabic"; +static const char glyph_tehmedialarabic[] = "tehmedialarabic"; +static const char glyph_tehmeeminitialarabic[] = "tehmeeminitialarabic"; +static const char glyph_tehmeemisolatedarabic[] = "tehmeemisolatedarabic"; +static const char glyph_tehnoonfinalarabic[] = "tehnoonfinalarabic"; +static const char glyph_tekatakana[] = "tekatakana"; +static const char glyph_tekatakanahalfwidth[] = "tekatakanahalfwidth"; +static const char glyph_telephone[] = "telephone"; +static const char glyph_telephoneblack[] = "telephoneblack"; +static const char glyph_telishagedolahebrew[] = "telishagedolahebrew"; +static const char glyph_telishaqetanahebrew[] = "telishaqetanahebrew"; +static const char glyph_tencircle[] = "tencircle"; +static const char glyph_tenideographicparen[] = "tenideographicparen"; +static const char glyph_tenparen[] = "tenparen"; +static const char glyph_tenperiod[] = "tenperiod"; +static const char glyph_tenroman[] = "tenroman"; +static const char glyph_tesh[] = "tesh"; +static const char glyph_tet[] = "tet"; +static const char glyph_tetdagesh[] = "tetdagesh"; +static const char glyph_tetdageshhebrew[] = "tetdageshhebrew"; +static const char glyph_tethebrew[] = "tethebrew"; +static const char glyph_tetsecyrillic[] = "tetsecyrillic"; +static const char glyph_tevirhebrew[] = "tevirhebrew"; +static const char glyph_tevirlefthebrew[] = "tevirlefthebrew"; +static const char glyph_thabengali[] = "thabengali"; +static const char glyph_thadeva[] = "thadeva"; +static const char glyph_thagujarati[] = "thagujarati"; +static const char glyph_thagurmukhi[] = "thagurmukhi"; +static const char glyph_thalarabic[] = "thalarabic"; +static const char glyph_thalfinalarabic[] = "thalfinalarabic"; +static const char glyph_thanthakhatlowleftthai[] = "thanthakhatlowleftthai"; +static const char glyph_thanthakhatlowrightthai[] = "thanthakhatlowrightthai"; +static const char glyph_thanthakhatthai[] = "thanthakhatthai"; +static const char glyph_thanthakhatupperleftthai[] = +"thanthakhatupperleftthai"; +static const char glyph_theharabic[] = "theharabic"; +static const char glyph_thehfinalarabic[] = "thehfinalarabic"; +static const char glyph_thehinitialarabic[] = "thehinitialarabic"; +static const char glyph_thehmedialarabic[] = "thehmedialarabic"; +static const char glyph_thereexists[] = "thereexists"; +static const char glyph_therefore[] = "therefore"; +static const char glyph_theta[] = "theta"; +static const char glyph_theta1[] = "theta1"; +static const char glyph_thetasymbolgreek[] = "thetasymbolgreek"; +static const char glyph_thieuthacirclekorean[] = "thieuthacirclekorean"; +static const char glyph_thieuthaparenkorean[] = "thieuthaparenkorean"; +static const char glyph_thieuthcirclekorean[] = "thieuthcirclekorean"; +static const char glyph_thieuthkorean[] = "thieuthkorean"; +static const char glyph_thieuthparenkorean[] = "thieuthparenkorean"; +static const char glyph_thirteencircle[] = "thirteencircle"; +static const char glyph_thirteenparen[] = "thirteenparen"; +static const char glyph_thirteenperiod[] = "thirteenperiod"; +static const char glyph_thonangmonthothai[] = "thonangmonthothai"; +static const char glyph_thook[] = "thook"; +static const char glyph_thophuthaothai[] = "thophuthaothai"; +static const char glyph_thorn[] = "thorn"; +static const char glyph_thothahanthai[] = "thothahanthai"; +static const char glyph_thothanthai[] = "thothanthai"; +static const char glyph_thothongthai[] = "thothongthai"; +static const char glyph_thothungthai[] = "thothungthai"; +static const char glyph_thousandcyrillic[] = "thousandcyrillic"; +static const char glyph_thousandsseparatorarabic[] = +"thousandsseparatorarabic"; +static const char glyph_thousandsseparatorpersian[] = +"thousandsseparatorpersian"; +static const char glyph_three[] = "three"; +static const char glyph_threearabic[] = "threearabic"; +static const char glyph_threebengali[] = "threebengali"; +static const char glyph_threecircle[] = "threecircle"; +static const char glyph_threecircleinversesansserif[] = +"threecircleinversesansserif"; +static const char glyph_threedeva[] = "threedeva"; +static const char glyph_threeeighths[] = "threeeighths"; +static const char glyph_threegujarati[] = "threegujarati"; +static const char glyph_threegurmukhi[] = "threegurmukhi"; +static const char glyph_threehackarabic[] = "threehackarabic"; +static const char glyph_threehangzhou[] = "threehangzhou"; +static const char glyph_threeideographicparen[] = "threeideographicparen"; +static const char glyph_threeinferior[] = "threeinferior"; +static const char glyph_threemonospace[] = "threemonospace"; +static const char glyph_threenumeratorbengali[] = "threenumeratorbengali"; +static const char glyph_threeoldstyle[] = "threeoldstyle"; +static const char glyph_threeparen[] = "threeparen"; +static const char glyph_threeperiod[] = "threeperiod"; +static const char glyph_threepersian[] = "threepersian"; +static const char glyph_threequarters[] = "threequarters"; +static const char glyph_threequartersemdash[] = "threequartersemdash"; +static const char glyph_threeroman[] = "threeroman"; +static const char glyph_threesuperior[] = "threesuperior"; +static const char glyph_threethai[] = "threethai"; +static const char glyph_thzsquare[] = "thzsquare"; +static const char glyph_tihiragana[] = "tihiragana"; +static const char glyph_tikatakana[] = "tikatakana"; +static const char glyph_tikatakanahalfwidth[] = "tikatakanahalfwidth"; +static const char glyph_tikeutacirclekorean[] = "tikeutacirclekorean"; +static const char glyph_tikeutaparenkorean[] = "tikeutaparenkorean"; +static const char glyph_tikeutcirclekorean[] = "tikeutcirclekorean"; +static const char glyph_tikeutkorean[] = "tikeutkorean"; +static const char glyph_tikeutparenkorean[] = "tikeutparenkorean"; +static const char glyph_tilde[] = "tilde"; +static const char glyph_tildebelowcmb[] = "tildebelowcmb"; +static const char glyph_tildecmb[] = "tildecmb"; +static const char glyph_tildecomb[] = "tildecomb"; +static const char glyph_tildedoublecmb[] = "tildedoublecmb"; +static const char glyph_tildeoperator[] = "tildeoperator"; +static const char glyph_tildeoverlaycmb[] = "tildeoverlaycmb"; +static const char glyph_tildeverticalcmb[] = "tildeverticalcmb"; +static const char glyph_timescircle[] = "timescircle"; +static const char glyph_tipehahebrew[] = "tipehahebrew"; +static const char glyph_tipehalefthebrew[] = "tipehalefthebrew"; +static const char glyph_tippigurmukhi[] = "tippigurmukhi"; +static const char glyph_titlocyrilliccmb[] = "titlocyrilliccmb"; +static const char glyph_tiwnarmenian[] = "tiwnarmenian"; +static const char glyph_tlinebelow[] = "tlinebelow"; +static const char glyph_tmonospace[] = "tmonospace"; +static const char glyph_toarmenian[] = "toarmenian"; +static const char glyph_tohiragana[] = "tohiragana"; +static const char glyph_tokatakana[] = "tokatakana"; +static const char glyph_tokatakanahalfwidth[] = "tokatakanahalfwidth"; +static const char glyph_tonebarextrahighmod[] = "tonebarextrahighmod"; +static const char glyph_tonebarextralowmod[] = "tonebarextralowmod"; +static const char glyph_tonebarhighmod[] = "tonebarhighmod"; +static const char glyph_tonebarlowmod[] = "tonebarlowmod"; +static const char glyph_tonebarmidmod[] = "tonebarmidmod"; +static const char glyph_tonefive[] = "tonefive"; +static const char glyph_tonesix[] = "tonesix"; +static const char glyph_tonetwo[] = "tonetwo"; +static const char glyph_tonos[] = "tonos"; +static const char glyph_tonsquare[] = "tonsquare"; +static const char glyph_topatakthai[] = "topatakthai"; +static const char glyph_tortoiseshellbracketleft[] = +"tortoiseshellbracketleft"; +static const char glyph_tortoiseshellbracketleftsmall[] = +"tortoiseshellbracketleftsmall"; +static const char glyph_tortoiseshellbracketleftvertical[] = +"tortoiseshellbracketleftvertical"; +static const char glyph_tortoiseshellbracketright[] = +"tortoiseshellbracketright"; +static const char glyph_tortoiseshellbracketrightsmall[] = +"tortoiseshellbracketrightsmall"; +static const char glyph_tortoiseshellbracketrightvertical[] = +"tortoiseshellbracketrightvertical"; +static const char glyph_totaothai[] = "totaothai"; +static const char glyph_tpalatalhook[] = "tpalatalhook"; +static const char glyph_tparen[] = "tparen"; +static const char glyph_trademark[] = "trademark"; +static const char glyph_trademarksans[] = "trademarksans"; +static const char glyph_trademarkserif[] = "trademarkserif"; +static const char glyph_tretroflexhook[] = "tretroflexhook"; +static const char glyph_triagdn[] = "triagdn"; +static const char glyph_triaglf[] = "triaglf"; +static const char glyph_triagrt[] = "triagrt"; +static const char glyph_triagup[] = "triagup"; +static const char glyph_ts[] = "ts"; +static const char glyph_tsadi[] = "tsadi"; +static const char glyph_tsadidagesh[] = "tsadidagesh"; +static const char glyph_tsadidageshhebrew[] = "tsadidageshhebrew"; +static const char glyph_tsadihebrew[] = "tsadihebrew"; +static const char glyph_tsecyrillic[] = "tsecyrillic"; +static const char glyph_tsere[] = "tsere"; +static const char glyph_tsere12[] = "tsere12"; +static const char glyph_tsere1e[] = "tsere1e"; +static const char glyph_tsere2b[] = "tsere2b"; +static const char glyph_tserehebrew[] = "tserehebrew"; +static const char glyph_tserenarrowhebrew[] = "tserenarrowhebrew"; +static const char glyph_tserequarterhebrew[] = "tserequarterhebrew"; +static const char glyph_tserewidehebrew[] = "tserewidehebrew"; +static const char glyph_tshecyrillic[] = "tshecyrillic"; +static const char glyph_tsuperior[] = "tsuperior"; +static const char glyph_ttabengali[] = "ttabengali"; +static const char glyph_ttadeva[] = "ttadeva"; +static const char glyph_ttagujarati[] = "ttagujarati"; +static const char glyph_ttagurmukhi[] = "ttagurmukhi"; +static const char glyph_tteharabic[] = "tteharabic"; +static const char glyph_ttehfinalarabic[] = "ttehfinalarabic"; +static const char glyph_ttehinitialarabic[] = "ttehinitialarabic"; +static const char glyph_ttehmedialarabic[] = "ttehmedialarabic"; +static const char glyph_tthabengali[] = "tthabengali"; +static const char glyph_tthadeva[] = "tthadeva"; +static const char glyph_tthagujarati[] = "tthagujarati"; +static const char glyph_tthagurmukhi[] = "tthagurmukhi"; +static const char glyph_tturned[] = "tturned"; +static const char glyph_tuhiragana[] = "tuhiragana"; +static const char glyph_tukatakana[] = "tukatakana"; +static const char glyph_tukatakanahalfwidth[] = "tukatakanahalfwidth"; +static const char glyph_tusmallhiragana[] = "tusmallhiragana"; +static const char glyph_tusmallkatakana[] = "tusmallkatakana"; +static const char glyph_tusmallkatakanahalfwidth[] = +"tusmallkatakanahalfwidth"; +static const char glyph_twelvecircle[] = "twelvecircle"; +static const char glyph_twelveparen[] = "twelveparen"; +static const char glyph_twelveperiod[] = "twelveperiod"; +static const char glyph_twelveroman[] = "twelveroman"; +static const char glyph_twentycircle[] = "twentycircle"; +static const char glyph_twentyhangzhou[] = "twentyhangzhou"; +static const char glyph_twentyparen[] = "twentyparen"; +static const char glyph_twentyperiod[] = "twentyperiod"; +static const char glyph_two[] = "two"; +static const char glyph_twoarabic[] = "twoarabic"; +static const char glyph_twobengali[] = "twobengali"; +static const char glyph_twocircle[] = "twocircle"; +static const char glyph_twocircleinversesansserif[] = +"twocircleinversesansserif"; +static const char glyph_twodeva[] = "twodeva"; +static const char glyph_twodotenleader[] = "twodotenleader"; +static const char glyph_twodotleader[] = "twodotleader"; +static const char glyph_twodotleadervertical[] = "twodotleadervertical"; +static const char glyph_twogujarati[] = "twogujarati"; +static const char glyph_twogurmukhi[] = "twogurmukhi"; +static const char glyph_twohackarabic[] = "twohackarabic"; +static const char glyph_twohangzhou[] = "twohangzhou"; +static const char glyph_twoideographicparen[] = "twoideographicparen"; +static const char glyph_twoinferior[] = "twoinferior"; +static const char glyph_twomonospace[] = "twomonospace"; +static const char glyph_twonumeratorbengali[] = "twonumeratorbengali"; +static const char glyph_twooldstyle[] = "twooldstyle"; +static const char glyph_twoparen[] = "twoparen"; +static const char glyph_twoperiod[] = "twoperiod"; +static const char glyph_twopersian[] = "twopersian"; +static const char glyph_tworoman[] = "tworoman"; +static const char glyph_twostroke[] = "twostroke"; +static const char glyph_twosuperior[] = "twosuperior"; +static const char glyph_twothai[] = "twothai"; +static const char glyph_twothirds[] = "twothirds"; +static const char glyph_u[] = "u"; +static const char glyph_uacute[] = "uacute"; +static const char glyph_ubar[] = "ubar"; +static const char glyph_ubengali[] = "ubengali"; +static const char glyph_ubopomofo[] = "ubopomofo"; +static const char glyph_ubreve[] = "ubreve"; +static const char glyph_ucaron[] = "ucaron"; +static const char glyph_ucircle[] = "ucircle"; +static const char glyph_ucircumflex[] = "ucircumflex"; +static const char glyph_ucircumflexbelow[] = "ucircumflexbelow"; +static const char glyph_ucyrillic[] = "ucyrillic"; +static const char glyph_udattadeva[] = "udattadeva"; +static const char glyph_udblacute[] = "udblacute"; +static const char glyph_udblgrave[] = "udblgrave"; +static const char glyph_udeva[] = "udeva"; +static const char glyph_udieresis[] = "udieresis"; +static const char glyph_udieresisacute[] = "udieresisacute"; +static const char glyph_udieresisbelow[] = "udieresisbelow"; +static const char glyph_udieresiscaron[] = "udieresiscaron"; +static const char glyph_udieresiscyrillic[] = "udieresiscyrillic"; +static const char glyph_udieresisgrave[] = "udieresisgrave"; +static const char glyph_udieresismacron[] = "udieresismacron"; +static const char glyph_udotbelow[] = "udotbelow"; +static const char glyph_ugrave[] = "ugrave"; +static const char glyph_ugujarati[] = "ugujarati"; +static const char glyph_ugurmukhi[] = "ugurmukhi"; +static const char glyph_uhiragana[] = "uhiragana"; +static const char glyph_uhookabove[] = "uhookabove"; +static const char glyph_uhorn[] = "uhorn"; +static const char glyph_uhornacute[] = "uhornacute"; +static const char glyph_uhorndotbelow[] = "uhorndotbelow"; +static const char glyph_uhorngrave[] = "uhorngrave"; +static const char glyph_uhornhookabove[] = "uhornhookabove"; +static const char glyph_uhorntilde[] = "uhorntilde"; +static const char glyph_uhungarumlaut[] = "uhungarumlaut"; +static const char glyph_uhungarumlautcyrillic[] = "uhungarumlautcyrillic"; +static const char glyph_uinvertedbreve[] = "uinvertedbreve"; +static const char glyph_ukatakana[] = "ukatakana"; +static const char glyph_ukatakanahalfwidth[] = "ukatakanahalfwidth"; +static const char glyph_ukcyrillic[] = "ukcyrillic"; +static const char glyph_ukorean[] = "ukorean"; +static const char glyph_umacron[] = "umacron"; +static const char glyph_umacroncyrillic[] = "umacroncyrillic"; +static const char glyph_umacrondieresis[] = "umacrondieresis"; +static const char glyph_umatragurmukhi[] = "umatragurmukhi"; +static const char glyph_umonospace[] = "umonospace"; +static const char glyph_underscore[] = "underscore"; +static const char glyph_underscoredbl[] = "underscoredbl"; +static const char glyph_underscoremonospace[] = "underscoremonospace"; +static const char glyph_underscorevertical[] = "underscorevertical"; +static const char glyph_underscorewavy[] = "underscorewavy"; +static const char glyph_union[] = "union"; +static const char glyph_universal[] = "universal"; +static const char glyph_uogonek[] = "uogonek"; +static const char glyph_uparen[] = "uparen"; +static const char glyph_upblock[] = "upblock"; +static const char glyph_upperdothebrew[] = "upperdothebrew"; +static const char glyph_upsilon[] = "upsilon"; +static const char glyph_upsilondieresis[] = "upsilondieresis"; +static const char glyph_upsilondieresistonos[] = "upsilondieresistonos"; +static const char glyph_upsilonlatin[] = "upsilonlatin"; +static const char glyph_upsilontonos[] = "upsilontonos"; +static const char glyph_uptackbelowcmb[] = "uptackbelowcmb"; +static const char glyph_uptackmod[] = "uptackmod"; +static const char glyph_uragurmukhi[] = "uragurmukhi"; +static const char glyph_uring[] = "uring"; +static const char glyph_ushortcyrillic[] = "ushortcyrillic"; +static const char glyph_usmallhiragana[] = "usmallhiragana"; +static const char glyph_usmallkatakana[] = "usmallkatakana"; +static const char glyph_usmallkatakanahalfwidth[] = "usmallkatakanahalfwidth"; +static const char glyph_ustraightcyrillic[] = "ustraightcyrillic"; +static const char glyph_ustraightstrokecyrillic[] = "ustraightstrokecyrillic"; +static const char glyph_utilde[] = "utilde"; +static const char glyph_utildeacute[] = "utildeacute"; +static const char glyph_utildebelow[] = "utildebelow"; +static const char glyph_uubengali[] = "uubengali"; +static const char glyph_uudeva[] = "uudeva"; +static const char glyph_uugujarati[] = "uugujarati"; +static const char glyph_uugurmukhi[] = "uugurmukhi"; +static const char glyph_uumatragurmukhi[] = "uumatragurmukhi"; +static const char glyph_uuvowelsignbengali[] = "uuvowelsignbengali"; +static const char glyph_uuvowelsigndeva[] = "uuvowelsigndeva"; +static const char glyph_uuvowelsigngujarati[] = "uuvowelsigngujarati"; +static const char glyph_uvowelsignbengali[] = "uvowelsignbengali"; +static const char glyph_uvowelsigndeva[] = "uvowelsigndeva"; +static const char glyph_uvowelsigngujarati[] = "uvowelsigngujarati"; +static const char glyph_v[] = "v"; +static const char glyph_vadeva[] = "vadeva"; +static const char glyph_vagujarati[] = "vagujarati"; +static const char glyph_vagurmukhi[] = "vagurmukhi"; +static const char glyph_vakatakana[] = "vakatakana"; +static const char glyph_vav[] = "vav"; +static const char glyph_vavdagesh[] = "vavdagesh"; +static const char glyph_vavdagesh65[] = "vavdagesh65"; +static const char glyph_vavdageshhebrew[] = "vavdageshhebrew"; +static const char glyph_vavhebrew[] = "vavhebrew"; +static const char glyph_vavholam[] = "vavholam"; +static const char glyph_vavholamhebrew[] = "vavholamhebrew"; +static const char glyph_vavvavhebrew[] = "vavvavhebrew"; +static const char glyph_vavyodhebrew[] = "vavyodhebrew"; +static const char glyph_vcircle[] = "vcircle"; +static const char glyph_vdotbelow[] = "vdotbelow"; +static const char glyph_vecyrillic[] = "vecyrillic"; +static const char glyph_veharabic[] = "veharabic"; +static const char glyph_vehfinalarabic[] = "vehfinalarabic"; +static const char glyph_vehinitialarabic[] = "vehinitialarabic"; +static const char glyph_vehmedialarabic[] = "vehmedialarabic"; +static const char glyph_vekatakana[] = "vekatakana"; +static const char glyph_venus[] = "venus"; +static const char glyph_verticalbar[] = "verticalbar"; +static const char glyph_verticallineabovecmb[] = "verticallineabovecmb"; +static const char glyph_verticallinebelowcmb[] = "verticallinebelowcmb"; +static const char glyph_verticallinelowmod[] = "verticallinelowmod"; +static const char glyph_verticallinemod[] = "verticallinemod"; +static const char glyph_vewarmenian[] = "vewarmenian"; +static const char glyph_vhook[] = "vhook"; +static const char glyph_vikatakana[] = "vikatakana"; +static const char glyph_viramabengali[] = "viramabengali"; +static const char glyph_viramadeva[] = "viramadeva"; +static const char glyph_viramagujarati[] = "viramagujarati"; +static const char glyph_visargabengali[] = "visargabengali"; +static const char glyph_visargadeva[] = "visargadeva"; +static const char glyph_visargagujarati[] = "visargagujarati"; +static const char glyph_vmonospace[] = "vmonospace"; +static const char glyph_voarmenian[] = "voarmenian"; +static const char glyph_voicediterationhiragana[] = "voicediterationhiragana"; +static const char glyph_voicediterationkatakana[] = "voicediterationkatakana"; +static const char glyph_voicedmarkkana[] = "voicedmarkkana"; +static const char glyph_voicedmarkkanahalfwidth[] = "voicedmarkkanahalfwidth"; +static const char glyph_vokatakana[] = "vokatakana"; +static const char glyph_vparen[] = "vparen"; +static const char glyph_vtilde[] = "vtilde"; +static const char glyph_vturned[] = "vturned"; +static const char glyph_vuhiragana[] = "vuhiragana"; +static const char glyph_vukatakana[] = "vukatakana"; +static const char glyph_w[] = "w"; +static const char glyph_wacute[] = "wacute"; +static const char glyph_waekorean[] = "waekorean"; +static const char glyph_wahiragana[] = "wahiragana"; +static const char glyph_wakatakana[] = "wakatakana"; +static const char glyph_wakatakanahalfwidth[] = "wakatakanahalfwidth"; +static const char glyph_wakorean[] = "wakorean"; +static const char glyph_wasmallhiragana[] = "wasmallhiragana"; +static const char glyph_wasmallkatakana[] = "wasmallkatakana"; +static const char glyph_wattosquare[] = "wattosquare"; +static const char glyph_wavedash[] = "wavedash"; +static const char glyph_wavyunderscorevertical[] = "wavyunderscorevertical"; +static const char glyph_wawarabic[] = "wawarabic"; +static const char glyph_wawfinalarabic[] = "wawfinalarabic"; +static const char glyph_wawhamzaabovearabic[] = "wawhamzaabovearabic"; +static const char glyph_wawhamzaabovefinalarabic[] = +"wawhamzaabovefinalarabic"; +static const char glyph_wbsquare[] = "wbsquare"; +static const char glyph_wcircle[] = "wcircle"; +static const char glyph_wcircumflex[] = "wcircumflex"; +static const char glyph_wdieresis[] = "wdieresis"; +static const char glyph_wdotaccent[] = "wdotaccent"; +static const char glyph_wdotbelow[] = "wdotbelow"; +static const char glyph_wehiragana[] = "wehiragana"; +static const char glyph_weierstrass[] = "weierstrass"; +static const char glyph_wekatakana[] = "wekatakana"; +static const char glyph_wekorean[] = "wekorean"; +static const char glyph_weokorean[] = "weokorean"; +static const char glyph_wgrave[] = "wgrave"; +static const char glyph_whitebullet[] = "whitebullet"; +static const char glyph_whitecircle[] = "whitecircle"; +static const char glyph_whitecircleinverse[] = "whitecircleinverse"; +static const char glyph_whitecornerbracketleft[] = +"whitecornerbracketleft"; +static const char glyph_whitecornerbracketleftvertical[] = +"whitecornerbracketleftvertical"; +static const char glyph_whitecornerbracketright[] = +"whitecornerbracketright"; +static const char glyph_whitecornerbracketrightvertical[] = +"whitecornerbracketrightvertical"; +static const char glyph_whitediamond[] = "whitediamond"; +static const char glyph_whitediamondcontainingblacksmalldiamond[] = +"whitediamondcontainingblacksmalldiamond"; +static const char glyph_whitedownpointingsmalltriangle[] = +"whitedownpointingsmalltriangle"; +static const char glyph_whitedownpointingtriangle[] = +"whitedownpointingtriangle"; +static const char glyph_whiteleftpointingsmalltriangle[] = +"whiteleftpointingsmalltriangle"; +static const char glyph_whiteleftpointingtriangle[] = +"whiteleftpointingtriangle"; +static const char glyph_whitelenticularbracketleft[] = +"whitelenticularbracketleft"; +static const char glyph_whitelenticularbracketright[] = +"whitelenticularbracketright"; +static const char glyph_whiterightpointingsmalltriangle[] = +"whiterightpointingsmalltriangle"; +static const char glyph_whiterightpointingtriangle[] = +"whiterightpointingtriangle"; +static const char glyph_whitesmallsquare[] = "whitesmallsquare"; +static const char glyph_whitesmilingface[] = "whitesmilingface"; +static const char glyph_whitesquare[] = "whitesquare"; +static const char glyph_whitestar[] = "whitestar"; +static const char glyph_whitetelephone[] = "whitetelephone"; +static const char glyph_whitetortoiseshellbracketleft[] = +"whitetortoiseshellbracketleft"; +static const char glyph_whitetortoiseshellbracketright[] = +"whitetortoiseshellbracketright"; +static const char glyph_whiteuppointingsmalltriangle[] = +"whiteuppointingsmalltriangle"; +static const char glyph_whiteuppointingtriangle[] = "whiteuppointingtriangle"; +static const char glyph_wihiragana[] = "wihiragana"; +static const char glyph_wikatakana[] = "wikatakana"; +static const char glyph_wikorean[] = "wikorean"; +static const char glyph_wmonospace[] = "wmonospace"; +static const char glyph_wohiragana[] = "wohiragana"; +static const char glyph_wokatakana[] = "wokatakana"; +static const char glyph_wokatakanahalfwidth[] = "wokatakanahalfwidth"; +static const char glyph_won[] = "won"; +static const char glyph_wonmonospace[] = "wonmonospace"; +static const char glyph_wowaenthai[] = "wowaenthai"; +static const char glyph_wparen[] = "wparen"; +static const char glyph_wring[] = "wring"; +static const char glyph_wsuperior[] = "wsuperior"; +static const char glyph_wturned[] = "wturned"; +static const char glyph_wynn[] = "wynn"; +static const char glyph_x[] = "x"; +static const char glyph_xabovecmb[] = "xabovecmb"; +static const char glyph_xbopomofo[] = "xbopomofo"; +static const char glyph_xcircle[] = "xcircle"; +static const char glyph_xdieresis[] = "xdieresis"; +static const char glyph_xdotaccent[] = "xdotaccent"; +static const char glyph_xeharmenian[] = "xeharmenian"; +static const char glyph_xi[] = "xi"; +static const char glyph_xmonospace[] = "xmonospace"; +static const char glyph_xparen[] = "xparen"; +static const char glyph_xsuperior[] = "xsuperior"; +static const char glyph_y[] = "y"; +static const char glyph_yaadosquare[] = "yaadosquare"; +static const char glyph_yabengali[] = "yabengali"; +static const char glyph_yacute[] = "yacute"; +static const char glyph_yadeva[] = "yadeva"; +static const char glyph_yaekorean[] = "yaekorean"; +static const char glyph_yagujarati[] = "yagujarati"; +static const char glyph_yagurmukhi[] = "yagurmukhi"; +static const char glyph_yahiragana[] = "yahiragana"; +static const char glyph_yakatakana[] = "yakatakana"; +static const char glyph_yakatakanahalfwidth[] = "yakatakanahalfwidth"; +static const char glyph_yakorean[] = "yakorean"; +static const char glyph_yamakkanthai[] = "yamakkanthai"; +static const char glyph_yasmallhiragana[] = "yasmallhiragana"; +static const char glyph_yasmallkatakana[] = "yasmallkatakana"; +static const char glyph_yasmallkatakanahalfwidth[] = +"yasmallkatakanahalfwidth"; +static const char glyph_yatcyrillic[] = "yatcyrillic"; +static const char glyph_ycircle[] = "ycircle"; +static const char glyph_ycircumflex[] = "ycircumflex"; +static const char glyph_ydieresis[] = "ydieresis"; +static const char glyph_ydotaccent[] = "ydotaccent"; +static const char glyph_ydotbelow[] = "ydotbelow"; +static const char glyph_yeharabic[] = "yeharabic"; +static const char glyph_yehbarreearabic[] = "yehbarreearabic"; +static const char glyph_yehbarreefinalarabic[] = "yehbarreefinalarabic"; +static const char glyph_yehfinalarabic[] = "yehfinalarabic"; +static const char glyph_yehhamzaabovearabic[] = "yehhamzaabovearabic"; +static const char glyph_yehhamzaabovefinalarabic[] = +"yehhamzaabovefinalarabic"; +static const char glyph_yehhamzaaboveinitialarabic[] = +"yehhamzaaboveinitialarabic"; +static const char glyph_yehhamzaabovemedialarabic[] = +"yehhamzaabovemedialarabic"; +static const char glyph_yehinitialarabic[] = "yehinitialarabic"; +static const char glyph_yehmedialarabic[] = "yehmedialarabic"; +static const char glyph_yehmeeminitialarabic[] = "yehmeeminitialarabic"; +static const char glyph_yehmeemisolatedarabic[] = "yehmeemisolatedarabic"; +static const char glyph_yehnoonfinalarabic[] = "yehnoonfinalarabic"; +static const char glyph_yehthreedotsbelowarabic[] = "yehthreedotsbelowarabic"; +static const char glyph_yekorean[] = "yekorean"; +static const char glyph_yen[] = "yen"; +static const char glyph_yenmonospace[] = "yenmonospace"; +static const char glyph_yeokorean[] = "yeokorean"; +static const char glyph_yeorinhieuhkorean[] = "yeorinhieuhkorean"; +static const char glyph_yerahbenyomohebrew[] = "yerahbenyomohebrew"; +static const char glyph_yerahbenyomolefthebrew[] = "yerahbenyomolefthebrew"; +static const char glyph_yericyrillic[] = "yericyrillic"; +static const char glyph_yerudieresiscyrillic[] = "yerudieresiscyrillic"; +static const char glyph_yesieungkorean[] = "yesieungkorean"; +static const char glyph_yesieungpansioskorean[] = "yesieungpansioskorean"; +static const char glyph_yesieungsioskorean[] = "yesieungsioskorean"; +static const char glyph_yetivhebrew[] = "yetivhebrew"; +static const char glyph_ygrave[] = "ygrave"; +static const char glyph_yhook[] = "yhook"; +static const char glyph_yhookabove[] = "yhookabove"; +static const char glyph_yiarmenian[] = "yiarmenian"; +static const char glyph_yicyrillic[] = "yicyrillic"; +static const char glyph_yikorean[] = "yikorean"; +static const char glyph_yinyang[] = "yinyang"; +static const char glyph_yiwnarmenian[] = "yiwnarmenian"; +static const char glyph_ymonospace[] = "ymonospace"; +static const char glyph_yod[] = "yod"; +static const char glyph_yoddagesh[] = "yoddagesh"; +static const char glyph_yoddageshhebrew[] = "yoddageshhebrew"; +static const char glyph_yodhebrew[] = "yodhebrew"; +static const char glyph_yodyodhebrew[] = "yodyodhebrew"; +static const char glyph_yodyodpatahhebrew[] = "yodyodpatahhebrew"; +static const char glyph_yohiragana[] = "yohiragana"; +static const char glyph_yoikorean[] = "yoikorean"; +static const char glyph_yokatakana[] = "yokatakana"; +static const char glyph_yokatakanahalfwidth[] = "yokatakanahalfwidth"; +static const char glyph_yokorean[] = "yokorean"; +static const char glyph_yosmallhiragana[] = "yosmallhiragana"; +static const char glyph_yosmallkatakana[] = "yosmallkatakana"; +static const char glyph_yosmallkatakanahalfwidth[] = +"yosmallkatakanahalfwidth"; +static const char glyph_yotgreek[] = "yotgreek"; +static const char glyph_yoyaekorean[] = "yoyaekorean"; +static const char glyph_yoyakorean[] = "yoyakorean"; +static const char glyph_yoyakthai[] = "yoyakthai"; +static const char glyph_yoyingthai[] = "yoyingthai"; +static const char glyph_yparen[] = "yparen"; +static const char glyph_ypogegrammeni[] = "ypogegrammeni"; +static const char glyph_ypogegrammenigreekcmb[] = "ypogegrammenigreekcmb"; +static const char glyph_yr[] = "yr"; +static const char glyph_yring[] = "yring"; +static const char glyph_ysuperior[] = "ysuperior"; +static const char glyph_ytilde[] = "ytilde"; +static const char glyph_yturned[] = "yturned"; +static const char glyph_yuhiragana[] = "yuhiragana"; +static const char glyph_yuikorean[] = "yuikorean"; +static const char glyph_yukatakana[] = "yukatakana"; +static const char glyph_yukatakanahalfwidth[] = "yukatakanahalfwidth"; +static const char glyph_yukorean[] = "yukorean"; +static const char glyph_yusbigcyrillic[] = "yusbigcyrillic"; +static const char glyph_yusbigiotifiedcyrillic[] = "yusbigiotifiedcyrillic"; +static const char glyph_yuslittlecyrillic[] = "yuslittlecyrillic"; +static const char glyph_yuslittleiotifiedcyrillic[] = +"yuslittleiotifiedcyrillic"; +static const char glyph_yusmallhiragana[] = "yusmallhiragana"; +static const char glyph_yusmallkatakana[] = "yusmallkatakana"; +static const char glyph_yusmallkatakanahalfwidth[] = +"yusmallkatakanahalfwidth"; +static const char glyph_yuyekorean[] = "yuyekorean"; +static const char glyph_yuyeokorean[] = "yuyeokorean"; +static const char glyph_yyabengali[] = "yyabengali"; +static const char glyph_yyadeva[] = "yyadeva"; +static const char glyph_z[] = "z"; +static const char glyph_zaarmenian[] = "zaarmenian"; +static const char glyph_zacute[] = "zacute"; +static const char glyph_zadeva[] = "zadeva"; +static const char glyph_zagurmukhi[] = "zagurmukhi"; +static const char glyph_zaharabic[] = "zaharabic"; +static const char glyph_zahfinalarabic[] = "zahfinalarabic"; +static const char glyph_zahinitialarabic[] = "zahinitialarabic"; +static const char glyph_zahiragana[] = "zahiragana"; +static const char glyph_zahmedialarabic[] = "zahmedialarabic"; +static const char glyph_zainarabic[] = "zainarabic"; +static const char glyph_zainfinalarabic[] = "zainfinalarabic"; +static const char glyph_zakatakana[] = "zakatakana"; +static const char glyph_zaqefgadolhebrew[] = "zaqefgadolhebrew"; +static const char glyph_zaqefqatanhebrew[] = "zaqefqatanhebrew"; +static const char glyph_zarqahebrew[] = "zarqahebrew"; +static const char glyph_zayin[] = "zayin"; +static const char glyph_zayindagesh[] = "zayindagesh"; +static const char glyph_zayindageshhebrew[] = "zayindageshhebrew"; +static const char glyph_zayinhebrew[] = "zayinhebrew"; +static const char glyph_zbopomofo[] = "zbopomofo"; +static const char glyph_zcaron[] = "zcaron"; +static const char glyph_zcircle[] = "zcircle"; +static const char glyph_zcircumflex[] = "zcircumflex"; +static const char glyph_zcurl[] = "zcurl"; +static const char glyph_zdot[] = "zdot"; +static const char glyph_zdotaccent[] = "zdotaccent"; +static const char glyph_zdotbelow[] = "zdotbelow"; +static const char glyph_zecyrillic[] = "zecyrillic"; +static const char glyph_zedescendercyrillic[] = "zedescendercyrillic"; +static const char glyph_zedieresiscyrillic[] = "zedieresiscyrillic"; +static const char glyph_zehiragana[] = "zehiragana"; +static const char glyph_zekatakana[] = "zekatakana"; +static const char glyph_zero[] = "zero"; +static const char glyph_zeroarabic[] = "zeroarabic"; +static const char glyph_zerobengali[] = "zerobengali"; +static const char glyph_zerodeva[] = "zerodeva"; +static const char glyph_zerogujarati[] = "zerogujarati"; +static const char glyph_zerogurmukhi[] = "zerogurmukhi"; +static const char glyph_zerohackarabic[] = "zerohackarabic"; +static const char glyph_zeroinferior[] = "zeroinferior"; +static const char glyph_zeromonospace[] = "zeromonospace"; +static const char glyph_zerooldstyle[] = "zerooldstyle"; +static const char glyph_zeropersian[] = "zeropersian"; +static const char glyph_zerosuperior[] = "zerosuperior"; +static const char glyph_zerothai[] = "zerothai"; +static const char glyph_zerowidthjoiner[] = "zerowidthjoiner"; +static const char glyph_zerowidthnonjoiner[] = "zerowidthnonjoiner"; +static const char glyph_zerowidthspace[] = "zerowidthspace"; +static const char glyph_zeta[] = "zeta"; +static const char glyph_zhbopomofo[] = "zhbopomofo"; +static const char glyph_zhearmenian[] = "zhearmenian"; +static const char glyph_zhebrevecyrillic[] = "zhebrevecyrillic"; +static const char glyph_zhecyrillic[] = "zhecyrillic"; +static const char glyph_zhedescendercyrillic[] = "zhedescendercyrillic"; +static const char glyph_zhedieresiscyrillic[] = "zhedieresiscyrillic"; +static const char glyph_zihiragana[] = "zihiragana"; +static const char glyph_zikatakana[] = "zikatakana"; +static const char glyph_zinorhebrew[] = "zinorhebrew"; +static const char glyph_zlinebelow[] = "zlinebelow"; +static const char glyph_zmonospace[] = "zmonospace"; +static const char glyph_zohiragana[] = "zohiragana"; +static const char glyph_zokatakana[] = "zokatakana"; +static const char glyph_zparen[] = "zparen"; +static const char glyph_zretroflexhook[] = "zretroflexhook"; +static const char glyph_zstroke[] = "zstroke"; +static const char glyph_zuhiragana[] = "zuhiragana"; +static const char glyph_zukatakana[] = "zukatakana"; + + +/* Glyph names of ZapfDingbats font */ +static const char glyph_a100[] = "a100"; +static const char glyph_a101[] = "a101"; +static const char glyph_a102[] = "a102"; +static const char glyph_a103[] = "a103"; +static const char glyph_a104[] = "a104"; +static const char glyph_a105[] = "a105"; +static const char glyph_a106[] = "a106"; +static const char glyph_a107[] = "a107"; +static const char glyph_a108[] = "a108"; +static const char glyph_a109[] = "a109"; +static const char glyph_a10[] = "a10"; +static const char glyph_a110[] = "a110"; +static const char glyph_a111[] = "a111"; +static const char glyph_a112[] = "a112"; +static const char glyph_a117[] = "a117"; +static const char glyph_a118[] = "a118"; +static const char glyph_a119[] = "a119"; +static const char glyph_a11[] = "a11"; +static const char glyph_a120[] = "a120"; +static const char glyph_a121[] = "a121"; +static const char glyph_a122[] = "a122"; +static const char glyph_a123[] = "a123"; +static const char glyph_a124[] = "a124"; +static const char glyph_a125[] = "a125"; +static const char glyph_a126[] = "a126"; +static const char glyph_a127[] = "a127"; +static const char glyph_a128[] = "a128"; +static const char glyph_a129[] = "a129"; +static const char glyph_a12[] = "a12"; +static const char glyph_a130[] = "a130"; +static const char glyph_a131[] = "a131"; +static const char glyph_a132[] = "a132"; +static const char glyph_a133[] = "a133"; +static const char glyph_a134[] = "a134"; +static const char glyph_a135[] = "a135"; +static const char glyph_a136[] = "a136"; +static const char glyph_a137[] = "a137"; +static const char glyph_a138[] = "a138"; +static const char glyph_a139[] = "a139"; +static const char glyph_a13[] = "a13"; +static const char glyph_a140[] = "a140"; +static const char glyph_a141[] = "a141"; +static const char glyph_a142[] = "a142"; +static const char glyph_a143[] = "a143"; +static const char glyph_a144[] = "a144"; +static const char glyph_a145[] = "a145"; +static const char glyph_a146[] = "a146"; +static const char glyph_a147[] = "a147"; +static const char glyph_a148[] = "a148"; +static const char glyph_a149[] = "a149"; +static const char glyph_a14[] = "a14"; +static const char glyph_a150[] = "a150"; +static const char glyph_a151[] = "a151"; +static const char glyph_a152[] = "a152"; +static const char glyph_a153[] = "a153"; +static const char glyph_a154[] = "a154"; +static const char glyph_a155[] = "a155"; +static const char glyph_a156[] = "a156"; +static const char glyph_a157[] = "a157"; +static const char glyph_a158[] = "a158"; +static const char glyph_a159[] = "a159"; +static const char glyph_a15[] = "a15"; +static const char glyph_a160[] = "a160"; +static const char glyph_a161[] = "a161"; +static const char glyph_a162[] = "a162"; +static const char glyph_a163[] = "a163"; +static const char glyph_a164[] = "a164"; +static const char glyph_a165[] = "a165"; +static const char glyph_a166[] = "a166"; +static const char glyph_a167[] = "a167"; +static const char glyph_a168[] = "a168"; +static const char glyph_a169[] = "a169"; +static const char glyph_a16[] = "a16"; +static const char glyph_a170[] = "a170"; +static const char glyph_a171[] = "a171"; +static const char glyph_a172[] = "a172"; +static const char glyph_a173[] = "a173"; +static const char glyph_a174[] = "a174"; +static const char glyph_a175[] = "a175"; +static const char glyph_a176[] = "a176"; +static const char glyph_a177[] = "a177"; +static const char glyph_a178[] = "a178"; +static const char glyph_a179[] = "a179"; +static const char glyph_a17[] = "a17"; +static const char glyph_a180[] = "a180"; +static const char glyph_a181[] = "a181"; +static const char glyph_a182[] = "a182"; +static const char glyph_a183[] = "a183"; +static const char glyph_a184[] = "a184"; +static const char glyph_a185[] = "a185"; +static const char glyph_a186[] = "a186"; +static const char glyph_a187[] = "a187"; +static const char glyph_a188[] = "a188"; +static const char glyph_a189[] = "a189"; +static const char glyph_a18[] = "a18"; +static const char glyph_a190[] = "a190"; +static const char glyph_a191[] = "a191"; +static const char glyph_a192[] = "a192"; +static const char glyph_a193[] = "a193"; +static const char glyph_a194[] = "a194"; +static const char glyph_a195[] = "a195"; +static const char glyph_a196[] = "a196"; +static const char glyph_a197[] = "a197"; +static const char glyph_a198[] = "a198"; +static const char glyph_a199[] = "a199"; +static const char glyph_a19[] = "a19"; +static const char glyph_a1[] = "a1"; +static const char glyph_a200[] = "a200"; +static const char glyph_a201[] = "a201"; +static const char glyph_a202[] = "a202"; +static const char glyph_a203[] = "a203"; +static const char glyph_a204[] = "a204"; +static const char glyph_a205[] = "a205"; +static const char glyph_a206[] = "a206"; +static const char glyph_a20[] = "a20"; +static const char glyph_a21[] = "a21"; +static const char glyph_a22[] = "a22"; +static const char glyph_a23[] = "a23"; +static const char glyph_a24[] = "a24"; +static const char glyph_a25[] = "a25"; +static const char glyph_a26[] = "a26"; +static const char glyph_a27[] = "a27"; +static const char glyph_a28[] = "a28"; +static const char glyph_a29[] = "a29"; +static const char glyph_a2[] = "a2"; +static const char glyph_a30[] = "a30"; +static const char glyph_a31[] = "a31"; +static const char glyph_a32[] = "a32"; +static const char glyph_a33[] = "a33"; +static const char glyph_a34[] = "a34"; +static const char glyph_a35[] = "a35"; +static const char glyph_a36[] = "a36"; +static const char glyph_a37[] = "a37"; +static const char glyph_a38[] = "a38"; +static const char glyph_a39[] = "a39"; +static const char glyph_a3[] = "a3"; +static const char glyph_a40[] = "a40"; +static const char glyph_a41[] = "a41"; +static const char glyph_a42[] = "a42"; +static const char glyph_a43[] = "a43"; +static const char glyph_a44[] = "a44"; +static const char glyph_a45[] = "a45"; +static const char glyph_a46[] = "a46"; +static const char glyph_a47[] = "a47"; +static const char glyph_a48[] = "a48"; +static const char glyph_a49[] = "a49"; +static const char glyph_a4[] = "a4"; +static const char glyph_a50[] = "a50"; +static const char glyph_a51[] = "a51"; +static const char glyph_a52[] = "a52"; +static const char glyph_a53[] = "a53"; +static const char glyph_a54[] = "a54"; +static const char glyph_a55[] = "a55"; +static const char glyph_a56[] = "a56"; +static const char glyph_a57[] = "a57"; +static const char glyph_a58[] = "a58"; +static const char glyph_a59[] = "a59"; +static const char glyph_a5[] = "a5"; +static const char glyph_a60[] = "a60"; +static const char glyph_a61[] = "a61"; +static const char glyph_a62[] = "a62"; +static const char glyph_a63[] = "a63"; +static const char glyph_a64[] = "a64"; +static const char glyph_a65[] = "a65"; +static const char glyph_a66[] = "a66"; +static const char glyph_a67[] = "a67"; +static const char glyph_a68[] = "a68"; +static const char glyph_a69[] = "a69"; +static const char glyph_a6[] = "a6"; +static const char glyph_a70[] = "a70"; +static const char glyph_a71[] = "a71"; +static const char glyph_a72[] = "a72"; +static const char glyph_a73[] = "a73"; +static const char glyph_a74[] = "a74"; +static const char glyph_a75[] = "a75"; +static const char glyph_a76[] = "a76"; +static const char glyph_a77[] = "a77"; +static const char glyph_a78[] = "a78"; +static const char glyph_a79[] = "a79"; +static const char glyph_a7[] = "a7"; +static const char glyph_a81[] = "a81"; +static const char glyph_a82[] = "a82"; +static const char glyph_a83[] = "a83"; +static const char glyph_a84[] = "a84"; +static const char glyph_a85[] = "a85"; +static const char glyph_a86[] = "a86"; +static const char glyph_a87[] = "a87"; +static const char glyph_a88[] = "a88"; +static const char glyph_a89[] = "a89"; +static const char glyph_a8[] = "a8"; +static const char glyph_a90[] = "a90"; +static const char glyph_a91[] = "a91"; +static const char glyph_a92[] = "a92"; +static const char glyph_a93[] = "a93"; +static const char glyph_a94[] = "a94"; +static const char glyph_a95[] = "a95"; +static const char glyph_a96[] = "a96"; +static const char glyph_a97[] = "a97"; +static const char glyph_a98[] = "a98"; +static const char glyph_a99[] = "a99"; +static const char glyph_a9[] = "a9"; + + +/* + * Adobe Glyph List (AGL) version 1.2' - sorted by names + * + * Version 1.2' means: + * Version 1.2 + resolved double-mappings by following + * glyph names defined in AGL version 2.0: + * + * Deltagreek (Delta) + * Omegagreek (Omega) + * Tcedilla (Tcommaaccent) + * bulletoperator (periodcentered) + * divisionslash (fraction) + * firsttonechinese (macron) + * mugreek (mu) + * nbspace (space) + * sfthyphen (hyphen) + * tcedilla (tcommaaccent) + * + * (cf. table 'tab_double_mappping' below and + * function 'pdc_get_alter_glyphname') + * + */ + +static const pdc_glyph_tab tab_agl2uni[] = +{ +#ifndef PDFLIB_EBCDIC + { 0x0000, glyph__notdef }, + { 0x0041, glyph_A }, + { 0x00C6, glyph_AE }, + { 0x01FC, glyph_AEacute }, + { 0xF7E6, glyph_AEsmall }, + { 0x00C1, glyph_Aacute }, + { 0xF7E1, glyph_Aacutesmall }, + { 0x0102, glyph_Abreve }, + { 0x00C2, glyph_Acircumflex }, + { 0xF7E2, glyph_Acircumflexsmall }, + { 0xF6C9, glyph_Acute }, + { 0xF7B4, glyph_Acutesmall }, + { 0x00C4, glyph_Adieresis }, + { 0xF7E4, glyph_Adieresissmall }, + { 0x00C0, glyph_Agrave }, + { 0xF7E0, glyph_Agravesmall }, + { 0x0391, glyph_Alpha }, + { 0x0386, glyph_Alphatonos }, + { 0x0100, glyph_Amacron }, + { 0x0104, glyph_Aogonek }, + { 0x00C5, glyph_Aring }, + { 0x01FA, glyph_Aringacute }, + { 0xF7E5, glyph_Aringsmall }, + { 0xF761, glyph_Asmall }, + { 0x00C3, glyph_Atilde }, + { 0xF7E3, glyph_Atildesmall }, + { 0x0042, glyph_B }, + { 0x0392, glyph_Beta }, + { 0xF6F4, glyph_Brevesmall }, + { 0xF762, glyph_Bsmall }, + { 0x0043, glyph_C }, + { 0x0106, glyph_Cacute }, + { 0xF6CA, glyph_Caron }, + { 0xF6F5, glyph_Caronsmall }, + { 0x010C, glyph_Ccaron }, + { 0x00C7, glyph_Ccedilla }, + { 0xF7E7, glyph_Ccedillasmall }, + { 0x0108, glyph_Ccircumflex }, + { 0x010A, glyph_Cdotaccent }, + { 0xF7B8, glyph_Cedillasmall }, + { 0x03A7, glyph_Chi }, + { 0xF6F6, glyph_Circumflexsmall }, + { 0xF763, glyph_Csmall }, + { 0x0044, glyph_D }, + { 0x010E, glyph_Dcaron }, + { 0x0110, glyph_Dcroat }, + { 0x2206, glyph_Delta }, + { 0x0394, glyph_Deltagreek }, + { 0xF6CB, glyph_Dieresis }, + { 0xF6CC, glyph_DieresisAcute }, + { 0xF6CD, glyph_DieresisGrave }, + { 0xF7A8, glyph_Dieresissmall }, + { 0xF6F7, glyph_Dotaccentsmall }, + { 0xF764, glyph_Dsmall }, + { 0x0045, glyph_E }, + { 0x00C9, glyph_Eacute }, + { 0xF7E9, glyph_Eacutesmall }, + { 0x0114, glyph_Ebreve }, + { 0x011A, glyph_Ecaron }, + { 0x00CA, glyph_Ecircumflex }, + { 0xF7EA, glyph_Ecircumflexsmall }, + { 0x00CB, glyph_Edieresis }, + { 0xF7EB, glyph_Edieresissmall }, + { 0x0116, glyph_Edotaccent }, + { 0x00C8, glyph_Egrave }, + { 0xF7E8, glyph_Egravesmall }, + { 0x0112, glyph_Emacron }, + { 0x014A, glyph_Eng }, + { 0x0118, glyph_Eogonek }, + { 0x0395, glyph_Epsilon }, + { 0x0388, glyph_Epsilontonos }, + { 0xF765, glyph_Esmall }, + { 0x0397, glyph_Eta }, + { 0x0389, glyph_Etatonos }, + { 0x00D0, glyph_Eth }, + { 0xF7F0, glyph_Ethsmall }, + { 0x20AC, glyph_Euro }, + { 0x0046, glyph_F }, + { 0xF766, glyph_Fsmall }, + { 0x0047, glyph_G }, + { 0x0393, glyph_Gamma }, + { 0x011E, glyph_Gbreve }, + { 0x01E6, glyph_Gcaron }, + { 0x011C, glyph_Gcircumflex }, + { 0x0122, glyph_Gcommaaccent }, + { 0x0120, glyph_Gdotaccent }, + { 0xF6CE, glyph_Grave }, + { 0xF760, glyph_Gravesmall }, + { 0xF767, glyph_Gsmall }, + { 0x0048, glyph_H }, + { 0x25CF, glyph_H18533 }, + { 0x25AA, glyph_H18543 }, + { 0x25AB, glyph_H18551 }, + { 0x25A1, glyph_H22073 }, + { 0x0126, glyph_Hbar }, + { 0x0124, glyph_Hcircumflex }, + { 0xF768, glyph_Hsmall }, + { 0xF6CF, glyph_Hungarumlaut }, + { 0xF6F8, glyph_Hungarumlautsmall }, + { 0x0049, glyph_I }, + { 0x0132, glyph_IJ }, + { 0x00CD, glyph_Iacute }, + { 0xF7ED, glyph_Iacutesmall }, + { 0x012C, glyph_Ibreve }, + { 0x00CE, glyph_Icircumflex }, + { 0xF7EE, glyph_Icircumflexsmall }, + { 0x00CF, glyph_Idieresis }, + { 0xF7EF, glyph_Idieresissmall }, + { 0x0130, glyph_Idotaccent }, + { 0x2111, glyph_Ifraktur }, + { 0x00CC, glyph_Igrave }, + { 0xF7EC, glyph_Igravesmall }, + { 0x012A, glyph_Imacron }, + { 0x012E, glyph_Iogonek }, + { 0x0399, glyph_Iota }, + { 0x03AA, glyph_Iotadieresis }, + { 0x038A, glyph_Iotatonos }, + { 0xF769, glyph_Ismall }, + { 0x0128, glyph_Itilde }, + { 0x004A, glyph_J }, + { 0x0134, glyph_Jcircumflex }, + { 0xF76A, glyph_Jsmall }, + { 0x004B, glyph_K }, + { 0x039A, glyph_Kappa }, + { 0x0136, glyph_Kcommaaccent }, + { 0xF76B, glyph_Ksmall }, + { 0x004C, glyph_L }, + { 0xF6BF, glyph_LL }, + { 0x0139, glyph_Lacute }, + { 0x039B, glyph_Lambda }, + { 0x013D, glyph_Lcaron }, + { 0x013B, glyph_Lcommaaccent }, + { 0x013F, glyph_Ldot }, + { 0x0141, glyph_Lslash }, + { 0xF6F9, glyph_Lslashsmall }, + { 0xF76C, glyph_Lsmall }, + { 0x004D, glyph_M }, + { 0xF6D0, glyph_Macron }, + { 0xF7AF, glyph_Macronsmall }, + { 0xF76D, glyph_Msmall }, + { 0x039C, glyph_Mu }, + { 0x004E, glyph_N }, + { 0x0143, glyph_Nacute }, + { 0x0147, glyph_Ncaron }, + { 0x0145, glyph_Ncommaaccent }, + { 0xF76E, glyph_Nsmall }, + { 0x00D1, glyph_Ntilde }, + { 0xF7F1, glyph_Ntildesmall }, + { 0x039D, glyph_Nu }, + { 0x004F, glyph_O }, + { 0x0152, glyph_OE }, + { 0xF6FA, glyph_OEsmall }, + { 0x00D3, glyph_Oacute }, + { 0xF7F3, glyph_Oacutesmall }, + { 0x014E, glyph_Obreve }, + { 0x00D4, glyph_Ocircumflex }, + { 0xF7F4, glyph_Ocircumflexsmall }, + { 0x00D6, glyph_Odieresis }, + { 0xF7F6, glyph_Odieresissmall }, + { 0xF6FB, glyph_Ogoneksmall }, + { 0x00D2, glyph_Ograve }, + { 0xF7F2, glyph_Ogravesmall }, + { 0x01A0, glyph_Ohorn }, + { 0x0150, glyph_Ohungarumlaut }, + { 0x014C, glyph_Omacron }, + { 0x2126, glyph_Omega }, + { 0x03A9, glyph_Omegagreek }, + { 0x038F, glyph_Omegatonos }, + { 0x039F, glyph_Omicron }, + { 0x038C, glyph_Omicrontonos }, + { 0x00D8, glyph_Oslash }, + { 0x01FE, glyph_Oslashacute }, + { 0xF7F8, glyph_Oslashsmall }, + { 0xF76F, glyph_Osmall }, + { 0x00D5, glyph_Otilde }, + { 0xF7F5, glyph_Otildesmall }, + { 0x0050, glyph_P }, + { 0x03A6, glyph_Phi }, + { 0x03A0, glyph_Pi }, + { 0x03A8, glyph_Psi }, + { 0xF770, glyph_Psmall }, + { 0x0051, glyph_Q }, + { 0xF771, glyph_Qsmall }, + { 0x0052, glyph_R }, + { 0x0154, glyph_Racute }, + { 0x0158, glyph_Rcaron }, + { 0x0156, glyph_Rcommaaccent }, + { 0x211C, glyph_Rfraktur }, + { 0x03A1, glyph_Rho }, + { 0xF6FC, glyph_Ringsmall }, + { 0xF772, glyph_Rsmall }, + { 0x0053, glyph_S }, + { 0x250C, glyph_SF010000 }, + { 0x2514, glyph_SF020000 }, + { 0x2510, glyph_SF030000 }, + { 0x2518, glyph_SF040000 }, + { 0x253C, glyph_SF050000 }, + { 0x252C, glyph_SF060000 }, + { 0x2534, glyph_SF070000 }, + { 0x251C, glyph_SF080000 }, + { 0x2524, glyph_SF090000 }, + { 0x2500, glyph_SF100000 }, + { 0x2502, glyph_SF110000 }, + { 0x2561, glyph_SF190000 }, + { 0x2562, glyph_SF200000 }, + { 0x2556, glyph_SF210000 }, + { 0x2555, glyph_SF220000 }, + { 0x2563, glyph_SF230000 }, + { 0x2551, glyph_SF240000 }, + { 0x2557, glyph_SF250000 }, + { 0x255D, glyph_SF260000 }, + { 0x255C, glyph_SF270000 }, + { 0x255B, glyph_SF280000 }, + { 0x255E, glyph_SF360000 }, + { 0x255F, glyph_SF370000 }, + { 0x255A, glyph_SF380000 }, + { 0x2554, glyph_SF390000 }, + { 0x2569, glyph_SF400000 }, + { 0x2566, glyph_SF410000 }, + { 0x2560, glyph_SF420000 }, + { 0x2550, glyph_SF430000 }, + { 0x256C, glyph_SF440000 }, + { 0x2567, glyph_SF450000 }, + { 0x2568, glyph_SF460000 }, + { 0x2564, glyph_SF470000 }, + { 0x2565, glyph_SF480000 }, + { 0x2559, glyph_SF490000 }, + { 0x2558, glyph_SF500000 }, + { 0x2552, glyph_SF510000 }, + { 0x2553, glyph_SF520000 }, + { 0x256B, glyph_SF530000 }, + { 0x256A, glyph_SF540000 }, + { 0x015A, glyph_Sacute }, + { 0x0160, glyph_Scaron }, + { 0xF6FD, glyph_Scaronsmall }, + { 0x015E, glyph_Scedilla }, + { 0x015C, glyph_Scircumflex }, + { 0x0218, glyph_Scommaaccent }, + { 0x03A3, glyph_Sigma }, + { 0xF773, glyph_Ssmall }, + { 0x0054, glyph_T }, + { 0x03A4, glyph_Tau }, + { 0x0166, glyph_Tbar }, + { 0x0164, glyph_Tcaron }, + { 0x0162, glyph_Tcedilla }, + { 0x021A, glyph_Tcommaaccent }, + { 0x0398, glyph_Theta }, + { 0x00DE, glyph_Thorn }, + { 0xF7FE, glyph_Thornsmall }, + { 0xF6FE, glyph_Tildesmall }, + { 0xF774, glyph_Tsmall }, + { 0x0055, glyph_U }, + { 0x00DA, glyph_Uacute }, + { 0xF7FA, glyph_Uacutesmall }, + { 0x016C, glyph_Ubreve }, + { 0x00DB, glyph_Ucircumflex }, + { 0xF7FB, glyph_Ucircumflexsmall }, + { 0x00DC, glyph_Udieresis }, + { 0xF7FC, glyph_Udieresissmall }, + { 0x00D9, glyph_Ugrave }, + { 0xF7F9, glyph_Ugravesmall }, + { 0x01AF, glyph_Uhorn }, + { 0x0170, glyph_Uhungarumlaut }, + { 0x016A, glyph_Umacron }, + { 0x0172, glyph_Uogonek }, + { 0x03A5, glyph_Upsilon }, + { 0x03D2, glyph_Upsilon1 }, + { 0x03AB, glyph_Upsilondieresis }, + { 0x038E, glyph_Upsilontonos }, + { 0x016E, glyph_Uring }, + { 0xF775, glyph_Usmall }, + { 0x0168, glyph_Utilde }, + { 0x0056, glyph_V }, + { 0xF776, glyph_Vsmall }, + { 0x0057, glyph_W }, + { 0x1E82, glyph_Wacute }, + { 0x0174, glyph_Wcircumflex }, + { 0x1E84, glyph_Wdieresis }, + { 0x1E80, glyph_Wgrave }, + { 0xF777, glyph_Wsmall }, + { 0x0058, glyph_X }, + { 0x039E, glyph_Xi }, + { 0xF778, glyph_Xsmall }, + { 0x0059, glyph_Y }, + { 0x00DD, glyph_Yacute }, + { 0xF7FD, glyph_Yacutesmall }, + { 0x0176, glyph_Ycircumflex }, + { 0x0178, glyph_Ydieresis }, + { 0xF7FF, glyph_Ydieresissmall }, + { 0x1EF2, glyph_Ygrave }, + { 0xF779, glyph_Ysmall }, + { 0x005A, glyph_Z }, + { 0x0179, glyph_Zacute }, + { 0x017D, glyph_Zcaron }, + { 0xF6FF, glyph_Zcaronsmall }, + { 0x017B, glyph_Zdotaccent }, + { 0x0396, glyph_Zeta }, + { 0xF77A, glyph_Zsmall }, + { 0x0061, glyph_a }, + { 0x00E1, glyph_aacute }, + { 0x0103, glyph_abreve }, + { 0x00E2, glyph_acircumflex }, + { 0x00B4, glyph_acute }, + { 0x0301, glyph_acutecomb }, + { 0x00E4, glyph_adieresis }, + { 0x00E6, glyph_ae }, + { 0x01FD, glyph_aeacute }, + { 0x2015, glyph_afii00208 }, + { 0x0410, glyph_afii10017 }, + { 0x0411, glyph_afii10018 }, + { 0x0412, glyph_afii10019 }, + { 0x0413, glyph_afii10020 }, + { 0x0414, glyph_afii10021 }, + { 0x0415, glyph_afii10022 }, + { 0x0401, glyph_afii10023 }, + { 0x0416, glyph_afii10024 }, + { 0x0417, glyph_afii10025 }, + { 0x0418, glyph_afii10026 }, + { 0x0419, glyph_afii10027 }, + { 0x041A, glyph_afii10028 }, + { 0x041B, glyph_afii10029 }, + { 0x041C, glyph_afii10030 }, + { 0x041D, glyph_afii10031 }, + { 0x041E, glyph_afii10032 }, + { 0x041F, glyph_afii10033 }, + { 0x0420, glyph_afii10034 }, + { 0x0421, glyph_afii10035 }, + { 0x0422, glyph_afii10036 }, + { 0x0423, glyph_afii10037 }, + { 0x0424, glyph_afii10038 }, + { 0x0425, glyph_afii10039 }, + { 0x0426, glyph_afii10040 }, + { 0x0427, glyph_afii10041 }, + { 0x0428, glyph_afii10042 }, + { 0x0429, glyph_afii10043 }, + { 0x042A, glyph_afii10044 }, + { 0x042B, glyph_afii10045 }, + { 0x042C, glyph_afii10046 }, + { 0x042D, glyph_afii10047 }, + { 0x042E, glyph_afii10048 }, + { 0x042F, glyph_afii10049 }, + { 0x0490, glyph_afii10050 }, + { 0x0402, glyph_afii10051 }, + { 0x0403, glyph_afii10052 }, + { 0x0404, glyph_afii10053 }, + { 0x0405, glyph_afii10054 }, + { 0x0406, glyph_afii10055 }, + { 0x0407, glyph_afii10056 }, + { 0x0408, glyph_afii10057 }, + { 0x0409, glyph_afii10058 }, + { 0x040A, glyph_afii10059 }, + { 0x040B, glyph_afii10060 }, + { 0x040C, glyph_afii10061 }, + { 0x040E, glyph_afii10062 }, + { 0xF6C4, glyph_afii10063 }, + { 0xF6C5, glyph_afii10064 }, + { 0x0430, glyph_afii10065 }, + { 0x0431, glyph_afii10066 }, + { 0x0432, glyph_afii10067 }, + { 0x0433, glyph_afii10068 }, + { 0x0434, glyph_afii10069 }, + { 0x0435, glyph_afii10070 }, + { 0x0451, glyph_afii10071 }, + { 0x0436, glyph_afii10072 }, + { 0x0437, glyph_afii10073 }, + { 0x0438, glyph_afii10074 }, + { 0x0439, glyph_afii10075 }, + { 0x043A, glyph_afii10076 }, + { 0x043B, glyph_afii10077 }, + { 0x043C, glyph_afii10078 }, + { 0x043D, glyph_afii10079 }, + { 0x043E, glyph_afii10080 }, + { 0x043F, glyph_afii10081 }, + { 0x0440, glyph_afii10082 }, + { 0x0441, glyph_afii10083 }, + { 0x0442, glyph_afii10084 }, + { 0x0443, glyph_afii10085 }, + { 0x0444, glyph_afii10086 }, + { 0x0445, glyph_afii10087 }, + { 0x0446, glyph_afii10088 }, + { 0x0447, glyph_afii10089 }, + { 0x0448, glyph_afii10090 }, + { 0x0449, glyph_afii10091 }, + { 0x044A, glyph_afii10092 }, + { 0x044B, glyph_afii10093 }, + { 0x044C, glyph_afii10094 }, + { 0x044D, glyph_afii10095 }, + { 0x044E, glyph_afii10096 }, + { 0x044F, glyph_afii10097 }, + { 0x0491, glyph_afii10098 }, + { 0x0452, glyph_afii10099 }, + { 0x0453, glyph_afii10100 }, + { 0x0454, glyph_afii10101 }, + { 0x0455, glyph_afii10102 }, + { 0x0456, glyph_afii10103 }, + { 0x0457, glyph_afii10104 }, + { 0x0458, glyph_afii10105 }, + { 0x0459, glyph_afii10106 }, + { 0x045A, glyph_afii10107 }, + { 0x045B, glyph_afii10108 }, + { 0x045C, glyph_afii10109 }, + { 0x045E, glyph_afii10110 }, + { 0x040F, glyph_afii10145 }, + { 0x0462, glyph_afii10146 }, + { 0x0472, glyph_afii10147 }, + { 0x0474, glyph_afii10148 }, + { 0xF6C6, glyph_afii10192 }, + { 0x045F, glyph_afii10193 }, + { 0x0463, glyph_afii10194 }, + { 0x0473, glyph_afii10195 }, + { 0x0475, glyph_afii10196 }, + { 0xF6C7, glyph_afii10831 }, + { 0xF6C8, glyph_afii10832 }, + { 0x04D9, glyph_afii10846 }, + { 0x200E, glyph_afii299 }, + { 0x200F, glyph_afii300 }, + { 0x200D, glyph_afii301 }, + { 0x066A, glyph_afii57381 }, + { 0x060C, glyph_afii57388 }, + { 0x0660, glyph_afii57392 }, + { 0x0661, glyph_afii57393 }, + { 0x0662, glyph_afii57394 }, + { 0x0663, glyph_afii57395 }, + { 0x0664, glyph_afii57396 }, + { 0x0665, glyph_afii57397 }, + { 0x0666, glyph_afii57398 }, + { 0x0667, glyph_afii57399 }, + { 0x0668, glyph_afii57400 }, + { 0x0669, glyph_afii57401 }, + { 0x061B, glyph_afii57403 }, + { 0x061F, glyph_afii57407 }, + { 0x0621, glyph_afii57409 }, + { 0x0622, glyph_afii57410 }, + { 0x0623, glyph_afii57411 }, + { 0x0624, glyph_afii57412 }, + { 0x0625, glyph_afii57413 }, + { 0x0626, glyph_afii57414 }, + { 0x0627, glyph_afii57415 }, + { 0x0628, glyph_afii57416 }, + { 0x0629, glyph_afii57417 }, + { 0x062A, glyph_afii57418 }, + { 0x062B, glyph_afii57419 }, + { 0x062C, glyph_afii57420 }, + { 0x062D, glyph_afii57421 }, + { 0x062E, glyph_afii57422 }, + { 0x062F, glyph_afii57423 }, + { 0x0630, glyph_afii57424 }, + { 0x0631, glyph_afii57425 }, + { 0x0632, glyph_afii57426 }, + { 0x0633, glyph_afii57427 }, + { 0x0634, glyph_afii57428 }, + { 0x0635, glyph_afii57429 }, + { 0x0636, glyph_afii57430 }, + { 0x0637, glyph_afii57431 }, + { 0x0638, glyph_afii57432 }, + { 0x0639, glyph_afii57433 }, + { 0x063A, glyph_afii57434 }, + { 0x0640, glyph_afii57440 }, + { 0x0641, glyph_afii57441 }, + { 0x0642, glyph_afii57442 }, + { 0x0643, glyph_afii57443 }, + { 0x0644, glyph_afii57444 }, + { 0x0645, glyph_afii57445 }, + { 0x0646, glyph_afii57446 }, + { 0x0648, glyph_afii57448 }, + { 0x0649, glyph_afii57449 }, + { 0x064A, glyph_afii57450 }, + { 0x064B, glyph_afii57451 }, + { 0x064C, glyph_afii57452 }, + { 0x064D, glyph_afii57453 }, + { 0x064E, glyph_afii57454 }, + { 0x064F, glyph_afii57455 }, + { 0x0650, glyph_afii57456 }, + { 0x0651, glyph_afii57457 }, + { 0x0652, glyph_afii57458 }, + { 0x0647, glyph_afii57470 }, + { 0x06A4, glyph_afii57505 }, + { 0x067E, glyph_afii57506 }, + { 0x0686, glyph_afii57507 }, + { 0x0698, glyph_afii57508 }, + { 0x06AF, glyph_afii57509 }, + { 0x0679, glyph_afii57511 }, + { 0x0688, glyph_afii57512 }, + { 0x0691, glyph_afii57513 }, + { 0x06BA, glyph_afii57514 }, + { 0x06D2, glyph_afii57519 }, + { 0x06D5, glyph_afii57534 }, + { 0x20AA, glyph_afii57636 }, + { 0x05BE, glyph_afii57645 }, + { 0x05C3, glyph_afii57658 }, + { 0x05D0, glyph_afii57664 }, + { 0x05D1, glyph_afii57665 }, + { 0x05D2, glyph_afii57666 }, + { 0x05D3, glyph_afii57667 }, + { 0x05D4, glyph_afii57668 }, + { 0x05D5, glyph_afii57669 }, + { 0x05D6, glyph_afii57670 }, + { 0x05D7, glyph_afii57671 }, + { 0x05D8, glyph_afii57672 }, + { 0x05D9, glyph_afii57673 }, + { 0x05DA, glyph_afii57674 }, + { 0x05DB, glyph_afii57675 }, + { 0x05DC, glyph_afii57676 }, + { 0x05DD, glyph_afii57677 }, + { 0x05DE, glyph_afii57678 }, + { 0x05DF, glyph_afii57679 }, + { 0x05E0, glyph_afii57680 }, + { 0x05E1, glyph_afii57681 }, + { 0x05E2, glyph_afii57682 }, + { 0x05E3, glyph_afii57683 }, + { 0x05E4, glyph_afii57684 }, + { 0x05E5, glyph_afii57685 }, + { 0x05E6, glyph_afii57686 }, + { 0x05E7, glyph_afii57687 }, + { 0x05E8, glyph_afii57688 }, + { 0x05E9, glyph_afii57689 }, + { 0x05EA, glyph_afii57690 }, + { 0xFB2A, glyph_afii57694 }, + { 0xFB2B, glyph_afii57695 }, + { 0xFB4B, glyph_afii57700 }, + { 0xFB1F, glyph_afii57705 }, + { 0x05F0, glyph_afii57716 }, + { 0x05F1, glyph_afii57717 }, + { 0x05F2, glyph_afii57718 }, + { 0xFB35, glyph_afii57723 }, + { 0x05B4, glyph_afii57793 }, + { 0x05B5, glyph_afii57794 }, + { 0x05B6, glyph_afii57795 }, + { 0x05BB, glyph_afii57796 }, + { 0x05B8, glyph_afii57797 }, + { 0x05B7, glyph_afii57798 }, + { 0x05B0, glyph_afii57799 }, + { 0x05B2, glyph_afii57800 }, + { 0x05B1, glyph_afii57801 }, + { 0x05B3, glyph_afii57802 }, + { 0x05C2, glyph_afii57803 }, + { 0x05C1, glyph_afii57804 }, + { 0x05B9, glyph_afii57806 }, + { 0x05BC, glyph_afii57807 }, + { 0x05BD, glyph_afii57839 }, + { 0x05BF, glyph_afii57841 }, + { 0x05C0, glyph_afii57842 }, + { 0x02BC, glyph_afii57929 }, + { 0x2105, glyph_afii61248 }, + { 0x2113, glyph_afii61289 }, + { 0x2116, glyph_afii61352 }, + { 0x202C, glyph_afii61573 }, + { 0x202D, glyph_afii61574 }, + { 0x202E, glyph_afii61575 }, + { 0x200C, glyph_afii61664 }, + { 0x066D, glyph_afii63167 }, + { 0x02BD, glyph_afii64937 }, + { 0x00E0, glyph_agrave }, + { 0x2135, glyph_aleph }, + { 0x03B1, glyph_alpha }, + { 0x03AC, glyph_alphatonos }, + { 0x0101, glyph_amacron }, + { 0x0026, glyph_ampersand }, + { 0xF726, glyph_ampersandsmall }, + { 0x2220, glyph_angle }, + { 0x2329, glyph_angleleft }, + { 0x232A, glyph_angleright }, + { 0x0387, glyph_anoteleia }, + { 0x0105, glyph_aogonek }, + { 0xF8FF, glyph_apple }, + { 0x2248, glyph_approxequal }, + { 0x00E5, glyph_aring }, + { 0x01FB, glyph_aringacute }, + { 0x2194, glyph_arrowboth }, + { 0x21D4, glyph_arrowdblboth }, + { 0x21D3, glyph_arrowdbldown }, + { 0x21D0, glyph_arrowdblleft }, + { 0x21D2, glyph_arrowdblright }, + { 0x21D1, glyph_arrowdblup }, + { 0x2193, glyph_arrowdown }, + { 0xF8E7, glyph_arrowhorizex }, + { 0x2190, glyph_arrowleft }, + { 0x2192, glyph_arrowright }, + { 0x2191, glyph_arrowup }, + { 0x2195, glyph_arrowupdn }, + { 0x21A8, glyph_arrowupdnbse }, + { 0xF8E6, glyph_arrowvertex }, + { 0x005E, glyph_asciicircum }, + { 0x007E, glyph_asciitilde }, + { 0x002A, glyph_asterisk }, + { 0x2217, glyph_asteriskmath }, + { 0xF6E9, glyph_asuperior }, + { 0x0040, glyph_at }, + { 0x00E3, glyph_atilde }, + { 0x0062, glyph_b }, + { 0x005C, glyph_backslash }, + { 0x007C, glyph_bar }, + { 0x03B2, glyph_beta }, + { 0x2588, glyph_block }, + { 0xF8F4, glyph_braceex }, + { 0x007B, glyph_braceleft }, + { 0xF8F3, glyph_braceleftbt }, + { 0xF8F2, glyph_braceleftmid }, + { 0xF8F1, glyph_bracelefttp }, + { 0x007D, glyph_braceright }, + { 0xF8FE, glyph_bracerightbt }, + { 0xF8FD, glyph_bracerightmid }, + { 0xF8FC, glyph_bracerighttp }, + { 0x005B, glyph_bracketleft }, + { 0xF8F0, glyph_bracketleftbt }, + { 0xF8EF, glyph_bracketleftex }, + { 0xF8EE, glyph_bracketlefttp }, + { 0x005D, glyph_bracketright }, + { 0xF8FB, glyph_bracketrightbt }, + { 0xF8FA, glyph_bracketrightex }, + { 0xF8F9, glyph_bracketrighttp }, + { 0x02D8, glyph_breve }, + { 0x00A6, glyph_brokenbar }, + { 0xF6EA, glyph_bsuperior }, + { 0x2022, glyph_bullet }, + { 0x2219, glyph_bulletoperator }, + { 0x0063, glyph_c }, + { 0x0107, glyph_cacute }, + { 0x02C7, glyph_caron }, + { 0x21B5, glyph_carriagereturn }, + { 0x010D, glyph_ccaron }, + { 0x00E7, glyph_ccedilla }, + { 0x0109, glyph_ccircumflex }, + { 0x010B, glyph_cdotaccent }, + { 0x00B8, glyph_cedilla }, + { 0x00A2, glyph_cent }, + { 0xF6DF, glyph_centinferior }, + { 0xF7A2, glyph_centoldstyle }, + { 0xF6E0, glyph_centsuperior }, + { 0x03C7, glyph_chi }, + { 0x25CB, glyph_circle }, + { 0x2297, glyph_circlemultiply }, + { 0x2295, glyph_circleplus }, + { 0x02C6, glyph_circumflex }, + { 0x2663, glyph_club }, + { 0x003A, glyph_colon }, + { 0x20A1, glyph_colonmonetary }, + { 0x002C, glyph_comma }, + { 0xF6C3, glyph_commaaccent }, + { 0xF6E1, glyph_commainferior }, + { 0xF6E2, glyph_commasuperior }, + { 0x2245, glyph_congruent }, + { 0x00A9, glyph_copyright }, + { 0xF8E9, glyph_copyrightsans }, + { 0xF6D9, glyph_copyrightserif }, + { 0x00A4, glyph_currency }, + { 0xF6D1, glyph_cyrBreve }, + { 0xF6D2, glyph_cyrFlex }, + { 0xF6D4, glyph_cyrbreve }, + { 0xF6D5, glyph_cyrflex }, + { 0x0064, glyph_d }, + { 0x2020, glyph_dagger }, + { 0x2021, glyph_daggerdbl }, + { 0xF6D3, glyph_dblGrave }, + { 0xF6D6, glyph_dblgrave }, + { 0x010F, glyph_dcaron }, + { 0x0111, glyph_dcroat }, + { 0x00B0, glyph_degree }, + { 0x03B4, glyph_delta }, + { 0x2666, glyph_diamond }, + { 0x00A8, glyph_dieresis }, + { 0xF6D7, glyph_dieresisacute }, + { 0xF6D8, glyph_dieresisgrave }, + { 0x0385, glyph_dieresistonos }, + { 0x00F7, glyph_divide }, + { 0x2215, glyph_divisionslash }, + { 0x2593, glyph_dkshade }, + { 0x2584, glyph_dnblock }, + { 0x0024, glyph_dollar }, + { 0xF6E3, glyph_dollarinferior }, + { 0xF724, glyph_dollaroldstyle }, + { 0xF6E4, glyph_dollarsuperior }, + { 0x20AB, glyph_dong }, + { 0x02D9, glyph_dotaccent }, + { 0x0323, glyph_dotbelowcomb }, + { 0x0131, glyph_dotlessi }, + { 0xF6BE, glyph_dotlessj }, + { 0x22C5, glyph_dotmath }, + { 0xF6EB, glyph_dsuperior }, + { 0x0065, glyph_e }, + { 0x00E9, glyph_eacute }, + { 0x0115, glyph_ebreve }, + { 0x011B, glyph_ecaron }, + { 0x00EA, glyph_ecircumflex }, + { 0x00EB, glyph_edieresis }, + { 0x0117, glyph_edotaccent }, + { 0x00E8, glyph_egrave }, + { 0x0038, glyph_eight }, + { 0x2088, glyph_eightinferior }, + { 0xF738, glyph_eightoldstyle }, + { 0x2078, glyph_eightsuperior }, + { 0x2208, glyph_element }, + { 0x2026, glyph_ellipsis }, + { 0x0113, glyph_emacron }, + { 0x2014, glyph_emdash }, + { 0x2205, glyph_emptyset }, + { 0x2013, glyph_endash }, + { 0x014B, glyph_eng }, + { 0x0119, glyph_eogonek }, + { 0x03B5, glyph_epsilon }, + { 0x03AD, glyph_epsilontonos }, + { 0x003D, glyph_equal }, + { 0x2261, glyph_equivalence }, + { 0x212E, glyph_estimated }, + { 0xF6EC, glyph_esuperior }, + { 0x03B7, glyph_eta }, + { 0x03AE, glyph_etatonos }, + { 0x00F0, glyph_eth }, + { 0x0021, glyph_exclam }, + { 0x203C, glyph_exclamdbl }, + { 0x00A1, glyph_exclamdown }, + { 0xF7A1, glyph_exclamdownsmall }, + { 0xF721, glyph_exclamsmall }, + { 0x2203, glyph_existential }, + { 0x0066, glyph_f }, + { 0x2640, glyph_female }, + { 0xFB00, glyph_ff }, + { 0xFB03, glyph_ffi }, + { 0xFB04, glyph_ffl }, + { 0xFB01, glyph_fi }, + { 0x2012, glyph_figuredash }, + { 0x25A0, glyph_filledbox }, + { 0x25AC, glyph_filledrect }, + { 0x02C9, glyph_firsttonechinese }, + { 0x0035, glyph_five }, + { 0x215D, glyph_fiveeighths }, + { 0x2085, glyph_fiveinferior }, + { 0xF735, glyph_fiveoldstyle }, + { 0x2075, glyph_fivesuperior }, + { 0xFB02, glyph_fl }, + { 0x0192, glyph_florin }, + { 0x0034, glyph_four }, + { 0x2084, glyph_fourinferior }, + { 0xF734, glyph_fouroldstyle }, + { 0x2074, glyph_foursuperior }, + { 0x2044, glyph_fraction }, + { 0x20A3, glyph_franc }, + { 0x0067, glyph_g }, + { 0x03B3, glyph_gamma }, + { 0x011F, glyph_gbreve }, + { 0x01E7, glyph_gcaron }, + { 0x011D, glyph_gcircumflex }, + { 0x0123, glyph_gcommaaccent }, + { 0x0121, glyph_gdotaccent }, + { 0x00DF, glyph_germandbls }, + { 0x2207, glyph_gradient }, + { 0x0060, glyph_grave }, + { 0x0300, glyph_gravecomb }, + { 0x003E, glyph_greater }, + { 0x2265, glyph_greaterequal }, + { 0x00AB, glyph_guillemotleft }, + { 0x00BB, glyph_guillemotright }, + { 0x2039, glyph_guilsinglleft }, + { 0x203A, glyph_guilsinglright }, + { 0x0068, glyph_h }, + { 0x0127, glyph_hbar }, + { 0x0125, glyph_hcircumflex }, + { 0x2665, glyph_heart }, + { 0x0309, glyph_hookabovecomb }, + { 0x2302, glyph_house }, + { 0x02DD, glyph_hungarumlaut }, + { 0x002D, glyph_hyphen }, + { 0xF6E5, glyph_hypheninferior }, + { 0xF6E6, glyph_hyphensuperior }, + { 0x0069, glyph_i }, + { 0x00ED, glyph_iacute }, + { 0x012D, glyph_ibreve }, + { 0x00EE, glyph_icircumflex }, + { 0x00EF, glyph_idieresis }, + { 0x00EC, glyph_igrave }, + { 0x0133, glyph_ij }, + { 0x012B, glyph_imacron }, + { 0x221E, glyph_infinity }, + { 0x222B, glyph_integral }, + { 0x2321, glyph_integralbt }, + { 0xF8F5, glyph_integralex }, + { 0x2320, glyph_integraltp }, + { 0x2229, glyph_intersection }, + { 0x25D8, glyph_invbullet }, + { 0x25D9, glyph_invcircle }, + { 0x263B, glyph_invsmileface }, + { 0x012F, glyph_iogonek }, + { 0x03B9, glyph_iota }, + { 0x03CA, glyph_iotadieresis }, + { 0x0390, glyph_iotadieresistonos }, + { 0x03AF, glyph_iotatonos }, + { 0xF6ED, glyph_isuperior }, + { 0x0129, glyph_itilde }, + { 0x006A, glyph_j }, + { 0x0135, glyph_jcircumflex }, + { 0x006B, glyph_k }, + { 0x03BA, glyph_kappa }, + { 0x0137, glyph_kcommaaccent }, + { 0x0138, glyph_kgreenlandic }, + { 0x006C, glyph_l }, + { 0x013A, glyph_lacute }, + { 0x03BB, glyph_lambda }, + { 0x013E, glyph_lcaron }, + { 0x013C, glyph_lcommaaccent }, + { 0x0140, glyph_ldot }, + { 0x003C, glyph_less }, + { 0x2264, glyph_lessequal }, + { 0x258C, glyph_lfblock }, + { 0x20A4, glyph_lira }, + { 0xF6C0, glyph_ll }, + { 0x2227, glyph_logicaland }, + { 0x00AC, glyph_logicalnot }, + { 0x2228, glyph_logicalor }, + { 0x017F, glyph_longs }, + { 0x25CA, glyph_lozenge }, + { 0x0142, glyph_lslash }, + { 0xF6EE, glyph_lsuperior }, + { 0x2591, glyph_ltshade }, + { 0x006D, glyph_m }, + { 0x00AF, glyph_macron }, + { 0x2642, glyph_male }, + { 0x2212, glyph_minus }, + { 0x2032, glyph_minute }, + { 0xF6EF, glyph_msuperior }, + { 0x00B5, glyph_mu }, + { 0x03BC, glyph_mugreek }, + { 0x00D7, glyph_multiply }, + { 0x266A, glyph_musicalnote }, + { 0x266B, glyph_musicalnotedbl }, + { 0x006E, glyph_n }, + { 0x0144, glyph_nacute }, + { 0x0149, glyph_napostrophe }, + { 0x00A0, glyph_nbspace }, + { 0x0148, glyph_ncaron }, + { 0x0146, glyph_ncommaaccent }, + { 0x0039, glyph_nine }, + { 0x2089, glyph_nineinferior }, + { 0xF739, glyph_nineoldstyle }, + { 0x2079, glyph_ninesuperior }, + { 0x2209, glyph_notelement }, + { 0x2260, glyph_notequal }, + { 0x2284, glyph_notsubset }, + { 0x207F, glyph_nsuperior }, + { 0x00F1, glyph_ntilde }, + { 0x03BD, glyph_nu }, + { 0x0023, glyph_numbersign }, + { 0x006F, glyph_o }, + { 0x00F3, glyph_oacute }, + { 0x014F, glyph_obreve }, + { 0x00F4, glyph_ocircumflex }, + { 0x00F6, glyph_odieresis }, + { 0x0153, glyph_oe }, + { 0x02DB, glyph_ogonek }, + { 0x00F2, glyph_ograve }, + { 0x01A1, glyph_ohorn }, + { 0x0151, glyph_ohungarumlaut }, + { 0x014D, glyph_omacron }, + { 0x03C9, glyph_omega }, + { 0x03D6, glyph_omega1 }, + { 0x03CE, glyph_omegatonos }, + { 0x03BF, glyph_omicron }, + { 0x03CC, glyph_omicrontonos }, + { 0x0031, glyph_one }, + { 0x2024, glyph_onedotenleader }, + { 0x215B, glyph_oneeighth }, + { 0xF6DC, glyph_onefitted }, + { 0x00BD, glyph_onehalf }, + { 0x2081, glyph_oneinferior }, + { 0xF731, glyph_oneoldstyle }, + { 0x00BC, glyph_onequarter }, + { 0x00B9, glyph_onesuperior }, + { 0x2153, glyph_onethird }, + { 0x25E6, glyph_openbullet }, + { 0x00AA, glyph_ordfeminine }, + { 0x00BA, glyph_ordmasculine }, + { 0x221F, glyph_orthogonal }, + { 0x00F8, glyph_oslash }, + { 0x01FF, glyph_oslashacute }, + { 0xF6F0, glyph_osuperior }, + { 0x00F5, glyph_otilde }, + { 0x0070, glyph_p }, + { 0x00B6, glyph_paragraph }, + { 0x0028, glyph_parenleft }, + { 0xF8ED, glyph_parenleftbt }, + { 0xF8EC, glyph_parenleftex }, + { 0x208D, glyph_parenleftinferior }, + { 0x207D, glyph_parenleftsuperior }, + { 0xF8EB, glyph_parenlefttp }, + { 0x0029, glyph_parenright }, + { 0xF8F8, glyph_parenrightbt }, + { 0xF8F7, glyph_parenrightex }, + { 0x208E, glyph_parenrightinferior }, + { 0x207E, glyph_parenrightsuperior }, + { 0xF8F6, glyph_parenrighttp }, + { 0x2202, glyph_partialdiff }, + { 0x0025, glyph_percent }, + { 0x002E, glyph_period }, + { 0x00B7, glyph_periodcentered }, + { 0xF6E7, glyph_periodinferior }, + { 0xF6E8, glyph_periodsuperior }, + { 0x22A5, glyph_perpendicular }, + { 0x2030, glyph_perthousand }, + { 0x20A7, glyph_peseta }, + { 0x03C6, glyph_phi }, + { 0x03D5, glyph_phi1 }, + { 0x03C0, glyph_pi }, + { 0x002B, glyph_plus }, + { 0x00B1, glyph_plusminus }, + { 0x211E, glyph_prescription }, + { 0x220F, glyph_product }, + { 0x2282, glyph_propersubset }, + { 0x2283, glyph_propersuperset }, + { 0x221D, glyph_proportional }, + { 0x03C8, glyph_psi }, + { 0x0071, glyph_q }, + { 0x003F, glyph_question }, + { 0x00BF, glyph_questiondown }, + { 0xF7BF, glyph_questiondownsmall }, + { 0xF73F, glyph_questionsmall }, + { 0x0022, glyph_quotedbl }, + { 0x201E, glyph_quotedblbase }, + { 0x201C, glyph_quotedblleft }, + { 0x201D, glyph_quotedblright }, + { 0x2018, glyph_quoteleft }, + { 0x201B, glyph_quotereversed }, + { 0x2019, glyph_quoteright }, + { 0x201A, glyph_quotesinglbase }, + { 0x0027, glyph_quotesingle }, + { 0x0072, glyph_r }, + { 0x0155, glyph_racute }, + { 0x221A, glyph_radical }, + { 0xF8E5, glyph_radicalex }, + { 0x0159, glyph_rcaron }, + { 0x0157, glyph_rcommaaccent }, + { 0x2286, glyph_reflexsubset }, + { 0x2287, glyph_reflexsuperset }, + { 0x00AE, glyph_registered }, + { 0xF8E8, glyph_registersans }, + { 0xF6DA, glyph_registerserif }, + { 0x2310, glyph_revlogicalnot }, + { 0x03C1, glyph_rho }, + { 0x02DA, glyph_ring }, + { 0xF6F1, glyph_rsuperior }, + { 0x2590, glyph_rtblock }, + { 0xF6DD, glyph_rupiah }, + { 0x0073, glyph_s }, + { 0x015B, glyph_sacute }, + { 0x0161, glyph_scaron }, + { 0x015F, glyph_scedilla }, + { 0x015D, glyph_scircumflex }, + { 0x0219, glyph_scommaaccent }, + { 0x2033, glyph_second }, + { 0x00A7, glyph_section }, + { 0x003B, glyph_semicolon }, + { 0x0037, glyph_seven }, + { 0x215E, glyph_seveneighths }, + { 0x2087, glyph_seveninferior }, + { 0xF737, glyph_sevenoldstyle }, + { 0x2077, glyph_sevensuperior }, + { 0x00AD, glyph_sfthyphen }, + { 0x2592, glyph_shade }, + { 0x03C3, glyph_sigma }, + { 0x03C2, glyph_sigma1 }, + { 0x223C, glyph_similar }, + { 0x0036, glyph_six }, + { 0x2086, glyph_sixinferior }, + { 0xF736, glyph_sixoldstyle }, + { 0x2076, glyph_sixsuperior }, + { 0x002F, glyph_slash }, + { 0x263A, glyph_smileface }, + { 0x0020, glyph_space }, + { 0x2660, glyph_spade }, + { 0xF6F2, glyph_ssuperior }, + { 0x00A3, glyph_sterling }, + { 0x220B, glyph_suchthat }, + { 0x2211, glyph_summation }, + { 0x263C, glyph_sun }, + { 0x0074, glyph_t }, + { 0x03C4, glyph_tau }, + { 0x0167, glyph_tbar }, + { 0x0165, glyph_tcaron }, + { 0x0163, glyph_tcedilla }, + { 0x021B, glyph_tcommaaccent }, + { 0x2234, glyph_therefore }, + { 0x03B8, glyph_theta }, + { 0x03D1, glyph_theta1 }, + { 0x00FE, glyph_thorn }, + { 0x0033, glyph_three }, + { 0x215C, glyph_threeeighths }, + { 0x2083, glyph_threeinferior }, + { 0xF733, glyph_threeoldstyle }, + { 0x00BE, glyph_threequarters }, + { 0xF6DE, glyph_threequartersemdash }, + { 0x00B3, glyph_threesuperior }, + { 0x02DC, glyph_tilde }, + { 0x0303, glyph_tildecomb }, + { 0x0384, glyph_tonos }, + { 0x2122, glyph_trademark }, + { 0xF8EA, glyph_trademarksans }, + { 0xF6DB, glyph_trademarkserif }, + { 0x25BC, glyph_triagdn }, + { 0x25C4, glyph_triaglf }, + { 0x25BA, glyph_triagrt }, + { 0x25B2, glyph_triagup }, + { 0xF6F3, glyph_tsuperior }, + { 0x0032, glyph_two }, + { 0x2025, glyph_twodotenleader }, + { 0x2082, glyph_twoinferior }, + { 0xF732, glyph_twooldstyle }, + { 0x00B2, glyph_twosuperior }, + { 0x2154, glyph_twothirds }, + { 0x0075, glyph_u }, + { 0x00FA, glyph_uacute }, + { 0x016D, glyph_ubreve }, + { 0x00FB, glyph_ucircumflex }, + { 0x00FC, glyph_udieresis }, + { 0x00F9, glyph_ugrave }, + { 0x01B0, glyph_uhorn }, + { 0x0171, glyph_uhungarumlaut }, + { 0x016B, glyph_umacron }, + { 0x005F, glyph_underscore }, + { 0x2017, glyph_underscoredbl }, + { 0x222A, glyph_union }, + { 0x2200, glyph_universal }, + { 0x0173, glyph_uogonek }, + { 0x2580, glyph_upblock }, + { 0x03C5, glyph_upsilon }, + { 0x03CB, glyph_upsilondieresis }, + { 0x03B0, glyph_upsilondieresistonos }, + { 0x03CD, glyph_upsilontonos }, + { 0x016F, glyph_uring }, + { 0x0169, glyph_utilde }, + { 0x0076, glyph_v }, + { 0x0077, glyph_w }, + { 0x1E83, glyph_wacute }, + { 0x0175, glyph_wcircumflex }, + { 0x1E85, glyph_wdieresis }, + { 0x2118, glyph_weierstrass }, + { 0x1E81, glyph_wgrave }, + { 0x0078, glyph_x }, + { 0x03BE, glyph_xi }, + { 0x0079, glyph_y }, + { 0x00FD, glyph_yacute }, + { 0x0177, glyph_ycircumflex }, + { 0x00FF, glyph_ydieresis }, + { 0x00A5, glyph_yen }, + { 0x1EF3, glyph_ygrave }, + { 0x007A, glyph_z }, + { 0x017A, glyph_zacute }, + { 0x017E, glyph_zcaron }, + { 0x017C, glyph_zdotaccent }, + { 0x0030, glyph_zero }, + { 0x2080, glyph_zeroinferior }, + { 0xF730, glyph_zerooldstyle }, + { 0x2070, glyph_zerosuperior }, + { 0x03B6, glyph_zeta }, +#else +#endif +}; /* tab_agl2uni */ + +/* + * Adobe Glyph List (AGL) version 1.2 - sorted by Unicode values + */ +static const pdc_glyph_tab tab_uni2agl[] = +{ + { 0x0020, glyph_space }, + { 0x0021, glyph_exclam }, + { 0x0022, glyph_quotedbl }, + { 0x0023, glyph_numbersign }, + { 0x0024, glyph_dollar }, + { 0x0025, glyph_percent }, + { 0x0026, glyph_ampersand }, + { 0x0027, glyph_quotesingle }, + { 0x0028, glyph_parenleft }, + { 0x0029, glyph_parenright }, + { 0x002A, glyph_asterisk }, + { 0x002B, glyph_plus }, + { 0x002C, glyph_comma }, + { 0x002D, glyph_hyphen }, + { 0x002E, glyph_period }, + { 0x002F, glyph_slash }, + { 0x0030, glyph_zero }, + { 0x0031, glyph_one }, + { 0x0032, glyph_two }, + { 0x0033, glyph_three }, + { 0x0034, glyph_four }, + { 0x0035, glyph_five }, + { 0x0036, glyph_six }, + { 0x0037, glyph_seven }, + { 0x0038, glyph_eight }, + { 0x0039, glyph_nine }, + { 0x003A, glyph_colon }, + { 0x003B, glyph_semicolon }, + { 0x003C, glyph_less }, + { 0x003D, glyph_equal }, + { 0x003E, glyph_greater }, + { 0x003F, glyph_question }, + { 0x0040, glyph_at }, + { 0x0041, glyph_A }, + { 0x0042, glyph_B }, + { 0x0043, glyph_C }, + { 0x0044, glyph_D }, + { 0x0045, glyph_E }, + { 0x0046, glyph_F }, + { 0x0047, glyph_G }, + { 0x0048, glyph_H }, + { 0x0049, glyph_I }, + { 0x004A, glyph_J }, + { 0x004B, glyph_K }, + { 0x004C, glyph_L }, + { 0x004D, glyph_M }, + { 0x004E, glyph_N }, + { 0x004F, glyph_O }, + { 0x0050, glyph_P }, + { 0x0051, glyph_Q }, + { 0x0052, glyph_R }, + { 0x0053, glyph_S }, + { 0x0054, glyph_T }, + { 0x0055, glyph_U }, + { 0x0056, glyph_V }, + { 0x0057, glyph_W }, + { 0x0058, glyph_X }, + { 0x0059, glyph_Y }, + { 0x005A, glyph_Z }, + { 0x005B, glyph_bracketleft }, + { 0x005C, glyph_backslash }, + { 0x005D, glyph_bracketright }, + { 0x005E, glyph_asciicircum }, + { 0x005F, glyph_underscore }, + { 0x0060, glyph_grave }, + { 0x0061, glyph_a }, + { 0x0062, glyph_b }, + { 0x0063, glyph_c }, + { 0x0064, glyph_d }, + { 0x0065, glyph_e }, + { 0x0066, glyph_f }, + { 0x0067, glyph_g }, + { 0x0068, glyph_h }, + { 0x0069, glyph_i }, + { 0x006A, glyph_j }, + { 0x006B, glyph_k }, + { 0x006C, glyph_l }, + { 0x006D, glyph_m }, + { 0x006E, glyph_n }, + { 0x006F, glyph_o }, + { 0x0070, glyph_p }, + { 0x0071, glyph_q }, + { 0x0072, glyph_r }, + { 0x0073, glyph_s }, + { 0x0074, glyph_t }, + { 0x0075, glyph_u }, + { 0x0076, glyph_v }, + { 0x0077, glyph_w }, + { 0x0078, glyph_x }, + { 0x0079, glyph_y }, + { 0x007A, glyph_z }, + { 0x007B, glyph_braceleft }, + { 0x007C, glyph_bar }, + { 0x007D, glyph_braceright }, + { 0x007E, glyph_asciitilde }, + { 0x00A0, glyph_nbspace }, + { 0x00A1, glyph_exclamdown }, + { 0x00A2, glyph_cent }, + { 0x00A3, glyph_sterling }, + { 0x00A4, glyph_currency }, + { 0x00A5, glyph_yen }, + { 0x00A6, glyph_brokenbar }, + { 0x00A7, glyph_section }, + { 0x00A8, glyph_dieresis }, + { 0x00A9, glyph_copyright }, + { 0x00AA, glyph_ordfeminine }, + { 0x00AB, glyph_guillemotleft }, + { 0x00AC, glyph_logicalnot }, + { 0x00AD, glyph_sfthyphen }, + { 0x00AE, glyph_registered }, + { 0x00AF, glyph_macron }, + { 0x00B0, glyph_degree }, + { 0x00B1, glyph_plusminus }, + { 0x00B2, glyph_twosuperior }, + { 0x00B3, glyph_threesuperior }, + { 0x00B4, glyph_acute }, + { 0x00B5, glyph_mu }, + { 0x00B6, glyph_paragraph }, + { 0x00B7, glyph_periodcentered }, + { 0x00B8, glyph_cedilla }, + { 0x00B9, glyph_onesuperior }, + { 0x00BA, glyph_ordmasculine }, + { 0x00BB, glyph_guillemotright }, + { 0x00BC, glyph_onequarter }, + { 0x00BD, glyph_onehalf }, + { 0x00BE, glyph_threequarters }, + { 0x00BF, glyph_questiondown }, + { 0x00C0, glyph_Agrave }, + { 0x00C1, glyph_Aacute }, + { 0x00C2, glyph_Acircumflex }, + { 0x00C3, glyph_Atilde }, + { 0x00C4, glyph_Adieresis }, + { 0x00C5, glyph_Aring }, + { 0x00C6, glyph_AE }, + { 0x00C7, glyph_Ccedilla }, + { 0x00C8, glyph_Egrave }, + { 0x00C9, glyph_Eacute }, + { 0x00CA, glyph_Ecircumflex }, + { 0x00CB, glyph_Edieresis }, + { 0x00CC, glyph_Igrave }, + { 0x00CD, glyph_Iacute }, + { 0x00CE, glyph_Icircumflex }, + { 0x00CF, glyph_Idieresis }, + { 0x00D0, glyph_Eth }, + { 0x00D1, glyph_Ntilde }, + { 0x00D2, glyph_Ograve }, + { 0x00D3, glyph_Oacute }, + { 0x00D4, glyph_Ocircumflex }, + { 0x00D5, glyph_Otilde }, + { 0x00D6, glyph_Odieresis }, + { 0x00D7, glyph_multiply }, + { 0x00D8, glyph_Oslash }, + { 0x00D9, glyph_Ugrave }, + { 0x00DA, glyph_Uacute }, + { 0x00DB, glyph_Ucircumflex }, + { 0x00DC, glyph_Udieresis }, + { 0x00DD, glyph_Yacute }, + { 0x00DE, glyph_Thorn }, + { 0x00DF, glyph_germandbls }, + { 0x00E0, glyph_agrave }, + { 0x00E1, glyph_aacute }, + { 0x00E2, glyph_acircumflex }, + { 0x00E3, glyph_atilde }, + { 0x00E4, glyph_adieresis }, + { 0x00E5, glyph_aring }, + { 0x00E6, glyph_ae }, + { 0x00E7, glyph_ccedilla }, + { 0x00E8, glyph_egrave }, + { 0x00E9, glyph_eacute }, + { 0x00EA, glyph_ecircumflex }, + { 0x00EB, glyph_edieresis }, + { 0x00EC, glyph_igrave }, + { 0x00ED, glyph_iacute }, + { 0x00EE, glyph_icircumflex }, + { 0x00EF, glyph_idieresis }, + { 0x00F0, glyph_eth }, + { 0x00F1, glyph_ntilde }, + { 0x00F2, glyph_ograve }, + { 0x00F3, glyph_oacute }, + { 0x00F4, glyph_ocircumflex }, + { 0x00F5, glyph_otilde }, + { 0x00F6, glyph_odieresis }, + { 0x00F7, glyph_divide }, + { 0x00F8, glyph_oslash }, + { 0x00F9, glyph_ugrave }, + { 0x00FA, glyph_uacute }, + { 0x00FB, glyph_ucircumflex }, + { 0x00FC, glyph_udieresis }, + { 0x00FD, glyph_yacute }, + { 0x00FE, glyph_thorn }, + { 0x00FF, glyph_ydieresis }, + { 0x0100, glyph_Amacron }, + { 0x0101, glyph_amacron }, + { 0x0102, glyph_Abreve }, + { 0x0103, glyph_abreve }, + { 0x0104, glyph_Aogonek }, + { 0x0105, glyph_aogonek }, + { 0x0106, glyph_Cacute }, + { 0x0107, glyph_cacute }, + { 0x0108, glyph_Ccircumflex }, + { 0x0109, glyph_ccircumflex }, + { 0x010A, glyph_Cdotaccent }, + { 0x010B, glyph_cdotaccent }, + { 0x010C, glyph_Ccaron }, + { 0x010D, glyph_ccaron }, + { 0x010E, glyph_Dcaron }, + { 0x010F, glyph_dcaron }, + { 0x0110, glyph_Dcroat }, + { 0x0111, glyph_dcroat }, + { 0x0112, glyph_Emacron }, + { 0x0113, glyph_emacron }, + { 0x0114, glyph_Ebreve }, + { 0x0115, glyph_ebreve }, + { 0x0116, glyph_Edotaccent }, + { 0x0117, glyph_edotaccent }, + { 0x0118, glyph_Eogonek }, + { 0x0119, glyph_eogonek }, + { 0x011A, glyph_Ecaron }, + { 0x011B, glyph_ecaron }, + { 0x011C, glyph_Gcircumflex }, + { 0x011D, glyph_gcircumflex }, + { 0x011E, glyph_Gbreve }, + { 0x011F, glyph_gbreve }, + { 0x0120, glyph_Gdotaccent }, + { 0x0121, glyph_gdotaccent }, + { 0x0122, glyph_Gcommaaccent }, + { 0x0123, glyph_gcommaaccent }, + { 0x0124, glyph_Hcircumflex }, + { 0x0125, glyph_hcircumflex }, + { 0x0126, glyph_Hbar }, + { 0x0127, glyph_hbar }, + { 0x0128, glyph_Itilde }, + { 0x0129, glyph_itilde }, + { 0x012A, glyph_Imacron }, + { 0x012B, glyph_imacron }, + { 0x012C, glyph_Ibreve }, + { 0x012D, glyph_ibreve }, + { 0x012E, glyph_Iogonek }, + { 0x012F, glyph_iogonek }, + { 0x0130, glyph_Idotaccent }, + { 0x0131, glyph_dotlessi }, + { 0x0132, glyph_IJ }, + { 0x0133, glyph_ij }, + { 0x0134, glyph_Jcircumflex }, + { 0x0135, glyph_jcircumflex }, + { 0x0136, glyph_Kcommaaccent }, + { 0x0137, glyph_kcommaaccent }, + { 0x0138, glyph_kgreenlandic }, + { 0x0139, glyph_Lacute }, + { 0x013A, glyph_lacute }, + { 0x013B, glyph_Lcommaaccent }, + { 0x013C, glyph_lcommaaccent }, + { 0x013D, glyph_Lcaron }, + { 0x013E, glyph_lcaron }, + { 0x013F, glyph_Ldot }, + { 0x0140, glyph_ldot }, + { 0x0141, glyph_Lslash }, + { 0x0142, glyph_lslash }, + { 0x0143, glyph_Nacute }, + { 0x0144, glyph_nacute }, + { 0x0145, glyph_Ncommaaccent }, + { 0x0146, glyph_ncommaaccent }, + { 0x0147, glyph_Ncaron }, + { 0x0148, glyph_ncaron }, + { 0x0149, glyph_napostrophe }, + { 0x014A, glyph_Eng }, + { 0x014B, glyph_eng }, + { 0x014C, glyph_Omacron }, + { 0x014D, glyph_omacron }, + { 0x014E, glyph_Obreve }, + { 0x014F, glyph_obreve }, + { 0x0150, glyph_Ohungarumlaut }, + { 0x0151, glyph_ohungarumlaut }, + { 0x0152, glyph_OE }, + { 0x0153, glyph_oe }, + { 0x0154, glyph_Racute }, + { 0x0155, glyph_racute }, + { 0x0156, glyph_Rcommaaccent }, + { 0x0157, glyph_rcommaaccent }, + { 0x0158, glyph_Rcaron }, + { 0x0159, glyph_rcaron }, + { 0x015A, glyph_Sacute }, + { 0x015B, glyph_sacute }, + { 0x015C, glyph_Scircumflex }, + { 0x015D, glyph_scircumflex }, + { 0x015E, glyph_Scedilla }, + { 0x015F, glyph_scedilla }, + { 0x0160, glyph_Scaron }, + { 0x0161, glyph_scaron }, + { 0x0162, glyph_Tcedilla }, + { 0x0163, glyph_tcedilla }, + { 0x0164, glyph_Tcaron }, + { 0x0165, glyph_tcaron }, + { 0x0166, glyph_Tbar }, + { 0x0167, glyph_tbar }, + { 0x0168, glyph_Utilde }, + { 0x0169, glyph_utilde }, + { 0x016A, glyph_Umacron }, + { 0x016B, glyph_umacron }, + { 0x016C, glyph_Ubreve }, + { 0x016D, glyph_ubreve }, + { 0x016E, glyph_Uring }, + { 0x016F, glyph_uring }, + { 0x0170, glyph_Uhungarumlaut }, + { 0x0171, glyph_uhungarumlaut }, + { 0x0172, glyph_Uogonek }, + { 0x0173, glyph_uogonek }, + { 0x0174, glyph_Wcircumflex }, + { 0x0175, glyph_wcircumflex }, + { 0x0176, glyph_Ycircumflex }, + { 0x0177, glyph_ycircumflex }, + { 0x0178, glyph_Ydieresis }, + { 0x0179, glyph_Zacute }, + { 0x017A, glyph_zacute }, + { 0x017B, glyph_Zdotaccent }, + { 0x017C, glyph_zdotaccent }, + { 0x017D, glyph_Zcaron }, + { 0x017E, glyph_zcaron }, + { 0x017F, glyph_longs }, + { 0x0192, glyph_florin }, + { 0x01A0, glyph_Ohorn }, + { 0x01A1, glyph_ohorn }, + { 0x01AF, glyph_Uhorn }, + { 0x01B0, glyph_uhorn }, + { 0x01E6, glyph_Gcaron }, + { 0x01E7, glyph_gcaron }, + { 0x01FA, glyph_Aringacute }, + { 0x01FB, glyph_aringacute }, + { 0x01FC, glyph_AEacute }, + { 0x01FD, glyph_aeacute }, + { 0x01FE, glyph_Oslashacute }, + { 0x01FF, glyph_oslashacute }, + { 0x0218, glyph_Scommaaccent }, + { 0x0219, glyph_scommaaccent }, + { 0x021A, glyph_Tcommaaccent }, + { 0x021B, glyph_tcommaaccent }, + { 0x02BC, glyph_afii57929 }, + { 0x02BD, glyph_afii64937 }, + { 0x02C6, glyph_circumflex }, + { 0x02C7, glyph_caron }, + { 0x02C9, glyph_firsttonechinese }, + { 0x02D8, glyph_breve }, + { 0x02D9, glyph_dotaccent }, + { 0x02DA, glyph_ring }, + { 0x02DB, glyph_ogonek }, + { 0x02DC, glyph_tilde }, + { 0x02DD, glyph_hungarumlaut }, + { 0x0300, glyph_gravecomb }, + { 0x0301, glyph_acutecomb }, + { 0x0303, glyph_tildecomb }, + { 0x0309, glyph_hookabovecomb }, + { 0x0323, glyph_dotbelowcomb }, + { 0x0384, glyph_tonos }, + { 0x0385, glyph_dieresistonos }, + { 0x0386, glyph_Alphatonos }, + { 0x0387, glyph_anoteleia }, + { 0x0388, glyph_Epsilontonos }, + { 0x0389, glyph_Etatonos }, + { 0x038A, glyph_Iotatonos }, + { 0x038C, glyph_Omicrontonos }, + { 0x038E, glyph_Upsilontonos }, + { 0x038F, glyph_Omegatonos }, + { 0x0390, glyph_iotadieresistonos }, + { 0x0391, glyph_Alpha }, + { 0x0392, glyph_Beta }, + { 0x0393, glyph_Gamma }, + { 0x0394, glyph_Deltagreek }, + { 0x0395, glyph_Epsilon }, + { 0x0396, glyph_Zeta }, + { 0x0397, glyph_Eta }, + { 0x0398, glyph_Theta }, + { 0x0399, glyph_Iota }, + { 0x039A, glyph_Kappa }, + { 0x039B, glyph_Lambda }, + { 0x039C, glyph_Mu }, + { 0x039D, glyph_Nu }, + { 0x039E, glyph_Xi }, + { 0x039F, glyph_Omicron }, + { 0x03A0, glyph_Pi }, + { 0x03A1, glyph_Rho }, + { 0x03A3, glyph_Sigma }, + { 0x03A4, glyph_Tau }, + { 0x03A5, glyph_Upsilon }, + { 0x03A6, glyph_Phi }, + { 0x03A7, glyph_Chi }, + { 0x03A8, glyph_Psi }, + { 0x03A9, glyph_Omegagreek }, + { 0x03AA, glyph_Iotadieresis }, + { 0x03AB, glyph_Upsilondieresis }, + { 0x03AC, glyph_alphatonos }, + { 0x03AD, glyph_epsilontonos }, + { 0x03AE, glyph_etatonos }, + { 0x03AF, glyph_iotatonos }, + { 0x03B0, glyph_upsilondieresistonos }, + { 0x03B1, glyph_alpha }, + { 0x03B2, glyph_beta }, + { 0x03B3, glyph_gamma }, + { 0x03B4, glyph_delta }, + { 0x03B5, glyph_epsilon }, + { 0x03B6, glyph_zeta }, + { 0x03B7, glyph_eta }, + { 0x03B8, glyph_theta }, + { 0x03B9, glyph_iota }, + { 0x03BA, glyph_kappa }, + { 0x03BB, glyph_lambda }, + { 0x03BC, glyph_mugreek }, + { 0x03BD, glyph_nu }, + { 0x03BE, glyph_xi }, + { 0x03BF, glyph_omicron }, + { 0x03C0, glyph_pi }, + { 0x03C1, glyph_rho }, + { 0x03C2, glyph_sigma1 }, + { 0x03C3, glyph_sigma }, + { 0x03C4, glyph_tau }, + { 0x03C5, glyph_upsilon }, + { 0x03C6, glyph_phi }, + { 0x03C7, glyph_chi }, + { 0x03C8, glyph_psi }, + { 0x03C9, glyph_omega }, + { 0x03CA, glyph_iotadieresis }, + { 0x03CB, glyph_upsilondieresis }, + { 0x03CC, glyph_omicrontonos }, + { 0x03CD, glyph_upsilontonos }, + { 0x03CE, glyph_omegatonos }, + { 0x03D1, glyph_theta1 }, + { 0x03D2, glyph_Upsilon1 }, + { 0x03D5, glyph_phi1 }, + { 0x03D6, glyph_omega1 }, + { 0x0401, glyph_afii10023 }, + { 0x0402, glyph_afii10051 }, + { 0x0403, glyph_afii10052 }, + { 0x0404, glyph_afii10053 }, + { 0x0405, glyph_afii10054 }, + { 0x0406, glyph_afii10055 }, + { 0x0407, glyph_afii10056 }, + { 0x0408, glyph_afii10057 }, + { 0x0409, glyph_afii10058 }, + { 0x040A, glyph_afii10059 }, + { 0x040B, glyph_afii10060 }, + { 0x040C, glyph_afii10061 }, + { 0x040E, glyph_afii10062 }, + { 0x040F, glyph_afii10145 }, + { 0x0410, glyph_afii10017 }, + { 0x0411, glyph_afii10018 }, + { 0x0412, glyph_afii10019 }, + { 0x0413, glyph_afii10020 }, + { 0x0414, glyph_afii10021 }, + { 0x0415, glyph_afii10022 }, + { 0x0416, glyph_afii10024 }, + { 0x0417, glyph_afii10025 }, + { 0x0418, glyph_afii10026 }, + { 0x0419, glyph_afii10027 }, + { 0x041A, glyph_afii10028 }, + { 0x041B, glyph_afii10029 }, + { 0x041C, glyph_afii10030 }, + { 0x041D, glyph_afii10031 }, + { 0x041E, glyph_afii10032 }, + { 0x041F, glyph_afii10033 }, + { 0x0420, glyph_afii10034 }, + { 0x0421, glyph_afii10035 }, + { 0x0422, glyph_afii10036 }, + { 0x0423, glyph_afii10037 }, + { 0x0424, glyph_afii10038 }, + { 0x0425, glyph_afii10039 }, + { 0x0426, glyph_afii10040 }, + { 0x0427, glyph_afii10041 }, + { 0x0428, glyph_afii10042 }, + { 0x0429, glyph_afii10043 }, + { 0x042A, glyph_afii10044 }, + { 0x042B, glyph_afii10045 }, + { 0x042C, glyph_afii10046 }, + { 0x042D, glyph_afii10047 }, + { 0x042E, glyph_afii10048 }, + { 0x042F, glyph_afii10049 }, + { 0x0430, glyph_afii10065 }, + { 0x0431, glyph_afii10066 }, + { 0x0432, glyph_afii10067 }, + { 0x0433, glyph_afii10068 }, + { 0x0434, glyph_afii10069 }, + { 0x0435, glyph_afii10070 }, + { 0x0436, glyph_afii10072 }, + { 0x0437, glyph_afii10073 }, + { 0x0438, glyph_afii10074 }, + { 0x0439, glyph_afii10075 }, + { 0x043A, glyph_afii10076 }, + { 0x043B, glyph_afii10077 }, + { 0x043C, glyph_afii10078 }, + { 0x043D, glyph_afii10079 }, + { 0x043E, glyph_afii10080 }, + { 0x043F, glyph_afii10081 }, + { 0x0440, glyph_afii10082 }, + { 0x0441, glyph_afii10083 }, + { 0x0442, glyph_afii10084 }, + { 0x0443, glyph_afii10085 }, + { 0x0444, glyph_afii10086 }, + { 0x0445, glyph_afii10087 }, + { 0x0446, glyph_afii10088 }, + { 0x0447, glyph_afii10089 }, + { 0x0448, glyph_afii10090 }, + { 0x0449, glyph_afii10091 }, + { 0x044A, glyph_afii10092 }, + { 0x044B, glyph_afii10093 }, + { 0x044C, glyph_afii10094 }, + { 0x044D, glyph_afii10095 }, + { 0x044E, glyph_afii10096 }, + { 0x044F, glyph_afii10097 }, + { 0x0451, glyph_afii10071 }, + { 0x0452, glyph_afii10099 }, + { 0x0453, glyph_afii10100 }, + { 0x0454, glyph_afii10101 }, + { 0x0455, glyph_afii10102 }, + { 0x0456, glyph_afii10103 }, + { 0x0457, glyph_afii10104 }, + { 0x0458, glyph_afii10105 }, + { 0x0459, glyph_afii10106 }, + { 0x045A, glyph_afii10107 }, + { 0x045B, glyph_afii10108 }, + { 0x045C, glyph_afii10109 }, + { 0x045E, glyph_afii10110 }, + { 0x045F, glyph_afii10193 }, + { 0x0462, glyph_afii10146 }, + { 0x0463, glyph_afii10194 }, + { 0x0472, glyph_afii10147 }, + { 0x0473, glyph_afii10195 }, + { 0x0474, glyph_afii10148 }, + { 0x0475, glyph_afii10196 }, + { 0x0490, glyph_afii10050 }, + { 0x0491, glyph_afii10098 }, + { 0x04D9, glyph_afii10846 }, + { 0x05B0, glyph_afii57799 }, + { 0x05B1, glyph_afii57801 }, + { 0x05B2, glyph_afii57800 }, + { 0x05B3, glyph_afii57802 }, + { 0x05B4, glyph_afii57793 }, + { 0x05B5, glyph_afii57794 }, + { 0x05B6, glyph_afii57795 }, + { 0x05B7, glyph_afii57798 }, + { 0x05B8, glyph_afii57797 }, + { 0x05B9, glyph_afii57806 }, + { 0x05BB, glyph_afii57796 }, + { 0x05BC, glyph_afii57807 }, + { 0x05BD, glyph_afii57839 }, + { 0x05BE, glyph_afii57645 }, + { 0x05BF, glyph_afii57841 }, + { 0x05C0, glyph_afii57842 }, + { 0x05C1, glyph_afii57804 }, + { 0x05C2, glyph_afii57803 }, + { 0x05C3, glyph_afii57658 }, + { 0x05D0, glyph_afii57664 }, + { 0x05D1, glyph_afii57665 }, + { 0x05D2, glyph_afii57666 }, + { 0x05D3, glyph_afii57667 }, + { 0x05D4, glyph_afii57668 }, + { 0x05D5, glyph_afii57669 }, + { 0x05D6, glyph_afii57670 }, + { 0x05D7, glyph_afii57671 }, + { 0x05D8, glyph_afii57672 }, + { 0x05D9, glyph_afii57673 }, + { 0x05DA, glyph_afii57674 }, + { 0x05DB, glyph_afii57675 }, + { 0x05DC, glyph_afii57676 }, + { 0x05DD, glyph_afii57677 }, + { 0x05DE, glyph_afii57678 }, + { 0x05DF, glyph_afii57679 }, + { 0x05E0, glyph_afii57680 }, + { 0x05E1, glyph_afii57681 }, + { 0x05E2, glyph_afii57682 }, + { 0x05E3, glyph_afii57683 }, + { 0x05E4, glyph_afii57684 }, + { 0x05E5, glyph_afii57685 }, + { 0x05E6, glyph_afii57686 }, + { 0x05E7, glyph_afii57687 }, + { 0x05E8, glyph_afii57688 }, + { 0x05E9, glyph_afii57689 }, + { 0x05EA, glyph_afii57690 }, + { 0x05F0, glyph_afii57716 }, + { 0x05F1, glyph_afii57717 }, + { 0x05F2, glyph_afii57718 }, + { 0x060C, glyph_afii57388 }, + { 0x061B, glyph_afii57403 }, + { 0x061F, glyph_afii57407 }, + { 0x0621, glyph_afii57409 }, + { 0x0622, glyph_afii57410 }, + { 0x0623, glyph_afii57411 }, + { 0x0624, glyph_afii57412 }, + { 0x0625, glyph_afii57413 }, + { 0x0626, glyph_afii57414 }, + { 0x0627, glyph_afii57415 }, + { 0x0628, glyph_afii57416 }, + { 0x0629, glyph_afii57417 }, + { 0x062A, glyph_afii57418 }, + { 0x062B, glyph_afii57419 }, + { 0x062C, glyph_afii57420 }, + { 0x062D, glyph_afii57421 }, + { 0x062E, glyph_afii57422 }, + { 0x062F, glyph_afii57423 }, + { 0x0630, glyph_afii57424 }, + { 0x0631, glyph_afii57425 }, + { 0x0632, glyph_afii57426 }, + { 0x0633, glyph_afii57427 }, + { 0x0634, glyph_afii57428 }, + { 0x0635, glyph_afii57429 }, + { 0x0636, glyph_afii57430 }, + { 0x0637, glyph_afii57431 }, + { 0x0638, glyph_afii57432 }, + { 0x0639, glyph_afii57433 }, + { 0x063A, glyph_afii57434 }, + { 0x0640, glyph_afii57440 }, + { 0x0641, glyph_afii57441 }, + { 0x0642, glyph_afii57442 }, + { 0x0643, glyph_afii57443 }, + { 0x0644, glyph_afii57444 }, + { 0x0645, glyph_afii57445 }, + { 0x0646, glyph_afii57446 }, + { 0x0647, glyph_afii57470 }, + { 0x0648, glyph_afii57448 }, + { 0x0649, glyph_afii57449 }, + { 0x064A, glyph_afii57450 }, + { 0x064B, glyph_afii57451 }, + { 0x064C, glyph_afii57452 }, + { 0x064D, glyph_afii57453 }, + { 0x064E, glyph_afii57454 }, + { 0x064F, glyph_afii57455 }, + { 0x0650, glyph_afii57456 }, + { 0x0651, glyph_afii57457 }, + { 0x0652, glyph_afii57458 }, + { 0x0660, glyph_afii57392 }, + { 0x0661, glyph_afii57393 }, + { 0x0662, glyph_afii57394 }, + { 0x0663, glyph_afii57395 }, + { 0x0664, glyph_afii57396 }, + { 0x0665, glyph_afii57397 }, + { 0x0666, glyph_afii57398 }, + { 0x0667, glyph_afii57399 }, + { 0x0668, glyph_afii57400 }, + { 0x0669, glyph_afii57401 }, + { 0x066A, glyph_afii57381 }, + { 0x066D, glyph_afii63167 }, + { 0x0679, glyph_afii57511 }, + { 0x067E, glyph_afii57506 }, + { 0x0686, glyph_afii57507 }, + { 0x0688, glyph_afii57512 }, + { 0x0691, glyph_afii57513 }, + { 0x0698, glyph_afii57508 }, + { 0x06A4, glyph_afii57505 }, + { 0x06AF, glyph_afii57509 }, + { 0x06BA, glyph_afii57514 }, + { 0x06D2, glyph_afii57519 }, + { 0x06D5, glyph_afii57534 }, + { 0x1E80, glyph_Wgrave }, + { 0x1E81, glyph_wgrave }, + { 0x1E82, glyph_Wacute }, + { 0x1E83, glyph_wacute }, + { 0x1E84, glyph_Wdieresis }, + { 0x1E85, glyph_wdieresis }, + { 0x1EF2, glyph_Ygrave }, + { 0x1EF3, glyph_ygrave }, + { 0x200C, glyph_afii61664 }, + { 0x200D, glyph_afii301 }, + { 0x200E, glyph_afii299 }, + { 0x200F, glyph_afii300 }, + { 0x2012, glyph_figuredash }, + { 0x2013, glyph_endash }, + { 0x2014, glyph_emdash }, + { 0x2015, glyph_afii00208 }, + { 0x2017, glyph_underscoredbl }, + { 0x2018, glyph_quoteleft }, + { 0x2019, glyph_quoteright }, + { 0x201A, glyph_quotesinglbase }, + { 0x201B, glyph_quotereversed }, + { 0x201C, glyph_quotedblleft }, + { 0x201D, glyph_quotedblright }, + { 0x201E, glyph_quotedblbase }, + { 0x2020, glyph_dagger }, + { 0x2021, glyph_daggerdbl }, + { 0x2022, glyph_bullet }, + { 0x2024, glyph_onedotenleader }, + { 0x2025, glyph_twodotenleader }, + { 0x2026, glyph_ellipsis }, + { 0x202C, glyph_afii61573 }, + { 0x202D, glyph_afii61574 }, + { 0x202E, glyph_afii61575 }, + { 0x2030, glyph_perthousand }, + { 0x2032, glyph_minute }, + { 0x2033, glyph_second }, + { 0x2039, glyph_guilsinglleft }, + { 0x203A, glyph_guilsinglright }, + { 0x203C, glyph_exclamdbl }, + { 0x2044, glyph_fraction }, + { 0x2070, glyph_zerosuperior }, + { 0x2074, glyph_foursuperior }, + { 0x2075, glyph_fivesuperior }, + { 0x2076, glyph_sixsuperior }, + { 0x2077, glyph_sevensuperior }, + { 0x2078, glyph_eightsuperior }, + { 0x2079, glyph_ninesuperior }, + { 0x207D, glyph_parenleftsuperior }, + { 0x207E, glyph_parenrightsuperior }, + { 0x207F, glyph_nsuperior }, + { 0x2080, glyph_zeroinferior }, + { 0x2081, glyph_oneinferior }, + { 0x2082, glyph_twoinferior }, + { 0x2083, glyph_threeinferior }, + { 0x2084, glyph_fourinferior }, + { 0x2085, glyph_fiveinferior }, + { 0x2086, glyph_sixinferior }, + { 0x2087, glyph_seveninferior }, + { 0x2088, glyph_eightinferior }, + { 0x2089, glyph_nineinferior }, + { 0x208D, glyph_parenleftinferior }, + { 0x208E, glyph_parenrightinferior }, + { 0x20A1, glyph_colonmonetary }, + { 0x20A3, glyph_franc }, + { 0x20A4, glyph_lira }, + { 0x20A7, glyph_peseta }, + { 0x20AA, glyph_afii57636 }, + { 0x20AB, glyph_dong }, + { 0x20AC, glyph_Euro }, + { 0x2105, glyph_afii61248 }, + { 0x2111, glyph_Ifraktur }, + { 0x2113, glyph_afii61289 }, + { 0x2116, glyph_afii61352 }, + { 0x2118, glyph_weierstrass }, + { 0x211C, glyph_Rfraktur }, + { 0x211E, glyph_prescription }, + { 0x2122, glyph_trademark }, + { 0x2126, glyph_Omega }, + { 0x212E, glyph_estimated }, + { 0x2135, glyph_aleph }, + { 0x2153, glyph_onethird }, + { 0x2154, glyph_twothirds }, + { 0x215B, glyph_oneeighth }, + { 0x215C, glyph_threeeighths }, + { 0x215D, glyph_fiveeighths }, + { 0x215E, glyph_seveneighths }, + { 0x2190, glyph_arrowleft }, + { 0x2191, glyph_arrowup }, + { 0x2192, glyph_arrowright }, + { 0x2193, glyph_arrowdown }, + { 0x2194, glyph_arrowboth }, + { 0x2195, glyph_arrowupdn }, + { 0x21A8, glyph_arrowupdnbse }, + { 0x21B5, glyph_carriagereturn }, + { 0x21D0, glyph_arrowdblleft }, + { 0x21D1, glyph_arrowdblup }, + { 0x21D2, glyph_arrowdblright }, + { 0x21D3, glyph_arrowdbldown }, + { 0x21D4, glyph_arrowdblboth }, + { 0x2200, glyph_universal }, + { 0x2202, glyph_partialdiff }, + { 0x2203, glyph_existential }, + { 0x2205, glyph_emptyset }, + { 0x2206, glyph_Delta }, + { 0x2207, glyph_gradient }, + { 0x2208, glyph_element }, + { 0x2209, glyph_notelement }, + { 0x220B, glyph_suchthat }, + { 0x220F, glyph_product }, + { 0x2211, glyph_summation }, + { 0x2212, glyph_minus }, + { 0x2215, glyph_divisionslash }, + { 0x2217, glyph_asteriskmath }, + { 0x2219, glyph_bulletoperator }, + { 0x221A, glyph_radical }, + { 0x221D, glyph_proportional }, + { 0x221E, glyph_infinity }, + { 0x221F, glyph_orthogonal }, + { 0x2220, glyph_angle }, + { 0x2227, glyph_logicaland }, + { 0x2228, glyph_logicalor }, + { 0x2229, glyph_intersection }, + { 0x222A, glyph_union }, + { 0x222B, glyph_integral }, + { 0x2234, glyph_therefore }, + { 0x223C, glyph_similar }, + { 0x2245, glyph_congruent }, + { 0x2248, glyph_approxequal }, + { 0x2260, glyph_notequal }, + { 0x2261, glyph_equivalence }, + { 0x2264, glyph_lessequal }, + { 0x2265, glyph_greaterequal }, + { 0x2282, glyph_propersubset }, + { 0x2283, glyph_propersuperset }, + { 0x2284, glyph_notsubset }, + { 0x2286, glyph_reflexsubset }, + { 0x2287, glyph_reflexsuperset }, + { 0x2295, glyph_circleplus }, + { 0x2297, glyph_circlemultiply }, + { 0x22A5, glyph_perpendicular }, + { 0x22C5, glyph_dotmath }, + { 0x2302, glyph_house }, + { 0x2310, glyph_revlogicalnot }, + { 0x2320, glyph_integraltp }, + { 0x2321, glyph_integralbt }, + { 0x2329, glyph_angleleft }, + { 0x232A, glyph_angleright }, + { 0x2500, glyph_SF100000 }, + { 0x2502, glyph_SF110000 }, + { 0x250C, glyph_SF010000 }, + { 0x2510, glyph_SF030000 }, + { 0x2514, glyph_SF020000 }, + { 0x2518, glyph_SF040000 }, + { 0x251C, glyph_SF080000 }, + { 0x2524, glyph_SF090000 }, + { 0x252C, glyph_SF060000 }, + { 0x2534, glyph_SF070000 }, + { 0x253C, glyph_SF050000 }, + { 0x2550, glyph_SF430000 }, + { 0x2551, glyph_SF240000 }, + { 0x2552, glyph_SF510000 }, + { 0x2553, glyph_SF520000 }, + { 0x2554, glyph_SF390000 }, + { 0x2555, glyph_SF220000 }, + { 0x2556, glyph_SF210000 }, + { 0x2557, glyph_SF250000 }, + { 0x2558, glyph_SF500000 }, + { 0x2559, glyph_SF490000 }, + { 0x255A, glyph_SF380000 }, + { 0x255B, glyph_SF280000 }, + { 0x255C, glyph_SF270000 }, + { 0x255D, glyph_SF260000 }, + { 0x255E, glyph_SF360000 }, + { 0x255F, glyph_SF370000 }, + { 0x2560, glyph_SF420000 }, + { 0x2561, glyph_SF190000 }, + { 0x2562, glyph_SF200000 }, + { 0x2563, glyph_SF230000 }, + { 0x2564, glyph_SF470000 }, + { 0x2565, glyph_SF480000 }, + { 0x2566, glyph_SF410000 }, + { 0x2567, glyph_SF450000 }, + { 0x2568, glyph_SF460000 }, + { 0x2569, glyph_SF400000 }, + { 0x256A, glyph_SF540000 }, + { 0x256B, glyph_SF530000 }, + { 0x256C, glyph_SF440000 }, + { 0x2580, glyph_upblock }, + { 0x2584, glyph_dnblock }, + { 0x2588, glyph_block }, + { 0x258C, glyph_lfblock }, + { 0x2590, glyph_rtblock }, + { 0x2591, glyph_ltshade }, + { 0x2592, glyph_shade }, + { 0x2593, glyph_dkshade }, + { 0x25A0, glyph_filledbox }, + { 0x25A1, glyph_H22073 }, + { 0x25AA, glyph_H18543 }, + { 0x25AB, glyph_H18551 }, + { 0x25AC, glyph_filledrect }, + { 0x25B2, glyph_triagup }, + { 0x25BA, glyph_triagrt }, + { 0x25BC, glyph_triagdn }, + { 0x25C4, glyph_triaglf }, + { 0x25CA, glyph_lozenge }, + { 0x25CB, glyph_circle }, + { 0x25CF, glyph_H18533 }, + { 0x25D8, glyph_invbullet }, + { 0x25D9, glyph_invcircle }, + { 0x25E6, glyph_openbullet }, + { 0x263A, glyph_smileface }, + { 0x263B, glyph_invsmileface }, + { 0x263C, glyph_sun }, + { 0x2640, glyph_female }, + { 0x2642, glyph_male }, + { 0x2660, glyph_spade }, + { 0x2663, glyph_club }, + { 0x2665, glyph_heart }, + { 0x2666, glyph_diamond }, + { 0x266A, glyph_musicalnote }, + { 0x266B, glyph_musicalnotedbl }, + { 0xF6BE, glyph_dotlessj }, + { 0xF6BF, glyph_LL }, + { 0xF6C0, glyph_ll }, + { 0xF6C3, glyph_commaaccent }, + { 0xF6C4, glyph_afii10063 }, + { 0xF6C5, glyph_afii10064 }, + { 0xF6C6, glyph_afii10192 }, + { 0xF6C7, glyph_afii10831 }, + { 0xF6C8, glyph_afii10832 }, + { 0xF6C9, glyph_Acute }, + { 0xF6CA, glyph_Caron }, + { 0xF6CB, glyph_Dieresis }, + { 0xF6CC, glyph_DieresisAcute }, + { 0xF6CD, glyph_DieresisGrave }, + { 0xF6CE, glyph_Grave }, + { 0xF6CF, glyph_Hungarumlaut }, + { 0xF6D0, glyph_Macron }, + { 0xF6D1, glyph_cyrBreve }, + { 0xF6D2, glyph_cyrFlex }, + { 0xF6D3, glyph_dblGrave }, + { 0xF6D4, glyph_cyrbreve }, + { 0xF6D5, glyph_cyrflex }, + { 0xF6D6, glyph_dblgrave }, + { 0xF6D7, glyph_dieresisacute }, + { 0xF6D8, glyph_dieresisgrave }, + { 0xF6D9, glyph_copyrightserif }, + { 0xF6DA, glyph_registerserif }, + { 0xF6DB, glyph_trademarkserif }, + { 0xF6DC, glyph_onefitted }, + { 0xF6DD, glyph_rupiah }, + { 0xF6DE, glyph_threequartersemdash }, + { 0xF6DF, glyph_centinferior }, + { 0xF6E0, glyph_centsuperior }, + { 0xF6E1, glyph_commainferior }, + { 0xF6E2, glyph_commasuperior }, + { 0xF6E3, glyph_dollarinferior }, + { 0xF6E4, glyph_dollarsuperior }, + { 0xF6E5, glyph_hypheninferior }, + { 0xF6E6, glyph_hyphensuperior }, + { 0xF6E7, glyph_periodinferior }, + { 0xF6E8, glyph_periodsuperior }, + { 0xF6E9, glyph_asuperior }, + { 0xF6EA, glyph_bsuperior }, + { 0xF6EB, glyph_dsuperior }, + { 0xF6EC, glyph_esuperior }, + { 0xF6ED, glyph_isuperior }, + { 0xF6EE, glyph_lsuperior }, + { 0xF6EF, glyph_msuperior }, + { 0xF6F0, glyph_osuperior }, + { 0xF6F1, glyph_rsuperior }, + { 0xF6F2, glyph_ssuperior }, + { 0xF6F3, glyph_tsuperior }, + { 0xF6F4, glyph_Brevesmall }, + { 0xF6F5, glyph_Caronsmall }, + { 0xF6F6, glyph_Circumflexsmall }, + { 0xF6F7, glyph_Dotaccentsmall }, + { 0xF6F8, glyph_Hungarumlautsmall }, + { 0xF6F9, glyph_Lslashsmall }, + { 0xF6FA, glyph_OEsmall }, + { 0xF6FB, glyph_Ogoneksmall }, + { 0xF6FC, glyph_Ringsmall }, + { 0xF6FD, glyph_Scaronsmall }, + { 0xF6FE, glyph_Tildesmall }, + { 0xF6FF, glyph_Zcaronsmall }, + { 0xF721, glyph_exclamsmall }, + { 0xF724, glyph_dollaroldstyle }, + { 0xF726, glyph_ampersandsmall }, + { 0xF730, glyph_zerooldstyle }, + { 0xF731, glyph_oneoldstyle }, + { 0xF732, glyph_twooldstyle }, + { 0xF733, glyph_threeoldstyle }, + { 0xF734, glyph_fouroldstyle }, + { 0xF735, glyph_fiveoldstyle }, + { 0xF736, glyph_sixoldstyle }, + { 0xF737, glyph_sevenoldstyle }, + { 0xF738, glyph_eightoldstyle }, + { 0xF739, glyph_nineoldstyle }, + { 0xF73F, glyph_questionsmall }, + { 0xF760, glyph_Gravesmall }, + { 0xF761, glyph_Asmall }, + { 0xF762, glyph_Bsmall }, + { 0xF763, glyph_Csmall }, + { 0xF764, glyph_Dsmall }, + { 0xF765, glyph_Esmall }, + { 0xF766, glyph_Fsmall }, + { 0xF767, glyph_Gsmall }, + { 0xF768, glyph_Hsmall }, + { 0xF769, glyph_Ismall }, + { 0xF76A, glyph_Jsmall }, + { 0xF76B, glyph_Ksmall }, + { 0xF76C, glyph_Lsmall }, + { 0xF76D, glyph_Msmall }, + { 0xF76E, glyph_Nsmall }, + { 0xF76F, glyph_Osmall }, + { 0xF770, glyph_Psmall }, + { 0xF771, glyph_Qsmall }, + { 0xF772, glyph_Rsmall }, + { 0xF773, glyph_Ssmall }, + { 0xF774, glyph_Tsmall }, + { 0xF775, glyph_Usmall }, + { 0xF776, glyph_Vsmall }, + { 0xF777, glyph_Wsmall }, + { 0xF778, glyph_Xsmall }, + { 0xF779, glyph_Ysmall }, + { 0xF77A, glyph_Zsmall }, + { 0xF7A1, glyph_exclamdownsmall }, + { 0xF7A2, glyph_centoldstyle }, + { 0xF7A8, glyph_Dieresissmall }, + { 0xF7AF, glyph_Macronsmall }, + { 0xF7B4, glyph_Acutesmall }, + { 0xF7B8, glyph_Cedillasmall }, + { 0xF7BF, glyph_questiondownsmall }, + { 0xF7E0, glyph_Agravesmall }, + { 0xF7E1, glyph_Aacutesmall }, + { 0xF7E2, glyph_Acircumflexsmall }, + { 0xF7E3, glyph_Atildesmall }, + { 0xF7E4, glyph_Adieresissmall }, + { 0xF7E5, glyph_Aringsmall }, + { 0xF7E6, glyph_AEsmall }, + { 0xF7E7, glyph_Ccedillasmall }, + { 0xF7E8, glyph_Egravesmall }, + { 0xF7E9, glyph_Eacutesmall }, + { 0xF7EA, glyph_Ecircumflexsmall }, + { 0xF7EB, glyph_Edieresissmall }, + { 0xF7EC, glyph_Igravesmall }, + { 0xF7ED, glyph_Iacutesmall }, + { 0xF7EE, glyph_Icircumflexsmall }, + { 0xF7EF, glyph_Idieresissmall }, + { 0xF7F0, glyph_Ethsmall }, + { 0xF7F1, glyph_Ntildesmall }, + { 0xF7F2, glyph_Ogravesmall }, + { 0xF7F3, glyph_Oacutesmall }, + { 0xF7F4, glyph_Ocircumflexsmall }, + { 0xF7F5, glyph_Otildesmall }, + { 0xF7F6, glyph_Odieresissmall }, + { 0xF7F8, glyph_Oslashsmall }, + { 0xF7F9, glyph_Ugravesmall }, + { 0xF7FA, glyph_Uacutesmall }, + { 0xF7FB, glyph_Ucircumflexsmall }, + { 0xF7FC, glyph_Udieresissmall }, + { 0xF7FD, glyph_Yacutesmall }, + { 0xF7FE, glyph_Thornsmall }, + { 0xF7FF, glyph_Ydieresissmall }, + { 0xF8E5, glyph_radicalex }, + { 0xF8E6, glyph_arrowvertex }, + { 0xF8E7, glyph_arrowhorizex }, + { 0xF8E8, glyph_registersans }, + { 0xF8E9, glyph_copyrightsans }, + { 0xF8EA, glyph_trademarksans }, + { 0xF8EB, glyph_parenlefttp }, + { 0xF8EC, glyph_parenleftex }, + { 0xF8ED, glyph_parenleftbt }, + { 0xF8EE, glyph_bracketlefttp }, + { 0xF8EF, glyph_bracketleftex }, + { 0xF8F0, glyph_bracketleftbt }, + { 0xF8F1, glyph_bracelefttp }, + { 0xF8F2, glyph_braceleftmid }, + { 0xF8F3, glyph_braceleftbt }, + { 0xF8F4, glyph_braceex }, + { 0xF8F5, glyph_integralex }, + { 0xF8F6, glyph_parenrighttp }, + { 0xF8F7, glyph_parenrightex }, + { 0xF8F8, glyph_parenrightbt }, + { 0xF8F9, glyph_bracketrighttp }, + { 0xF8FA, glyph_bracketrightex }, + { 0xF8FB, glyph_bracketrightbt }, + { 0xF8FC, glyph_bracerighttp }, + { 0xF8FD, glyph_bracerightmid }, + { 0xF8FE, glyph_bracerightbt }, + { 0xF8FF, glyph_apple }, + { 0xFB00, glyph_ff }, + { 0xFB01, glyph_fi }, + { 0xFB02, glyph_fl }, + { 0xFB03, glyph_ffi }, + { 0xFB04, glyph_ffl }, + { 0xFB1F, glyph_afii57705 }, + { 0xFB2A, glyph_afii57694 }, + { 0xFB2B, glyph_afii57695 }, + { 0xFB35, glyph_afii57723 }, + { 0xFB4B, glyph_afii57700 }, +}; /* tab_uni2agl */ + +/* ZapfDingbats glyphs - sorted by names */ +static const pdc_glyph_tab tab_zadb2uni[] = +{ + { 0x2701, glyph_a1 }, + { 0x2721, glyph_a10 }, + { 0x275E, glyph_a100 }, + { 0x2761, glyph_a101 }, + { 0x2762, glyph_a102 }, + { 0x2763, glyph_a103 }, + { 0x2764, glyph_a104 }, + { 0x2710, glyph_a105 }, + { 0x2765, glyph_a106 }, + { 0x2766, glyph_a107 }, + { 0x2767, glyph_a108 }, + { 0x2660, glyph_a109 }, + { 0x261B, glyph_a11 }, + { 0x2665, glyph_a110 }, + { 0x2666, glyph_a111 }, + { 0x2663, glyph_a112 }, + { 0x2709, glyph_a117 }, + { 0x2708, glyph_a118 }, + { 0x2707, glyph_a119 }, + { 0x261E, glyph_a12 }, + { 0x2460, glyph_a120 }, + { 0x2461, glyph_a121 }, + { 0x2462, glyph_a122 }, + { 0x2463, glyph_a123 }, + { 0x2464, glyph_a124 }, + { 0x2465, glyph_a125 }, + { 0x2466, glyph_a126 }, + { 0x2467, glyph_a127 }, + { 0x2468, glyph_a128 }, + { 0x2469, glyph_a129 }, + { 0x270C, glyph_a13 }, + { 0x2776, glyph_a130 }, + { 0x2777, glyph_a131 }, + { 0x2778, glyph_a132 }, + { 0x2779, glyph_a133 }, + { 0x277A, glyph_a134 }, + { 0x277B, glyph_a135 }, + { 0x277C, glyph_a136 }, + { 0x277D, glyph_a137 }, + { 0x277E, glyph_a138 }, + { 0x277F, glyph_a139 }, + { 0x270D, glyph_a14 }, + { 0x2780, glyph_a140 }, + { 0x2781, glyph_a141 }, + { 0x2782, glyph_a142 }, + { 0x2783, glyph_a143 }, + { 0x2784, glyph_a144 }, + { 0x2785, glyph_a145 }, + { 0x2786, glyph_a146 }, + { 0x2787, glyph_a147 }, + { 0x2788, glyph_a148 }, + { 0x2789, glyph_a149 }, + { 0x270E, glyph_a15 }, + { 0x278A, glyph_a150 }, + { 0x278B, glyph_a151 }, + { 0x278C, glyph_a152 }, + { 0x278D, glyph_a153 }, + { 0x278E, glyph_a154 }, + { 0x278F, glyph_a155 }, + { 0x2790, glyph_a156 }, + { 0x2791, glyph_a157 }, + { 0x2792, glyph_a158 }, + { 0x2793, glyph_a159 }, + { 0x270F, glyph_a16 }, + { 0x2794, glyph_a160 }, + { 0x2192, glyph_a161 }, + { 0x27A3, glyph_a162 }, + { 0x2194, glyph_a163 }, + { 0x2195, glyph_a164 }, + { 0x2799, glyph_a165 }, + { 0x279B, glyph_a166 }, + { 0x279C, glyph_a167 }, + { 0x279D, glyph_a168 }, + { 0x279E, glyph_a169 }, + { 0x2711, glyph_a17 }, + { 0x279F, glyph_a170 }, + { 0x27A0, glyph_a171 }, + { 0x27A1, glyph_a172 }, + { 0x27A2, glyph_a173 }, + { 0x27A4, glyph_a174 }, + { 0x27A5, glyph_a175 }, + { 0x27A6, glyph_a176 }, + { 0x27A7, glyph_a177 }, + { 0x27A8, glyph_a178 }, + { 0x27A9, glyph_a179 }, + { 0x2712, glyph_a18 }, + { 0x27AB, glyph_a180 }, + { 0x27AD, glyph_a181 }, + { 0x27AF, glyph_a182 }, + { 0x27B2, glyph_a183 }, + { 0x27B3, glyph_a184 }, + { 0x27B5, glyph_a185 }, + { 0x27B8, glyph_a186 }, + { 0x27BA, glyph_a187 }, + { 0x27BB, glyph_a188 }, + { 0x27BC, glyph_a189 }, + { 0x2713, glyph_a19 }, + { 0x27BD, glyph_a190 }, + { 0x27BE, glyph_a191 }, + { 0x279A, glyph_a192 }, + { 0x27AA, glyph_a193 }, + { 0x27B6, glyph_a194 }, + { 0x27B9, glyph_a195 }, + { 0x2798, glyph_a196 }, + { 0x27B4, glyph_a197 }, + { 0x27B7, glyph_a198 }, + { 0x27AC, glyph_a199 }, + { 0x2702, glyph_a2 }, + { 0x2714, glyph_a20 }, + { 0x27AE, glyph_a200 }, + { 0x27B1, glyph_a201 }, + { 0x2703, glyph_a202 }, + { 0x2750, glyph_a203 }, + { 0x2752, glyph_a204 }, + { 0x276E, glyph_a205 }, + { 0x2770, glyph_a206 }, + { 0x2715, glyph_a21 }, + { 0x2716, glyph_a22 }, + { 0x2717, glyph_a23 }, + { 0x2718, glyph_a24 }, + { 0x2719, glyph_a25 }, + { 0x271A, glyph_a26 }, + { 0x271B, glyph_a27 }, + { 0x271C, glyph_a28 }, + { 0x2722, glyph_a29 }, + { 0x2704, glyph_a3 }, + { 0x2723, glyph_a30 }, + { 0x2724, glyph_a31 }, + { 0x2725, glyph_a32 }, + { 0x2726, glyph_a33 }, + { 0x2727, glyph_a34 }, + { 0x2605, glyph_a35 }, + { 0x2729, glyph_a36 }, + { 0x272A, glyph_a37 }, + { 0x272B, glyph_a38 }, + { 0x272C, glyph_a39 }, + { 0x260E, glyph_a4 }, + { 0x272D, glyph_a40 }, + { 0x272E, glyph_a41 }, + { 0x272F, glyph_a42 }, + { 0x2730, glyph_a43 }, + { 0x2731, glyph_a44 }, + { 0x2732, glyph_a45 }, + { 0x2733, glyph_a46 }, + { 0x2734, glyph_a47 }, + { 0x2735, glyph_a48 }, + { 0x2736, glyph_a49 }, + { 0x2706, glyph_a5 }, + { 0x2737, glyph_a50 }, + { 0x2738, glyph_a51 }, + { 0x2739, glyph_a52 }, + { 0x273A, glyph_a53 }, + { 0x273B, glyph_a54 }, + { 0x273C, glyph_a55 }, + { 0x273D, glyph_a56 }, + { 0x273E, glyph_a57 }, + { 0x273F, glyph_a58 }, + { 0x2740, glyph_a59 }, + { 0x271D, glyph_a6 }, + { 0x2741, glyph_a60 }, + { 0x2742, glyph_a61 }, + { 0x2743, glyph_a62 }, + { 0x2744, glyph_a63 }, + { 0x2745, glyph_a64 }, + { 0x2746, glyph_a65 }, + { 0x2747, glyph_a66 }, + { 0x2748, glyph_a67 }, + { 0x2749, glyph_a68 }, + { 0x274A, glyph_a69 }, + { 0x271E, glyph_a7 }, + { 0x274B, glyph_a70 }, + { 0x25CF, glyph_a71 }, + { 0x274D, glyph_a72 }, + { 0x25A0, glyph_a73 }, + { 0x274F, glyph_a74 }, + { 0x2751, glyph_a75 }, + { 0x25B2, glyph_a76 }, + { 0x25BC, glyph_a77 }, + { 0x25C6, glyph_a78 }, + { 0x2756, glyph_a79 }, + { 0x271F, glyph_a8 }, + { 0x25D7, glyph_a81 }, + { 0x2758, glyph_a82 }, + { 0x2759, glyph_a83 }, + { 0x275A, glyph_a84 }, + { 0x276F, glyph_a85 }, + { 0x2771, glyph_a86 }, + { 0x2772, glyph_a87 }, + { 0x2773, glyph_a88 }, + { 0x2768, glyph_a89 }, + { 0x2720, glyph_a9 }, + { 0x2769, glyph_a90 }, + { 0x276C, glyph_a91 }, + { 0x276D, glyph_a92 }, + { 0x276A, glyph_a93 }, + { 0x276B, glyph_a94 }, + { 0x2774, glyph_a95 }, + { 0x2775, glyph_a96 }, + { 0x275B, glyph_a97 }, + { 0x275C, glyph_a98 }, + { 0x275D, glyph_a99 }, + { 0x0020, glyph_space }, +}; /* tab_zadb2uni */ + +/* ZapfDingbats glyphs - sorted by unicode values */ +static const pdc_glyph_tab tab_uni2zadb[] = +{ + { 0x0020, glyph_space }, + { 0x2192, glyph_a161 }, + { 0x2194, glyph_a163 }, + { 0x2195, glyph_a164 }, + { 0x2460, glyph_a120 }, + { 0x2461, glyph_a121 }, + { 0x2462, glyph_a122 }, + { 0x2463, glyph_a123 }, + { 0x2464, glyph_a124 }, + { 0x2465, glyph_a125 }, + { 0x2466, glyph_a126 }, + { 0x2467, glyph_a127 }, + { 0x2468, glyph_a128 }, + { 0x2469, glyph_a129 }, + { 0x25A0, glyph_a73 }, + { 0x25B2, glyph_a76 }, + { 0x25BC, glyph_a77 }, + { 0x25C6, glyph_a78 }, + { 0x25CF, glyph_a71 }, + { 0x25D7, glyph_a81 }, + { 0x2605, glyph_a35 }, + { 0x260E, glyph_a4 }, + { 0x261B, glyph_a11 }, + { 0x261E, glyph_a12 }, + { 0x2660, glyph_a109 }, + { 0x2663, glyph_a112 }, + { 0x2665, glyph_a110 }, + { 0x2666, glyph_a111 }, + { 0x2701, glyph_a1 }, + { 0x2702, glyph_a2 }, + { 0x2703, glyph_a202 }, + { 0x2704, glyph_a3 }, + { 0x2706, glyph_a5 }, + { 0x2707, glyph_a119 }, + { 0x2708, glyph_a118 }, + { 0x2709, glyph_a117 }, + { 0x270C, glyph_a13 }, + { 0x270D, glyph_a14 }, + { 0x270E, glyph_a15 }, + { 0x270F, glyph_a16 }, + { 0x2710, glyph_a105 }, + { 0x2711, glyph_a17 }, + { 0x2712, glyph_a18 }, + { 0x2713, glyph_a19 }, + { 0x2714, glyph_a20 }, + { 0x2715, glyph_a21 }, + { 0x2716, glyph_a22 }, + { 0x2717, glyph_a23 }, + { 0x2718, glyph_a24 }, + { 0x2719, glyph_a25 }, + { 0x271A, glyph_a26 }, + { 0x271B, glyph_a27 }, + { 0x271C, glyph_a28 }, + { 0x271D, glyph_a6 }, + { 0x271E, glyph_a7 }, + { 0x271F, glyph_a8 }, + { 0x2720, glyph_a9 }, + { 0x2721, glyph_a10 }, + { 0x2722, glyph_a29 }, + { 0x2723, glyph_a30 }, + { 0x2724, glyph_a31 }, + { 0x2725, glyph_a32 }, + { 0x2726, glyph_a33 }, + { 0x2727, glyph_a34 }, + { 0x2729, glyph_a36 }, + { 0x272A, glyph_a37 }, + { 0x272B, glyph_a38 }, + { 0x272C, glyph_a39 }, + { 0x272D, glyph_a40 }, + { 0x272E, glyph_a41 }, + { 0x272F, glyph_a42 }, + { 0x2730, glyph_a43 }, + { 0x2731, glyph_a44 }, + { 0x2732, glyph_a45 }, + { 0x2733, glyph_a46 }, + { 0x2734, glyph_a47 }, + { 0x2735, glyph_a48 }, + { 0x2736, glyph_a49 }, + { 0x2737, glyph_a50 }, + { 0x2738, glyph_a51 }, + { 0x2739, glyph_a52 }, + { 0x273A, glyph_a53 }, + { 0x273B, glyph_a54 }, + { 0x273C, glyph_a55 }, + { 0x273D, glyph_a56 }, + { 0x273E, glyph_a57 }, + { 0x273F, glyph_a58 }, + { 0x2740, glyph_a59 }, + { 0x2741, glyph_a60 }, + { 0x2742, glyph_a61 }, + { 0x2743, glyph_a62 }, + { 0x2744, glyph_a63 }, + { 0x2745, glyph_a64 }, + { 0x2746, glyph_a65 }, + { 0x2747, glyph_a66 }, + { 0x2748, glyph_a67 }, + { 0x2749, glyph_a68 }, + { 0x274A, glyph_a69 }, + { 0x274B, glyph_a70 }, + { 0x274D, glyph_a72 }, + { 0x274F, glyph_a74 }, + { 0x2750, glyph_a203 }, + { 0x2751, glyph_a75 }, + { 0x2752, glyph_a204 }, + { 0x2756, glyph_a79 }, + { 0x2758, glyph_a82 }, + { 0x2759, glyph_a83 }, + { 0x275A, glyph_a84 }, + { 0x275B, glyph_a97 }, + { 0x275C, glyph_a98 }, + { 0x275D, glyph_a99 }, + { 0x275E, glyph_a100 }, + { 0x2761, glyph_a101 }, + { 0x2762, glyph_a102 }, + { 0x2763, glyph_a103 }, + { 0x2764, glyph_a104 }, + { 0x2765, glyph_a106 }, + { 0x2766, glyph_a107 }, + { 0x2767, glyph_a108 }, + + /* >= Unicode 4.0*/ + { 0x2768, glyph_a89 }, + { 0x2769, glyph_a90 }, + { 0x276A, glyph_a93 }, + { 0x276B, glyph_a94 }, + { 0x276C, glyph_a91 }, + { 0x276D, glyph_a92 }, + { 0x276E, glyph_a205 }, + { 0x276F, glyph_a85 }, + { 0x2770, glyph_a206 }, + { 0x2771, glyph_a86 }, + { 0x2772, glyph_a87 }, + { 0x2773, glyph_a88 }, + { 0x2774, glyph_a95 }, + { 0x2775, glyph_a96 }, + /* ---------------- */ + + { 0x2776, glyph_a130 }, + { 0x2777, glyph_a131 }, + { 0x2778, glyph_a132 }, + { 0x2779, glyph_a133 }, + { 0x277A, glyph_a134 }, + { 0x277B, glyph_a135 }, + { 0x277C, glyph_a136 }, + { 0x277D, glyph_a137 }, + { 0x277E, glyph_a138 }, + { 0x277F, glyph_a139 }, + { 0x2780, glyph_a140 }, + { 0x2781, glyph_a141 }, + { 0x2782, glyph_a142 }, + { 0x2783, glyph_a143 }, + { 0x2784, glyph_a144 }, + { 0x2785, glyph_a145 }, + { 0x2786, glyph_a146 }, + { 0x2787, glyph_a147 }, + { 0x2788, glyph_a148 }, + { 0x2789, glyph_a149 }, + { 0x278A, glyph_a150 }, + { 0x278B, glyph_a151 }, + { 0x278C, glyph_a152 }, + { 0x278D, glyph_a153 }, + { 0x278E, glyph_a154 }, + { 0x278F, glyph_a155 }, + { 0x2790, glyph_a156 }, + { 0x2791, glyph_a157 }, + { 0x2792, glyph_a158 }, + { 0x2793, glyph_a159 }, + { 0x2794, glyph_a160 }, + { 0x2798, glyph_a196 }, + { 0x2799, glyph_a165 }, + { 0x279A, glyph_a192 }, + { 0x279B, glyph_a166 }, + { 0x279C, glyph_a167 }, + { 0x279D, glyph_a168 }, + { 0x279E, glyph_a169 }, + { 0x279F, glyph_a170 }, + { 0x27A0, glyph_a171 }, + { 0x27A1, glyph_a172 }, + { 0x27A2, glyph_a173 }, + { 0x27A3, glyph_a162 }, + { 0x27A4, glyph_a174 }, + { 0x27A5, glyph_a175 }, + { 0x27A6, glyph_a176 }, + { 0x27A7, glyph_a177 }, + { 0x27A8, glyph_a178 }, + { 0x27A9, glyph_a179 }, + { 0x27AA, glyph_a193 }, + { 0x27AB, glyph_a180 }, + { 0x27AC, glyph_a199 }, + { 0x27AD, glyph_a181 }, + { 0x27AE, glyph_a200 }, + { 0x27AF, glyph_a182 }, + { 0x27B1, glyph_a201 }, + { 0x27B2, glyph_a183 }, + { 0x27B3, glyph_a184 }, + { 0x27B4, glyph_a197 }, + { 0x27B5, glyph_a185 }, + { 0x27B6, glyph_a194 }, + { 0x27B7, glyph_a198 }, + { 0x27B8, glyph_a186 }, + { 0x27B9, glyph_a195 }, + { 0x27BA, glyph_a187 }, + { 0x27BB, glyph_a188 }, + { 0x27BC, glyph_a189 }, + { 0x27BD, glyph_a190 }, + { 0x27BE, glyph_a191 }, + + /* < Unicode 4.0 */ + { 0xF8D7, glyph_a89 }, + { 0xF8D8, glyph_a90 }, + { 0xF8D9, glyph_a93 }, + { 0xF8DA, glyph_a94 }, + { 0xF8DB, glyph_a91 }, + { 0xF8DC, glyph_a92 }, + { 0xF8DD, glyph_a205 }, + { 0xF8DE, glyph_a85 }, + { 0xF8DF, glyph_a206 }, + { 0xF8E0, glyph_a86 }, + { 0xF8E1, glyph_a87 }, + { 0xF8E2, glyph_a88 }, + { 0xF8E3, glyph_a95 }, + { 0xF8E4, glyph_a96 }, +}; /* tab_uni2zadb */ + + +/* + * Difference table of AGL version 2.0 - 1.2' - sorted by names + * + */ +static const pdc_glyph_tab tab_diffagl2uni[] = +{ +#ifndef PDFLIB_EBCDIC + + { 0x01E2, glyph_AEmacron }, + { 0x1EAE, glyph_Abreveacute }, + { 0x04D0, glyph_Abrevecyrillic }, + { 0x1EB6, glyph_Abrevedotbelow }, + { 0x1EB0, glyph_Abrevegrave }, + { 0x1EB2, glyph_Abrevehookabove }, + { 0x1EB4, glyph_Abrevetilde }, + { 0x01CD, glyph_Acaron }, + { 0x24B6, glyph_Acircle }, + { 0x1EA4, glyph_Acircumflexacute }, + { 0x1EAC, glyph_Acircumflexdotbelow }, + { 0x1EA6, glyph_Acircumflexgrave }, + { 0x1EA8, glyph_Acircumflexhookabove }, + { 0x1EAA, glyph_Acircumflextilde }, + { 0x0410, glyph_Acyrillic }, + { 0x0200, glyph_Adblgrave }, + { 0x04D2, glyph_Adieresiscyrillic }, + { 0x01DE, glyph_Adieresismacron }, + { 0x1EA0, glyph_Adotbelow }, + { 0x01E0, glyph_Adotmacron }, + { 0x1EA2, glyph_Ahookabove }, + { 0x04D4, glyph_Aiecyrillic }, + { 0x0202, glyph_Ainvertedbreve }, + { 0xFF21, glyph_Amonospace }, + { 0x1E00, glyph_Aringbelow }, + { 0x0531, glyph_Aybarmenian }, + { 0x24B7, glyph_Bcircle }, + { 0x1E02, glyph_Bdotaccent }, + { 0x1E04, glyph_Bdotbelow }, + { 0x0411, glyph_Becyrillic }, + { 0x0532, glyph_Benarmenian }, + { 0x0181, glyph_Bhook }, + { 0x1E06, glyph_Blinebelow }, + { 0xFF22, glyph_Bmonospace }, + { 0x0182, glyph_Btopbar }, + { 0x053E, glyph_Caarmenian }, + { 0x1E08, glyph_Ccedillaacute }, + { 0x24B8, glyph_Ccircle }, + { 0x010A, glyph_Cdot }, + { 0x0549, glyph_Chaarmenian }, + { 0x04BC, glyph_Cheabkhasiancyrillic }, + { 0x0427, glyph_Checyrillic }, + { 0x04BE, glyph_Chedescenderabkhasiancyrillic }, + { 0x04B6, glyph_Chedescendercyrillic }, + { 0x04F4, glyph_Chedieresiscyrillic }, + { 0x0543, glyph_Cheharmenian }, + { 0x04CB, glyph_Chekhakassiancyrillic }, + { 0x04B8, glyph_Cheverticalstrokecyrillic }, + { 0x0187, glyph_Chook }, + { 0xFF23, glyph_Cmonospace }, + { 0x0551, glyph_Coarmenian }, + { 0x01F1, glyph_DZ }, + { 0x01C4, glyph_DZcaron }, + { 0x0534, glyph_Daarmenian }, + { 0x0189, glyph_Dafrican }, + { 0x1E10, glyph_Dcedilla }, + { 0x24B9, glyph_Dcircle }, + { 0x1E12, glyph_Dcircumflexbelow }, + { 0x1E0A, glyph_Ddotaccent }, + { 0x1E0C, glyph_Ddotbelow }, + { 0x0414, glyph_Decyrillic }, + { 0x03EE, glyph_Deicoptic }, + { 0x018A, glyph_Dhook }, + { 0x03DC, glyph_Digammagreek }, + { 0x0402, glyph_Djecyrillic }, + { 0x1E0E, glyph_Dlinebelow }, + { 0xFF24, glyph_Dmonospace }, + { 0x0110, glyph_Dslash }, + { 0x018B, glyph_Dtopbar }, + { 0x01F2, glyph_Dz }, + { 0x01C5, glyph_Dzcaron }, + { 0x04E0, glyph_Dzeabkhasiancyrillic }, + { 0x0405, glyph_Dzecyrillic }, + { 0x040F, glyph_Dzhecyrillic }, + { 0x1E1C, glyph_Ecedillabreve }, + { 0x0535, glyph_Echarmenian }, + { 0x24BA, glyph_Ecircle }, + { 0x1EBE, glyph_Ecircumflexacute }, + { 0x1E18, glyph_Ecircumflexbelow }, + { 0x1EC6, glyph_Ecircumflexdotbelow }, + { 0x1EC0, glyph_Ecircumflexgrave }, + { 0x1EC2, glyph_Ecircumflexhookabove }, + { 0x1EC4, glyph_Ecircumflextilde }, + { 0x0404, glyph_Ecyrillic }, + { 0x0204, glyph_Edblgrave }, + { 0x0116, glyph_Edot }, + { 0x1EB8, glyph_Edotbelow }, + { 0x0424, glyph_Efcyrillic }, + { 0x0537, glyph_Eharmenian }, + { 0x1EBA, glyph_Ehookabove }, + { 0x2167, glyph_Eightroman }, + { 0x0206, glyph_Einvertedbreve }, + { 0x0464, glyph_Eiotifiedcyrillic }, + { 0x041B, glyph_Elcyrillic }, + { 0x216A, glyph_Elevenroman }, + { 0x1E16, glyph_Emacronacute }, + { 0x1E14, glyph_Emacrongrave }, + { 0x041C, glyph_Emcyrillic }, + { 0xFF25, glyph_Emonospace }, + { 0x041D, glyph_Encyrillic }, + { 0x04A2, glyph_Endescendercyrillic }, + { 0x04A4, glyph_Enghecyrillic }, + { 0x04C7, glyph_Enhookcyrillic }, + { 0x0190, glyph_Eopen }, + { 0x0420, glyph_Ercyrillic }, + { 0x018E, glyph_Ereversed }, + { 0x042D, glyph_Ereversedcyrillic }, + { 0x0421, glyph_Escyrillic }, + { 0x04AA, glyph_Esdescendercyrillic }, + { 0x01A9, glyph_Esh }, + { 0x0538, glyph_Etarmenian }, + { 0x1EBC, glyph_Etilde }, + { 0x1E1A, glyph_Etildebelow }, + { 0x01B7, glyph_Ezh }, + { 0x01EE, glyph_Ezhcaron }, + { 0x01B8, glyph_Ezhreversed }, + { 0x24BB, glyph_Fcircle }, + { 0x1E1E, glyph_Fdotaccent }, + { 0x0556, glyph_Feharmenian }, + { 0x03E4, glyph_Feicoptic }, + { 0x0191, glyph_Fhook }, + { 0x0472, glyph_Fitacyrillic }, + { 0x2164, glyph_Fiveroman }, + { 0xFF26, glyph_Fmonospace }, + { 0x2163, glyph_Fourroman }, + { 0x3387, glyph_GBsquare }, + { 0x01F4, glyph_Gacute }, + { 0x0194, glyph_Gammaafrican }, + { 0x03EA, glyph_Gangiacoptic }, + { 0x0122, glyph_Gcedilla }, + { 0x24BC, glyph_Gcircle }, + { 0x0120, glyph_Gdot }, + { 0x0413, glyph_Gecyrillic }, + { 0x0542, glyph_Ghadarmenian }, + { 0x0494, glyph_Ghemiddlehookcyrillic }, + { 0x0492, glyph_Ghestrokecyrillic }, + { 0x0490, glyph_Gheupturncyrillic }, + { 0x0193, glyph_Ghook }, + { 0x0533, glyph_Gimarmenian }, + { 0x0403, glyph_Gjecyrillic }, + { 0x1E20, glyph_Gmacron }, + { 0xFF27, glyph_Gmonospace }, + { 0x029B, glyph_Gsmallhook }, + { 0x01E4, glyph_Gstroke }, + { 0x33CB, glyph_HPsquare }, + { 0x04A8, glyph_Haabkhasiancyrillic }, + { 0x04B2, glyph_Hadescendercyrillic }, + { 0x042A, glyph_Hardsigncyrillic }, + { 0x1E2A, glyph_Hbrevebelow }, + { 0x1E28, glyph_Hcedilla }, + { 0x24BD, glyph_Hcircle }, + { 0x1E26, glyph_Hdieresis }, + { 0x1E22, glyph_Hdotaccent }, + { 0x1E24, glyph_Hdotbelow }, + { 0xFF28, glyph_Hmonospace }, + { 0x0540, glyph_Hoarmenian }, + { 0x03E8, glyph_Horicoptic }, + { 0x3390, glyph_Hzsquare }, + { 0x042F, glyph_IAcyrillic }, + { 0x042E, glyph_IUcyrillic }, + { 0x01CF, glyph_Icaron }, + { 0x24BE, glyph_Icircle }, + { 0x0406, glyph_Icyrillic }, + { 0x0208, glyph_Idblgrave }, + { 0x1E2E, glyph_Idieresisacute }, + { 0x04E4, glyph_Idieresiscyrillic }, + { 0x0130, glyph_Idot }, + { 0x1ECA, glyph_Idotbelow }, + { 0x04D6, glyph_Iebrevecyrillic }, + { 0x0415, glyph_Iecyrillic }, + { 0x1EC8, glyph_Ihookabove }, + { 0x0418, glyph_Iicyrillic }, + { 0x020A, glyph_Iinvertedbreve }, + { 0x0419, glyph_Iishortcyrillic }, + { 0x04E2, glyph_Imacroncyrillic }, + { 0xFF29, glyph_Imonospace }, + { 0x053B, glyph_Iniarmenian }, + { 0x0401, glyph_Iocyrillic }, + { 0x0196, glyph_Iotaafrican }, + { 0x0197, glyph_Istroke }, + { 0x1E2C, glyph_Itildebelow }, + { 0x0474, glyph_Izhitsacyrillic }, + { 0x0476, glyph_Izhitsadblgravecyrillic }, + { 0x0541, glyph_Jaarmenian }, + { 0x24BF, glyph_Jcircle }, + { 0x0408, glyph_Jecyrillic }, + { 0x054B, glyph_Jheharmenian }, + { 0xFF2A, glyph_Jmonospace }, + { 0x3385, glyph_KBsquare }, + { 0x33CD, glyph_KKsquare }, + { 0x04A0, glyph_Kabashkircyrillic }, + { 0x1E30, glyph_Kacute }, + { 0x041A, glyph_Kacyrillic }, + { 0x049A, glyph_Kadescendercyrillic }, + { 0x04C3, glyph_Kahookcyrillic }, + { 0x049E, glyph_Kastrokecyrillic }, + { 0x049C, glyph_Kaverticalstrokecyrillic }, + { 0x01E8, glyph_Kcaron }, + { 0x0136, glyph_Kcedilla }, + { 0x24C0, glyph_Kcircle }, + { 0x1E32, glyph_Kdotbelow }, + { 0x0554, glyph_Keharmenian }, + { 0x053F, glyph_Kenarmenian }, + { 0x0425, glyph_Khacyrillic }, + { 0x03E6, glyph_Kheicoptic }, + { 0x0198, glyph_Khook }, + { 0x040C, glyph_Kjecyrillic }, + { 0x1E34, glyph_Klinebelow }, + { 0xFF2B, glyph_Kmonospace }, + { 0x0480, glyph_Koppacyrillic }, + { 0x03DE, glyph_Koppagreek }, + { 0x046E, glyph_Ksicyrillic }, + { 0x01C7, glyph_LJ }, + { 0x013B, glyph_Lcedilla }, + { 0x24C1, glyph_Lcircle }, + { 0x1E3C, glyph_Lcircumflexbelow }, + { 0x013F, glyph_Ldotaccent }, + { 0x1E36, glyph_Ldotbelow }, + { 0x1E38, glyph_Ldotbelowmacron }, + { 0x053C, glyph_Liwnarmenian }, + { 0x01C8, glyph_Lj }, + { 0x0409, glyph_Ljecyrillic }, + { 0x1E3A, glyph_Llinebelow }, + { 0xFF2C, glyph_Lmonospace }, + { 0x3386, glyph_MBsquare }, + { 0x1E3E, glyph_Macute }, + { 0x24C2, glyph_Mcircle }, + { 0x1E40, glyph_Mdotaccent }, + { 0x1E42, glyph_Mdotbelow }, + { 0x0544, glyph_Menarmenian }, + { 0xFF2D, glyph_Mmonospace }, + { 0x019C, glyph_Mturned }, + { 0x01CA, glyph_NJ }, + { 0x0145, glyph_Ncedilla }, + { 0x24C3, glyph_Ncircle }, + { 0x1E4A, glyph_Ncircumflexbelow }, + { 0x1E44, glyph_Ndotaccent }, + { 0x1E46, glyph_Ndotbelow }, + { 0x019D, glyph_Nhookleft }, + { 0x2168, glyph_Nineroman }, + { 0x01CB, glyph_Nj }, + { 0x040A, glyph_Njecyrillic }, + { 0x1E48, glyph_Nlinebelow }, + { 0xFF2E, glyph_Nmonospace }, + { 0x0546, glyph_Nowarmenian }, + { 0x04E8, glyph_Obarredcyrillic }, + { 0x04EA, glyph_Obarreddieresiscyrillic }, + { 0x01D1, glyph_Ocaron }, + { 0x019F, glyph_Ocenteredtilde }, + { 0x24C4, glyph_Ocircle }, + { 0x1ED0, glyph_Ocircumflexacute }, + { 0x1ED8, glyph_Ocircumflexdotbelow }, + { 0x1ED2, glyph_Ocircumflexgrave }, + { 0x1ED4, glyph_Ocircumflexhookabove }, + { 0x1ED6, glyph_Ocircumflextilde }, + { 0x041E, glyph_Ocyrillic }, + { 0x0150, glyph_Odblacute }, + { 0x020C, glyph_Odblgrave }, + { 0x04E6, glyph_Odieresiscyrillic }, + { 0x1ECC, glyph_Odotbelow }, + { 0x0555, glyph_Oharmenian }, + { 0x2126, glyph_Ohm }, + { 0x1ECE, glyph_Ohookabove }, + { 0x1EDA, glyph_Ohornacute }, + { 0x1EE2, glyph_Ohorndotbelow }, + { 0x1EDC, glyph_Ohorngrave }, + { 0x1EDE, glyph_Ohornhookabove }, + { 0x1EE0, glyph_Ohorntilde }, + { 0x01A2, glyph_Oi }, + { 0x020E, glyph_Oinvertedbreve }, + { 0x1E52, glyph_Omacronacute }, + { 0x1E50, glyph_Omacrongrave }, + { 0x0460, glyph_Omegacyrillic }, + { 0x047A, glyph_Omegaroundcyrillic }, + { 0x047C, glyph_Omegatitlocyrillic }, + { 0xFF2F, glyph_Omonospace }, + { 0x2160, glyph_Oneroman }, + { 0x01EA, glyph_Oogonek }, + { 0x01EC, glyph_Oogonekmacron }, + { 0x0186, glyph_Oopen }, + { 0x01FE, glyph_Ostrokeacute }, + { 0x047E, glyph_Otcyrillic }, + { 0x1E4C, glyph_Otildeacute }, + { 0x1E4E, glyph_Otildedieresis }, + { 0x1E54, glyph_Pacute }, + { 0x24C5, glyph_Pcircle }, + { 0x1E56, glyph_Pdotaccent }, + { 0x041F, glyph_Pecyrillic }, + { 0x054A, glyph_Peharmenian }, + { 0x04A6, glyph_Pemiddlehookcyrillic }, + { 0x01A4, glyph_Phook }, + { 0x0553, glyph_Piwrarmenian }, + { 0xFF30, glyph_Pmonospace }, + { 0x0470, glyph_Psicyrillic }, + { 0x24C6, glyph_Qcircle }, + { 0xFF31, glyph_Qmonospace }, + { 0x054C, glyph_Raarmenian }, + { 0x0156, glyph_Rcedilla }, + { 0x24C7, glyph_Rcircle }, + { 0x0210, glyph_Rdblgrave }, + { 0x1E58, glyph_Rdotaccent }, + { 0x1E5A, glyph_Rdotbelow }, + { 0x1E5C, glyph_Rdotbelowmacron }, + { 0x0550, glyph_Reharmenian }, + { 0x0212, glyph_Rinvertedbreve }, + { 0x1E5E, glyph_Rlinebelow }, + { 0xFF32, glyph_Rmonospace }, + { 0x0281, glyph_Rsmallinverted }, + { 0x02B6, glyph_Rsmallinvertedsuperior }, + { 0x1E64, glyph_Sacutedotaccent }, + { 0x03E0, glyph_Sampigreek }, + { 0x1E66, glyph_Scarondotaccent }, + { 0x018F, glyph_Schwa }, + { 0x04D8, glyph_Schwacyrillic }, + { 0x04DA, glyph_Schwadieresiscyrillic }, + { 0x24C8, glyph_Scircle }, + { 0x1E60, glyph_Sdotaccent }, + { 0x1E62, glyph_Sdotbelow }, + { 0x1E68, glyph_Sdotbelowdotaccent }, + { 0x054D, glyph_Seharmenian }, + { 0x2166, glyph_Sevenroman }, + { 0x0547, glyph_Shaarmenian }, + { 0x0428, glyph_Shacyrillic }, + { 0x0429, glyph_Shchacyrillic }, + { 0x03E2, glyph_Sheicoptic }, + { 0x04BA, glyph_Shhacyrillic }, + { 0x03EC, glyph_Shimacoptic }, + { 0x2165, glyph_Sixroman }, + { 0xFF33, glyph_Smonospace }, + { 0x042C, glyph_Softsigncyrillic }, + { 0x03DA, glyph_Stigmagreek }, + { 0x24C9, glyph_Tcircle }, + { 0x1E70, glyph_Tcircumflexbelow }, + { 0x1E6A, glyph_Tdotaccent }, + { 0x1E6C, glyph_Tdotbelow }, + { 0x0422, glyph_Tecyrillic }, + { 0x04AC, glyph_Tedescendercyrillic }, + { 0x2169, glyph_Tenroman }, + { 0x04B4, glyph_Tetsecyrillic }, + { 0x01AC, glyph_Thook }, + { 0x2162, glyph_Threeroman }, + { 0x054F, glyph_Tiwnarmenian }, + { 0x1E6E, glyph_Tlinebelow }, + { 0xFF34, glyph_Tmonospace }, + { 0x0539, glyph_Toarmenian }, + { 0x01BC, glyph_Tonefive }, + { 0x0184, glyph_Tonesix }, + { 0x01A7, glyph_Tonetwo }, + { 0x01AE, glyph_Tretroflexhook }, + { 0x0426, glyph_Tsecyrillic }, + { 0x040B, glyph_Tshecyrillic }, + { 0x216B, glyph_Twelveroman }, + { 0x2161, glyph_Tworoman }, + { 0x01D3, glyph_Ucaron }, + { 0x24CA, glyph_Ucircle }, + { 0x1E76, glyph_Ucircumflexbelow }, + { 0x0423, glyph_Ucyrillic }, + { 0x0170, glyph_Udblacute }, + { 0x0214, glyph_Udblgrave }, + { 0x01D7, glyph_Udieresisacute }, + { 0x1E72, glyph_Udieresisbelow }, + { 0x01D9, glyph_Udieresiscaron }, + { 0x04F0, glyph_Udieresiscyrillic }, + { 0x01DB, glyph_Udieresisgrave }, + { 0x01D5, glyph_Udieresismacron }, + { 0x1EE4, glyph_Udotbelow }, + { 0x1EE6, glyph_Uhookabove }, + { 0x1EE8, glyph_Uhornacute }, + { 0x1EF0, glyph_Uhorndotbelow }, + { 0x1EEA, glyph_Uhorngrave }, + { 0x1EEC, glyph_Uhornhookabove }, + { 0x1EEE, glyph_Uhorntilde }, + { 0x04F2, glyph_Uhungarumlautcyrillic }, + { 0x0216, glyph_Uinvertedbreve }, + { 0x0478, glyph_Ukcyrillic }, + { 0x04EE, glyph_Umacroncyrillic }, + { 0x1E7A, glyph_Umacrondieresis }, + { 0xFF35, glyph_Umonospace }, + { 0x03D3, glyph_Upsilonacutehooksymbolgreek }, + { 0x01B1, glyph_Upsilonafrican }, + { 0x03D4, glyph_Upsilondieresishooksymbolgreek }, + { 0x03D2, glyph_Upsilonhooksymbol }, + { 0x040E, glyph_Ushortcyrillic }, + { 0x04AE, glyph_Ustraightcyrillic }, + { 0x04B0, glyph_Ustraightstrokecyrillic }, + { 0x1E78, glyph_Utildeacute }, + { 0x1E74, glyph_Utildebelow }, + { 0x24CB, glyph_Vcircle }, + { 0x1E7E, glyph_Vdotbelow }, + { 0x0412, glyph_Vecyrillic }, + { 0x054E, glyph_Vewarmenian }, + { 0x01B2, glyph_Vhook }, + { 0xFF36, glyph_Vmonospace }, + { 0x0548, glyph_Voarmenian }, + { 0x1E7C, glyph_Vtilde }, + { 0x24CC, glyph_Wcircle }, + { 0x1E86, glyph_Wdotaccent }, + { 0x1E88, glyph_Wdotbelow }, + { 0xFF37, glyph_Wmonospace }, + { 0x24CD, glyph_Xcircle }, + { 0x1E8C, glyph_Xdieresis }, + { 0x1E8A, glyph_Xdotaccent }, + { 0x053D, glyph_Xeharmenian }, + { 0xFF38, glyph_Xmonospace }, + { 0x0462, glyph_Yatcyrillic }, + { 0x24CE, glyph_Ycircle }, + { 0x1E8E, glyph_Ydotaccent }, + { 0x1EF4, glyph_Ydotbelow }, + { 0x042B, glyph_Yericyrillic }, + { 0x04F8, glyph_Yerudieresiscyrillic }, + { 0x01B3, glyph_Yhook }, + { 0x1EF6, glyph_Yhookabove }, + { 0x0545, glyph_Yiarmenian }, + { 0x0407, glyph_Yicyrillic }, + { 0x0552, glyph_Yiwnarmenian }, + { 0xFF39, glyph_Ymonospace }, + { 0x1EF8, glyph_Ytilde }, + { 0x046A, glyph_Yusbigcyrillic }, + { 0x046C, glyph_Yusbigiotifiedcyrillic }, + { 0x0466, glyph_Yuslittlecyrillic }, + { 0x0468, glyph_Yuslittleiotifiedcyrillic }, + { 0x0536, glyph_Zaarmenian }, + { 0x24CF, glyph_Zcircle }, + { 0x1E90, glyph_Zcircumflex }, + { 0x017B, glyph_Zdot }, + { 0x1E92, glyph_Zdotbelow }, + { 0x0417, glyph_Zecyrillic }, + { 0x0498, glyph_Zedescendercyrillic }, + { 0x04DE, glyph_Zedieresiscyrillic }, + { 0x053A, glyph_Zhearmenian }, + { 0x04C1, glyph_Zhebrevecyrillic }, + { 0x0416, glyph_Zhecyrillic }, + { 0x0496, glyph_Zhedescendercyrillic }, + { 0x04DC, glyph_Zhedieresiscyrillic }, + { 0x1E94, glyph_Zlinebelow }, + { 0xFF3A, glyph_Zmonospace }, + { 0x01B5, glyph_Zstroke }, + { 0x0986, glyph_aabengali }, + { 0x0906, glyph_aadeva }, + { 0x0A86, glyph_aagujarati }, + { 0x0A06, glyph_aagurmukhi }, + { 0x0A3E, glyph_aamatragurmukhi }, + { 0x3303, glyph_aarusquare }, + { 0x09BE, glyph_aavowelsignbengali }, + { 0x093E, glyph_aavowelsigndeva }, + { 0x0ABE, glyph_aavowelsigngujarati }, + { 0x055F, glyph_abbreviationmarkarmenian }, + { 0x0970, glyph_abbreviationsigndeva }, + { 0x0985, glyph_abengali }, + { 0x311A, glyph_abopomofo }, + { 0x1EAF, glyph_abreveacute }, + { 0x04D1, glyph_abrevecyrillic }, + { 0x1EB7, glyph_abrevedotbelow }, + { 0x1EB1, glyph_abrevegrave }, + { 0x1EB3, glyph_abrevehookabove }, + { 0x1EB5, glyph_abrevetilde }, + { 0x01CE, glyph_acaron }, + { 0x24D0, glyph_acircle }, + { 0x1EA5, glyph_acircumflexacute }, + { 0x1EAD, glyph_acircumflexdotbelow }, + { 0x1EA7, glyph_acircumflexgrave }, + { 0x1EA9, glyph_acircumflexhookabove }, + { 0x1EAB, glyph_acircumflextilde }, + { 0x0317, glyph_acutebelowcmb }, + { 0x0301, glyph_acutecmb }, + { 0x0954, glyph_acutedeva }, + { 0x02CF, glyph_acutelowmod }, + { 0x0341, glyph_acutetonecmb }, + { 0x0430, glyph_acyrillic }, + { 0x0201, glyph_adblgrave }, + { 0x0A71, glyph_addakgurmukhi }, + { 0x0905, glyph_adeva }, + { 0x04D3, glyph_adieresiscyrillic }, + { 0x01DF, glyph_adieresismacron }, + { 0x1EA1, glyph_adotbelow }, + { 0x01E1, glyph_adotmacron }, + { 0x3150, glyph_aekorean }, + { 0x01E3, glyph_aemacron }, + { 0x20A4, glyph_afii08941 }, + { 0x0A85, glyph_agujarati }, + { 0x0A05, glyph_agurmukhi }, + { 0x3042, glyph_ahiragana }, + { 0x1EA3, glyph_ahookabove }, + { 0x0990, glyph_aibengali }, + { 0x311E, glyph_aibopomofo }, + { 0x0910, glyph_aideva }, + { 0x04D5, glyph_aiecyrillic }, + { 0x0A90, glyph_aigujarati }, + { 0x0A10, glyph_aigurmukhi }, + { 0x0A48, glyph_aimatragurmukhi }, + { 0x0639, glyph_ainarabic }, + { 0xFECA, glyph_ainfinalarabic }, + { 0xFECB, glyph_aininitialarabic }, + { 0xFECC, glyph_ainmedialarabic }, + { 0x0203, glyph_ainvertedbreve }, + { 0x09C8, glyph_aivowelsignbengali }, + { 0x0948, glyph_aivowelsigndeva }, + { 0x0AC8, glyph_aivowelsigngujarati }, + { 0x30A2, glyph_akatakana }, + { 0xFF71, glyph_akatakanahalfwidth }, + { 0x314F, glyph_akorean }, + { 0x05D0, glyph_alef }, + { 0x0627, glyph_alefarabic }, + { 0xFB30, glyph_alefdageshhebrew }, + { 0xFE8E, glyph_aleffinalarabic }, + { 0x0623, glyph_alefhamzaabovearabic }, + { 0xFE84, glyph_alefhamzaabovefinalarabic }, + { 0x0625, glyph_alefhamzabelowarabic }, + { 0xFE88, glyph_alefhamzabelowfinalarabic }, + { 0x05D0, glyph_alefhebrew }, + { 0xFB4F, glyph_aleflamedhebrew }, + { 0x0622, glyph_alefmaddaabovearabic }, + { 0xFE82, glyph_alefmaddaabovefinalarabic }, + { 0x0649, glyph_alefmaksuraarabic }, + { 0xFEF0, glyph_alefmaksurafinalarabic }, + { 0xFEF3, glyph_alefmaksurainitialarabic }, + { 0xFEF4, glyph_alefmaksuramedialarabic }, + { 0xFB2E, glyph_alefpatahhebrew }, + { 0xFB2F, glyph_alefqamatshebrew }, + { 0x224C, glyph_allequal }, + { 0xFF41, glyph_amonospace }, + { 0xFF06, glyph_ampersandmonospace }, + { 0x33C2, glyph_amsquare }, + { 0x3122, glyph_anbopomofo }, + { 0x3124, glyph_angbopomofo }, + { 0x0E5A, glyph_angkhankhuthai }, + { 0x3008, glyph_anglebracketleft }, + { 0xFE3F, glyph_anglebracketleftvertical }, + { 0x3009, glyph_anglebracketright }, + { 0xFE40, glyph_anglebracketrightvertical }, + { 0x212B, glyph_angstrom }, + { 0x0952, glyph_anudattadeva }, + { 0x0982, glyph_anusvarabengali }, + { 0x0902, glyph_anusvaradeva }, + { 0x0A82, glyph_anusvaragujarati }, + { 0x3300, glyph_apaatosquare }, + { 0x249C, glyph_aparen }, + { 0x055A, glyph_apostrophearmenian }, + { 0x02BC, glyph_apostrophemod }, + { 0x2250, glyph_approaches }, + { 0x2252, glyph_approxequalorimage }, + { 0x2245, glyph_approximatelyequal }, + { 0x318E, glyph_araeaekorean }, + { 0x318D, glyph_araeakorean }, + { 0x2312, glyph_arc }, + { 0x1E9A, glyph_arighthalfring }, + { 0x1E01, glyph_aringbelow }, + { 0x21E3, glyph_arrowdashdown }, + { 0x21E0, glyph_arrowdashleft }, + { 0x21E2, glyph_arrowdashright }, + { 0x21E1, glyph_arrowdashup }, + { 0x2199, glyph_arrowdownleft }, + { 0x2198, glyph_arrowdownright }, + { 0x21E9, glyph_arrowdownwhite }, + { 0x02C5, glyph_arrowheaddownmod }, + { 0x02C2, glyph_arrowheadleftmod }, + { 0x02C3, glyph_arrowheadrightmod }, + { 0x02C4, glyph_arrowheadupmod }, + { 0x21D0, glyph_arrowleftdbl }, + { 0x21CD, glyph_arrowleftdblstroke }, + { 0x21C6, glyph_arrowleftoverright }, + { 0x21E6, glyph_arrowleftwhite }, + { 0x21CF, glyph_arrowrightdblstroke }, + { 0x279E, glyph_arrowrightheavy }, + { 0x21C4, glyph_arrowrightoverleft }, + { 0x21E8, glyph_arrowrightwhite }, + { 0x21E4, glyph_arrowtableft }, + { 0x21E5, glyph_arrowtabright }, + { 0x21A8, glyph_arrowupdownbase }, + { 0x2196, glyph_arrowupleft }, + { 0x21C5, glyph_arrowupleftofdown }, + { 0x2197, glyph_arrowupright }, + { 0x21E7, glyph_arrowupwhite }, + { 0xFF3E, glyph_asciicircummonospace }, + { 0xFF5E, glyph_asciitildemonospace }, + { 0x0251, glyph_ascript }, + { 0x0252, glyph_ascriptturned }, + { 0x3041, glyph_asmallhiragana }, + { 0x30A1, glyph_asmallkatakana }, + { 0xFF67, glyph_asmallkatakanahalfwidth }, + { 0x066D, glyph_asteriskaltonearabic }, + { 0x066D, glyph_asteriskarabic }, + { 0xFF0A, glyph_asteriskmonospace }, + { 0xFE61, glyph_asterisksmall }, + { 0x2042, glyph_asterism }, + { 0x2243, glyph_asymptoticallyequal }, + { 0xFF20, glyph_atmonospace }, + { 0xFE6B, glyph_atsmall }, + { 0x0250, glyph_aturned }, + { 0x0994, glyph_aubengali }, + { 0x3120, glyph_aubopomofo }, + { 0x0914, glyph_audeva }, + { 0x0A94, glyph_augujarati }, + { 0x0A14, glyph_augurmukhi }, + { 0x09D7, glyph_aulengthmarkbengali }, + { 0x0A4C, glyph_aumatragurmukhi }, + { 0x09CC, glyph_auvowelsignbengali }, + { 0x094C, glyph_auvowelsigndeva }, + { 0x0ACC, glyph_auvowelsigngujarati }, + { 0x093D, glyph_avagrahadeva }, + { 0x0561, glyph_aybarmenian }, + { 0x05E2, glyph_ayin }, + { 0xFB20, glyph_ayinaltonehebrew }, + { 0x05E2, glyph_ayinhebrew }, + { 0x09AC, glyph_babengali }, + { 0xFF3C, glyph_backslashmonospace }, + { 0x092C, glyph_badeva }, + { 0x0AAC, glyph_bagujarati }, + { 0x0A2C, glyph_bagurmukhi }, + { 0x3070, glyph_bahiragana }, + { 0x0E3F, glyph_bahtthai }, + { 0x30D0, glyph_bakatakana }, + { 0xFF5C, glyph_barmonospace }, + { 0x3105, glyph_bbopomofo }, + { 0x24D1, glyph_bcircle }, + { 0x1E03, glyph_bdotaccent }, + { 0x1E05, glyph_bdotbelow }, + { 0x266C, glyph_beamedsixteenthnotes }, + { 0x2235, glyph_because }, + { 0x0431, glyph_becyrillic }, + { 0x0628, glyph_beharabic }, + { 0xFE90, glyph_behfinalarabic }, + { 0xFE91, glyph_behinitialarabic }, + { 0x3079, glyph_behiragana }, + { 0xFE92, glyph_behmedialarabic }, + { 0xFC9F, glyph_behmeeminitialarabic }, + { 0xFC08, glyph_behmeemisolatedarabic }, + { 0xFC6D, glyph_behnoonfinalarabic }, + { 0x30D9, glyph_bekatakana }, + { 0x0562, glyph_benarmenian }, + { 0x05D1, glyph_bet }, + { 0x03D0, glyph_betasymbolgreek }, + { 0xFB31, glyph_betdagesh }, + { 0xFB31, glyph_betdageshhebrew }, + { 0x05D1, glyph_bethebrew }, + { 0xFB4C, glyph_betrafehebrew }, + { 0x09AD, glyph_bhabengali }, + { 0x092D, glyph_bhadeva }, + { 0x0AAD, glyph_bhagujarati }, + { 0x0A2D, glyph_bhagurmukhi }, + { 0x0253, glyph_bhook }, + { 0x3073, glyph_bihiragana }, + { 0x30D3, glyph_bikatakana }, + { 0x0298, glyph_bilabialclick }, + { 0x0A02, glyph_bindigurmukhi }, + { 0x3331, glyph_birusquare }, + { 0x25CF, glyph_blackcircle }, + { 0x25C6, glyph_blackdiamond }, + { 0x25BC, glyph_blackdownpointingtriangle }, + { 0x25C4, glyph_blackleftpointingpointer }, + { 0x25C0, glyph_blackleftpointingtriangle }, + { 0x3010, glyph_blacklenticularbracketleft }, + { 0xFE3B, glyph_blacklenticularbracketleftvertical }, + { 0x3011, glyph_blacklenticularbracketright }, + { 0xFE3C, glyph_blacklenticularbracketrightvertical }, + { 0x25E3, glyph_blacklowerlefttriangle }, + { 0x25E2, glyph_blacklowerrighttriangle }, + { 0x25AC, glyph_blackrectangle }, + { 0x25BA, glyph_blackrightpointingpointer }, + { 0x25B6, glyph_blackrightpointingtriangle }, + { 0x25AA, glyph_blacksmallsquare }, + { 0x263B, glyph_blacksmilingface }, + { 0x25A0, glyph_blacksquare }, + { 0x2605, glyph_blackstar }, + { 0x25E4, glyph_blackupperlefttriangle }, + { 0x25E5, glyph_blackupperrighttriangle }, + { 0x25B4, glyph_blackuppointingsmalltriangle }, + { 0x25B2, glyph_blackuppointingtriangle }, + { 0x2423, glyph_blank }, + { 0x1E07, glyph_blinebelow }, + { 0xFF42, glyph_bmonospace }, + { 0x0E1A, glyph_bobaimaithai }, + { 0x307C, glyph_bohiragana }, + { 0x30DC, glyph_bokatakana }, + { 0x249D, glyph_bparen }, + { 0x33C3, glyph_bqsquare }, + { 0xFF5B, glyph_braceleftmonospace }, + { 0xFE5B, glyph_braceleftsmall }, + { 0xFE37, glyph_braceleftvertical }, + { 0xFF5D, glyph_bracerightmonospace }, + { 0xFE5C, glyph_bracerightsmall }, + { 0xFE38, glyph_bracerightvertical }, + { 0xFF3B, glyph_bracketleftmonospace }, + { 0xFF3D, glyph_bracketrightmonospace }, + { 0x032E, glyph_brevebelowcmb }, + { 0x0306, glyph_brevecmb }, + { 0x032F, glyph_breveinvertedbelowcmb }, + { 0x0311, glyph_breveinvertedcmb }, + { 0x0361, glyph_breveinverteddoublecmb }, + { 0x032A, glyph_bridgebelowcmb }, + { 0x033A, glyph_bridgeinvertedbelowcmb }, + { 0x0180, glyph_bstroke }, + { 0x0183, glyph_btopbar }, + { 0x3076, glyph_buhiragana }, + { 0x30D6, glyph_bukatakana }, + { 0x25D8, glyph_bulletinverse }, + { 0x25CE, glyph_bullseye }, + { 0x056E, glyph_caarmenian }, + { 0x099A, glyph_cabengali }, + { 0x091A, glyph_cadeva }, + { 0x0A9A, glyph_cagujarati }, + { 0x0A1A, glyph_cagurmukhi }, + { 0x3388, glyph_calsquare }, + { 0x0981, glyph_candrabindubengali }, + { 0x0310, glyph_candrabinducmb }, + { 0x0901, glyph_candrabindudeva }, + { 0x0A81, glyph_candrabindugujarati }, + { 0x21EA, glyph_capslock }, + { 0x2105, glyph_careof }, + { 0x032C, glyph_caronbelowcmb }, + { 0x030C, glyph_caroncmb }, + { 0x3118, glyph_cbopomofo }, + { 0x1E09, glyph_ccedillaacute }, + { 0x24D2, glyph_ccircle }, + { 0x0255, glyph_ccurl }, + { 0x010B, glyph_cdot }, + { 0x33C5, glyph_cdsquare }, + { 0x0327, glyph_cedillacmb }, + { 0x2103, glyph_centigrade }, + { 0xFFE0, glyph_centmonospace }, + { 0x0579, glyph_chaarmenian }, + { 0x099B, glyph_chabengali }, + { 0x091B, glyph_chadeva }, + { 0x0A9B, glyph_chagujarati }, + { 0x0A1B, glyph_chagurmukhi }, + { 0x3114, glyph_chbopomofo }, + { 0x04BD, glyph_cheabkhasiancyrillic }, + { 0x2713, glyph_checkmark }, + { 0x0447, glyph_checyrillic }, + { 0x04BF, glyph_chedescenderabkhasiancyrillic }, + { 0x04B7, glyph_chedescendercyrillic }, + { 0x04F5, glyph_chedieresiscyrillic }, + { 0x0573, glyph_cheharmenian }, + { 0x04CC, glyph_chekhakassiancyrillic }, + { 0x04B9, glyph_cheverticalstrokecyrillic }, + { 0x3277, glyph_chieuchacirclekorean }, + { 0x3217, glyph_chieuchaparenkorean }, + { 0x3269, glyph_chieuchcirclekorean }, + { 0x314A, glyph_chieuchkorean }, + { 0x3209, glyph_chieuchparenkorean }, + { 0x0E0A, glyph_chochangthai }, + { 0x0E08, glyph_chochanthai }, + { 0x0E09, glyph_chochingthai }, + { 0x0E0C, glyph_chochoethai }, + { 0x0188, glyph_chook }, + { 0x3276, glyph_cieucacirclekorean }, + { 0x3216, glyph_cieucaparenkorean }, + { 0x3268, glyph_cieuccirclekorean }, + { 0x3148, glyph_cieuckorean }, + { 0x3208, glyph_cieucparenkorean }, + { 0x321C, glyph_cieucuparenkorean }, + { 0x2299, glyph_circleot }, + { 0x3036, glyph_circlepostalmark }, + { 0x25D0, glyph_circlewithlefthalfblack }, + { 0x25D1, glyph_circlewithrighthalfblack }, + { 0x032D, glyph_circumflexbelowcmb }, + { 0x0302, glyph_circumflexcmb }, + { 0x2327, glyph_clear }, + { 0x01C2, glyph_clickalveolar }, + { 0x01C0, glyph_clickdental }, + { 0x01C1, glyph_clicklateral }, + { 0x01C3, glyph_clickretroflex }, + { 0x2663, glyph_clubsuitblack }, + { 0x2667, glyph_clubsuitwhite }, + { 0x33A4, glyph_cmcubedsquare }, + { 0xFF43, glyph_cmonospace }, + { 0x33A0, glyph_cmsquaredsquare }, + { 0x0581, glyph_coarmenian }, + { 0xFF1A, glyph_colonmonospace }, + { 0x20A1, glyph_colonsign }, + { 0xFE55, glyph_colonsmall }, + { 0x02D1, glyph_colontriangularhalfmod }, + { 0x02D0, glyph_colontriangularmod }, + { 0x0313, glyph_commaabovecmb }, + { 0x0315, glyph_commaaboverightcmb }, + { 0x060C, glyph_commaarabic }, + { 0x055D, glyph_commaarmenian }, + { 0xFF0C, glyph_commamonospace }, + { 0x0314, glyph_commareversedabovecmb }, + { 0x02BD, glyph_commareversedmod }, + { 0xFE50, glyph_commasmall }, + { 0x0312, glyph_commaturnedabovecmb }, + { 0x02BB, glyph_commaturnedmod }, + { 0x263C, glyph_compass }, + { 0x222E, glyph_contourintegral }, + { 0x2303, glyph_control }, + { 0x0006, glyph_controlACK }, + { 0x0007, glyph_controlBEL }, + { 0x0008, glyph_controlBS }, + { 0x0018, glyph_controlCAN }, + { 0x000D, glyph_controlCR }, + { 0x0011, glyph_controlDC1 }, + { 0x0012, glyph_controlDC2 }, + { 0x0013, glyph_controlDC3 }, + { 0x0014, glyph_controlDC4 }, + { 0x007F, glyph_controlDEL }, + { 0x0010, glyph_controlDLE }, + { 0x0019, glyph_controlEM }, + { 0x0005, glyph_controlENQ }, + { 0x0004, glyph_controlEOT }, + { 0x001B, glyph_controlESC }, + { 0x0017, glyph_controlETB }, + { 0x0003, glyph_controlETX }, + { 0x000C, glyph_controlFF }, + { 0x001C, glyph_controlFS }, + { 0x001D, glyph_controlGS }, + { 0x0009, glyph_controlHT }, + { 0x000A, glyph_controlLF }, + { 0x0015, glyph_controlNAK }, + { 0x001E, glyph_controlRS }, + { 0x000F, glyph_controlSI }, + { 0x000E, glyph_controlSO }, + { 0x0002, glyph_controlSOT }, + { 0x0001, glyph_controlSTX }, + { 0x001A, glyph_controlSUB }, + { 0x0016, glyph_controlSYN }, + { 0x001F, glyph_controlUS }, + { 0x000B, glyph_controlVT }, + { 0x300C, glyph_cornerbracketleft }, + { 0xFF62, glyph_cornerbracketlefthalfwidth }, + { 0xFE41, glyph_cornerbracketleftvertical }, + { 0x300D, glyph_cornerbracketright }, + { 0xFF63, glyph_cornerbracketrighthalfwidth }, + { 0xFE42, glyph_cornerbracketrightvertical }, + { 0x337F, glyph_corporationsquare }, + { 0x33C7, glyph_cosquare }, + { 0x33C6, glyph_coverkgsquare }, + { 0x249E, glyph_cparen }, + { 0x20A2, glyph_cruzeiro }, + { 0x0297, glyph_cstretched }, + { 0x22CF, glyph_curlyand }, + { 0x22CE, glyph_curlyor }, + { 0x0564, glyph_daarmenian }, + { 0x09A6, glyph_dabengali }, + { 0x0636, glyph_dadarabic }, + { 0x0926, glyph_dadeva }, + { 0xFEBE, glyph_dadfinalarabic }, + { 0xFEBF, glyph_dadinitialarabic }, + { 0xFEC0, glyph_dadmedialarabic }, + { 0x05BC, glyph_dagesh }, + { 0x05BC, glyph_dageshhebrew }, + { 0x0AA6, glyph_dagujarati }, + { 0x0A26, glyph_dagurmukhi }, + { 0x3060, glyph_dahiragana }, + { 0x30C0, glyph_dakatakana }, + { 0x062F, glyph_dalarabic }, + { 0x05D3, glyph_dalet }, + { 0xFB33, glyph_daletdagesh }, + { 0xFB33, glyph_daletdageshhebrew }, + { 0x05D3, glyph_dalethatafpatah }, + { 0x05B2, glyph_dalethatafpatah }, + { 0x05D3, glyph_dalethatafpatahhebrew }, + { 0x05B2, glyph_dalethatafpatahhebrew }, + { 0x05D3, glyph_dalethatafsegol }, + { 0x05B1, glyph_dalethatafsegol }, + { 0x05D3, glyph_dalethatafsegolhebrew }, + { 0x05B1, glyph_dalethatafsegolhebrew }, + { 0x05D3, glyph_dalethebrew }, + { 0x05D3, glyph_dalethiriq }, + { 0x05B4, glyph_dalethiriq }, + { 0x05D3, glyph_dalethiriqhebrew }, + { 0x05B4, glyph_dalethiriqhebrew }, + { 0x05D3, glyph_daletholam }, + { 0x05B9, glyph_daletholam }, + { 0x05D3, glyph_daletholamhebrew }, + { 0x05B9, glyph_daletholamhebrew }, + { 0x05D3, glyph_daletpatah }, + { 0x05B7, glyph_daletpatah }, + { 0x05D3, glyph_daletpatahhebrew }, + { 0x05B7, glyph_daletpatahhebrew }, + { 0x05D3, glyph_daletqamats }, + { 0x05B8, glyph_daletqamats }, + { 0x05D3, glyph_daletqamatshebrew }, + { 0x05B8, glyph_daletqamatshebrew }, + { 0x05D3, glyph_daletqubuts }, + { 0x05BB, glyph_daletqubuts }, + { 0x05D3, glyph_daletqubutshebrew }, + { 0x05BB, glyph_daletqubutshebrew }, + { 0x05D3, glyph_daletsegol }, + { 0x05B6, glyph_daletsegol }, + { 0x05D3, glyph_daletsegolhebrew }, + { 0x05B6, glyph_daletsegolhebrew }, + { 0x05D3, glyph_daletsheva }, + { 0x05B0, glyph_daletsheva }, + { 0x05D3, glyph_daletshevahebrew }, + { 0x05B0, glyph_daletshevahebrew }, + { 0x05D3, glyph_dalettsere }, + { 0x05B5, glyph_dalettsere }, + { 0x05D3, glyph_dalettserehebrew }, + { 0x05B5, glyph_dalettserehebrew }, + { 0xFEAA, glyph_dalfinalarabic }, + { 0x064F, glyph_dammaarabic }, + { 0x064F, glyph_dammalowarabic }, + { 0x064C, glyph_dammatanaltonearabic }, + { 0x064C, glyph_dammatanarabic }, + { 0x0964, glyph_danda }, + { 0x05A7, glyph_dargahebrew }, + { 0x05A7, glyph_dargalefthebrew }, + { 0x0485, glyph_dasiapneumatacyrilliccmb }, + { 0x300A, glyph_dblanglebracketleft }, + { 0xFE3D, glyph_dblanglebracketleftvertical }, + { 0x300B, glyph_dblanglebracketright }, + { 0xFE3E, glyph_dblanglebracketrightvertical }, + { 0x032B, glyph_dblarchinvertedbelowcmb }, + { 0x21D4, glyph_dblarrowleft }, + { 0x21D2, glyph_dblarrowright }, + { 0x0965, glyph_dbldanda }, + { 0x030F, glyph_dblgravecmb }, + { 0x222C, glyph_dblintegral }, + { 0x2017, glyph_dbllowline }, + { 0x0333, glyph_dbllowlinecmb }, + { 0x033F, glyph_dbloverlinecmb }, + { 0x02BA, glyph_dblprimemod }, + { 0x2016, glyph_dblverticalbar }, + { 0x030E, glyph_dblverticallineabovecmb }, + { 0x3109, glyph_dbopomofo }, + { 0x33C8, glyph_dbsquare }, + { 0x1E11, glyph_dcedilla }, + { 0x24D3, glyph_dcircle }, + { 0x1E13, glyph_dcircumflexbelow }, + { 0x09A1, glyph_ddabengali }, + { 0x0921, glyph_ddadeva }, + { 0x0AA1, glyph_ddagujarati }, + { 0x0A21, glyph_ddagurmukhi }, + { 0x0688, glyph_ddalarabic }, + { 0xFB89, glyph_ddalfinalarabic }, + { 0x095C, glyph_dddhadeva }, + { 0x09A2, glyph_ddhabengali }, + { 0x0922, glyph_ddhadeva }, + { 0x0AA2, glyph_ddhagujarati }, + { 0x0A22, glyph_ddhagurmukhi }, + { 0x1E0B, glyph_ddotaccent }, + { 0x1E0D, glyph_ddotbelow }, + { 0x066B, glyph_decimalseparatorarabic }, + { 0x066B, glyph_decimalseparatorpersian }, + { 0x0434, glyph_decyrillic }, + { 0x05AD, glyph_dehihebrew }, + { 0x3067, glyph_dehiragana }, + { 0x03EF, glyph_deicoptic }, + { 0x30C7, glyph_dekatakana }, + { 0x232B, glyph_deleteleft }, + { 0x2326, glyph_deleteright }, + { 0x018D, glyph_deltaturned }, + { 0x09F8, glyph_denominatorminusonenumeratorbengali }, + { 0x02A4, glyph_dezh }, + { 0x09A7, glyph_dhabengali }, + { 0x0927, glyph_dhadeva }, + { 0x0AA7, glyph_dhagujarati }, + { 0x0A27, glyph_dhagurmukhi }, + { 0x0257, glyph_dhook }, + { 0x0385, glyph_dialytikatonos }, + { 0x0344, glyph_dialytikatonoscmb }, + { 0x2662, glyph_diamondsuitwhite }, + { 0x0324, glyph_dieresisbelowcmb }, + { 0x0308, glyph_dieresiscmb }, + { 0x3062, glyph_dihiragana }, + { 0x30C2, glyph_dikatakana }, + { 0x3003, glyph_dittomark }, + { 0x2223, glyph_divides }, + { 0x0452, glyph_djecyrillic }, + { 0x1E0F, glyph_dlinebelow }, + { 0x3397, glyph_dlsquare }, + { 0x0111, glyph_dmacron }, + { 0xFF44, glyph_dmonospace }, + { 0x0E0E, glyph_dochadathai }, + { 0x0E14, glyph_dodekthai }, + { 0x3069, glyph_dohiragana }, + { 0x30C9, glyph_dokatakana }, + { 0xFF04, glyph_dollarmonospace }, + { 0xFE69, glyph_dollarsmall }, + { 0x3326, glyph_dorusquare }, + { 0x0307, glyph_dotaccentcmb }, + { 0x0323, glyph_dotbelowcmb }, + { 0x30FB, glyph_dotkatakana }, + { 0x0284, glyph_dotlessjstrokehook }, + { 0x25CC, glyph_dottedcircle }, + { 0xFB1F, glyph_doubleyodpatah }, + { 0xFB1F, glyph_doubleyodpatahhebrew }, + { 0x031E, glyph_downtackbelowcmb }, + { 0x02D5, glyph_downtackmod }, + { 0x249F, glyph_dparen }, + { 0x0256, glyph_dtail }, + { 0x018C, glyph_dtopbar }, + { 0x3065, glyph_duhiragana }, + { 0x30C5, glyph_dukatakana }, + { 0x01F3, glyph_dz }, + { 0x02A3, glyph_dzaltone }, + { 0x01C6, glyph_dzcaron }, + { 0x02A5, glyph_dzcurl }, + { 0x04E1, glyph_dzeabkhasiancyrillic }, + { 0x0455, glyph_dzecyrillic }, + { 0x045F, glyph_dzhecyrillic }, + { 0x2641, glyph_earth }, + { 0x098F, glyph_ebengali }, + { 0x311C, glyph_ebopomofo }, + { 0x090D, glyph_ecandradeva }, + { 0x0A8D, glyph_ecandragujarati }, + { 0x0945, glyph_ecandravowelsigndeva }, + { 0x0AC5, glyph_ecandravowelsigngujarati }, + { 0x1E1D, glyph_ecedillabreve }, + { 0x0565, glyph_echarmenian }, + { 0x0587, glyph_echyiwnarmenian }, + { 0x24D4, glyph_ecircle }, + { 0x1EBF, glyph_ecircumflexacute }, + { 0x1E19, glyph_ecircumflexbelow }, + { 0x1EC7, glyph_ecircumflexdotbelow }, + { 0x1EC1, glyph_ecircumflexgrave }, + { 0x1EC3, glyph_ecircumflexhookabove }, + { 0x1EC5, glyph_ecircumflextilde }, + { 0x0454, glyph_ecyrillic }, + { 0x0205, glyph_edblgrave }, + { 0x090F, glyph_edeva }, + { 0x0117, glyph_edot }, + { 0x1EB9, glyph_edotbelow }, + { 0x0A0F, glyph_eegurmukhi }, + { 0x0A47, glyph_eematragurmukhi }, + { 0x0444, glyph_efcyrillic }, + { 0x0A8F, glyph_egujarati }, + { 0x0567, glyph_eharmenian }, + { 0x311D, glyph_ehbopomofo }, + { 0x3048, glyph_ehiragana }, + { 0x1EBB, glyph_ehookabove }, + { 0x311F, glyph_eibopomofo }, + { 0x0668, glyph_eightarabic }, + { 0x09EE, glyph_eightbengali }, + { 0x2467, glyph_eightcircle }, + { 0x2791, glyph_eightcircleinversesansserif }, + { 0x096E, glyph_eightdeva }, + { 0x2471, glyph_eighteencircle }, + { 0x2485, glyph_eighteenparen }, + { 0x2499, glyph_eighteenperiod }, + { 0x0AEE, glyph_eightgujarati }, + { 0x0A6E, glyph_eightgurmukhi }, + { 0x0668, glyph_eighthackarabic }, + { 0x3028, glyph_eighthangzhou }, + { 0x266B, glyph_eighthnotebeamed }, + { 0x3227, glyph_eightideographicparen }, + { 0xFF18, glyph_eightmonospace }, + { 0x247B, glyph_eightparen }, + { 0x248F, glyph_eightperiod }, + { 0x06F8, glyph_eightpersian }, + { 0x2177, glyph_eightroman }, + { 0x0E58, glyph_eightthai }, + { 0x0207, glyph_einvertedbreve }, + { 0x0465, glyph_eiotifiedcyrillic }, + { 0x30A8, glyph_ekatakana }, + { 0xFF74, glyph_ekatakanahalfwidth }, + { 0x0A74, glyph_ekonkargurmukhi }, + { 0x3154, glyph_ekorean }, + { 0x043B, glyph_elcyrillic }, + { 0x246A, glyph_elevencircle }, + { 0x247E, glyph_elevenparen }, + { 0x2492, glyph_elevenperiod }, + { 0x217A, glyph_elevenroman }, + { 0x22EE, glyph_ellipsisvertical }, + { 0x1E17, glyph_emacronacute }, + { 0x1E15, glyph_emacrongrave }, + { 0x043C, glyph_emcyrillic }, + { 0xFE31, glyph_emdashvertical }, + { 0xFF45, glyph_emonospace }, + { 0x055B, glyph_emphasismarkarmenian }, + { 0x3123, glyph_enbopomofo }, + { 0x043D, glyph_encyrillic }, + { 0xFE32, glyph_endashvertical }, + { 0x04A3, glyph_endescendercyrillic }, + { 0x3125, glyph_engbopomofo }, + { 0x04A5, glyph_enghecyrillic }, + { 0x04C8, glyph_enhookcyrillic }, + { 0x2002, glyph_enspace }, + { 0x3153, glyph_eokorean }, + { 0x025B, glyph_eopen }, + { 0x029A, glyph_eopenclosed }, + { 0x025C, glyph_eopenreversed }, + { 0x025E, glyph_eopenreversedclosed }, + { 0x025D, glyph_eopenreversedhook }, + { 0x24A0, glyph_eparen }, + { 0xFF1D, glyph_equalmonospace }, + { 0xFE66, glyph_equalsmall }, + { 0x207C, glyph_equalsuperior }, + { 0x3126, glyph_erbopomofo }, + { 0x0440, glyph_ercyrillic }, + { 0x0258, glyph_ereversed }, + { 0x044D, glyph_ereversedcyrillic }, + { 0x0441, glyph_escyrillic }, + { 0x04AB, glyph_esdescendercyrillic }, + { 0x0283, glyph_esh }, + { 0x0286, glyph_eshcurl }, + { 0x090E, glyph_eshortdeva }, + { 0x0946, glyph_eshortvowelsigndeva }, + { 0x01AA, glyph_eshreversedloop }, + { 0x0285, glyph_eshsquatreversed }, + { 0x3047, glyph_esmallhiragana }, + { 0x30A7, glyph_esmallkatakana }, + { 0xFF6A, glyph_esmallkatakanahalfwidth }, + { 0x0568, glyph_etarmenian }, + { 0x1EBD, glyph_etilde }, + { 0x1E1B, glyph_etildebelow }, + { 0x0591, glyph_etnahtafoukhhebrew }, + { 0x0591, glyph_etnahtafoukhlefthebrew }, + { 0x0591, glyph_etnahtahebrew }, + { 0x0591, glyph_etnahtalefthebrew }, + { 0x01DD, glyph_eturned }, + { 0x3161, glyph_eukorean }, + { 0x20AC, glyph_euro }, + { 0x09C7, glyph_evowelsignbengali }, + { 0x0947, glyph_evowelsigndeva }, + { 0x0AC7, glyph_evowelsigngujarati }, + { 0x055C, glyph_exclamarmenian }, + { 0xFF01, glyph_exclammonospace }, + { 0x0292, glyph_ezh }, + { 0x01EF, glyph_ezhcaron }, + { 0x0293, glyph_ezhcurl }, + { 0x01B9, glyph_ezhreversed }, + { 0x01BA, glyph_ezhtail }, + { 0x095E, glyph_fadeva }, + { 0x0A5E, glyph_fagurmukhi }, + { 0x2109, glyph_fahrenheit }, + { 0x064E, glyph_fathaarabic }, + { 0x064E, glyph_fathalowarabic }, + { 0x064B, glyph_fathatanarabic }, + { 0x3108, glyph_fbopomofo }, + { 0x24D5, glyph_fcircle }, + { 0x1E1F, glyph_fdotaccent }, + { 0x0641, glyph_feharabic }, + { 0x0586, glyph_feharmenian }, + { 0xFED2, glyph_fehfinalarabic }, + { 0xFED3, glyph_fehinitialarabic }, + { 0xFED4, glyph_fehmedialarabic }, + { 0x03E5, glyph_feicoptic }, + { 0x246E, glyph_fifteencircle }, + { 0x2482, glyph_fifteenparen }, + { 0x2496, glyph_fifteenperiod }, + { 0x05DA, glyph_finalkaf }, + { 0xFB3A, glyph_finalkafdagesh }, + { 0xFB3A, glyph_finalkafdageshhebrew }, + { 0x05DA, glyph_finalkafhebrew }, + { 0x05DA, glyph_finalkafqamats }, + { 0x05B8, glyph_finalkafqamats }, + { 0x05DA, glyph_finalkafqamatshebrew }, + { 0x05B8, glyph_finalkafqamatshebrew }, + { 0x05DA, glyph_finalkafsheva }, + { 0x05B0, glyph_finalkafsheva }, + { 0x05DA, glyph_finalkafshevahebrew }, + { 0x05B0, glyph_finalkafshevahebrew }, + { 0x05DD, glyph_finalmem }, + { 0x05DD, glyph_finalmemhebrew }, + { 0x05DF, glyph_finalnun }, + { 0x05DF, glyph_finalnunhebrew }, + { 0x05E3, glyph_finalpe }, + { 0x05E3, glyph_finalpehebrew }, + { 0x05E5, glyph_finaltsadi }, + { 0x05E5, glyph_finaltsadihebrew }, + { 0x25C9, glyph_fisheye }, + { 0x0473, glyph_fitacyrillic }, + { 0x0665, glyph_fivearabic }, + { 0x09EB, glyph_fivebengali }, + { 0x2464, glyph_fivecircle }, + { 0x278E, glyph_fivecircleinversesansserif }, + { 0x096B, glyph_fivedeva }, + { 0x0AEB, glyph_fivegujarati }, + { 0x0A6B, glyph_fivegurmukhi }, + { 0x0665, glyph_fivehackarabic }, + { 0x3025, glyph_fivehangzhou }, + { 0x3224, glyph_fiveideographicparen }, + { 0xFF15, glyph_fivemonospace }, + { 0x2478, glyph_fiveparen }, + { 0x248C, glyph_fiveperiod }, + { 0x06F5, glyph_fivepersian }, + { 0x2174, glyph_fiveroman }, + { 0x0E55, glyph_fivethai }, + { 0xFF46, glyph_fmonospace }, + { 0x3399, glyph_fmsquare }, + { 0x0E1F, glyph_fofanthai }, + { 0x0E1D, glyph_fofathai }, + { 0x0E4F, glyph_fongmanthai }, + { 0x2200, glyph_forall }, + { 0x0664, glyph_fourarabic }, + { 0x09EA, glyph_fourbengali }, + { 0x2463, glyph_fourcircle }, + { 0x278D, glyph_fourcircleinversesansserif }, + { 0x096A, glyph_fourdeva }, + { 0x0AEA, glyph_fourgujarati }, + { 0x0A6A, glyph_fourgurmukhi }, + { 0x0664, glyph_fourhackarabic }, + { 0x3024, glyph_fourhangzhou }, + { 0x3223, glyph_fourideographicparen }, + { 0xFF14, glyph_fourmonospace }, + { 0x09F7, glyph_fournumeratorbengali }, + { 0x2477, glyph_fourparen }, + { 0x248B, glyph_fourperiod }, + { 0x06F4, glyph_fourpersian }, + { 0x2173, glyph_fourroman }, + { 0x246D, glyph_fourteencircle }, + { 0x2481, glyph_fourteenparen }, + { 0x2495, glyph_fourteenperiod }, + { 0x0E54, glyph_fourthai }, + { 0x02CB, glyph_fourthtonechinese }, + { 0x24A1, glyph_fparen }, + { 0x0997, glyph_gabengali }, + { 0x01F5, glyph_gacute }, + { 0x0917, glyph_gadeva }, + { 0x06AF, glyph_gafarabic }, + { 0xFB93, glyph_gaffinalarabic }, + { 0xFB94, glyph_gafinitialarabic }, + { 0xFB95, glyph_gafmedialarabic }, + { 0x0A97, glyph_gagujarati }, + { 0x0A17, glyph_gagurmukhi }, + { 0x304C, glyph_gahiragana }, + { 0x30AC, glyph_gakatakana }, + { 0x0263, glyph_gammalatinsmall }, + { 0x02E0, glyph_gammasuperior }, + { 0x03EB, glyph_gangiacoptic }, + { 0x310D, glyph_gbopomofo }, + { 0x0123, glyph_gcedilla }, + { 0x24D6, glyph_gcircle }, + { 0x0121, glyph_gdot }, + { 0x0433, glyph_gecyrillic }, + { 0x3052, glyph_gehiragana }, + { 0x30B2, glyph_gekatakana }, + { 0x2251, glyph_geometricallyequal }, + { 0x059C, glyph_gereshaccenthebrew }, + { 0x05F3, glyph_gereshhebrew }, + { 0x059D, glyph_gereshmuqdamhebrew }, + { 0x059E, glyph_gershayimaccenthebrew }, + { 0x05F4, glyph_gershayimhebrew }, + { 0x3013, glyph_getamark }, + { 0x0998, glyph_ghabengali }, + { 0x0572, glyph_ghadarmenian }, + { 0x0918, glyph_ghadeva }, + { 0x0A98, glyph_ghagujarati }, + { 0x0A18, glyph_ghagurmukhi }, + { 0x063A, glyph_ghainarabic }, + { 0xFECE, glyph_ghainfinalarabic }, + { 0xFECF, glyph_ghaininitialarabic }, + { 0xFED0, glyph_ghainmedialarabic }, + { 0x0495, glyph_ghemiddlehookcyrillic }, + { 0x0493, glyph_ghestrokecyrillic }, + { 0x0491, glyph_gheupturncyrillic }, + { 0x095A, glyph_ghhadeva }, + { 0x0A5A, glyph_ghhagurmukhi }, + { 0x0260, glyph_ghook }, + { 0x3393, glyph_ghzsquare }, + { 0x304E, glyph_gihiragana }, + { 0x30AE, glyph_gikatakana }, + { 0x0563, glyph_gimarmenian }, + { 0x05D2, glyph_gimel }, + { 0xFB32, glyph_gimeldagesh }, + { 0xFB32, glyph_gimeldageshhebrew }, + { 0x05D2, glyph_gimelhebrew }, + { 0x0453, glyph_gjecyrillic }, + { 0x01BE, glyph_glottalinvertedstroke }, + { 0x0294, glyph_glottalstop }, + { 0x0296, glyph_glottalstopinverted }, + { 0x02C0, glyph_glottalstopmod }, + { 0x0295, glyph_glottalstopreversed }, + { 0x02C1, glyph_glottalstopreversedmod }, + { 0x02E4, glyph_glottalstopreversedsuperior }, + { 0x02A1, glyph_glottalstopstroke }, + { 0x02A2, glyph_glottalstopstrokereversed }, + { 0x1E21, glyph_gmacron }, + { 0xFF47, glyph_gmonospace }, + { 0x3054, glyph_gohiragana }, + { 0x30B4, glyph_gokatakana }, + { 0x24A2, glyph_gparen }, + { 0x33AC, glyph_gpasquare }, + { 0x0316, glyph_gravebelowcmb }, + { 0x0300, glyph_gravecmb }, + { 0x0953, glyph_gravedeva }, + { 0x02CE, glyph_gravelowmod }, + { 0xFF40, glyph_gravemonospace }, + { 0x0340, glyph_gravetonecmb }, + { 0x22DB, glyph_greaterequalorless }, + { 0xFF1E, glyph_greatermonospace }, + { 0x2273, glyph_greaterorequivalent }, + { 0x2277, glyph_greaterorless }, + { 0x2267, glyph_greateroverequal }, + { 0xFE65, glyph_greatersmall }, + { 0x0261, glyph_gscript }, + { 0x01E5, glyph_gstroke }, + { 0x3050, glyph_guhiragana }, + { 0x30B0, glyph_gukatakana }, + { 0x3318, glyph_guramusquare }, + { 0x33C9, glyph_gysquare }, + { 0x04A9, glyph_haabkhasiancyrillic }, + { 0x06C1, glyph_haaltonearabic }, + { 0x09B9, glyph_habengali }, + { 0x04B3, glyph_hadescendercyrillic }, + { 0x0939, glyph_hadeva }, + { 0x0AB9, glyph_hagujarati }, + { 0x0A39, glyph_hagurmukhi }, + { 0x062D, glyph_haharabic }, + { 0xFEA2, glyph_hahfinalarabic }, + { 0xFEA3, glyph_hahinitialarabic }, + { 0x306F, glyph_hahiragana }, + { 0xFEA4, glyph_hahmedialarabic }, + { 0x332A, glyph_haitusquare }, + { 0x30CF, glyph_hakatakana }, + { 0xFF8A, glyph_hakatakanahalfwidth }, + { 0x0A4D, glyph_halantgurmukhi }, + { 0x0621, glyph_hamzaarabic }, + { 0x0621, glyph_hamzadammaarabic }, + { 0x064F, glyph_hamzadammaarabic }, + { 0x0621, glyph_hamzadammatanarabic }, + { 0x064C, glyph_hamzadammatanarabic }, + { 0x0621, glyph_hamzafathaarabic }, + { 0x064E, glyph_hamzafathaarabic }, + { 0x0621, glyph_hamzafathatanarabic }, + { 0x064B, glyph_hamzafathatanarabic }, + { 0x0621, glyph_hamzalowarabic }, + { 0x0621, glyph_hamzalowkasraarabic }, + { 0x0650, glyph_hamzalowkasraarabic }, + { 0x0621, glyph_hamzalowkasratanarabic }, + { 0x064D, glyph_hamzalowkasratanarabic }, + { 0x0621, glyph_hamzasukunarabic }, + { 0x0652, glyph_hamzasukunarabic }, + { 0x3164, glyph_hangulfiller }, + { 0x044A, glyph_hardsigncyrillic }, + { 0x21BC, glyph_harpoonleftbarbup }, + { 0x21C0, glyph_harpoonrightbarbup }, + { 0x33CA, glyph_hasquare }, + { 0x05B2, glyph_hatafpatah }, + { 0x05B2, glyph_hatafpatah16 }, + { 0x05B2, glyph_hatafpatah23 }, + { 0x05B2, glyph_hatafpatah2f }, + { 0x05B2, glyph_hatafpatahhebrew }, + { 0x05B2, glyph_hatafpatahnarrowhebrew }, + { 0x05B2, glyph_hatafpatahquarterhebrew }, + { 0x05B2, glyph_hatafpatahwidehebrew }, + { 0x05B3, glyph_hatafqamats }, + { 0x05B3, glyph_hatafqamats1b }, + { 0x05B3, glyph_hatafqamats28 }, + { 0x05B3, glyph_hatafqamats34 }, + { 0x05B3, glyph_hatafqamatshebrew }, + { 0x05B3, glyph_hatafqamatsnarrowhebrew }, + { 0x05B3, glyph_hatafqamatsquarterhebrew }, + { 0x05B3, glyph_hatafqamatswidehebrew }, + { 0x05B1, glyph_hatafsegol }, + { 0x05B1, glyph_hatafsegol17 }, + { 0x05B1, glyph_hatafsegol24 }, + { 0x05B1, glyph_hatafsegol30 }, + { 0x05B1, glyph_hatafsegolhebrew }, + { 0x05B1, glyph_hatafsegolnarrowhebrew }, + { 0x05B1, glyph_hatafsegolquarterhebrew }, + { 0x05B1, glyph_hatafsegolwidehebrew }, + { 0x310F, glyph_hbopomofo }, + { 0x1E2B, glyph_hbrevebelow }, + { 0x1E29, glyph_hcedilla }, + { 0x24D7, glyph_hcircle }, + { 0x1E27, glyph_hdieresis }, + { 0x1E23, glyph_hdotaccent }, + { 0x1E25, glyph_hdotbelow }, + { 0x05D4, glyph_he }, + { 0x2665, glyph_heartsuitblack }, + { 0x2661, glyph_heartsuitwhite }, + { 0xFB34, glyph_hedagesh }, + { 0xFB34, glyph_hedageshhebrew }, + { 0x06C1, glyph_hehaltonearabic }, + { 0x0647, glyph_heharabic }, + { 0x05D4, glyph_hehebrew }, + { 0xFBA7, glyph_hehfinalaltonearabic }, + { 0xFEEA, glyph_hehfinalalttwoarabic }, + { 0xFEEA, glyph_hehfinalarabic }, + { 0xFBA5, glyph_hehhamzaabovefinalarabic }, + { 0xFBA4, glyph_hehhamzaaboveisolatedarabic }, + { 0xFBA8, glyph_hehinitialaltonearabic }, + { 0xFEEB, glyph_hehinitialarabic }, + { 0x3078, glyph_hehiragana }, + { 0xFBA9, glyph_hehmedialaltonearabic }, + { 0xFEEC, glyph_hehmedialarabic }, + { 0x337B, glyph_heiseierasquare }, + { 0x30D8, glyph_hekatakana }, + { 0xFF8D, glyph_hekatakanahalfwidth }, + { 0x3336, glyph_hekutaarusquare }, + { 0x0267, glyph_henghook }, + { 0x3339, glyph_herutusquare }, + { 0x05D7, glyph_het }, + { 0x05D7, glyph_hethebrew }, + { 0x0266, glyph_hhook }, + { 0x02B1, glyph_hhooksuperior }, + { 0x327B, glyph_hieuhacirclekorean }, + { 0x321B, glyph_hieuhaparenkorean }, + { 0x326D, glyph_hieuhcirclekorean }, + { 0x314E, glyph_hieuhkorean }, + { 0x320D, glyph_hieuhparenkorean }, + { 0x3072, glyph_hihiragana }, + { 0x30D2, glyph_hikatakana }, + { 0xFF8B, glyph_hikatakanahalfwidth }, + { 0x05B4, glyph_hiriq }, + { 0x05B4, glyph_hiriq14 }, + { 0x05B4, glyph_hiriq21 }, + { 0x05B4, glyph_hiriq2d }, + { 0x05B4, glyph_hiriqhebrew }, + { 0x05B4, glyph_hiriqnarrowhebrew }, + { 0x05B4, glyph_hiriqquarterhebrew }, + { 0x05B4, glyph_hiriqwidehebrew }, + { 0x1E96, glyph_hlinebelow }, + { 0xFF48, glyph_hmonospace }, + { 0x0570, glyph_hoarmenian }, + { 0x0E2B, glyph_hohipthai }, + { 0x307B, glyph_hohiragana }, + { 0x30DB, glyph_hokatakana }, + { 0xFF8E, glyph_hokatakanahalfwidth }, + { 0x05B9, glyph_holam }, + { 0x05B9, glyph_holam19 }, + { 0x05B9, glyph_holam26 }, + { 0x05B9, glyph_holam32 }, + { 0x05B9, glyph_holamhebrew }, + { 0x05B9, glyph_holamnarrowhebrew }, + { 0x05B9, glyph_holamquarterhebrew }, + { 0x05B9, glyph_holamwidehebrew }, + { 0x0E2E, glyph_honokhukthai }, + { 0x0309, glyph_hookcmb }, + { 0x0321, glyph_hookpalatalizedbelowcmb }, + { 0x0322, glyph_hookretroflexbelowcmb }, + { 0x3342, glyph_hoonsquare }, + { 0x03E9, glyph_horicoptic }, + { 0x2015, glyph_horizontalbar }, + { 0x031B, glyph_horncmb }, + { 0x2668, glyph_hotsprings }, + { 0x24A3, glyph_hparen }, + { 0x02B0, glyph_hsuperior }, + { 0x0265, glyph_hturned }, + { 0x3075, glyph_huhiragana }, + { 0x3333, glyph_huiitosquare }, + { 0x30D5, glyph_hukatakana }, + { 0xFF8C, glyph_hukatakanahalfwidth }, + { 0x030B, glyph_hungarumlautcmb }, + { 0x0195, glyph_hv }, + { 0xFF0D, glyph_hyphenmonospace }, + { 0xFE63, glyph_hyphensmall }, + { 0x2010, glyph_hyphentwo }, + { 0x044F, glyph_iacyrillic }, + { 0x0987, glyph_ibengali }, + { 0x3127, glyph_ibopomofo }, + { 0x01D0, glyph_icaron }, + { 0x24D8, glyph_icircle }, + { 0x0456, glyph_icyrillic }, + { 0x0209, glyph_idblgrave }, + { 0x328F, glyph_ideographearthcircle }, + { 0x328B, glyph_ideographfirecircle }, + { 0x323F, glyph_ideographicallianceparen }, + { 0x323A, glyph_ideographiccallparen }, + { 0x32A5, glyph_ideographiccentrecircle }, + { 0x3006, glyph_ideographicclose }, + { 0x3001, glyph_ideographiccomma }, + { 0xFF64, glyph_ideographiccommaleft }, + { 0x3237, glyph_ideographiccongratulationparen }, + { 0x32A3, glyph_ideographiccorrectcircle }, + { 0x322F, glyph_ideographicearthparen }, + { 0x323D, glyph_ideographicenterpriseparen }, + { 0x329D, glyph_ideographicexcellentcircle }, + { 0x3240, glyph_ideographicfestivalparen }, + { 0x3296, glyph_ideographicfinancialcircle }, + { 0x3236, glyph_ideographicfinancialparen }, + { 0x322B, glyph_ideographicfireparen }, + { 0x3232, glyph_ideographichaveparen }, + { 0x32A4, glyph_ideographichighcircle }, + { 0x3005, glyph_ideographiciterationmark }, + { 0x3298, glyph_ideographiclaborcircle }, + { 0x3238, glyph_ideographiclaborparen }, + { 0x32A7, glyph_ideographicleftcircle }, + { 0x32A6, glyph_ideographiclowcircle }, + { 0x32A9, glyph_ideographicmedicinecircle }, + { 0x322E, glyph_ideographicmetalparen }, + { 0x322A, glyph_ideographicmoonparen }, + { 0x3234, glyph_ideographicnameparen }, + { 0x3002, glyph_ideographicperiod }, + { 0x329E, glyph_ideographicprintcircle }, + { 0x3243, glyph_ideographicreachparen }, + { 0x3239, glyph_ideographicrepresentparen }, + { 0x323E, glyph_ideographicresourceparen }, + { 0x32A8, glyph_ideographicrightcircle }, + { 0x3299, glyph_ideographicsecretcircle }, + { 0x3242, glyph_ideographicselfparen }, + { 0x3233, glyph_ideographicsocietyparen }, + { 0x3000, glyph_ideographicspace }, + { 0x3235, glyph_ideographicspecialparen }, + { 0x3231, glyph_ideographicstockparen }, + { 0x323B, glyph_ideographicstudyparen }, + { 0x3230, glyph_ideographicsunparen }, + { 0x323C, glyph_ideographicsuperviseparen }, + { 0x322C, glyph_ideographicwaterparen }, + { 0x322D, glyph_ideographicwoodparen }, + { 0x3007, glyph_ideographiczero }, + { 0x328E, glyph_ideographmetalcircle }, + { 0x328A, glyph_ideographmooncircle }, + { 0x3294, glyph_ideographnamecircle }, + { 0x3290, glyph_ideographsuncircle }, + { 0x328C, glyph_ideographwatercircle }, + { 0x328D, glyph_ideographwoodcircle }, + { 0x0907, glyph_ideva }, + { 0x1E2F, glyph_idieresisacute }, + { 0x04E5, glyph_idieresiscyrillic }, + { 0x1ECB, glyph_idotbelow }, + { 0x04D7, glyph_iebrevecyrillic }, + { 0x0435, glyph_iecyrillic }, + { 0x3275, glyph_ieungacirclekorean }, + { 0x3215, glyph_ieungaparenkorean }, + { 0x3267, glyph_ieungcirclekorean }, + { 0x3147, glyph_ieungkorean }, + { 0x3207, glyph_ieungparenkorean }, + { 0x0A87, glyph_igujarati }, + { 0x0A07, glyph_igurmukhi }, + { 0x3044, glyph_ihiragana }, + { 0x1EC9, glyph_ihookabove }, + { 0x0988, glyph_iibengali }, + { 0x0438, glyph_iicyrillic }, + { 0x0908, glyph_iideva }, + { 0x0A88, glyph_iigujarati }, + { 0x0A08, glyph_iigurmukhi }, + { 0x0A40, glyph_iimatragurmukhi }, + { 0x020B, glyph_iinvertedbreve }, + { 0x0439, glyph_iishortcyrillic }, + { 0x09C0, glyph_iivowelsignbengali }, + { 0x0940, glyph_iivowelsigndeva }, + { 0x0AC0, glyph_iivowelsigngujarati }, + { 0x30A4, glyph_ikatakana }, + { 0xFF72, glyph_ikatakanahalfwidth }, + { 0x3163, glyph_ikorean }, + { 0x02DC, glyph_ilde }, + { 0x05AC, glyph_iluyhebrew }, + { 0x04E3, glyph_imacroncyrillic }, + { 0x2253, glyph_imageorapproximatelyequal }, + { 0x0A3F, glyph_imatragurmukhi }, + { 0xFF49, glyph_imonospace }, + { 0x2206, glyph_increment }, + { 0x056B, glyph_iniarmenian }, + { 0x2321, glyph_integralbottom }, + { 0x2320, glyph_integraltop }, + { 0x3305, glyph_intisquare }, + { 0x0451, glyph_iocyrillic }, + { 0x0269, glyph_iotalatin }, + { 0x24A4, glyph_iparen }, + { 0x0A72, glyph_irigurmukhi }, + { 0x3043, glyph_ismallhiragana }, + { 0x30A3, glyph_ismallkatakana }, + { 0xFF68, glyph_ismallkatakanahalfwidth }, + { 0x09FA, glyph_issharbengali }, + { 0x0268, glyph_istroke }, + { 0x309D, glyph_iterationhiragana }, + { 0x30FD, glyph_iterationkatakana }, + { 0x1E2D, glyph_itildebelow }, + { 0x3129, glyph_iubopomofo }, + { 0x044E, glyph_iucyrillic }, + { 0x09BF, glyph_ivowelsignbengali }, + { 0x093F, glyph_ivowelsigndeva }, + { 0x0ABF, glyph_ivowelsigngujarati }, + { 0x0475, glyph_izhitsacyrillic }, + { 0x0477, glyph_izhitsadblgravecyrillic }, + { 0x0571, glyph_jaarmenian }, + { 0x099C, glyph_jabengali }, + { 0x091C, glyph_jadeva }, + { 0x0A9C, glyph_jagujarati }, + { 0x0A1C, glyph_jagurmukhi }, + { 0x3110, glyph_jbopomofo }, + { 0x01F0, glyph_jcaron }, + { 0x24D9, glyph_jcircle }, + { 0x029D, glyph_jcrossedtail }, + { 0x025F, glyph_jdotlessstroke }, + { 0x0458, glyph_jecyrillic }, + { 0x062C, glyph_jeemarabic }, + { 0xFE9E, glyph_jeemfinalarabic }, + { 0xFE9F, glyph_jeeminitialarabic }, + { 0xFEA0, glyph_jeemmedialarabic }, + { 0x0698, glyph_jeharabic }, + { 0xFB8B, glyph_jehfinalarabic }, + { 0x099D, glyph_jhabengali }, + { 0x091D, glyph_jhadeva }, + { 0x0A9D, glyph_jhagujarati }, + { 0x0A1D, glyph_jhagurmukhi }, + { 0x057B, glyph_jheharmenian }, + { 0x3004, glyph_jis }, + { 0xFF4A, glyph_jmonospace }, + { 0x24A5, glyph_jparen }, + { 0x02B2, glyph_jsuperior }, + { 0x04A1, glyph_kabashkircyrillic }, + { 0x0995, glyph_kabengali }, + { 0x1E31, glyph_kacute }, + { 0x043A, glyph_kacyrillic }, + { 0x049B, glyph_kadescendercyrillic }, + { 0x0915, glyph_kadeva }, + { 0x05DB, glyph_kaf }, + { 0x0643, glyph_kafarabic }, + { 0xFB3B, glyph_kafdagesh }, + { 0xFB3B, glyph_kafdageshhebrew }, + { 0xFEDA, glyph_kaffinalarabic }, + { 0x05DB, glyph_kafhebrew }, + { 0xFEDB, glyph_kafinitialarabic }, + { 0xFEDC, glyph_kafmedialarabic }, + { 0xFB4D, glyph_kafrafehebrew }, + { 0x0A95, glyph_kagujarati }, + { 0x0A15, glyph_kagurmukhi }, + { 0x304B, glyph_kahiragana }, + { 0x04C4, glyph_kahookcyrillic }, + { 0x30AB, glyph_kakatakana }, + { 0xFF76, glyph_kakatakanahalfwidth }, + { 0x03F0, glyph_kappasymbolgreek }, + { 0x3171, glyph_kapyeounmieumkorean }, + { 0x3184, glyph_kapyeounphieuphkorean }, + { 0x3178, glyph_kapyeounpieupkorean }, + { 0x3179, glyph_kapyeounssangpieupkorean }, + { 0x330D, glyph_karoriisquare }, + { 0x0640, glyph_kashidaautoarabic }, + { 0x0640, glyph_kashidaautonosidebearingarabic }, + { 0x30F5, glyph_kasmallkatakana }, + { 0x3384, glyph_kasquare }, + { 0x0650, glyph_kasraarabic }, + { 0x064D, glyph_kasratanarabic }, + { 0x049F, glyph_kastrokecyrillic }, + { 0xFF70, glyph_katahiraprolongmarkhalfwidth }, + { 0x049D, glyph_kaverticalstrokecyrillic }, + { 0x310E, glyph_kbopomofo }, + { 0x3389, glyph_kcalsquare }, + { 0x01E9, glyph_kcaron }, + { 0x0137, glyph_kcedilla }, + { 0x24DA, glyph_kcircle }, + { 0x1E33, glyph_kdotbelow }, + { 0x0584, glyph_keharmenian }, + { 0x3051, glyph_kehiragana }, + { 0x30B1, glyph_kekatakana }, + { 0xFF79, glyph_kekatakanahalfwidth }, + { 0x056F, glyph_kenarmenian }, + { 0x30F6, glyph_kesmallkatakana }, + { 0x0996, glyph_khabengali }, + { 0x0445, glyph_khacyrillic }, + { 0x0916, glyph_khadeva }, + { 0x0A96, glyph_khagujarati }, + { 0x0A16, glyph_khagurmukhi }, + { 0x062E, glyph_khaharabic }, + { 0xFEA6, glyph_khahfinalarabic }, + { 0xFEA7, glyph_khahinitialarabic }, + { 0xFEA8, glyph_khahmedialarabic }, + { 0x03E7, glyph_kheicoptic }, + { 0x0959, glyph_khhadeva }, + { 0x0A59, glyph_khhagurmukhi }, + { 0x3278, glyph_khieukhacirclekorean }, + { 0x3218, glyph_khieukhaparenkorean }, + { 0x326A, glyph_khieukhcirclekorean }, + { 0x314B, glyph_khieukhkorean }, + { 0x320A, glyph_khieukhparenkorean }, + { 0x0E02, glyph_khokhaithai }, + { 0x0E05, glyph_khokhonthai }, + { 0x0E03, glyph_khokhuatthai }, + { 0x0E04, glyph_khokhwaithai }, + { 0x0E5B, glyph_khomutthai }, + { 0x0199, glyph_khook }, + { 0x0E06, glyph_khorakhangthai }, + { 0x3391, glyph_khzsquare }, + { 0x304D, glyph_kihiragana }, + { 0x30AD, glyph_kikatakana }, + { 0xFF77, glyph_kikatakanahalfwidth }, + { 0x3315, glyph_kiroguramusquare }, + { 0x3316, glyph_kiromeetorusquare }, + { 0x3314, glyph_kirosquare }, + { 0x326E, glyph_kiyeokacirclekorean }, + { 0x320E, glyph_kiyeokaparenkorean }, + { 0x3260, glyph_kiyeokcirclekorean }, + { 0x3131, glyph_kiyeokkorean }, + { 0x3200, glyph_kiyeokparenkorean }, + { 0x3133, glyph_kiyeoksioskorean }, + { 0x045C, glyph_kjecyrillic }, + { 0x1E35, glyph_klinebelow }, + { 0x3398, glyph_klsquare }, + { 0x33A6, glyph_kmcubedsquare }, + { 0xFF4B, glyph_kmonospace }, + { 0x33A2, glyph_kmsquaredsquare }, + { 0x3053, glyph_kohiragana }, + { 0x33C0, glyph_kohmsquare }, + { 0x0E01, glyph_kokaithai }, + { 0x30B3, glyph_kokatakana }, + { 0xFF7A, glyph_kokatakanahalfwidth }, + { 0x331E, glyph_kooposquare }, + { 0x0481, glyph_koppacyrillic }, + { 0x327F, glyph_koreanstandardsymbol }, + { 0x0343, glyph_koroniscmb }, + { 0x24A6, glyph_kparen }, + { 0x33AA, glyph_kpasquare }, + { 0x046F, glyph_ksicyrillic }, + { 0x33CF, glyph_ktsquare }, + { 0x029E, glyph_kturned }, + { 0x304F, glyph_kuhiragana }, + { 0x30AF, glyph_kukatakana }, + { 0xFF78, glyph_kukatakanahalfwidth }, + { 0x33B8, glyph_kvsquare }, + { 0x33BE, glyph_kwsquare }, + { 0x09B2, glyph_labengali }, + { 0x0932, glyph_ladeva }, + { 0x0AB2, glyph_lagujarati }, + { 0x0A32, glyph_lagurmukhi }, + { 0x0E45, glyph_lakkhangyaothai }, + { 0xFEFC, glyph_lamaleffinalarabic }, + { 0xFEF8, glyph_lamalefhamzaabovefinalarabic }, + { 0xFEF7, glyph_lamalefhamzaaboveisolatedarabic }, + { 0xFEFA, glyph_lamalefhamzabelowfinalarabic }, + { 0xFEF9, glyph_lamalefhamzabelowisolatedarabic }, + { 0xFEFB, glyph_lamalefisolatedarabic }, + { 0xFEF6, glyph_lamalefmaddaabovefinalarabic }, + { 0xFEF5, glyph_lamalefmaddaaboveisolatedarabic }, + { 0x0644, glyph_lamarabic }, + { 0x019B, glyph_lambdastroke }, + { 0x05DC, glyph_lamed }, + { 0xFB3C, glyph_lameddagesh }, + { 0xFB3C, glyph_lameddageshhebrew }, + { 0x05DC, glyph_lamedhebrew }, + { 0x05DC, glyph_lamedholam }, + { 0x05B9, glyph_lamedholam }, + { 0x05DC, glyph_lamedholamdagesh }, + { 0x05B9, glyph_lamedholamdagesh }, + { 0x05BC, glyph_lamedholamdagesh }, + { 0x05DC, glyph_lamedholamdageshhebrew }, + { 0x05B9, glyph_lamedholamdageshhebrew }, + { 0x05BC, glyph_lamedholamdageshhebrew }, + { 0x05DC, glyph_lamedholamhebrew }, + { 0x05B9, glyph_lamedholamhebrew }, + { 0xFEDE, glyph_lamfinalarabic }, + { 0xFCCA, glyph_lamhahinitialarabic }, + { 0xFEDF, glyph_laminitialarabic }, + { 0xFCC9, glyph_lamjeeminitialarabic }, + { 0xFCCB, glyph_lamkhahinitialarabic }, + { 0xFDF2, glyph_lamlamhehisolatedarabic }, + { 0xFEE0, glyph_lammedialarabic }, + { 0xFD88, glyph_lammeemhahinitialarabic }, + { 0xFCCC, glyph_lammeeminitialarabic }, + { 0xFEDF, glyph_lammeemjeeminitialarabic }, + { 0xFEE4, glyph_lammeemjeeminitialarabic }, + { 0xFEA0, glyph_lammeemjeeminitialarabic }, + { 0xFEDF, glyph_lammeemkhahinitialarabic }, + { 0xFEE4, glyph_lammeemkhahinitialarabic }, + { 0xFEA8, glyph_lammeemkhahinitialarabic }, + { 0x25EF, glyph_largecircle }, + { 0x019A, glyph_lbar }, + { 0x026C, glyph_lbelt }, + { 0x310C, glyph_lbopomofo }, + { 0x013C, glyph_lcedilla }, + { 0x24DB, glyph_lcircle }, + { 0x1E3D, glyph_lcircumflexbelow }, + { 0x0140, glyph_ldotaccent }, + { 0x1E37, glyph_ldotbelow }, + { 0x1E39, glyph_ldotbelowmacron }, + { 0x031A, glyph_leftangleabovecmb }, + { 0x0318, glyph_lefttackbelowcmb }, + { 0x22DA, glyph_lessequalorgreater }, + { 0xFF1C, glyph_lessmonospace }, + { 0x2272, glyph_lessorequivalent }, + { 0x2276, glyph_lessorgreater }, + { 0x2266, glyph_lessoverequal }, + { 0xFE64, glyph_lesssmall }, + { 0x026E, glyph_lezh }, + { 0x026D, glyph_lhookretroflex }, + { 0x056C, glyph_liwnarmenian }, + { 0x01C9, glyph_lj }, + { 0x0459, glyph_ljecyrillic }, + { 0x0933, glyph_lladeva }, + { 0x0AB3, glyph_llagujarati }, + { 0x1E3B, glyph_llinebelow }, + { 0x0934, glyph_llladeva }, + { 0x09E1, glyph_llvocalicbengali }, + { 0x0961, glyph_llvocalicdeva }, + { 0x09E3, glyph_llvocalicvowelsignbengali }, + { 0x0963, glyph_llvocalicvowelsigndeva }, + { 0x026B, glyph_lmiddletilde }, + { 0xFF4C, glyph_lmonospace }, + { 0x33D0, glyph_lmsquare }, + { 0x0E2C, glyph_lochulathai }, + { 0x2310, glyph_logicalnotreversed }, + { 0x0E25, glyph_lolingthai }, + { 0xFE4E, glyph_lowlinecenterline }, + { 0x0332, glyph_lowlinecmb }, + { 0xFE4D, glyph_lowlinedashed }, + { 0x24A7, glyph_lparen }, + { 0x2113, glyph_lsquare }, + { 0x0E26, glyph_luthai }, + { 0x098C, glyph_lvocalicbengali }, + { 0x090C, glyph_lvocalicdeva }, + { 0x09E2, glyph_lvocalicvowelsignbengali }, + { 0x0962, glyph_lvocalicvowelsigndeva }, + { 0x33D3, glyph_lxsquare }, + { 0x09AE, glyph_mabengali }, + { 0x0331, glyph_macronbelowcmb }, + { 0x0304, glyph_macroncmb }, + { 0x02CD, glyph_macronlowmod }, + { 0xFFE3, glyph_macronmonospace }, + { 0x1E3F, glyph_macute }, + { 0x092E, glyph_madeva }, + { 0x0AAE, glyph_magujarati }, + { 0x0A2E, glyph_magurmukhi }, + { 0x05A4, glyph_mahapakhhebrew }, + { 0x05A4, glyph_mahapakhlefthebrew }, + { 0x307E, glyph_mahiragana }, + { 0xF895, glyph_maichattawalowleftthai }, + { 0xF894, glyph_maichattawalowrightthai }, + { 0x0E4B, glyph_maichattawathai }, + { 0xF893, glyph_maichattawaupperleftthai }, + { 0xF88C, glyph_maieklowleftthai }, + { 0xF88B, glyph_maieklowrightthai }, + { 0x0E48, glyph_maiekthai }, + { 0xF88A, glyph_maiekupperleftthai }, + { 0xF884, glyph_maihanakatleftthai }, + { 0x0E31, glyph_maihanakatthai }, + { 0xF889, glyph_maitaikhuleftthai }, + { 0x0E47, glyph_maitaikhuthai }, + { 0xF88F, glyph_maitholowleftthai }, + { 0xF88E, glyph_maitholowrightthai }, + { 0x0E49, glyph_maithothai }, + { 0xF88D, glyph_maithoupperleftthai }, + { 0xF892, glyph_maitrilowleftthai }, + { 0xF891, glyph_maitrilowrightthai }, + { 0x0E4A, glyph_maitrithai }, + { 0xF890, glyph_maitriupperleftthai }, + { 0x0E46, glyph_maiyamokthai }, + { 0x30DE, glyph_makatakana }, + { 0xFF8F, glyph_makatakanahalfwidth }, + { 0x3347, glyph_mansyonsquare }, + { 0x05BE, glyph_maqafhebrew }, + { 0x2642, glyph_mars }, + { 0x05AF, glyph_masoracirclehebrew }, + { 0x3383, glyph_masquare }, + { 0x3107, glyph_mbopomofo }, + { 0x33D4, glyph_mbsquare }, + { 0x24DC, glyph_mcircle }, + { 0x33A5, glyph_mcubedsquare }, + { 0x1E41, glyph_mdotaccent }, + { 0x1E43, glyph_mdotbelow }, + { 0x0645, glyph_meemarabic }, + { 0xFEE2, glyph_meemfinalarabic }, + { 0xFEE3, glyph_meeminitialarabic }, + { 0xFEE4, glyph_meemmedialarabic }, + { 0xFCD1, glyph_meemmeeminitialarabic }, + { 0xFC48, glyph_meemmeemisolatedarabic }, + { 0x334D, glyph_meetorusquare }, + { 0x3081, glyph_mehiragana }, + { 0x337E, glyph_meizierasquare }, + { 0x30E1, glyph_mekatakana }, + { 0xFF92, glyph_mekatakanahalfwidth }, + { 0x05DE, glyph_mem }, + { 0xFB3E, glyph_memdagesh }, + { 0xFB3E, glyph_memdageshhebrew }, + { 0x05DE, glyph_memhebrew }, + { 0x0574, glyph_menarmenian }, + { 0x05A5, glyph_merkhahebrew }, + { 0x05A6, glyph_merkhakefulahebrew }, + { 0x05A6, glyph_merkhakefulalefthebrew }, + { 0x05A5, glyph_merkhalefthebrew }, + { 0x0271, glyph_mhook }, + { 0x3392, glyph_mhzsquare }, + { 0xFF65, glyph_middledotkatakanahalfwidth }, + { 0x00B7, glyph_middot }, + { 0x3272, glyph_mieumacirclekorean }, + { 0x3212, glyph_mieumaparenkorean }, + { 0x3264, glyph_mieumcirclekorean }, + { 0x3141, glyph_mieumkorean }, + { 0x3170, glyph_mieumpansioskorean }, + { 0x3204, glyph_mieumparenkorean }, + { 0x316E, glyph_mieumpieupkorean }, + { 0x316F, glyph_mieumsioskorean }, + { 0x307F, glyph_mihiragana }, + { 0x30DF, glyph_mikatakana }, + { 0xFF90, glyph_mikatakanahalfwidth }, + { 0x0320, glyph_minusbelowcmb }, + { 0x2296, glyph_minuscircle }, + { 0x02D7, glyph_minusmod }, + { 0x2213, glyph_minusplus }, + { 0x334A, glyph_miribaarusquare }, + { 0x3349, glyph_mirisquare }, + { 0x0270, glyph_mlonglegturned }, + { 0x3396, glyph_mlsquare }, + { 0x33A3, glyph_mmcubedsquare }, + { 0xFF4D, glyph_mmonospace }, + { 0x339F, glyph_mmsquaredsquare }, + { 0x3082, glyph_mohiragana }, + { 0x33C1, glyph_mohmsquare }, + { 0x30E2, glyph_mokatakana }, + { 0xFF93, glyph_mokatakanahalfwidth }, + { 0x33D6, glyph_molsquare }, + { 0x0E21, glyph_momathai }, + { 0x33A7, glyph_moverssquare }, + { 0x33A8, glyph_moverssquaredsquare }, + { 0x24A8, glyph_mparen }, + { 0x33AB, glyph_mpasquare }, + { 0x33B3, glyph_mssquare }, + { 0x026F, glyph_mturned }, + { 0x00B5, glyph_mu1 }, + { 0x3382, glyph_muasquare }, + { 0x226B, glyph_muchgreater }, + { 0x226A, glyph_muchless }, + { 0x338C, glyph_mufsquare }, + { 0x338D, glyph_mugsquare }, + { 0x3080, glyph_muhiragana }, + { 0x30E0, glyph_mukatakana }, + { 0xFF91, glyph_mukatakanahalfwidth }, + { 0x3395, glyph_mulsquare }, + { 0x339B, glyph_mumsquare }, + { 0x05A3, glyph_munahhebrew }, + { 0x05A3, glyph_munahlefthebrew }, + { 0x266D, glyph_musicflatsign }, + { 0x266F, glyph_musicsharpsign }, + { 0x33B2, glyph_mussquare }, + { 0x33B6, glyph_muvsquare }, + { 0x33BC, glyph_muwsquare }, + { 0x33B9, glyph_mvmegasquare }, + { 0x33B7, glyph_mvsquare }, + { 0x33BF, glyph_mwmegasquare }, + { 0x33BD, glyph_mwsquare }, + { 0x09A8, glyph_nabengali }, + { 0x2207, glyph_nabla }, + { 0x0928, glyph_nadeva }, + { 0x0AA8, glyph_nagujarati }, + { 0x0A28, glyph_nagurmukhi }, + { 0x306A, glyph_nahiragana }, + { 0x30CA, glyph_nakatakana }, + { 0xFF85, glyph_nakatakanahalfwidth }, + { 0x3381, glyph_nasquare }, + { 0x310B, glyph_nbopomofo }, + { 0x0146, glyph_ncedilla }, + { 0x24DD, glyph_ncircle }, + { 0x1E4B, glyph_ncircumflexbelow }, + { 0x1E45, glyph_ndotaccent }, + { 0x1E47, glyph_ndotbelow }, + { 0x306D, glyph_nehiragana }, + { 0x30CD, glyph_nekatakana }, + { 0xFF88, glyph_nekatakanahalfwidth }, + { 0x20AA, glyph_newsheqelsign }, + { 0x338B, glyph_nfsquare }, + { 0x0999, glyph_ngabengali }, + { 0x0919, glyph_ngadeva }, + { 0x0A99, glyph_ngagujarati }, + { 0x0A19, glyph_ngagurmukhi }, + { 0x0E07, glyph_ngonguthai }, + { 0x3093, glyph_nhiragana }, + { 0x0272, glyph_nhookleft }, + { 0x0273, glyph_nhookretroflex }, + { 0x326F, glyph_nieunacirclekorean }, + { 0x320F, glyph_nieunaparenkorean }, + { 0x3135, glyph_nieuncieuckorean }, + { 0x3261, glyph_nieuncirclekorean }, + { 0x3136, glyph_nieunhieuhkorean }, + { 0x3134, glyph_nieunkorean }, + { 0x3168, glyph_nieunpansioskorean }, + { 0x3201, glyph_nieunparenkorean }, + { 0x3167, glyph_nieunsioskorean }, + { 0x3166, glyph_nieuntikeutkorean }, + { 0x306B, glyph_nihiragana }, + { 0x30CB, glyph_nikatakana }, + { 0xFF86, glyph_nikatakanahalfwidth }, + { 0xF899, glyph_nikhahitleftthai }, + { 0x0E4D, glyph_nikhahitthai }, + { 0x0669, glyph_ninearabic }, + { 0x09EF, glyph_ninebengali }, + { 0x2468, glyph_ninecircle }, + { 0x2792, glyph_ninecircleinversesansserif }, + { 0x096F, glyph_ninedeva }, + { 0x0AEF, glyph_ninegujarati }, + { 0x0A6F, glyph_ninegurmukhi }, + { 0x0669, glyph_ninehackarabic }, + { 0x3029, glyph_ninehangzhou }, + { 0x3228, glyph_nineideographicparen }, + { 0xFF19, glyph_ninemonospace }, + { 0x247C, glyph_nineparen }, + { 0x2490, glyph_nineperiod }, + { 0x06F9, glyph_ninepersian }, + { 0x2178, glyph_nineroman }, + { 0x2472, glyph_nineteencircle }, + { 0x2486, glyph_nineteenparen }, + { 0x249A, glyph_nineteenperiod }, + { 0x0E59, glyph_ninethai }, + { 0x01CC, glyph_nj }, + { 0x045A, glyph_njecyrillic }, + { 0x30F3, glyph_nkatakana }, + { 0xFF9D, glyph_nkatakanahalfwidth }, + { 0x019E, glyph_nlegrightlong }, + { 0x1E49, glyph_nlinebelow }, + { 0xFF4E, glyph_nmonospace }, + { 0x339A, glyph_nmsquare }, + { 0x09A3, glyph_nnabengali }, + { 0x0923, glyph_nnadeva }, + { 0x0AA3, glyph_nnagujarati }, + { 0x0A23, glyph_nnagurmukhi }, + { 0x0929, glyph_nnnadeva }, + { 0x306E, glyph_nohiragana }, + { 0x30CE, glyph_nokatakana }, + { 0xFF89, glyph_nokatakanahalfwidth }, + { 0x00A0, glyph_nonbreakingspace }, + { 0x0E13, glyph_nonenthai }, + { 0x0E19, glyph_nonuthai }, + { 0x0646, glyph_noonarabic }, + { 0xFEE6, glyph_noonfinalarabic }, + { 0x06BA, glyph_noonghunnaarabic }, + { 0xFB9F, glyph_noonghunnafinalarabic }, + { 0xFEE7, glyph_noonhehinitialarabic }, + { 0xFEEC, glyph_noonhehinitialarabic }, + { 0xFEE7, glyph_nooninitialarabic }, + { 0xFCD2, glyph_noonjeeminitialarabic }, + { 0xFC4B, glyph_noonjeemisolatedarabic }, + { 0xFEE8, glyph_noonmedialarabic }, + { 0xFCD5, glyph_noonmeeminitialarabic }, + { 0xFC4E, glyph_noonmeemisolatedarabic }, + { 0xFC8D, glyph_noonnoonfinalarabic }, + { 0x220C, glyph_notcontains }, + { 0x2209, glyph_notelementof }, + { 0x226F, glyph_notgreater }, + { 0x2271, glyph_notgreaternorequal }, + { 0x2279, glyph_notgreaternorless }, + { 0x2262, glyph_notidentical }, + { 0x226E, glyph_notless }, + { 0x2270, glyph_notlessnorequal }, + { 0x2226, glyph_notparallel }, + { 0x2280, glyph_notprecedes }, + { 0x2281, glyph_notsucceeds }, + { 0x2285, glyph_notsuperset }, + { 0x0576, glyph_nowarmenian }, + { 0x24A9, glyph_nparen }, + { 0x33B1, glyph_nssquare }, + { 0x306C, glyph_nuhiragana }, + { 0x30CC, glyph_nukatakana }, + { 0xFF87, glyph_nukatakanahalfwidth }, + { 0x09BC, glyph_nuktabengali }, + { 0x093C, glyph_nuktadeva }, + { 0x0ABC, glyph_nuktagujarati }, + { 0x0A3C, glyph_nuktagurmukhi }, + { 0xFF03, glyph_numbersignmonospace }, + { 0xFE5F, glyph_numbersignsmall }, + { 0x0374, glyph_numeralsigngreek }, + { 0x0375, glyph_numeralsignlowergreek }, + { 0x2116, glyph_numero }, + { 0x05E0, glyph_nun }, + { 0xFB40, glyph_nundagesh }, + { 0xFB40, glyph_nundageshhebrew }, + { 0x05E0, glyph_nunhebrew }, + { 0x33B5, glyph_nvsquare }, + { 0x33BB, glyph_nwsquare }, + { 0x099E, glyph_nyabengali }, + { 0x091E, glyph_nyadeva }, + { 0x0A9E, glyph_nyagujarati }, + { 0x0A1E, glyph_nyagurmukhi }, + { 0x0E2D, glyph_oangthai }, + { 0x0275, glyph_obarred }, + { 0x04E9, glyph_obarredcyrillic }, + { 0x04EB, glyph_obarreddieresiscyrillic }, + { 0x0993, glyph_obengali }, + { 0x311B, glyph_obopomofo }, + { 0x0911, glyph_ocandradeva }, + { 0x0A91, glyph_ocandragujarati }, + { 0x0949, glyph_ocandravowelsigndeva }, + { 0x0AC9, glyph_ocandravowelsigngujarati }, + { 0x01D2, glyph_ocaron }, + { 0x24DE, glyph_ocircle }, + { 0x1ED1, glyph_ocircumflexacute }, + { 0x1ED9, glyph_ocircumflexdotbelow }, + { 0x1ED3, glyph_ocircumflexgrave }, + { 0x1ED5, glyph_ocircumflexhookabove }, + { 0x1ED7, glyph_ocircumflextilde }, + { 0x043E, glyph_ocyrillic }, + { 0x0151, glyph_odblacute }, + { 0x020D, glyph_odblgrave }, + { 0x0913, glyph_odeva }, + { 0x04E7, glyph_odieresiscyrillic }, + { 0x1ECD, glyph_odotbelow }, + { 0x315A, glyph_oekorean }, + { 0x0328, glyph_ogonekcmb }, + { 0x0A93, glyph_ogujarati }, + { 0x0585, glyph_oharmenian }, + { 0x304A, glyph_ohiragana }, + { 0x1ECF, glyph_ohookabove }, + { 0x1EDB, glyph_ohornacute }, + { 0x1EE3, glyph_ohorndotbelow }, + { 0x1EDD, glyph_ohorngrave }, + { 0x1EDF, glyph_ohornhookabove }, + { 0x1EE1, glyph_ohorntilde }, + { 0x01A3, glyph_oi }, + { 0x020F, glyph_oinvertedbreve }, + { 0x30AA, glyph_okatakana }, + { 0xFF75, glyph_okatakanahalfwidth }, + { 0x3157, glyph_okorean }, + { 0x05AB, glyph_olehebrew }, + { 0x1E53, glyph_omacronacute }, + { 0x1E51, glyph_omacrongrave }, + { 0x0950, glyph_omdeva }, + { 0x0461, glyph_omegacyrillic }, + { 0x0277, glyph_omegalatinclosed }, + { 0x047B, glyph_omegaroundcyrillic }, + { 0x047D, glyph_omegatitlocyrillic }, + { 0x0AD0, glyph_omgujarati }, + { 0xFF4F, glyph_omonospace }, + { 0x0661, glyph_onearabic }, + { 0x09E7, glyph_onebengali }, + { 0x2460, glyph_onecircle }, + { 0x278A, glyph_onecircleinversesansserif }, + { 0x0967, glyph_onedeva }, + { 0x0AE7, glyph_onegujarati }, + { 0x0A67, glyph_onegurmukhi }, + { 0x0661, glyph_onehackarabic }, + { 0x3021, glyph_onehangzhou }, + { 0x3220, glyph_oneideographicparen }, + { 0xFF11, glyph_onemonospace }, + { 0x09F4, glyph_onenumeratorbengali }, + { 0x2474, glyph_oneparen }, + { 0x2488, glyph_oneperiod }, + { 0x06F1, glyph_onepersian }, + { 0x2170, glyph_oneroman }, + { 0x0E51, glyph_onethai }, + { 0x01EB, glyph_oogonek }, + { 0x01ED, glyph_oogonekmacron }, + { 0x0A13, glyph_oogurmukhi }, + { 0x0A4B, glyph_oomatragurmukhi }, + { 0x0254, glyph_oopen }, + { 0x24AA, glyph_oparen }, + { 0x2325, glyph_option }, + { 0x0912, glyph_oshortdeva }, + { 0x094A, glyph_oshortvowelsigndeva }, + { 0x3049, glyph_osmallhiragana }, + { 0x30A9, glyph_osmallkatakana }, + { 0xFF6B, glyph_osmallkatakanahalfwidth }, + { 0x01FF, glyph_ostrokeacute }, + { 0x047F, glyph_otcyrillic }, + { 0x1E4D, glyph_otildeacute }, + { 0x1E4F, glyph_otildedieresis }, + { 0x3121, glyph_oubopomofo }, + { 0x203E, glyph_overline }, + { 0xFE4A, glyph_overlinecenterline }, + { 0x0305, glyph_overlinecmb }, + { 0xFE49, glyph_overlinedashed }, + { 0xFE4C, glyph_overlinedblwavy }, + { 0xFE4B, glyph_overlinewavy }, + { 0x00AF, glyph_overscore }, + { 0x09CB, glyph_ovowelsignbengali }, + { 0x094B, glyph_ovowelsigndeva }, + { 0x0ACB, glyph_ovowelsigngujarati }, + { 0x3380, glyph_paampssquare }, + { 0x332B, glyph_paasentosquare }, + { 0x09AA, glyph_pabengali }, + { 0x1E55, glyph_pacute }, + { 0x092A, glyph_padeva }, + { 0x21DF, glyph_pagedown }, + { 0x21DE, glyph_pageup }, + { 0x0AAA, glyph_pagujarati }, + { 0x0A2A, glyph_pagurmukhi }, + { 0x3071, glyph_pahiragana }, + { 0x0E2F, glyph_paiyannoithai }, + { 0x30D1, glyph_pakatakana }, + { 0x0484, glyph_palatalizationcyrilliccmb }, + { 0x04C0, glyph_palochkacyrillic }, + { 0x317F, glyph_pansioskorean }, + { 0x2225, glyph_parallel }, + { 0xFD3E, glyph_parenleftaltonearabic }, + { 0xFF08, glyph_parenleftmonospace }, + { 0xFE59, glyph_parenleftsmall }, + { 0xFE35, glyph_parenleftvertical }, + { 0xFD3F, glyph_parenrightaltonearabic }, + { 0xFF09, glyph_parenrightmonospace }, + { 0xFE5A, glyph_parenrightsmall }, + { 0xFE36, glyph_parenrightvertical }, + { 0x05C0, glyph_paseqhebrew }, + { 0x0599, glyph_pashtahebrew }, + { 0x33A9, glyph_pasquare }, + { 0x05B7, glyph_patah }, + { 0x05B7, glyph_patah11 }, + { 0x05B7, glyph_patah1d }, + { 0x05B7, glyph_patah2a }, + { 0x05B7, glyph_patahhebrew }, + { 0x05B7, glyph_patahnarrowhebrew }, + { 0x05B7, glyph_patahquarterhebrew }, + { 0x05B7, glyph_patahwidehebrew }, + { 0x05A1, glyph_pazerhebrew }, + { 0x3106, glyph_pbopomofo }, + { 0x24DF, glyph_pcircle }, + { 0x1E57, glyph_pdotaccent }, + { 0x05E4, glyph_pe }, + { 0x043F, glyph_pecyrillic }, + { 0xFB44, glyph_pedagesh }, + { 0xFB44, glyph_pedageshhebrew }, + { 0x333B, glyph_peezisquare }, + { 0xFB43, glyph_pefinaldageshhebrew }, + { 0x067E, glyph_peharabic }, + { 0x057A, glyph_peharmenian }, + { 0x05E4, glyph_pehebrew }, + { 0xFB57, glyph_pehfinalarabic }, + { 0xFB58, glyph_pehinitialarabic }, + { 0x307A, glyph_pehiragana }, + { 0xFB59, glyph_pehmedialarabic }, + { 0x30DA, glyph_pekatakana }, + { 0x04A7, glyph_pemiddlehookcyrillic }, + { 0xFB4E, glyph_perafehebrew }, + { 0x066A, glyph_percentarabic }, + { 0xFF05, glyph_percentmonospace }, + { 0xFE6A, glyph_percentsmall }, + { 0x0589, glyph_periodarmenian }, + { 0xFF61, glyph_periodhalfwidth }, + { 0xFF0E, glyph_periodmonospace }, + { 0xFE52, glyph_periodsmall }, + { 0x0342, glyph_perispomenigreekcmb }, + { 0x338A, glyph_pfsquare }, + { 0x09AB, glyph_phabengali }, + { 0x092B, glyph_phadeva }, + { 0x0AAB, glyph_phagujarati }, + { 0x0A2B, glyph_phagurmukhi }, + { 0x327A, glyph_phieuphacirclekorean }, + { 0x321A, glyph_phieuphaparenkorean }, + { 0x326C, glyph_phieuphcirclekorean }, + { 0x314D, glyph_phieuphkorean }, + { 0x320C, glyph_phieuphparenkorean }, + { 0x0278, glyph_philatin }, + { 0x0E3A, glyph_phinthuthai }, + { 0x03D5, glyph_phisymbolgreek }, + { 0x01A5, glyph_phook }, + { 0x0E1E, glyph_phophanthai }, + { 0x0E1C, glyph_phophungthai }, + { 0x0E20, glyph_phosamphaothai }, + { 0x3273, glyph_pieupacirclekorean }, + { 0x3213, glyph_pieupaparenkorean }, + { 0x3176, glyph_pieupcieuckorean }, + { 0x3265, glyph_pieupcirclekorean }, + { 0x3172, glyph_pieupkiyeokkorean }, + { 0x3142, glyph_pieupkorean }, + { 0x3205, glyph_pieupparenkorean }, + { 0x3174, glyph_pieupsioskiyeokkorean }, + { 0x3144, glyph_pieupsioskorean }, + { 0x3175, glyph_pieupsiostikeutkorean }, + { 0x3177, glyph_pieupthieuthkorean }, + { 0x3173, glyph_pieuptikeutkorean }, + { 0x3074, glyph_pihiragana }, + { 0x30D4, glyph_pikatakana }, + { 0x03D6, glyph_pisymbolgreek }, + { 0x0583, glyph_piwrarmenian }, + { 0x031F, glyph_plusbelowcmb }, + { 0x2295, glyph_pluscircle }, + { 0x02D6, glyph_plusmod }, + { 0xFF0B, glyph_plusmonospace }, + { 0xFE62, glyph_plussmall }, + { 0x207A, glyph_plussuperior }, + { 0xFF50, glyph_pmonospace }, + { 0x33D8, glyph_pmsquare }, + { 0x307D, glyph_pohiragana }, + { 0x261F, glyph_pointingindexdownwhite }, + { 0x261C, glyph_pointingindexleftwhite }, + { 0x261E, glyph_pointingindexrightwhite }, + { 0x261D, glyph_pointingindexupwhite }, + { 0x30DD, glyph_pokatakana }, + { 0x0E1B, glyph_poplathai }, + { 0x3012, glyph_postalmark }, + { 0x3020, glyph_postalmarkface }, + { 0x24AB, glyph_pparen }, + { 0x227A, glyph_precedes }, + { 0x02B9, glyph_primemod }, + { 0x2035, glyph_primereversed }, + { 0x2305, glyph_projective }, + { 0x30FC, glyph_prolongedkana }, + { 0x2318, glyph_propellor }, + { 0x2237, glyph_proportion }, + { 0x0471, glyph_psicyrillic }, + { 0x0486, glyph_psilipneumatacyrilliccmb }, + { 0x33B0, glyph_pssquare }, + { 0x3077, glyph_puhiragana }, + { 0x30D7, glyph_pukatakana }, + { 0x33B4, glyph_pvsquare }, + { 0x33BA, glyph_pwsquare }, + { 0x0958, glyph_qadeva }, + { 0x05A8, glyph_qadmahebrew }, + { 0x0642, glyph_qafarabic }, + { 0xFED6, glyph_qaffinalarabic }, + { 0xFED7, glyph_qafinitialarabic }, + { 0xFED8, glyph_qafmedialarabic }, + { 0x05B8, glyph_qamats }, + { 0x05B8, glyph_qamats10 }, + { 0x05B8, glyph_qamats1a }, + { 0x05B8, glyph_qamats1c }, + { 0x05B8, glyph_qamats27 }, + { 0x05B8, glyph_qamats29 }, + { 0x05B8, glyph_qamats33 }, + { 0x05B8, glyph_qamatsde }, + { 0x05B8, glyph_qamatshebrew }, + { 0x05B8, glyph_qamatsnarrowhebrew }, + { 0x05B8, glyph_qamatsqatanhebrew }, + { 0x05B8, glyph_qamatsqatannarrowhebrew }, + { 0x05B8, glyph_qamatsqatanquarterhebrew }, + { 0x05B8, glyph_qamatsqatanwidehebrew }, + { 0x05B8, glyph_qamatsquarterhebrew }, + { 0x05B8, glyph_qamatswidehebrew }, + { 0x059F, glyph_qarneyparahebrew }, + { 0x3111, glyph_qbopomofo }, + { 0x24E0, glyph_qcircle }, + { 0x02A0, glyph_qhook }, + { 0xFF51, glyph_qmonospace }, + { 0x05E7, glyph_qof }, + { 0xFB47, glyph_qofdagesh }, + { 0xFB47, glyph_qofdageshhebrew }, + { 0x05E7, glyph_qofhatafpatah }, + { 0x05B2, glyph_qofhatafpatah }, + { 0x05E7, glyph_qofhatafpatahhebrew }, + { 0x05B2, glyph_qofhatafpatahhebrew }, + { 0x05E7, glyph_qofhatafsegol }, + { 0x05B1, glyph_qofhatafsegol }, + { 0x05E7, glyph_qofhatafsegolhebrew }, + { 0x05B1, glyph_qofhatafsegolhebrew }, + { 0x05E7, glyph_qofhebrew }, + { 0x05E7, glyph_qofhiriq }, + { 0x05B4, glyph_qofhiriq }, + { 0x05E7, glyph_qofhiriqhebrew }, + { 0x05B4, glyph_qofhiriqhebrew }, + { 0x05E7, glyph_qofholam }, + { 0x05B9, glyph_qofholam }, + { 0x05E7, glyph_qofholamhebrew }, + { 0x05B9, glyph_qofholamhebrew }, + { 0x05E7, glyph_qofpatah }, + { 0x05B7, glyph_qofpatah }, + { 0x05E7, glyph_qofpatahhebrew }, + { 0x05B7, glyph_qofpatahhebrew }, + { 0x05E7, glyph_qofqamats }, + { 0x05B8, glyph_qofqamats }, + { 0x05E7, glyph_qofqamatshebrew }, + { 0x05B8, glyph_qofqamatshebrew }, + { 0x05E7, glyph_qofqubuts }, + { 0x05BB, glyph_qofqubuts }, + { 0x05E7, glyph_qofqubutshebrew }, + { 0x05BB, glyph_qofqubutshebrew }, + { 0x05E7, glyph_qofsegol }, + { 0x05B6, glyph_qofsegol }, + { 0x05E7, glyph_qofsegolhebrew }, + { 0x05B6, glyph_qofsegolhebrew }, + { 0x05E7, glyph_qofsheva }, + { 0x05B0, glyph_qofsheva }, + { 0x05E7, glyph_qofshevahebrew }, + { 0x05B0, glyph_qofshevahebrew }, + { 0x05E7, glyph_qoftsere }, + { 0x05B5, glyph_qoftsere }, + { 0x05E7, glyph_qoftserehebrew }, + { 0x05B5, glyph_qoftserehebrew }, + { 0x24AC, glyph_qparen }, + { 0x2669, glyph_quarternote }, + { 0x05BB, glyph_qubuts }, + { 0x05BB, glyph_qubuts18 }, + { 0x05BB, glyph_qubuts25 }, + { 0x05BB, glyph_qubuts31 }, + { 0x05BB, glyph_qubutshebrew }, + { 0x05BB, glyph_qubutsnarrowhebrew }, + { 0x05BB, glyph_qubutsquarterhebrew }, + { 0x05BB, glyph_qubutswidehebrew }, + { 0x061F, glyph_questionarabic }, + { 0x055E, glyph_questionarmenian }, + { 0x037E, glyph_questiongreek }, + { 0xFF1F, glyph_questionmonospace }, + { 0xFF02, glyph_quotedblmonospace }, + { 0x301E, glyph_quotedblprime }, + { 0x301D, glyph_quotedblprimereversed }, + { 0x201B, glyph_quoteleftreversed }, + { 0x0149, glyph_quoterightn }, + { 0xFF07, glyph_quotesinglemonospace }, + { 0x057C, glyph_raarmenian }, + { 0x09B0, glyph_rabengali }, + { 0x0930, glyph_radeva }, + { 0x33AE, glyph_radoverssquare }, + { 0x33AF, glyph_radoverssquaredsquare }, + { 0x33AD, glyph_radsquare }, + { 0x05BF, glyph_rafe }, + { 0x05BF, glyph_rafehebrew }, + { 0x0AB0, glyph_ragujarati }, + { 0x0A30, glyph_ragurmukhi }, + { 0x3089, glyph_rahiragana }, + { 0x30E9, glyph_rakatakana }, + { 0xFF97, glyph_rakatakanahalfwidth }, + { 0x09F1, glyph_ralowerdiagonalbengali }, + { 0x09F0, glyph_ramiddlediagonalbengali }, + { 0x0264, glyph_ramshorn }, + { 0x2236, glyph_ratio }, + { 0x3116, glyph_rbopomofo }, + { 0x0157, glyph_rcedilla }, + { 0x24E1, glyph_rcircle }, + { 0x0211, glyph_rdblgrave }, + { 0x1E59, glyph_rdotaccent }, + { 0x1E5B, glyph_rdotbelow }, + { 0x1E5D, glyph_rdotbelowmacron }, + { 0x203B, glyph_referencemark }, + { 0x0631, glyph_reharabic }, + { 0x0580, glyph_reharmenian }, + { 0xFEAE, glyph_rehfinalarabic }, + { 0x308C, glyph_rehiragana }, + { 0x0631, glyph_rehyehaleflamarabic }, + { 0xFEF3, glyph_rehyehaleflamarabic }, + { 0xFE8E, glyph_rehyehaleflamarabic }, + { 0x0644, glyph_rehyehaleflamarabic }, + { 0x30EC, glyph_rekatakana }, + { 0xFF9A, glyph_rekatakanahalfwidth }, + { 0x05E8, glyph_resh }, + { 0xFB48, glyph_reshdageshhebrew }, + { 0x05E8, glyph_reshhatafpatah }, + { 0x05B2, glyph_reshhatafpatah }, + { 0x05E8, glyph_reshhatafpatahhebrew }, + { 0x05B2, glyph_reshhatafpatahhebrew }, + { 0x05E8, glyph_reshhatafsegol }, + { 0x05B1, glyph_reshhatafsegol }, + { 0x05E8, glyph_reshhatafsegolhebrew }, + { 0x05B1, glyph_reshhatafsegolhebrew }, + { 0x05E8, glyph_reshhebrew }, + { 0x05E8, glyph_reshhiriq }, + { 0x05B4, glyph_reshhiriq }, + { 0x05E8, glyph_reshhiriqhebrew }, + { 0x05B4, glyph_reshhiriqhebrew }, + { 0x05E8, glyph_reshholam }, + { 0x05B9, glyph_reshholam }, + { 0x05E8, glyph_reshholamhebrew }, + { 0x05B9, glyph_reshholamhebrew }, + { 0x05E8, glyph_reshpatah }, + { 0x05B7, glyph_reshpatah }, + { 0x05E8, glyph_reshpatahhebrew }, + { 0x05B7, glyph_reshpatahhebrew }, + { 0x05E8, glyph_reshqamats }, + { 0x05B8, glyph_reshqamats }, + { 0x05E8, glyph_reshqamatshebrew }, + { 0x05B8, glyph_reshqamatshebrew }, + { 0x05E8, glyph_reshqubuts }, + { 0x05BB, glyph_reshqubuts }, + { 0x05E8, glyph_reshqubutshebrew }, + { 0x05BB, glyph_reshqubutshebrew }, + { 0x05E8, glyph_reshsegol }, + { 0x05B6, glyph_reshsegol }, + { 0x05E8, glyph_reshsegolhebrew }, + { 0x05B6, glyph_reshsegolhebrew }, + { 0x05E8, glyph_reshsheva }, + { 0x05B0, glyph_reshsheva }, + { 0x05E8, glyph_reshshevahebrew }, + { 0x05B0, glyph_reshshevahebrew }, + { 0x05E8, glyph_reshtsere }, + { 0x05B5, glyph_reshtsere }, + { 0x05E8, glyph_reshtserehebrew }, + { 0x05B5, glyph_reshtserehebrew }, + { 0x223D, glyph_reversedtilde }, + { 0x0597, glyph_reviahebrew }, + { 0x0597, glyph_reviamugrashhebrew }, + { 0x027E, glyph_rfishhook }, + { 0x027F, glyph_rfishhookreversed }, + { 0x09DD, glyph_rhabengali }, + { 0x095D, glyph_rhadeva }, + { 0x027D, glyph_rhook }, + { 0x027B, glyph_rhookturned }, + { 0x02B5, glyph_rhookturnedsuperior }, + { 0x03F1, glyph_rhosymbolgreek }, + { 0x02DE, glyph_rhotichookmod }, + { 0x3271, glyph_rieulacirclekorean }, + { 0x3211, glyph_rieulaparenkorean }, + { 0x3263, glyph_rieulcirclekorean }, + { 0x3140, glyph_rieulhieuhkorean }, + { 0x313A, glyph_rieulkiyeokkorean }, + { 0x3169, glyph_rieulkiyeoksioskorean }, + { 0x3139, glyph_rieulkorean }, + { 0x313B, glyph_rieulmieumkorean }, + { 0x316C, glyph_rieulpansioskorean }, + { 0x3203, glyph_rieulparenkorean }, + { 0x313F, glyph_rieulphieuphkorean }, + { 0x313C, glyph_rieulpieupkorean }, + { 0x316B, glyph_rieulpieupsioskorean }, + { 0x313D, glyph_rieulsioskorean }, + { 0x313E, glyph_rieulthieuthkorean }, + { 0x316A, glyph_rieultikeutkorean }, + { 0x316D, glyph_rieulyeorinhieuhkorean }, + { 0x221F, glyph_rightangle }, + { 0x0319, glyph_righttackbelowcmb }, + { 0x22BF, glyph_righttriangle }, + { 0x308A, glyph_rihiragana }, + { 0x30EA, glyph_rikatakana }, + { 0xFF98, glyph_rikatakanahalfwidth }, + { 0x0325, glyph_ringbelowcmb }, + { 0x030A, glyph_ringcmb }, + { 0x02BF, glyph_ringhalfleft }, + { 0x0559, glyph_ringhalfleftarmenian }, + { 0x031C, glyph_ringhalfleftbelowcmb }, + { 0x02D3, glyph_ringhalfleftcentered }, + { 0x02BE, glyph_ringhalfright }, + { 0x0339, glyph_ringhalfrightbelowcmb }, + { 0x02D2, glyph_ringhalfrightcentered }, + { 0x0213, glyph_rinvertedbreve }, + { 0x3351, glyph_rittorusquare }, + { 0x1E5F, glyph_rlinebelow }, + { 0x027C, glyph_rlongleg }, + { 0x027A, glyph_rlonglegturned }, + { 0xFF52, glyph_rmonospace }, + { 0x308D, glyph_rohiragana }, + { 0x30ED, glyph_rokatakana }, + { 0xFF9B, glyph_rokatakanahalfwidth }, + { 0x0E23, glyph_roruathai }, + { 0x24AD, glyph_rparen }, + { 0x09DC, glyph_rrabengali }, + { 0x0931, glyph_rradeva }, + { 0x0A5C, glyph_rragurmukhi }, + { 0x0691, glyph_rreharabic }, + { 0xFB8D, glyph_rrehfinalarabic }, + { 0x09E0, glyph_rrvocalicbengali }, + { 0x0960, glyph_rrvocalicdeva }, + { 0x0AE0, glyph_rrvocalicgujarati }, + { 0x09C4, glyph_rrvocalicvowelsignbengali }, + { 0x0944, glyph_rrvocalicvowelsigndeva }, + { 0x0AC4, glyph_rrvocalicvowelsigngujarati }, + { 0x0279, glyph_rturned }, + { 0x02B4, glyph_rturnedsuperior }, + { 0x308B, glyph_ruhiragana }, + { 0x30EB, glyph_rukatakana }, + { 0xFF99, glyph_rukatakanahalfwidth }, + { 0x09F2, glyph_rupeemarkbengali }, + { 0x09F3, glyph_rupeesignbengali }, + { 0x0E24, glyph_ruthai }, + { 0x098B, glyph_rvocalicbengali }, + { 0x090B, glyph_rvocalicdeva }, + { 0x0A8B, glyph_rvocalicgujarati }, + { 0x09C3, glyph_rvocalicvowelsignbengali }, + { 0x0943, glyph_rvocalicvowelsigndeva }, + { 0x0AC3, glyph_rvocalicvowelsigngujarati }, + { 0x09B8, glyph_sabengali }, + { 0x1E65, glyph_sacutedotaccent }, + { 0x0635, glyph_sadarabic }, + { 0x0938, glyph_sadeva }, + { 0xFEBA, glyph_sadfinalarabic }, + { 0xFEBB, glyph_sadinitialarabic }, + { 0xFEBC, glyph_sadmedialarabic }, + { 0x0AB8, glyph_sagujarati }, + { 0x0A38, glyph_sagurmukhi }, + { 0x3055, glyph_sahiragana }, + { 0x30B5, glyph_sakatakana }, + { 0xFF7B, glyph_sakatakanahalfwidth }, + { 0xFDFA, glyph_sallallahoualayhewasallamarabic }, + { 0x05E1, glyph_samekh }, + { 0xFB41, glyph_samekhdagesh }, + { 0xFB41, glyph_samekhdageshhebrew }, + { 0x05E1, glyph_samekhhebrew }, + { 0x0E32, glyph_saraaathai }, + { 0x0E41, glyph_saraaethai }, + { 0x0E44, glyph_saraaimaimalaithai }, + { 0x0E43, glyph_saraaimaimuanthai }, + { 0x0E33, glyph_saraamthai }, + { 0x0E30, glyph_saraathai }, + { 0x0E40, glyph_saraethai }, + { 0xF886, glyph_saraiileftthai }, + { 0x0E35, glyph_saraiithai }, + { 0xF885, glyph_saraileftthai }, + { 0x0E34, glyph_saraithai }, + { 0x0E42, glyph_saraothai }, + { 0xF888, glyph_saraueeleftthai }, + { 0x0E37, glyph_saraueethai }, + { 0xF887, glyph_saraueleftthai }, + { 0x0E36, glyph_sarauethai }, + { 0x0E38, glyph_sarauthai }, + { 0x0E39, glyph_sarauuthai }, + { 0x3119, glyph_sbopomofo }, + { 0x1E67, glyph_scarondotaccent }, + { 0x0259, glyph_schwa }, + { 0x04D9, glyph_schwacyrillic }, + { 0x04DB, glyph_schwadieresiscyrillic }, + { 0x025A, glyph_schwahook }, + { 0x24E2, glyph_scircle }, + { 0x1E61, glyph_sdotaccent }, + { 0x1E63, glyph_sdotbelow }, + { 0x1E69, glyph_sdotbelowdotaccent }, + { 0x033C, glyph_seagullbelowcmb }, + { 0x02CA, glyph_secondtonechinese }, + { 0x0633, glyph_seenarabic }, + { 0xFEB2, glyph_seenfinalarabic }, + { 0xFEB3, glyph_seeninitialarabic }, + { 0xFEB4, glyph_seenmedialarabic }, + { 0x05B6, glyph_segol }, + { 0x05B6, glyph_segol13 }, + { 0x05B6, glyph_segol1f }, + { 0x05B6, glyph_segol2c }, + { 0x05B6, glyph_segolhebrew }, + { 0x05B6, glyph_segolnarrowhebrew }, + { 0x05B6, glyph_segolquarterhebrew }, + { 0x0592, glyph_segoltahebrew }, + { 0x05B6, glyph_segolwidehebrew }, + { 0x057D, glyph_seharmenian }, + { 0x305B, glyph_sehiragana }, + { 0x30BB, glyph_sekatakana }, + { 0xFF7E, glyph_sekatakanahalfwidth }, + { 0x061B, glyph_semicolonarabic }, + { 0xFF1B, glyph_semicolonmonospace }, + { 0xFE54, glyph_semicolonsmall }, + { 0x309C, glyph_semivoicedmarkkana }, + { 0xFF9F, glyph_semivoicedmarkkanahalfwidth }, + { 0x3322, glyph_sentisquare }, + { 0x3323, glyph_sentosquare }, + { 0x0667, glyph_sevenarabic }, + { 0x09ED, glyph_sevenbengali }, + { 0x2466, glyph_sevencircle }, + { 0x2790, glyph_sevencircleinversesansserif }, + { 0x096D, glyph_sevendeva }, + { 0x0AED, glyph_sevengujarati }, + { 0x0A6D, glyph_sevengurmukhi }, + { 0x0667, glyph_sevenhackarabic }, + { 0x3027, glyph_sevenhangzhou }, + { 0x3226, glyph_sevenideographicparen }, + { 0xFF17, glyph_sevenmonospace }, + { 0x247A, glyph_sevenparen }, + { 0x248E, glyph_sevenperiod }, + { 0x06F7, glyph_sevenpersian }, + { 0x2176, glyph_sevenroman }, + { 0x2470, glyph_seventeencircle }, + { 0x2484, glyph_seventeenparen }, + { 0x2498, glyph_seventeenperiod }, + { 0x0E57, glyph_seventhai }, + { 0x0577, glyph_shaarmenian }, + { 0x09B6, glyph_shabengali }, + { 0x0448, glyph_shacyrillic }, + { 0x0651, glyph_shaddaarabic }, + { 0xFC61, glyph_shaddadammaarabic }, + { 0xFC5E, glyph_shaddadammatanarabic }, + { 0xFC60, glyph_shaddafathaarabic }, + { 0x0651, glyph_shaddafathatanarabic }, + { 0x064B, glyph_shaddafathatanarabic }, + { 0xFC62, glyph_shaddakasraarabic }, + { 0xFC5F, glyph_shaddakasratanarabic }, + { 0x2593, glyph_shadedark }, + { 0x2591, glyph_shadelight }, + { 0x2592, glyph_shademedium }, + { 0x0936, glyph_shadeva }, + { 0x0AB6, glyph_shagujarati }, + { 0x0A36, glyph_shagurmukhi }, + { 0x0593, glyph_shalshelethebrew }, + { 0x3115, glyph_shbopomofo }, + { 0x0449, glyph_shchacyrillic }, + { 0x0634, glyph_sheenarabic }, + { 0xFEB6, glyph_sheenfinalarabic }, + { 0xFEB7, glyph_sheeninitialarabic }, + { 0xFEB8, glyph_sheenmedialarabic }, + { 0x03E3, glyph_sheicoptic }, + { 0x20AA, glyph_sheqel }, + { 0x20AA, glyph_sheqelhebrew }, + { 0x05B0, glyph_sheva }, + { 0x05B0, glyph_sheva115 }, + { 0x05B0, glyph_sheva15 }, + { 0x05B0, glyph_sheva22 }, + { 0x05B0, glyph_sheva2e }, + { 0x05B0, glyph_shevahebrew }, + { 0x05B0, glyph_shevanarrowhebrew }, + { 0x05B0, glyph_shevaquarterhebrew }, + { 0x05B0, glyph_shevawidehebrew }, + { 0x04BB, glyph_shhacyrillic }, + { 0x03ED, glyph_shimacoptic }, + { 0x05E9, glyph_shin }, + { 0xFB49, glyph_shindagesh }, + { 0xFB49, glyph_shindageshhebrew }, + { 0xFB2C, glyph_shindageshshindot }, + { 0xFB2C, glyph_shindageshshindothebrew }, + { 0xFB2D, glyph_shindageshsindot }, + { 0xFB2D, glyph_shindageshsindothebrew }, + { 0x05C1, glyph_shindothebrew }, + { 0x05E9, glyph_shinhebrew }, + { 0xFB2A, glyph_shinshindot }, + { 0xFB2A, glyph_shinshindothebrew }, + { 0xFB2B, glyph_shinsindot }, + { 0xFB2B, glyph_shinsindothebrew }, + { 0x0282, glyph_shook }, + { 0x03C2, glyph_sigmafinal }, + { 0x03F2, glyph_sigmalunatesymbolgreek }, + { 0x3057, glyph_sihiragana }, + { 0x30B7, glyph_sikatakana }, + { 0xFF7C, glyph_sikatakanahalfwidth }, + { 0x05BD, glyph_siluqhebrew }, + { 0x05BD, glyph_siluqlefthebrew }, + { 0x05C2, glyph_sindothebrew }, + { 0x3274, glyph_siosacirclekorean }, + { 0x3214, glyph_siosaparenkorean }, + { 0x317E, glyph_sioscieuckorean }, + { 0x3266, glyph_sioscirclekorean }, + { 0x317A, glyph_sioskiyeokkorean }, + { 0x3145, glyph_sioskorean }, + { 0x317B, glyph_siosnieunkorean }, + { 0x3206, glyph_siosparenkorean }, + { 0x317D, glyph_siospieupkorean }, + { 0x317C, glyph_siostikeutkorean }, + { 0x0666, glyph_sixarabic }, + { 0x09EC, glyph_sixbengali }, + { 0x2465, glyph_sixcircle }, + { 0x278F, glyph_sixcircleinversesansserif }, + { 0x096C, glyph_sixdeva }, + { 0x0AEC, glyph_sixgujarati }, + { 0x0A6C, glyph_sixgurmukhi }, + { 0x0666, glyph_sixhackarabic }, + { 0x3026, glyph_sixhangzhou }, + { 0x3225, glyph_sixideographicparen }, + { 0xFF16, glyph_sixmonospace }, + { 0x2479, glyph_sixparen }, + { 0x248D, glyph_sixperiod }, + { 0x06F6, glyph_sixpersian }, + { 0x2175, glyph_sixroman }, + { 0x246F, glyph_sixteencircle }, + { 0x09F9, glyph_sixteencurrencydenominatorbengali }, + { 0x2483, glyph_sixteenparen }, + { 0x2497, glyph_sixteenperiod }, + { 0x0E56, glyph_sixthai }, + { 0xFF0F, glyph_slashmonospace }, + { 0x017F, glyph_slong }, + { 0x1E9B, glyph_slongdotaccent }, + { 0xFF53, glyph_smonospace }, + { 0x05C3, glyph_sofpasuqhebrew }, + { 0x00AD, glyph_softhyphen }, + { 0x044C, glyph_softsigncyrillic }, + { 0x305D, glyph_sohiragana }, + { 0x30BD, glyph_sokatakana }, + { 0xFF7F, glyph_sokatakanahalfwidth }, + { 0x0338, glyph_soliduslongoverlaycmb }, + { 0x0337, glyph_solidusshortoverlaycmb }, + { 0x0E29, glyph_sorusithai }, + { 0x0E28, glyph_sosalathai }, + { 0x0E0B, glyph_sosothai }, + { 0x0E2A, glyph_sosuathai }, + { 0x0020, glyph_spacehackarabic }, + { 0x2660, glyph_spadesuitblack }, + { 0x2664, glyph_spadesuitwhite }, + { 0x24AE, glyph_sparen }, + { 0x033B, glyph_squarebelowcmb }, + { 0x33C4, glyph_squarecc }, + { 0x339D, glyph_squarecm }, + { 0x25A9, glyph_squarediagonalcrosshatchfill }, + { 0x25A4, glyph_squarehorizontalfill }, + { 0x338F, glyph_squarekg }, + { 0x339E, glyph_squarekm }, + { 0x33CE, glyph_squarekmcapital }, + { 0x33D1, glyph_squareln }, + { 0x33D2, glyph_squarelog }, + { 0x338E, glyph_squaremg }, + { 0x33D5, glyph_squaremil }, + { 0x339C, glyph_squaremm }, + { 0x33A1, glyph_squaremsquared }, + { 0x25A6, glyph_squareorthogonalcrosshatchfill }, + { 0x25A7, glyph_squareupperlefttolowerrightfill }, + { 0x25A8, glyph_squareupperrighttolowerleftfill }, + { 0x25A5, glyph_squareverticalfill }, + { 0x25A3, glyph_squarewhitewithsmallblack }, + { 0x33DB, glyph_srsquare }, + { 0x09B7, glyph_ssabengali }, + { 0x0937, glyph_ssadeva }, + { 0x0AB7, glyph_ssagujarati }, + { 0x3149, glyph_ssangcieuckorean }, + { 0x3185, glyph_ssanghieuhkorean }, + { 0x3180, glyph_ssangieungkorean }, + { 0x3132, glyph_ssangkiyeokkorean }, + { 0x3165, glyph_ssangnieunkorean }, + { 0x3143, glyph_ssangpieupkorean }, + { 0x3146, glyph_ssangsioskorean }, + { 0x3138, glyph_ssangtikeutkorean }, + { 0xFFE1, glyph_sterlingmonospace }, + { 0x0336, glyph_strokelongoverlaycmb }, + { 0x0335, glyph_strokeshortoverlaycmb }, + { 0x2282, glyph_subset }, + { 0x228A, glyph_subsetnotequal }, + { 0x2286, glyph_subsetorequal }, + { 0x227B, glyph_succeeds }, + { 0x3059, glyph_suhiragana }, + { 0x30B9, glyph_sukatakana }, + { 0xFF7D, glyph_sukatakanahalfwidth }, + { 0x0652, glyph_sukunarabic }, + { 0x2283, glyph_superset }, + { 0x228B, glyph_supersetnotequal }, + { 0x2287, glyph_supersetorequal }, + { 0x33DC, glyph_svsquare }, + { 0x337C, glyph_syouwaerasquare }, + { 0x09A4, glyph_tabengali }, + { 0x22A4, glyph_tackdown }, + { 0x22A3, glyph_tackleft }, + { 0x0924, glyph_tadeva }, + { 0x0AA4, glyph_tagujarati }, + { 0x0A24, glyph_tagurmukhi }, + { 0x0637, glyph_taharabic }, + { 0xFEC2, glyph_tahfinalarabic }, + { 0xFEC3, glyph_tahinitialarabic }, + { 0x305F, glyph_tahiragana }, + { 0xFEC4, glyph_tahmedialarabic }, + { 0x337D, glyph_taisyouerasquare }, + { 0x30BF, glyph_takatakana }, + { 0xFF80, glyph_takatakanahalfwidth }, + { 0x0640, glyph_tatweelarabic }, + { 0x05EA, glyph_tav }, + { 0xFB4A, glyph_tavdages }, + { 0xFB4A, glyph_tavdagesh }, + { 0xFB4A, glyph_tavdageshhebrew }, + { 0x05EA, glyph_tavhebrew }, + { 0x310A, glyph_tbopomofo }, + { 0x02A8, glyph_tccurl }, + { 0x0686, glyph_tcheharabic }, + { 0xFB7B, glyph_tchehfinalarabic }, + { 0xFB7C, glyph_tchehinitialarabic }, + { 0xFB7D, glyph_tchehmedialarabic }, + { 0xFB7C, glyph_tchehmeeminitialarabic }, + { 0xFEE4, glyph_tchehmeeminitialarabic }, + { 0x24E3, glyph_tcircle }, + { 0x1E71, glyph_tcircumflexbelow }, + { 0x1E97, glyph_tdieresis }, + { 0x1E6B, glyph_tdotaccent }, + { 0x1E6D, glyph_tdotbelow }, + { 0x0442, glyph_tecyrillic }, + { 0x04AD, glyph_tedescendercyrillic }, + { 0x062A, glyph_teharabic }, + { 0xFE96, glyph_tehfinalarabic }, + { 0xFCA2, glyph_tehhahinitialarabic }, + { 0xFC0C, glyph_tehhahisolatedarabic }, + { 0xFE97, glyph_tehinitialarabic }, + { 0x3066, glyph_tehiragana }, + { 0xFCA1, glyph_tehjeeminitialarabic }, + { 0xFC0B, glyph_tehjeemisolatedarabic }, + { 0x0629, glyph_tehmarbutaarabic }, + { 0xFE94, glyph_tehmarbutafinalarabic }, + { 0xFE98, glyph_tehmedialarabic }, + { 0xFCA4, glyph_tehmeeminitialarabic }, + { 0xFC0E, glyph_tehmeemisolatedarabic }, + { 0xFC73, glyph_tehnoonfinalarabic }, + { 0x30C6, glyph_tekatakana }, + { 0xFF83, glyph_tekatakanahalfwidth }, + { 0x2121, glyph_telephone }, + { 0x260E, glyph_telephoneblack }, + { 0x05A0, glyph_telishagedolahebrew }, + { 0x05A9, glyph_telishaqetanahebrew }, + { 0x2469, glyph_tencircle }, + { 0x3229, glyph_tenideographicparen }, + { 0x247D, glyph_tenparen }, + { 0x2491, glyph_tenperiod }, + { 0x2179, glyph_tenroman }, + { 0x02A7, glyph_tesh }, + { 0x05D8, glyph_tet }, + { 0xFB38, glyph_tetdagesh }, + { 0xFB38, glyph_tetdageshhebrew }, + { 0x05D8, glyph_tethebrew }, + { 0x04B5, glyph_tetsecyrillic }, + { 0x059B, glyph_tevirhebrew }, + { 0x059B, glyph_tevirlefthebrew }, + { 0x09A5, glyph_thabengali }, + { 0x0925, glyph_thadeva }, + { 0x0AA5, glyph_thagujarati }, + { 0x0A25, glyph_thagurmukhi }, + { 0x0630, glyph_thalarabic }, + { 0xFEAC, glyph_thalfinalarabic }, + { 0xF898, glyph_thanthakhatlowleftthai }, + { 0xF897, glyph_thanthakhatlowrightthai }, + { 0x0E4C, glyph_thanthakhatthai }, + { 0xF896, glyph_thanthakhatupperleftthai }, + { 0x062B, glyph_theharabic }, + { 0xFE9A, glyph_thehfinalarabic }, + { 0xFE9B, glyph_thehinitialarabic }, + { 0xFE9C, glyph_thehmedialarabic }, + { 0x2203, glyph_thereexists }, + { 0x03D1, glyph_thetasymbolgreek }, + { 0x3279, glyph_thieuthacirclekorean }, + { 0x3219, glyph_thieuthaparenkorean }, + { 0x326B, glyph_thieuthcirclekorean }, + { 0x314C, glyph_thieuthkorean }, + { 0x320B, glyph_thieuthparenkorean }, + { 0x246C, glyph_thirteencircle }, + { 0x2480, glyph_thirteenparen }, + { 0x2494, glyph_thirteenperiod }, + { 0x0E11, glyph_thonangmonthothai }, + { 0x01AD, glyph_thook }, + { 0x0E12, glyph_thophuthaothai }, + { 0x0E17, glyph_thothahanthai }, + { 0x0E10, glyph_thothanthai }, + { 0x0E18, glyph_thothongthai }, + { 0x0E16, glyph_thothungthai }, + { 0x0482, glyph_thousandcyrillic }, + { 0x066C, glyph_thousandsseparatorarabic }, + { 0x066C, glyph_thousandsseparatorpersian }, + { 0x0663, glyph_threearabic }, + { 0x09E9, glyph_threebengali }, + { 0x2462, glyph_threecircle }, + { 0x278C, glyph_threecircleinversesansserif }, + { 0x0969, glyph_threedeva }, + { 0x0AE9, glyph_threegujarati }, + { 0x0A69, glyph_threegurmukhi }, + { 0x0663, glyph_threehackarabic }, + { 0x3023, glyph_threehangzhou }, + { 0x3222, glyph_threeideographicparen }, + { 0xFF13, glyph_threemonospace }, + { 0x09F6, glyph_threenumeratorbengali }, + { 0x2476, glyph_threeparen }, + { 0x248A, glyph_threeperiod }, + { 0x06F3, glyph_threepersian }, + { 0x2172, glyph_threeroman }, + { 0x0E53, glyph_threethai }, + { 0x3394, glyph_thzsquare }, + { 0x3061, glyph_tihiragana }, + { 0x30C1, glyph_tikatakana }, + { 0xFF81, glyph_tikatakanahalfwidth }, + { 0x3270, glyph_tikeutacirclekorean }, + { 0x3210, glyph_tikeutaparenkorean }, + { 0x3262, glyph_tikeutcirclekorean }, + { 0x3137, glyph_tikeutkorean }, + { 0x3202, glyph_tikeutparenkorean }, + { 0x0330, glyph_tildebelowcmb }, + { 0x0303, glyph_tildecmb }, + { 0x0360, glyph_tildedoublecmb }, + { 0x223C, glyph_tildeoperator }, + { 0x0334, glyph_tildeoverlaycmb }, + { 0x033E, glyph_tildeverticalcmb }, + { 0x2297, glyph_timescircle }, + { 0x0596, glyph_tipehahebrew }, + { 0x0596, glyph_tipehalefthebrew }, + { 0x0A70, glyph_tippigurmukhi }, + { 0x0483, glyph_titlocyrilliccmb }, + { 0x057F, glyph_tiwnarmenian }, + { 0x1E6F, glyph_tlinebelow }, + { 0xFF54, glyph_tmonospace }, + { 0x0569, glyph_toarmenian }, + { 0x3068, glyph_tohiragana }, + { 0x30C8, glyph_tokatakana }, + { 0xFF84, glyph_tokatakanahalfwidth }, + { 0x02E5, glyph_tonebarextrahighmod }, + { 0x02E9, glyph_tonebarextralowmod }, + { 0x02E6, glyph_tonebarhighmod }, + { 0x02E8, glyph_tonebarlowmod }, + { 0x02E7, glyph_tonebarmidmod }, + { 0x01BD, glyph_tonefive }, + { 0x0185, glyph_tonesix }, + { 0x01A8, glyph_tonetwo }, + { 0x3327, glyph_tonsquare }, + { 0x0E0F, glyph_topatakthai }, + { 0x3014, glyph_tortoiseshellbracketleft }, + { 0xFE5D, glyph_tortoiseshellbracketleftsmall }, + { 0xFE39, glyph_tortoiseshellbracketleftvertical }, + { 0x3015, glyph_tortoiseshellbracketright }, + { 0xFE5E, glyph_tortoiseshellbracketrightsmall }, + { 0xFE3A, glyph_tortoiseshellbracketrightvertical }, + { 0x0E15, glyph_totaothai }, + { 0x01AB, glyph_tpalatalhook }, + { 0x24AF, glyph_tparen }, + { 0x0288, glyph_tretroflexhook }, + { 0x02A6, glyph_ts }, + { 0x05E6, glyph_tsadi }, + { 0xFB46, glyph_tsadidagesh }, + { 0xFB46, glyph_tsadidageshhebrew }, + { 0x05E6, glyph_tsadihebrew }, + { 0x0446, glyph_tsecyrillic }, + { 0x05B5, glyph_tsere }, + { 0x05B5, glyph_tsere12 }, + { 0x05B5, glyph_tsere1e }, + { 0x05B5, glyph_tsere2b }, + { 0x05B5, glyph_tserehebrew }, + { 0x05B5, glyph_tserenarrowhebrew }, + { 0x05B5, glyph_tserequarterhebrew }, + { 0x05B5, glyph_tserewidehebrew }, + { 0x045B, glyph_tshecyrillic }, + { 0x099F, glyph_ttabengali }, + { 0x091F, glyph_ttadeva }, + { 0x0A9F, glyph_ttagujarati }, + { 0x0A1F, glyph_ttagurmukhi }, + { 0x0679, glyph_tteharabic }, + { 0xFB67, glyph_ttehfinalarabic }, + { 0xFB68, glyph_ttehinitialarabic }, + { 0xFB69, glyph_ttehmedialarabic }, + { 0x09A0, glyph_tthabengali }, + { 0x0920, glyph_tthadeva }, + { 0x0AA0, glyph_tthagujarati }, + { 0x0A20, glyph_tthagurmukhi }, + { 0x0287, glyph_tturned }, + { 0x3064, glyph_tuhiragana }, + { 0x30C4, glyph_tukatakana }, + { 0xFF82, glyph_tukatakanahalfwidth }, + { 0x3063, glyph_tusmallhiragana }, + { 0x30C3, glyph_tusmallkatakana }, + { 0xFF6F, glyph_tusmallkatakanahalfwidth }, + { 0x246B, glyph_twelvecircle }, + { 0x247F, glyph_twelveparen }, + { 0x2493, glyph_twelveperiod }, + { 0x217B, glyph_twelveroman }, + { 0x2473, glyph_twentycircle }, + { 0x5344, glyph_twentyhangzhou }, + { 0x2487, glyph_twentyparen }, + { 0x249B, glyph_twentyperiod }, + { 0x0662, glyph_twoarabic }, + { 0x09E8, glyph_twobengali }, + { 0x2461, glyph_twocircle }, + { 0x278B, glyph_twocircleinversesansserif }, + { 0x0968, glyph_twodeva }, + { 0x2025, glyph_twodotleader }, + { 0xFE30, glyph_twodotleadervertical }, + { 0x0AE8, glyph_twogujarati }, + { 0x0A68, glyph_twogurmukhi }, + { 0x0662, glyph_twohackarabic }, + { 0x3022, glyph_twohangzhou }, + { 0x3221, glyph_twoideographicparen }, + { 0xFF12, glyph_twomonospace }, + { 0x09F5, glyph_twonumeratorbengali }, + { 0x2475, glyph_twoparen }, + { 0x2489, glyph_twoperiod }, + { 0x06F2, glyph_twopersian }, + { 0x2171, glyph_tworoman }, + { 0x01BB, glyph_twostroke }, + { 0x0E52, glyph_twothai }, + { 0x0289, glyph_ubar }, + { 0x0989, glyph_ubengali }, + { 0x3128, glyph_ubopomofo }, + { 0x01D4, glyph_ucaron }, + { 0x24E4, glyph_ucircle }, + { 0x1E77, glyph_ucircumflexbelow }, + { 0x0443, glyph_ucyrillic }, + { 0x0951, glyph_udattadeva }, + { 0x0171, glyph_udblacute }, + { 0x0215, glyph_udblgrave }, + { 0x0909, glyph_udeva }, + { 0x01D8, glyph_udieresisacute }, + { 0x1E73, glyph_udieresisbelow }, + { 0x01DA, glyph_udieresiscaron }, + { 0x04F1, glyph_udieresiscyrillic }, + { 0x01DC, glyph_udieresisgrave }, + { 0x01D6, glyph_udieresismacron }, + { 0x1EE5, glyph_udotbelow }, + { 0x0A89, glyph_ugujarati }, + { 0x0A09, glyph_ugurmukhi }, + { 0x3046, glyph_uhiragana }, + { 0x1EE7, glyph_uhookabove }, + { 0x1EE9, glyph_uhornacute }, + { 0x1EF1, glyph_uhorndotbelow }, + { 0x1EEB, glyph_uhorngrave }, + { 0x1EED, glyph_uhornhookabove }, + { 0x1EEF, glyph_uhorntilde }, + { 0x04F3, glyph_uhungarumlautcyrillic }, + { 0x0217, glyph_uinvertedbreve }, + { 0x30A6, glyph_ukatakana }, + { 0xFF73, glyph_ukatakanahalfwidth }, + { 0x0479, glyph_ukcyrillic }, + { 0x315C, glyph_ukorean }, + { 0x04EF, glyph_umacroncyrillic }, + { 0x1E7B, glyph_umacrondieresis }, + { 0x0A41, glyph_umatragurmukhi }, + { 0xFF55, glyph_umonospace }, + { 0xFF3F, glyph_underscoremonospace }, + { 0xFE33, glyph_underscorevertical }, + { 0xFE4F, glyph_underscorewavy }, + { 0x24B0, glyph_uparen }, + { 0x05C4, glyph_upperdothebrew }, + { 0x028A, glyph_upsilonlatin }, + { 0x031D, glyph_uptackbelowcmb }, + { 0x02D4, glyph_uptackmod }, + { 0x0A73, glyph_uragurmukhi }, + { 0x045E, glyph_ushortcyrillic }, + { 0x3045, glyph_usmallhiragana }, + { 0x30A5, glyph_usmallkatakana }, + { 0xFF69, glyph_usmallkatakanahalfwidth }, + { 0x04AF, glyph_ustraightcyrillic }, + { 0x04B1, glyph_ustraightstrokecyrillic }, + { 0x1E79, glyph_utildeacute }, + { 0x1E75, glyph_utildebelow }, + { 0x098A, glyph_uubengali }, + { 0x090A, glyph_uudeva }, + { 0x0A8A, glyph_uugujarati }, + { 0x0A0A, glyph_uugurmukhi }, + { 0x0A42, glyph_uumatragurmukhi }, + { 0x09C2, glyph_uuvowelsignbengali }, + { 0x0942, glyph_uuvowelsigndeva }, + { 0x0AC2, glyph_uuvowelsigngujarati }, + { 0x09C1, glyph_uvowelsignbengali }, + { 0x0941, glyph_uvowelsigndeva }, + { 0x0AC1, glyph_uvowelsigngujarati }, + { 0x0935, glyph_vadeva }, + { 0x0AB5, glyph_vagujarati }, + { 0x0A35, glyph_vagurmukhi }, + { 0x30F7, glyph_vakatakana }, + { 0x05D5, glyph_vav }, + { 0xFB35, glyph_vavdagesh }, + { 0xFB35, glyph_vavdagesh65 }, + { 0xFB35, glyph_vavdageshhebrew }, + { 0x05D5, glyph_vavhebrew }, + { 0xFB4B, glyph_vavholam }, + { 0xFB4B, glyph_vavholamhebrew }, + { 0x05F0, glyph_vavvavhebrew }, + { 0x05F1, glyph_vavyodhebrew }, + { 0x24E5, glyph_vcircle }, + { 0x1E7F, glyph_vdotbelow }, + { 0x0432, glyph_vecyrillic }, + { 0x06A4, glyph_veharabic }, + { 0xFB6B, glyph_vehfinalarabic }, + { 0xFB6C, glyph_vehinitialarabic }, + { 0xFB6D, glyph_vehmedialarabic }, + { 0x30F9, glyph_vekatakana }, + { 0x2640, glyph_venus }, + { 0x007C, glyph_verticalbar }, + { 0x030D, glyph_verticallineabovecmb }, + { 0x0329, glyph_verticallinebelowcmb }, + { 0x02CC, glyph_verticallinelowmod }, + { 0x02C8, glyph_verticallinemod }, + { 0x057E, glyph_vewarmenian }, + { 0x028B, glyph_vhook }, + { 0x30F8, glyph_vikatakana }, + { 0x09CD, glyph_viramabengali }, + { 0x094D, glyph_viramadeva }, + { 0x0ACD, glyph_viramagujarati }, + { 0x0983, glyph_visargabengali }, + { 0x0903, glyph_visargadeva }, + { 0x0A83, glyph_visargagujarati }, + { 0xFF56, glyph_vmonospace }, + { 0x0578, glyph_voarmenian }, + { 0x309E, glyph_voicediterationhiragana }, + { 0x30FE, glyph_voicediterationkatakana }, + { 0x309B, glyph_voicedmarkkana }, + { 0xFF9E, glyph_voicedmarkkanahalfwidth }, + { 0x30FA, glyph_vokatakana }, + { 0x24B1, glyph_vparen }, + { 0x1E7D, glyph_vtilde }, + { 0x028C, glyph_vturned }, + { 0x3094, glyph_vuhiragana }, + { 0x30F4, glyph_vukatakana }, + { 0x3159, glyph_waekorean }, + { 0x308F, glyph_wahiragana }, + { 0x30EF, glyph_wakatakana }, + { 0xFF9C, glyph_wakatakanahalfwidth }, + { 0x3158, glyph_wakorean }, + { 0x308E, glyph_wasmallhiragana }, + { 0x30EE, glyph_wasmallkatakana }, + { 0x3357, glyph_wattosquare }, + { 0x301C, glyph_wavedash }, + { 0xFE34, glyph_wavyunderscorevertical }, + { 0x0648, glyph_wawarabic }, + { 0xFEEE, glyph_wawfinalarabic }, + { 0x0624, glyph_wawhamzaabovearabic }, + { 0xFE86, glyph_wawhamzaabovefinalarabic }, + { 0x33DD, glyph_wbsquare }, + { 0x24E6, glyph_wcircle }, + { 0x1E87, glyph_wdotaccent }, + { 0x1E89, glyph_wdotbelow }, + { 0x3091, glyph_wehiragana }, + { 0x30F1, glyph_wekatakana }, + { 0x315E, glyph_wekorean }, + { 0x315D, glyph_weokorean }, + { 0x25E6, glyph_whitebullet }, + { 0x25CB, glyph_whitecircle }, + { 0x25D9, glyph_whitecircleinverse }, + { 0x300E, glyph_whitecornerbracketleft }, + { 0xFE43, glyph_whitecornerbracketleftvertical }, + { 0x300F, glyph_whitecornerbracketright }, + { 0xFE44, glyph_whitecornerbracketrightvertical }, + { 0x25C7, glyph_whitediamond }, + { 0x25C8, glyph_whitediamondcontainingblacksmalldiamond }, + { 0x25BF, glyph_whitedownpointingsmalltriangle }, + { 0x25BD, glyph_whitedownpointingtriangle }, + { 0x25C3, glyph_whiteleftpointingsmalltriangle }, + { 0x25C1, glyph_whiteleftpointingtriangle }, + { 0x3016, glyph_whitelenticularbracketleft }, + { 0x3017, glyph_whitelenticularbracketright }, + { 0x25B9, glyph_whiterightpointingsmalltriangle }, + { 0x25B7, glyph_whiterightpointingtriangle }, + { 0x25AB, glyph_whitesmallsquare }, + { 0x263A, glyph_whitesmilingface }, + { 0x25A1, glyph_whitesquare }, + { 0x2606, glyph_whitestar }, + { 0x260F, glyph_whitetelephone }, + { 0x3018, glyph_whitetortoiseshellbracketleft }, + { 0x3019, glyph_whitetortoiseshellbracketright }, + { 0x25B5, glyph_whiteuppointingsmalltriangle }, + { 0x25B3, glyph_whiteuppointingtriangle }, + { 0x3090, glyph_wihiragana }, + { 0x30F0, glyph_wikatakana }, + { 0x315F, glyph_wikorean }, + { 0xFF57, glyph_wmonospace }, + { 0x3092, glyph_wohiragana }, + { 0x30F2, glyph_wokatakana }, + { 0xFF66, glyph_wokatakanahalfwidth }, + { 0x20A9, glyph_won }, + { 0xFFE6, glyph_wonmonospace }, + { 0x0E27, glyph_wowaenthai }, + { 0x24B2, glyph_wparen }, + { 0x1E98, glyph_wring }, + { 0x02B7, glyph_wsuperior }, + { 0x028D, glyph_wturned }, + { 0x01BF, glyph_wynn }, + { 0x033D, glyph_xabovecmb }, + { 0x3112, glyph_xbopomofo }, + { 0x24E7, glyph_xcircle }, + { 0x1E8D, glyph_xdieresis }, + { 0x1E8B, glyph_xdotaccent }, + { 0x056D, glyph_xeharmenian }, + { 0xFF58, glyph_xmonospace }, + { 0x24B3, glyph_xparen }, + { 0x02E3, glyph_xsuperior }, + { 0x334E, glyph_yaadosquare }, + { 0x09AF, glyph_yabengali }, + { 0x092F, glyph_yadeva }, + { 0x3152, glyph_yaekorean }, + { 0x0AAF, glyph_yagujarati }, + { 0x0A2F, glyph_yagurmukhi }, + { 0x3084, glyph_yahiragana }, + { 0x30E4, glyph_yakatakana }, + { 0xFF94, glyph_yakatakanahalfwidth }, + { 0x3151, glyph_yakorean }, + { 0x0E4E, glyph_yamakkanthai }, + { 0x3083, glyph_yasmallhiragana }, + { 0x30E3, glyph_yasmallkatakana }, + { 0xFF6C, glyph_yasmallkatakanahalfwidth }, + { 0x0463, glyph_yatcyrillic }, + { 0x24E8, glyph_ycircle }, + { 0x1E8F, glyph_ydotaccent }, + { 0x1EF5, glyph_ydotbelow }, + { 0x064A, glyph_yeharabic }, + { 0x06D2, glyph_yehbarreearabic }, + { 0xFBAF, glyph_yehbarreefinalarabic }, + { 0xFEF2, glyph_yehfinalarabic }, + { 0x0626, glyph_yehhamzaabovearabic }, + { 0xFE8A, glyph_yehhamzaabovefinalarabic }, + { 0xFE8B, glyph_yehhamzaaboveinitialarabic }, + { 0xFE8C, glyph_yehhamzaabovemedialarabic }, + { 0xFEF3, glyph_yehinitialarabic }, + { 0xFEF4, glyph_yehmedialarabic }, + { 0xFCDD, glyph_yehmeeminitialarabic }, + { 0xFC58, glyph_yehmeemisolatedarabic }, + { 0xFC94, glyph_yehnoonfinalarabic }, + { 0x06D1, glyph_yehthreedotsbelowarabic }, + { 0x3156, glyph_yekorean }, + { 0xFFE5, glyph_yenmonospace }, + { 0x3155, glyph_yeokorean }, + { 0x3186, glyph_yeorinhieuhkorean }, + { 0x05AA, glyph_yerahbenyomohebrew }, + { 0x05AA, glyph_yerahbenyomolefthebrew }, + { 0x044B, glyph_yericyrillic }, + { 0x04F9, glyph_yerudieresiscyrillic }, + { 0x3181, glyph_yesieungkorean }, + { 0x3183, glyph_yesieungpansioskorean }, + { 0x3182, glyph_yesieungsioskorean }, + { 0x059A, glyph_yetivhebrew }, + { 0x01B4, glyph_yhook }, + { 0x1EF7, glyph_yhookabove }, + { 0x0575, glyph_yiarmenian }, + { 0x0457, glyph_yicyrillic }, + { 0x3162, glyph_yikorean }, + { 0x262F, glyph_yinyang }, + { 0x0582, glyph_yiwnarmenian }, + { 0xFF59, glyph_ymonospace }, + { 0x05D9, glyph_yod }, + { 0xFB39, glyph_yoddagesh }, + { 0xFB39, glyph_yoddageshhebrew }, + { 0x05D9, glyph_yodhebrew }, + { 0x05F2, glyph_yodyodhebrew }, + { 0xFB1F, glyph_yodyodpatahhebrew }, + { 0x3088, glyph_yohiragana }, + { 0x3189, glyph_yoikorean }, + { 0x30E8, glyph_yokatakana }, + { 0xFF96, glyph_yokatakanahalfwidth }, + { 0x315B, glyph_yokorean }, + { 0x3087, glyph_yosmallhiragana }, + { 0x30E7, glyph_yosmallkatakana }, + { 0xFF6E, glyph_yosmallkatakanahalfwidth }, + { 0x03F3, glyph_yotgreek }, + { 0x3188, glyph_yoyaekorean }, + { 0x3187, glyph_yoyakorean }, + { 0x0E22, glyph_yoyakthai }, + { 0x0E0D, glyph_yoyingthai }, + { 0x24B4, glyph_yparen }, + { 0x037A, glyph_ypogegrammeni }, + { 0x0345, glyph_ypogegrammenigreekcmb }, + { 0x01A6, glyph_yr }, + { 0x1E99, glyph_yring }, + { 0x02B8, glyph_ysuperior }, + { 0x1EF9, glyph_ytilde }, + { 0x028E, glyph_yturned }, + { 0x3086, glyph_yuhiragana }, + { 0x318C, glyph_yuikorean }, + { 0x30E6, glyph_yukatakana }, + { 0xFF95, glyph_yukatakanahalfwidth }, + { 0x3160, glyph_yukorean }, + { 0x046B, glyph_yusbigcyrillic }, + { 0x046D, glyph_yusbigiotifiedcyrillic }, + { 0x0467, glyph_yuslittlecyrillic }, + { 0x0469, glyph_yuslittleiotifiedcyrillic }, + { 0x3085, glyph_yusmallhiragana }, + { 0x30E5, glyph_yusmallkatakana }, + { 0xFF6D, glyph_yusmallkatakanahalfwidth }, + { 0x318B, glyph_yuyekorean }, + { 0x318A, glyph_yuyeokorean }, + { 0x09DF, glyph_yyabengali }, + { 0x095F, glyph_yyadeva }, + { 0x0566, glyph_zaarmenian }, + { 0x095B, glyph_zadeva }, + { 0x0A5B, glyph_zagurmukhi }, + { 0x0638, glyph_zaharabic }, + { 0xFEC6, glyph_zahfinalarabic }, + { 0xFEC7, glyph_zahinitialarabic }, + { 0x3056, glyph_zahiragana }, + { 0xFEC8, glyph_zahmedialarabic }, + { 0x0632, glyph_zainarabic }, + { 0xFEB0, glyph_zainfinalarabic }, + { 0x30B6, glyph_zakatakana }, + { 0x0595, glyph_zaqefgadolhebrew }, + { 0x0594, glyph_zaqefqatanhebrew }, + { 0x0598, glyph_zarqahebrew }, + { 0x05D6, glyph_zayin }, + { 0xFB36, glyph_zayindagesh }, + { 0xFB36, glyph_zayindageshhebrew }, + { 0x05D6, glyph_zayinhebrew }, + { 0x3117, glyph_zbopomofo }, + { 0x24E9, glyph_zcircle }, + { 0x1E91, glyph_zcircumflex }, + { 0x0291, glyph_zcurl }, + { 0x017C, glyph_zdot }, + { 0x1E93, glyph_zdotbelow }, + { 0x0437, glyph_zecyrillic }, + { 0x0499, glyph_zedescendercyrillic }, + { 0x04DF, glyph_zedieresiscyrillic }, + { 0x305C, glyph_zehiragana }, + { 0x30BC, glyph_zekatakana }, + { 0x0660, glyph_zeroarabic }, + { 0x09E6, glyph_zerobengali }, + { 0x0966, glyph_zerodeva }, + { 0x0AE6, glyph_zerogujarati }, + { 0x0A66, glyph_zerogurmukhi }, + { 0x0660, glyph_zerohackarabic }, + { 0xFF10, glyph_zeromonospace }, + { 0x06F0, glyph_zeropersian }, + { 0x0E50, glyph_zerothai }, + { 0xFEFF, glyph_zerowidthjoiner }, + { 0x200C, glyph_zerowidthnonjoiner }, + { 0x200B, glyph_zerowidthspace }, + { 0x3113, glyph_zhbopomofo }, + { 0x056A, glyph_zhearmenian }, + { 0x04C2, glyph_zhebrevecyrillic }, + { 0x0436, glyph_zhecyrillic }, + { 0x0497, glyph_zhedescendercyrillic }, + { 0x04DD, glyph_zhedieresiscyrillic }, + { 0x3058, glyph_zihiragana }, + { 0x30B8, glyph_zikatakana }, + { 0x05AE, glyph_zinorhebrew }, + { 0x1E95, glyph_zlinebelow }, + { 0xFF5A, glyph_zmonospace }, + { 0x305E, glyph_zohiragana }, + { 0x30BE, glyph_zokatakana }, + { 0x24B5, glyph_zparen }, + { 0x0290, glyph_zretroflexhook }, + { 0x01B6, glyph_zstroke }, + { 0x305A, glyph_zuhiragana }, + { 0x30BA, glyph_zukatakana }, +#else +#endif +}; /* tab_diffagl2uni */ + +/* + * Difference table of AGL version 2.0 - 1.2' - sorted by Unicode values + * + * Without Unicode values which map to multiple glyph names or which is + * contained in a Unicode sequence mapping to a single glyph name. + * This means, that all n:m entries are ignored! + * + * The multiple named Unicode values are listed in an extra table below. + * + */ +static const pdc_glyph_tab tab_uni2diffagl[] = +{ + { 0x0001, glyph_controlSTX }, + { 0x0002, glyph_controlSOT }, + { 0x0003, glyph_controlETX }, + { 0x0004, glyph_controlEOT }, + { 0x0005, glyph_controlENQ }, + { 0x0006, glyph_controlACK }, + { 0x0007, glyph_controlBEL }, + { 0x0008, glyph_controlBS }, + { 0x0009, glyph_controlHT }, + { 0x000A, glyph_controlLF }, + { 0x000B, glyph_controlVT }, + { 0x000C, glyph_controlFF }, + { 0x000D, glyph_controlCR }, + { 0x000E, glyph_controlSO }, + { 0x000F, glyph_controlSI }, + { 0x0010, glyph_controlDLE }, + { 0x0011, glyph_controlDC1 }, + { 0x0012, glyph_controlDC2 }, + { 0x0013, glyph_controlDC3 }, + { 0x0014, glyph_controlDC4 }, + { 0x0015, glyph_controlNAK }, + { 0x0016, glyph_controlSYN }, + { 0x0017, glyph_controlETB }, + { 0x0018, glyph_controlCAN }, + { 0x0019, glyph_controlEM }, + { 0x001A, glyph_controlSUB }, + { 0x001B, glyph_controlESC }, + { 0x001C, glyph_controlFS }, + { 0x001D, glyph_controlGS }, + { 0x001E, glyph_controlRS }, + { 0x001F, glyph_controlUS }, + { 0x0020, glyph_spacehackarabic }, + { 0x007C, glyph_verticalbar }, + { 0x007F, glyph_controlDEL }, + { 0x00A0, glyph_nonbreakingspace }, + { 0x00AD, glyph_softhyphen }, + { 0x00AF, glyph_overscore }, + { 0x00B5, glyph_mu1 }, + { 0x00B7, glyph_middot }, + { 0x010A, glyph_Cdot }, + { 0x010B, glyph_cdot }, + { 0x0110, glyph_Dslash }, + { 0x0111, glyph_dmacron }, + { 0x0116, glyph_Edot }, + { 0x0117, glyph_edot }, + { 0x0120, glyph_Gdot }, + { 0x0121, glyph_gdot }, + { 0x0122, glyph_Gcedilla }, + { 0x0123, glyph_gcedilla }, + { 0x0130, glyph_Idot }, + { 0x0136, glyph_Kcedilla }, + { 0x0137, glyph_kcedilla }, + { 0x013B, glyph_Lcedilla }, + { 0x013C, glyph_lcedilla }, + { 0x013F, glyph_Ldotaccent }, + { 0x0140, glyph_ldotaccent }, + { 0x0145, glyph_Ncedilla }, + { 0x0146, glyph_ncedilla }, + { 0x0149, glyph_quoterightn }, + { 0x0150, glyph_Odblacute }, + { 0x0151, glyph_odblacute }, + { 0x0156, glyph_Rcedilla }, + { 0x0157, glyph_rcedilla }, + { 0x0162, glyph_Tcedilla }, + { 0x0163, glyph_tcedilla }, + { 0x0170, glyph_Udblacute }, + { 0x0171, glyph_udblacute }, + { 0x017B, glyph_Zdot }, + { 0x017C, glyph_zdot }, + { 0x017F, glyph_slong }, + { 0x0180, glyph_bstroke }, + { 0x0181, glyph_Bhook }, + { 0x0182, glyph_Btopbar }, + { 0x0183, glyph_btopbar }, + { 0x0184, glyph_Tonesix }, + { 0x0185, glyph_tonesix }, + { 0x0186, glyph_Oopen }, + { 0x0187, glyph_Chook }, + { 0x0188, glyph_chook }, + { 0x0189, glyph_Dafrican }, + { 0x018A, glyph_Dhook }, + { 0x018B, glyph_Dtopbar }, + { 0x018C, glyph_dtopbar }, + { 0x018D, glyph_deltaturned }, + { 0x018E, glyph_Ereversed }, + { 0x018F, glyph_Schwa }, + { 0x0190, glyph_Eopen }, + { 0x0191, glyph_Fhook }, + { 0x0193, glyph_Ghook }, + { 0x0194, glyph_Gammaafrican }, + { 0x0195, glyph_hv }, + { 0x0196, glyph_Iotaafrican }, + { 0x0197, glyph_Istroke }, + { 0x0198, glyph_Khook }, + { 0x0199, glyph_khook }, + { 0x019A, glyph_lbar }, + { 0x019B, glyph_lambdastroke }, + { 0x019C, glyph_Mturned }, + { 0x019D, glyph_Nhookleft }, + { 0x019E, glyph_nlegrightlong }, + { 0x019F, glyph_Ocenteredtilde }, + { 0x01A2, glyph_Oi }, + { 0x01A3, glyph_oi }, + { 0x01A4, glyph_Phook }, + { 0x01A5, glyph_phook }, + { 0x01A6, glyph_yr }, + { 0x01A7, glyph_Tonetwo }, + { 0x01A8, glyph_tonetwo }, + { 0x01A9, glyph_Esh }, + { 0x01AA, glyph_eshreversedloop }, + { 0x01AB, glyph_tpalatalhook }, + { 0x01AC, glyph_Thook }, + { 0x01AD, glyph_thook }, + { 0x01AE, glyph_Tretroflexhook }, + { 0x01B1, glyph_Upsilonafrican }, + { 0x01B2, glyph_Vhook }, + { 0x01B3, glyph_Yhook }, + { 0x01B4, glyph_yhook }, + { 0x01B5, glyph_Zstroke }, + { 0x01B6, glyph_zstroke }, + { 0x01B7, glyph_Ezh }, + { 0x01B8, glyph_Ezhreversed }, + { 0x01B9, glyph_ezhreversed }, + { 0x01BA, glyph_ezhtail }, + { 0x01BB, glyph_twostroke }, + { 0x01BC, glyph_Tonefive }, + { 0x01BD, glyph_tonefive }, + { 0x01BE, glyph_glottalinvertedstroke }, + { 0x01BF, glyph_wynn }, + { 0x01C0, glyph_clickdental }, + { 0x01C1, glyph_clicklateral }, + { 0x01C2, glyph_clickalveolar }, + { 0x01C3, glyph_clickretroflex }, + { 0x01C4, glyph_DZcaron }, + { 0x01C5, glyph_Dzcaron }, + { 0x01C6, glyph_dzcaron }, + { 0x01C7, glyph_LJ }, + { 0x01C8, glyph_Lj }, + { 0x01C9, glyph_lj }, + { 0x01CA, glyph_NJ }, + { 0x01CB, glyph_Nj }, + { 0x01CC, glyph_nj }, + { 0x01CD, glyph_Acaron }, + { 0x01CE, glyph_acaron }, + { 0x01CF, glyph_Icaron }, + { 0x01D0, glyph_icaron }, + { 0x01D1, glyph_Ocaron }, + { 0x01D2, glyph_ocaron }, + { 0x01D3, glyph_Ucaron }, + { 0x01D4, glyph_ucaron }, + { 0x01D5, glyph_Udieresismacron }, + { 0x01D6, glyph_udieresismacron }, + { 0x01D7, glyph_Udieresisacute }, + { 0x01D8, glyph_udieresisacute }, + { 0x01D9, glyph_Udieresiscaron }, + { 0x01DA, glyph_udieresiscaron }, + { 0x01DB, glyph_Udieresisgrave }, + { 0x01DC, glyph_udieresisgrave }, + { 0x01DD, glyph_eturned }, + { 0x01DE, glyph_Adieresismacron }, + { 0x01DF, glyph_adieresismacron }, + { 0x01E0, glyph_Adotmacron }, + { 0x01E1, glyph_adotmacron }, + { 0x01E2, glyph_AEmacron }, + { 0x01E3, glyph_aemacron }, + { 0x01E4, glyph_Gstroke }, + { 0x01E5, glyph_gstroke }, + { 0x01E8, glyph_Kcaron }, + { 0x01E9, glyph_kcaron }, + { 0x01EA, glyph_Oogonek }, + { 0x01EB, glyph_oogonek }, + { 0x01EC, glyph_Oogonekmacron }, + { 0x01ED, glyph_oogonekmacron }, + { 0x01EE, glyph_Ezhcaron }, + { 0x01EF, glyph_ezhcaron }, + { 0x01F0, glyph_jcaron }, + { 0x01F1, glyph_DZ }, + { 0x01F2, glyph_Dz }, + { 0x01F3, glyph_dz }, + { 0x01F4, glyph_Gacute }, + { 0x01F5, glyph_gacute }, + { 0x01FE, glyph_Ostrokeacute }, + { 0x01FF, glyph_ostrokeacute }, + { 0x0200, glyph_Adblgrave }, + { 0x0201, glyph_adblgrave }, + { 0x0202, glyph_Ainvertedbreve }, + { 0x0203, glyph_ainvertedbreve }, + { 0x0204, glyph_Edblgrave }, + { 0x0205, glyph_edblgrave }, + { 0x0206, glyph_Einvertedbreve }, + { 0x0207, glyph_einvertedbreve }, + { 0x0208, glyph_Idblgrave }, + { 0x0209, glyph_idblgrave }, + { 0x020A, glyph_Iinvertedbreve }, + { 0x020B, glyph_iinvertedbreve }, + { 0x020C, glyph_Odblgrave }, + { 0x020D, glyph_odblgrave }, + { 0x020E, glyph_Oinvertedbreve }, + { 0x020F, glyph_oinvertedbreve }, + { 0x0210, glyph_Rdblgrave }, + { 0x0211, glyph_rdblgrave }, + { 0x0212, glyph_Rinvertedbreve }, + { 0x0213, glyph_rinvertedbreve }, + { 0x0214, glyph_Udblgrave }, + { 0x0215, glyph_udblgrave }, + { 0x0216, glyph_Uinvertedbreve }, + { 0x0217, glyph_uinvertedbreve }, + { 0x0250, glyph_aturned }, + { 0x0251, glyph_ascript }, + { 0x0252, glyph_ascriptturned }, + { 0x0253, glyph_bhook }, + { 0x0254, glyph_oopen }, + { 0x0255, glyph_ccurl }, + { 0x0256, glyph_dtail }, + { 0x0257, glyph_dhook }, + { 0x0258, glyph_ereversed }, + { 0x0259, glyph_schwa }, + { 0x025A, glyph_schwahook }, + { 0x025B, glyph_eopen }, + { 0x025C, glyph_eopenreversed }, + { 0x025D, glyph_eopenreversedhook }, + { 0x025E, glyph_eopenreversedclosed }, + { 0x025F, glyph_jdotlessstroke }, + { 0x0260, glyph_ghook }, + { 0x0261, glyph_gscript }, + { 0x0263, glyph_gammalatinsmall }, + { 0x0264, glyph_ramshorn }, + { 0x0265, glyph_hturned }, + { 0x0266, glyph_hhook }, + { 0x0267, glyph_henghook }, + { 0x0268, glyph_istroke }, + { 0x0269, glyph_iotalatin }, + { 0x026B, glyph_lmiddletilde }, + { 0x026C, glyph_lbelt }, + { 0x026D, glyph_lhookretroflex }, + { 0x026E, glyph_lezh }, + { 0x026F, glyph_mturned }, + { 0x0270, glyph_mlonglegturned }, + { 0x0271, glyph_mhook }, + { 0x0272, glyph_nhookleft }, + { 0x0273, glyph_nhookretroflex }, + { 0x0275, glyph_obarred }, + { 0x0277, glyph_omegalatinclosed }, + { 0x0278, glyph_philatin }, + { 0x0279, glyph_rturned }, + { 0x027A, glyph_rlonglegturned }, + { 0x027B, glyph_rhookturned }, + { 0x027C, glyph_rlongleg }, + { 0x027D, glyph_rhook }, + { 0x027E, glyph_rfishhook }, + { 0x027F, glyph_rfishhookreversed }, + { 0x0281, glyph_Rsmallinverted }, + { 0x0282, glyph_shook }, + { 0x0283, glyph_esh }, + { 0x0284, glyph_dotlessjstrokehook }, + { 0x0285, glyph_eshsquatreversed }, + { 0x0286, glyph_eshcurl }, + { 0x0287, glyph_tturned }, + { 0x0288, glyph_tretroflexhook }, + { 0x0289, glyph_ubar }, + { 0x028A, glyph_upsilonlatin }, + { 0x028B, glyph_vhook }, + { 0x028C, glyph_vturned }, + { 0x028D, glyph_wturned }, + { 0x028E, glyph_yturned }, + { 0x0290, glyph_zretroflexhook }, + { 0x0291, glyph_zcurl }, + { 0x0292, glyph_ezh }, + { 0x0293, glyph_ezhcurl }, + { 0x0294, glyph_glottalstop }, + { 0x0295, glyph_glottalstopreversed }, + { 0x0296, glyph_glottalstopinverted }, + { 0x0297, glyph_cstretched }, + { 0x0298, glyph_bilabialclick }, + { 0x029A, glyph_eopenclosed }, + { 0x029B, glyph_Gsmallhook }, + { 0x029D, glyph_jcrossedtail }, + { 0x029E, glyph_kturned }, + { 0x02A0, glyph_qhook }, + { 0x02A1, glyph_glottalstopstroke }, + { 0x02A2, glyph_glottalstopstrokereversed }, + { 0x02A3, glyph_dzaltone }, + { 0x02A4, glyph_dezh }, + { 0x02A5, glyph_dzcurl }, + { 0x02A6, glyph_ts }, + { 0x02A7, glyph_tesh }, + { 0x02A8, glyph_tccurl }, + { 0x02B0, glyph_hsuperior }, + { 0x02B1, glyph_hhooksuperior }, + { 0x02B2, glyph_jsuperior }, + { 0x02B4, glyph_rturnedsuperior }, + { 0x02B5, glyph_rhookturnedsuperior }, + { 0x02B6, glyph_Rsmallinvertedsuperior }, + { 0x02B7, glyph_wsuperior }, + { 0x02B8, glyph_ysuperior }, + { 0x02B9, glyph_primemod }, + { 0x02BA, glyph_dblprimemod }, + { 0x02BB, glyph_commaturnedmod }, + { 0x02BC, glyph_apostrophemod }, + { 0x02BD, glyph_commareversedmod }, + { 0x02BE, glyph_ringhalfright }, + { 0x02BF, glyph_ringhalfleft }, + { 0x02C0, glyph_glottalstopmod }, + { 0x02C1, glyph_glottalstopreversedmod }, + { 0x02C2, glyph_arrowheadleftmod }, + { 0x02C3, glyph_arrowheadrightmod }, + { 0x02C4, glyph_arrowheadupmod }, + { 0x02C5, glyph_arrowheaddownmod }, + { 0x02C8, glyph_verticallinemod }, + { 0x02CA, glyph_secondtonechinese }, + { 0x02CB, glyph_fourthtonechinese }, + { 0x02CC, glyph_verticallinelowmod }, + { 0x02CD, glyph_macronlowmod }, + { 0x02CE, glyph_gravelowmod }, + { 0x02CF, glyph_acutelowmod }, + { 0x02D0, glyph_colontriangularmod }, + { 0x02D1, glyph_colontriangularhalfmod }, + { 0x02D2, glyph_ringhalfrightcentered }, + { 0x02D3, glyph_ringhalfleftcentered }, + { 0x02D4, glyph_uptackmod }, + { 0x02D5, glyph_downtackmod }, + { 0x02D6, glyph_plusmod }, + { 0x02D7, glyph_minusmod }, + { 0x02DC, glyph_ilde }, + { 0x02DE, glyph_rhotichookmod }, + { 0x02E0, glyph_gammasuperior }, + { 0x02E3, glyph_xsuperior }, + { 0x02E4, glyph_glottalstopreversedsuperior }, + { 0x02E5, glyph_tonebarextrahighmod }, + { 0x02E6, glyph_tonebarhighmod }, + { 0x02E7, glyph_tonebarmidmod }, + { 0x02E8, glyph_tonebarlowmod }, + { 0x02E9, glyph_tonebarextralowmod }, + { 0x0300, glyph_gravecmb }, + { 0x0301, glyph_acutecmb }, + { 0x0302, glyph_circumflexcmb }, + { 0x0303, glyph_tildecmb }, + { 0x0304, glyph_macroncmb }, + { 0x0305, glyph_overlinecmb }, + { 0x0306, glyph_brevecmb }, + { 0x0307, glyph_dotaccentcmb }, + { 0x0308, glyph_dieresiscmb }, + { 0x0309, glyph_hookcmb }, + { 0x030A, glyph_ringcmb }, + { 0x030B, glyph_hungarumlautcmb }, + { 0x030C, glyph_caroncmb }, + { 0x030D, glyph_verticallineabovecmb }, + { 0x030E, glyph_dblverticallineabovecmb }, + { 0x030F, glyph_dblgravecmb }, + { 0x0310, glyph_candrabinducmb }, + { 0x0311, glyph_breveinvertedcmb }, + { 0x0312, glyph_commaturnedabovecmb }, + { 0x0313, glyph_commaabovecmb }, + { 0x0314, glyph_commareversedabovecmb }, + { 0x0315, glyph_commaaboverightcmb }, + { 0x0316, glyph_gravebelowcmb }, + { 0x0317, glyph_acutebelowcmb }, + { 0x0318, glyph_lefttackbelowcmb }, + { 0x0319, glyph_righttackbelowcmb }, + { 0x031A, glyph_leftangleabovecmb }, + { 0x031B, glyph_horncmb }, + { 0x031C, glyph_ringhalfleftbelowcmb }, + { 0x031D, glyph_uptackbelowcmb }, + { 0x031E, glyph_downtackbelowcmb }, + { 0x031F, glyph_plusbelowcmb }, + { 0x0320, glyph_minusbelowcmb }, + { 0x0321, glyph_hookpalatalizedbelowcmb }, + { 0x0322, glyph_hookretroflexbelowcmb }, + { 0x0323, glyph_dotbelowcmb }, + { 0x0324, glyph_dieresisbelowcmb }, + { 0x0325, glyph_ringbelowcmb }, + { 0x0327, glyph_cedillacmb }, + { 0x0328, glyph_ogonekcmb }, + { 0x0329, glyph_verticallinebelowcmb }, + { 0x032A, glyph_bridgebelowcmb }, + { 0x032B, glyph_dblarchinvertedbelowcmb }, + { 0x032C, glyph_caronbelowcmb }, + { 0x032D, glyph_circumflexbelowcmb }, + { 0x032E, glyph_brevebelowcmb }, + { 0x032F, glyph_breveinvertedbelowcmb }, + { 0x0330, glyph_tildebelowcmb }, + { 0x0331, glyph_macronbelowcmb }, + { 0x0332, glyph_lowlinecmb }, + { 0x0333, glyph_dbllowlinecmb }, + { 0x0334, glyph_tildeoverlaycmb }, + { 0x0335, glyph_strokeshortoverlaycmb }, + { 0x0336, glyph_strokelongoverlaycmb }, + { 0x0337, glyph_solidusshortoverlaycmb }, + { 0x0338, glyph_soliduslongoverlaycmb }, + { 0x0339, glyph_ringhalfrightbelowcmb }, + { 0x033A, glyph_bridgeinvertedbelowcmb }, + { 0x033B, glyph_squarebelowcmb }, + { 0x033C, glyph_seagullbelowcmb }, + { 0x033D, glyph_xabovecmb }, + { 0x033E, glyph_tildeverticalcmb }, + { 0x033F, glyph_dbloverlinecmb }, + { 0x0340, glyph_gravetonecmb }, + { 0x0341, glyph_acutetonecmb }, + { 0x0342, glyph_perispomenigreekcmb }, + { 0x0343, glyph_koroniscmb }, + { 0x0344, glyph_dialytikatonoscmb }, + { 0x0345, glyph_ypogegrammenigreekcmb }, + { 0x0360, glyph_tildedoublecmb }, + { 0x0361, glyph_breveinverteddoublecmb }, + { 0x0374, glyph_numeralsigngreek }, + { 0x0375, glyph_numeralsignlowergreek }, + { 0x037A, glyph_ypogegrammeni }, + { 0x037E, glyph_questiongreek }, + { 0x0385, glyph_dialytikatonos }, + { 0x03C2, glyph_sigmafinal }, + { 0x03D0, glyph_betasymbolgreek }, + { 0x03D1, glyph_thetasymbolgreek }, + { 0x03D2, glyph_Upsilonhooksymbol }, + { 0x03D3, glyph_Upsilonacutehooksymbolgreek }, + { 0x03D4, glyph_Upsilondieresishooksymbolgreek }, + { 0x03D5, glyph_phisymbolgreek }, + { 0x03D6, glyph_pisymbolgreek }, + { 0x03DA, glyph_Stigmagreek }, + { 0x03DC, glyph_Digammagreek }, + { 0x03DE, glyph_Koppagreek }, + { 0x03E0, glyph_Sampigreek }, + { 0x03E2, glyph_Sheicoptic }, + { 0x03E3, glyph_sheicoptic }, + { 0x03E4, glyph_Feicoptic }, + { 0x03E5, glyph_feicoptic }, + { 0x03E6, glyph_Kheicoptic }, + { 0x03E7, glyph_kheicoptic }, + { 0x03E8, glyph_Horicoptic }, + { 0x03E9, glyph_horicoptic }, + { 0x03EA, glyph_Gangiacoptic }, + { 0x03EB, glyph_gangiacoptic }, + { 0x03EC, glyph_Shimacoptic }, + { 0x03ED, glyph_shimacoptic }, + { 0x03EE, glyph_Deicoptic }, + { 0x03EF, glyph_deicoptic }, + { 0x03F0, glyph_kappasymbolgreek }, + { 0x03F1, glyph_rhosymbolgreek }, + { 0x03F2, glyph_sigmalunatesymbolgreek }, + { 0x03F3, glyph_yotgreek }, + { 0x0401, glyph_Iocyrillic }, + { 0x0402, glyph_Djecyrillic }, + { 0x0403, glyph_Gjecyrillic }, + { 0x0404, glyph_Ecyrillic }, + { 0x0405, glyph_Dzecyrillic }, + { 0x0406, glyph_Icyrillic }, + { 0x0407, glyph_Yicyrillic }, + { 0x0408, glyph_Jecyrillic }, + { 0x0409, glyph_Ljecyrillic }, + { 0x040A, glyph_Njecyrillic }, + { 0x040B, glyph_Tshecyrillic }, + { 0x040C, glyph_Kjecyrillic }, + { 0x040E, glyph_Ushortcyrillic }, + { 0x040F, glyph_Dzhecyrillic }, + { 0x0410, glyph_Acyrillic }, + { 0x0411, glyph_Becyrillic }, + { 0x0412, glyph_Vecyrillic }, + { 0x0413, glyph_Gecyrillic }, + { 0x0414, glyph_Decyrillic }, + { 0x0415, glyph_Iecyrillic }, + { 0x0416, glyph_Zhecyrillic }, + { 0x0417, glyph_Zecyrillic }, + { 0x0418, glyph_Iicyrillic }, + { 0x0419, glyph_Iishortcyrillic }, + { 0x041A, glyph_Kacyrillic }, + { 0x041B, glyph_Elcyrillic }, + { 0x041C, glyph_Emcyrillic }, + { 0x041D, glyph_Encyrillic }, + { 0x041E, glyph_Ocyrillic }, + { 0x041F, glyph_Pecyrillic }, + { 0x0420, glyph_Ercyrillic }, + { 0x0421, glyph_Escyrillic }, + { 0x0422, glyph_Tecyrillic }, + { 0x0423, glyph_Ucyrillic }, + { 0x0424, glyph_Efcyrillic }, + { 0x0425, glyph_Khacyrillic }, + { 0x0426, glyph_Tsecyrillic }, + { 0x0427, glyph_Checyrillic }, + { 0x0428, glyph_Shacyrillic }, + { 0x0429, glyph_Shchacyrillic }, + { 0x042A, glyph_Hardsigncyrillic }, + { 0x042B, glyph_Yericyrillic }, + { 0x042C, glyph_Softsigncyrillic }, + { 0x042D, glyph_Ereversedcyrillic }, + { 0x042E, glyph_IUcyrillic }, + { 0x042F, glyph_IAcyrillic }, + { 0x0430, glyph_acyrillic }, + { 0x0431, glyph_becyrillic }, + { 0x0432, glyph_vecyrillic }, + { 0x0433, glyph_gecyrillic }, + { 0x0434, glyph_decyrillic }, + { 0x0435, glyph_iecyrillic }, + { 0x0436, glyph_zhecyrillic }, + { 0x0437, glyph_zecyrillic }, + { 0x0438, glyph_iicyrillic }, + { 0x0439, glyph_iishortcyrillic }, + { 0x043A, glyph_kacyrillic }, + { 0x043B, glyph_elcyrillic }, + { 0x043C, glyph_emcyrillic }, + { 0x043D, glyph_encyrillic }, + { 0x043E, glyph_ocyrillic }, + { 0x043F, glyph_pecyrillic }, + { 0x0440, glyph_ercyrillic }, + { 0x0441, glyph_escyrillic }, + { 0x0442, glyph_tecyrillic }, + { 0x0443, glyph_ucyrillic }, + { 0x0444, glyph_efcyrillic }, + { 0x0445, glyph_khacyrillic }, + { 0x0446, glyph_tsecyrillic }, + { 0x0447, glyph_checyrillic }, + { 0x0448, glyph_shacyrillic }, + { 0x0449, glyph_shchacyrillic }, + { 0x044A, glyph_hardsigncyrillic }, + { 0x044B, glyph_yericyrillic }, + { 0x044C, glyph_softsigncyrillic }, + { 0x044D, glyph_ereversedcyrillic }, + { 0x044E, glyph_iucyrillic }, + { 0x044F, glyph_iacyrillic }, + { 0x0451, glyph_iocyrillic }, + { 0x0452, glyph_djecyrillic }, + { 0x0453, glyph_gjecyrillic }, + { 0x0454, glyph_ecyrillic }, + { 0x0455, glyph_dzecyrillic }, + { 0x0456, glyph_icyrillic }, + { 0x0457, glyph_yicyrillic }, + { 0x0458, glyph_jecyrillic }, + { 0x0459, glyph_ljecyrillic }, + { 0x045A, glyph_njecyrillic }, + { 0x045B, glyph_tshecyrillic }, + { 0x045C, glyph_kjecyrillic }, + { 0x045E, glyph_ushortcyrillic }, + { 0x045F, glyph_dzhecyrillic }, + { 0x0460, glyph_Omegacyrillic }, + { 0x0461, glyph_omegacyrillic }, + { 0x0462, glyph_Yatcyrillic }, + { 0x0463, glyph_yatcyrillic }, + { 0x0464, glyph_Eiotifiedcyrillic }, + { 0x0465, glyph_eiotifiedcyrillic }, + { 0x0466, glyph_Yuslittlecyrillic }, + { 0x0467, glyph_yuslittlecyrillic }, + { 0x0468, glyph_Yuslittleiotifiedcyrillic }, + { 0x0469, glyph_yuslittleiotifiedcyrillic }, + { 0x046A, glyph_Yusbigcyrillic }, + { 0x046B, glyph_yusbigcyrillic }, + { 0x046C, glyph_Yusbigiotifiedcyrillic }, + { 0x046D, glyph_yusbigiotifiedcyrillic }, + { 0x046E, glyph_Ksicyrillic }, + { 0x046F, glyph_ksicyrillic }, + { 0x0470, glyph_Psicyrillic }, + { 0x0471, glyph_psicyrillic }, + { 0x0472, glyph_Fitacyrillic }, + { 0x0473, glyph_fitacyrillic }, + { 0x0474, glyph_Izhitsacyrillic }, + { 0x0475, glyph_izhitsacyrillic }, + { 0x0476, glyph_Izhitsadblgravecyrillic }, + { 0x0477, glyph_izhitsadblgravecyrillic }, + { 0x0478, glyph_Ukcyrillic }, + { 0x0479, glyph_ukcyrillic }, + { 0x047A, glyph_Omegaroundcyrillic }, + { 0x047B, glyph_omegaroundcyrillic }, + { 0x047C, glyph_Omegatitlocyrillic }, + { 0x047D, glyph_omegatitlocyrillic }, + { 0x047E, glyph_Otcyrillic }, + { 0x047F, glyph_otcyrillic }, + { 0x0480, glyph_Koppacyrillic }, + { 0x0481, glyph_koppacyrillic }, + { 0x0482, glyph_thousandcyrillic }, + { 0x0483, glyph_titlocyrilliccmb }, + { 0x0484, glyph_palatalizationcyrilliccmb }, + { 0x0485, glyph_dasiapneumatacyrilliccmb }, + { 0x0486, glyph_psilipneumatacyrilliccmb }, + { 0x0490, glyph_Gheupturncyrillic }, + { 0x0491, glyph_gheupturncyrillic }, + { 0x0492, glyph_Ghestrokecyrillic }, + { 0x0493, glyph_ghestrokecyrillic }, + { 0x0494, glyph_Ghemiddlehookcyrillic }, + { 0x0495, glyph_ghemiddlehookcyrillic }, + { 0x0496, glyph_Zhedescendercyrillic }, + { 0x0497, glyph_zhedescendercyrillic }, + { 0x0498, glyph_Zedescendercyrillic }, + { 0x0499, glyph_zedescendercyrillic }, + { 0x049A, glyph_Kadescendercyrillic }, + { 0x049B, glyph_kadescendercyrillic }, + { 0x049C, glyph_Kaverticalstrokecyrillic }, + { 0x049D, glyph_kaverticalstrokecyrillic }, + { 0x049E, glyph_Kastrokecyrillic }, + { 0x049F, glyph_kastrokecyrillic }, + { 0x04A0, glyph_Kabashkircyrillic }, + { 0x04A1, glyph_kabashkircyrillic }, + { 0x04A2, glyph_Endescendercyrillic }, + { 0x04A3, glyph_endescendercyrillic }, + { 0x04A4, glyph_Enghecyrillic }, + { 0x04A5, glyph_enghecyrillic }, + { 0x04A6, glyph_Pemiddlehookcyrillic }, + { 0x04A7, glyph_pemiddlehookcyrillic }, + { 0x04A8, glyph_Haabkhasiancyrillic }, + { 0x04A9, glyph_haabkhasiancyrillic }, + { 0x04AA, glyph_Esdescendercyrillic }, + { 0x04AB, glyph_esdescendercyrillic }, + { 0x04AC, glyph_Tedescendercyrillic }, + { 0x04AD, glyph_tedescendercyrillic }, + { 0x04AE, glyph_Ustraightcyrillic }, + { 0x04AF, glyph_ustraightcyrillic }, + { 0x04B0, glyph_Ustraightstrokecyrillic }, + { 0x04B1, glyph_ustraightstrokecyrillic }, + { 0x04B2, glyph_Hadescendercyrillic }, + { 0x04B3, glyph_hadescendercyrillic }, + { 0x04B4, glyph_Tetsecyrillic }, + { 0x04B5, glyph_tetsecyrillic }, + { 0x04B6, glyph_Chedescendercyrillic }, + { 0x04B7, glyph_chedescendercyrillic }, + { 0x04B8, glyph_Cheverticalstrokecyrillic }, + { 0x04B9, glyph_cheverticalstrokecyrillic }, + { 0x04BA, glyph_Shhacyrillic }, + { 0x04BB, glyph_shhacyrillic }, + { 0x04BC, glyph_Cheabkhasiancyrillic }, + { 0x04BD, glyph_cheabkhasiancyrillic }, + { 0x04BE, glyph_Chedescenderabkhasiancyrillic }, + { 0x04BF, glyph_chedescenderabkhasiancyrillic }, + { 0x04C0, glyph_palochkacyrillic }, + { 0x04C1, glyph_Zhebrevecyrillic }, + { 0x04C2, glyph_zhebrevecyrillic }, + { 0x04C3, glyph_Kahookcyrillic }, + { 0x04C4, glyph_kahookcyrillic }, + { 0x04C7, glyph_Enhookcyrillic }, + { 0x04C8, glyph_enhookcyrillic }, + { 0x04CB, glyph_Chekhakassiancyrillic }, + { 0x04CC, glyph_chekhakassiancyrillic }, + { 0x04D0, glyph_Abrevecyrillic }, + { 0x04D1, glyph_abrevecyrillic }, + { 0x04D2, glyph_Adieresiscyrillic }, + { 0x04D3, glyph_adieresiscyrillic }, + { 0x04D4, glyph_Aiecyrillic }, + { 0x04D5, glyph_aiecyrillic }, + { 0x04D6, glyph_Iebrevecyrillic }, + { 0x04D7, glyph_iebrevecyrillic }, + { 0x04D8, glyph_Schwacyrillic }, + { 0x04D9, glyph_schwacyrillic }, + { 0x04DA, glyph_Schwadieresiscyrillic }, + { 0x04DB, glyph_schwadieresiscyrillic }, + { 0x04DC, glyph_Zhedieresiscyrillic }, + { 0x04DD, glyph_zhedieresiscyrillic }, + { 0x04DE, glyph_Zedieresiscyrillic }, + { 0x04DF, glyph_zedieresiscyrillic }, + { 0x04E0, glyph_Dzeabkhasiancyrillic }, + { 0x04E1, glyph_dzeabkhasiancyrillic }, + { 0x04E2, glyph_Imacroncyrillic }, + { 0x04E3, glyph_imacroncyrillic }, + { 0x04E4, glyph_Idieresiscyrillic }, + { 0x04E5, glyph_idieresiscyrillic }, + { 0x04E6, glyph_Odieresiscyrillic }, + { 0x04E7, glyph_odieresiscyrillic }, + { 0x04E8, glyph_Obarredcyrillic }, + { 0x04E9, glyph_obarredcyrillic }, + { 0x04EA, glyph_Obarreddieresiscyrillic }, + { 0x04EB, glyph_obarreddieresiscyrillic }, + { 0x04EE, glyph_Umacroncyrillic }, + { 0x04EF, glyph_umacroncyrillic }, + { 0x04F0, glyph_Udieresiscyrillic }, + { 0x04F1, glyph_udieresiscyrillic }, + { 0x04F2, glyph_Uhungarumlautcyrillic }, + { 0x04F3, glyph_uhungarumlautcyrillic }, + { 0x04F4, glyph_Chedieresiscyrillic }, + { 0x04F5, glyph_chedieresiscyrillic }, + { 0x04F8, glyph_Yerudieresiscyrillic }, + { 0x04F9, glyph_yerudieresiscyrillic }, + { 0x0531, glyph_Aybarmenian }, + { 0x0532, glyph_Benarmenian }, + { 0x0533, glyph_Gimarmenian }, + { 0x0534, glyph_Daarmenian }, + { 0x0535, glyph_Echarmenian }, + { 0x0536, glyph_Zaarmenian }, + { 0x0537, glyph_Eharmenian }, + { 0x0538, glyph_Etarmenian }, + { 0x0539, glyph_Toarmenian }, + { 0x053A, glyph_Zhearmenian }, + { 0x053B, glyph_Iniarmenian }, + { 0x053C, glyph_Liwnarmenian }, + { 0x053D, glyph_Xeharmenian }, + { 0x053E, glyph_Caarmenian }, + { 0x053F, glyph_Kenarmenian }, + { 0x0540, glyph_Hoarmenian }, + { 0x0541, glyph_Jaarmenian }, + { 0x0542, glyph_Ghadarmenian }, + { 0x0543, glyph_Cheharmenian }, + { 0x0544, glyph_Menarmenian }, + { 0x0545, glyph_Yiarmenian }, + { 0x0546, glyph_Nowarmenian }, + { 0x0547, glyph_Shaarmenian }, + { 0x0548, glyph_Voarmenian }, + { 0x0549, glyph_Chaarmenian }, + { 0x054A, glyph_Peharmenian }, + { 0x054B, glyph_Jheharmenian }, + { 0x054C, glyph_Raarmenian }, + { 0x054D, glyph_Seharmenian }, + { 0x054E, glyph_Vewarmenian }, + { 0x054F, glyph_Tiwnarmenian }, + { 0x0550, glyph_Reharmenian }, + { 0x0551, glyph_Coarmenian }, + { 0x0552, glyph_Yiwnarmenian }, + { 0x0553, glyph_Piwrarmenian }, + { 0x0554, glyph_Keharmenian }, + { 0x0555, glyph_Oharmenian }, + { 0x0556, glyph_Feharmenian }, + { 0x0559, glyph_ringhalfleftarmenian }, + { 0x055A, glyph_apostrophearmenian }, + { 0x055B, glyph_emphasismarkarmenian }, + { 0x055C, glyph_exclamarmenian }, + { 0x055D, glyph_commaarmenian }, + { 0x055E, glyph_questionarmenian }, + { 0x055F, glyph_abbreviationmarkarmenian }, + { 0x0561, glyph_aybarmenian }, + { 0x0562, glyph_benarmenian }, + { 0x0563, glyph_gimarmenian }, + { 0x0564, glyph_daarmenian }, + { 0x0565, glyph_echarmenian }, + { 0x0566, glyph_zaarmenian }, + { 0x0567, glyph_eharmenian }, + { 0x0568, glyph_etarmenian }, + { 0x0569, glyph_toarmenian }, + { 0x056A, glyph_zhearmenian }, + { 0x056B, glyph_iniarmenian }, + { 0x056C, glyph_liwnarmenian }, + { 0x056D, glyph_xeharmenian }, + { 0x056E, glyph_caarmenian }, + { 0x056F, glyph_kenarmenian }, + { 0x0570, glyph_hoarmenian }, + { 0x0571, glyph_jaarmenian }, + { 0x0572, glyph_ghadarmenian }, + { 0x0573, glyph_cheharmenian }, + { 0x0574, glyph_menarmenian }, + { 0x0575, glyph_yiarmenian }, + { 0x0576, glyph_nowarmenian }, + { 0x0577, glyph_shaarmenian }, + { 0x0578, glyph_voarmenian }, + { 0x0579, glyph_chaarmenian }, + { 0x057A, glyph_peharmenian }, + { 0x057B, glyph_jheharmenian }, + { 0x057C, glyph_raarmenian }, + { 0x057D, glyph_seharmenian }, + { 0x057E, glyph_vewarmenian }, + { 0x057F, glyph_tiwnarmenian }, + { 0x0580, glyph_reharmenian }, + { 0x0581, glyph_coarmenian }, + { 0x0582, glyph_yiwnarmenian }, + { 0x0583, glyph_piwrarmenian }, + { 0x0584, glyph_keharmenian }, + { 0x0585, glyph_oharmenian }, + { 0x0586, glyph_feharmenian }, + { 0x0587, glyph_echyiwnarmenian }, + { 0x0589, glyph_periodarmenian }, + { 0x0592, glyph_segoltahebrew }, + { 0x0593, glyph_shalshelethebrew }, + { 0x0594, glyph_zaqefqatanhebrew }, + { 0x0595, glyph_zaqefgadolhebrew }, + { 0x0598, glyph_zarqahebrew }, + { 0x0599, glyph_pashtahebrew }, + { 0x059A, glyph_yetivhebrew }, + { 0x059C, glyph_gereshaccenthebrew }, + { 0x059D, glyph_gereshmuqdamhebrew }, + { 0x059E, glyph_gershayimaccenthebrew }, + { 0x059F, glyph_qarneyparahebrew }, + { 0x05A0, glyph_telishagedolahebrew }, + { 0x05A1, glyph_pazerhebrew }, + { 0x05A8, glyph_qadmahebrew }, + { 0x05A9, glyph_telishaqetanahebrew }, + { 0x05AB, glyph_olehebrew }, + { 0x05AC, glyph_iluyhebrew }, + { 0x05AD, glyph_dehihebrew }, + { 0x05AE, glyph_zinorhebrew }, + { 0x05AF, glyph_masoracirclehebrew }, + { 0x05BE, glyph_maqafhebrew }, + { 0x05C0, glyph_paseqhebrew }, + { 0x05C1, glyph_shindothebrew }, + { 0x05C2, glyph_sindothebrew }, + { 0x05C3, glyph_sofpasuqhebrew }, + { 0x05C4, glyph_upperdothebrew }, + { 0x05F0, glyph_vavvavhebrew }, + { 0x05F1, glyph_vavyodhebrew }, + { 0x05F2, glyph_yodyodhebrew }, + { 0x05F3, glyph_gereshhebrew }, + { 0x05F4, glyph_gershayimhebrew }, + { 0x060C, glyph_commaarabic }, + { 0x061B, glyph_semicolonarabic }, + { 0x061F, glyph_questionarabic }, + { 0x0622, glyph_alefmaddaabovearabic }, + { 0x0623, glyph_alefhamzaabovearabic }, + { 0x0624, glyph_wawhamzaabovearabic }, + { 0x0625, glyph_alefhamzabelowarabic }, + { 0x0626, glyph_yehhamzaabovearabic }, + { 0x0627, glyph_alefarabic }, + { 0x0628, glyph_beharabic }, + { 0x0629, glyph_tehmarbutaarabic }, + { 0x062A, glyph_teharabic }, + { 0x062B, glyph_theharabic }, + { 0x062C, glyph_jeemarabic }, + { 0x062D, glyph_haharabic }, + { 0x062E, glyph_khaharabic }, + { 0x062F, glyph_dalarabic }, + { 0x0630, glyph_thalarabic }, + { 0x0631, glyph_reharabic }, + { 0x0632, glyph_zainarabic }, + { 0x0633, glyph_seenarabic }, + { 0x0634, glyph_sheenarabic }, + { 0x0635, glyph_sadarabic }, + { 0x0636, glyph_dadarabic }, + { 0x0637, glyph_taharabic }, + { 0x0638, glyph_zaharabic }, + { 0x0639, glyph_ainarabic }, + { 0x063A, glyph_ghainarabic }, + { 0x0641, glyph_feharabic }, + { 0x0642, glyph_qafarabic }, + { 0x0643, glyph_kafarabic }, + { 0x0644, glyph_lamarabic }, + { 0x0645, glyph_meemarabic }, + { 0x0646, glyph_noonarabic }, + { 0x0647, glyph_heharabic }, + { 0x0648, glyph_wawarabic }, + { 0x0649, glyph_alefmaksuraarabic }, + { 0x064A, glyph_yeharabic }, + { 0x064B, glyph_fathatanarabic }, + { 0x064D, glyph_kasratanarabic }, + { 0x0650, glyph_kasraarabic }, + { 0x0651, glyph_shaddaarabic }, + { 0x0652, glyph_sukunarabic }, + { 0x066A, glyph_percentarabic }, + { 0x0679, glyph_tteharabic }, + { 0x067E, glyph_peharabic }, + { 0x0686, glyph_tcheharabic }, + { 0x0688, glyph_ddalarabic }, + { 0x0691, glyph_rreharabic }, + { 0x0698, glyph_jeharabic }, + { 0x06A4, glyph_veharabic }, + { 0x06AF, glyph_gafarabic }, + { 0x06BA, glyph_noonghunnaarabic }, + { 0x06D1, glyph_yehthreedotsbelowarabic }, + { 0x06D2, glyph_yehbarreearabic }, + { 0x06F0, glyph_zeropersian }, + { 0x06F1, glyph_onepersian }, + { 0x06F2, glyph_twopersian }, + { 0x06F3, glyph_threepersian }, + { 0x06F4, glyph_fourpersian }, + { 0x06F5, glyph_fivepersian }, + { 0x06F6, glyph_sixpersian }, + { 0x06F7, glyph_sevenpersian }, + { 0x06F8, glyph_eightpersian }, + { 0x06F9, glyph_ninepersian }, + { 0x0901, glyph_candrabindudeva }, + { 0x0902, glyph_anusvaradeva }, + { 0x0903, glyph_visargadeva }, + { 0x0905, glyph_adeva }, + { 0x0906, glyph_aadeva }, + { 0x0907, glyph_ideva }, + { 0x0908, glyph_iideva }, + { 0x0909, glyph_udeva }, + { 0x090A, glyph_uudeva }, + { 0x090B, glyph_rvocalicdeva }, + { 0x090C, glyph_lvocalicdeva }, + { 0x090D, glyph_ecandradeva }, + { 0x090E, glyph_eshortdeva }, + { 0x090F, glyph_edeva }, + { 0x0910, glyph_aideva }, + { 0x0911, glyph_ocandradeva }, + { 0x0912, glyph_oshortdeva }, + { 0x0913, glyph_odeva }, + { 0x0914, glyph_audeva }, + { 0x0915, glyph_kadeva }, + { 0x0916, glyph_khadeva }, + { 0x0917, glyph_gadeva }, + { 0x0918, glyph_ghadeva }, + { 0x0919, glyph_ngadeva }, + { 0x091A, glyph_cadeva }, + { 0x091B, glyph_chadeva }, + { 0x091C, glyph_jadeva }, + { 0x091D, glyph_jhadeva }, + { 0x091E, glyph_nyadeva }, + { 0x091F, glyph_ttadeva }, + { 0x0920, glyph_tthadeva }, + { 0x0921, glyph_ddadeva }, + { 0x0922, glyph_ddhadeva }, + { 0x0923, glyph_nnadeva }, + { 0x0924, glyph_tadeva }, + { 0x0925, glyph_thadeva }, + { 0x0926, glyph_dadeva }, + { 0x0927, glyph_dhadeva }, + { 0x0928, glyph_nadeva }, + { 0x0929, glyph_nnnadeva }, + { 0x092A, glyph_padeva }, + { 0x092B, glyph_phadeva }, + { 0x092C, glyph_badeva }, + { 0x092D, glyph_bhadeva }, + { 0x092E, glyph_madeva }, + { 0x092F, glyph_yadeva }, + { 0x0930, glyph_radeva }, + { 0x0931, glyph_rradeva }, + { 0x0932, glyph_ladeva }, + { 0x0933, glyph_lladeva }, + { 0x0934, glyph_llladeva }, + { 0x0935, glyph_vadeva }, + { 0x0936, glyph_shadeva }, + { 0x0937, glyph_ssadeva }, + { 0x0938, glyph_sadeva }, + { 0x0939, glyph_hadeva }, + { 0x093C, glyph_nuktadeva }, + { 0x093D, glyph_avagrahadeva }, + { 0x093E, glyph_aavowelsigndeva }, + { 0x093F, glyph_ivowelsigndeva }, + { 0x0940, glyph_iivowelsigndeva }, + { 0x0941, glyph_uvowelsigndeva }, + { 0x0942, glyph_uuvowelsigndeva }, + { 0x0943, glyph_rvocalicvowelsigndeva }, + { 0x0944, glyph_rrvocalicvowelsigndeva }, + { 0x0945, glyph_ecandravowelsigndeva }, + { 0x0946, glyph_eshortvowelsigndeva }, + { 0x0947, glyph_evowelsigndeva }, + { 0x0948, glyph_aivowelsigndeva }, + { 0x0949, glyph_ocandravowelsigndeva }, + { 0x094A, glyph_oshortvowelsigndeva }, + { 0x094B, glyph_ovowelsigndeva }, + { 0x094C, glyph_auvowelsigndeva }, + { 0x094D, glyph_viramadeva }, + { 0x0950, glyph_omdeva }, + { 0x0951, glyph_udattadeva }, + { 0x0952, glyph_anudattadeva }, + { 0x0953, glyph_gravedeva }, + { 0x0954, glyph_acutedeva }, + { 0x0958, glyph_qadeva }, + { 0x0959, glyph_khhadeva }, + { 0x095A, glyph_ghhadeva }, + { 0x095B, glyph_zadeva }, + { 0x095C, glyph_dddhadeva }, + { 0x095D, glyph_rhadeva }, + { 0x095E, glyph_fadeva }, + { 0x095F, glyph_yyadeva }, + { 0x0960, glyph_rrvocalicdeva }, + { 0x0961, glyph_llvocalicdeva }, + { 0x0962, glyph_lvocalicvowelsigndeva }, + { 0x0963, glyph_llvocalicvowelsigndeva }, + { 0x0964, glyph_danda }, + { 0x0965, glyph_dbldanda }, + { 0x0966, glyph_zerodeva }, + { 0x0967, glyph_onedeva }, + { 0x0968, glyph_twodeva }, + { 0x0969, glyph_threedeva }, + { 0x096A, glyph_fourdeva }, + { 0x096B, glyph_fivedeva }, + { 0x096C, glyph_sixdeva }, + { 0x096D, glyph_sevendeva }, + { 0x096E, glyph_eightdeva }, + { 0x096F, glyph_ninedeva }, + { 0x0970, glyph_abbreviationsigndeva }, + { 0x0981, glyph_candrabindubengali }, + { 0x0982, glyph_anusvarabengali }, + { 0x0983, glyph_visargabengali }, + { 0x0985, glyph_abengali }, + { 0x0986, glyph_aabengali }, + { 0x0987, glyph_ibengali }, + { 0x0988, glyph_iibengali }, + { 0x0989, glyph_ubengali }, + { 0x098A, glyph_uubengali }, + { 0x098B, glyph_rvocalicbengali }, + { 0x098C, glyph_lvocalicbengali }, + { 0x098F, glyph_ebengali }, + { 0x0990, glyph_aibengali }, + { 0x0993, glyph_obengali }, + { 0x0994, glyph_aubengali }, + { 0x0995, glyph_kabengali }, + { 0x0996, glyph_khabengali }, + { 0x0997, glyph_gabengali }, + { 0x0998, glyph_ghabengali }, + { 0x0999, glyph_ngabengali }, + { 0x099A, glyph_cabengali }, + { 0x099B, glyph_chabengali }, + { 0x099C, glyph_jabengali }, + { 0x099D, glyph_jhabengali }, + { 0x099E, glyph_nyabengali }, + { 0x099F, glyph_ttabengali }, + { 0x09A0, glyph_tthabengali }, + { 0x09A1, glyph_ddabengali }, + { 0x09A2, glyph_ddhabengali }, + { 0x09A3, glyph_nnabengali }, + { 0x09A4, glyph_tabengali }, + { 0x09A5, glyph_thabengali }, + { 0x09A6, glyph_dabengali }, + { 0x09A7, glyph_dhabengali }, + { 0x09A8, glyph_nabengali }, + { 0x09AA, glyph_pabengali }, + { 0x09AB, glyph_phabengali }, + { 0x09AC, glyph_babengali }, + { 0x09AD, glyph_bhabengali }, + { 0x09AE, glyph_mabengali }, + { 0x09AF, glyph_yabengali }, + { 0x09B0, glyph_rabengali }, + { 0x09B2, glyph_labengali }, + { 0x09B6, glyph_shabengali }, + { 0x09B7, glyph_ssabengali }, + { 0x09B8, glyph_sabengali }, + { 0x09B9, glyph_habengali }, + { 0x09BC, glyph_nuktabengali }, + { 0x09BE, glyph_aavowelsignbengali }, + { 0x09BF, glyph_ivowelsignbengali }, + { 0x09C0, glyph_iivowelsignbengali }, + { 0x09C1, glyph_uvowelsignbengali }, + { 0x09C2, glyph_uuvowelsignbengali }, + { 0x09C3, glyph_rvocalicvowelsignbengali }, + { 0x09C4, glyph_rrvocalicvowelsignbengali }, + { 0x09C7, glyph_evowelsignbengali }, + { 0x09C8, glyph_aivowelsignbengali }, + { 0x09CB, glyph_ovowelsignbengali }, + { 0x09CC, glyph_auvowelsignbengali }, + { 0x09CD, glyph_viramabengali }, + { 0x09D7, glyph_aulengthmarkbengali }, + { 0x09DC, glyph_rrabengali }, + { 0x09DD, glyph_rhabengali }, + { 0x09DF, glyph_yyabengali }, + { 0x09E0, glyph_rrvocalicbengali }, + { 0x09E1, glyph_llvocalicbengali }, + { 0x09E2, glyph_lvocalicvowelsignbengali }, + { 0x09E3, glyph_llvocalicvowelsignbengali }, + { 0x09E6, glyph_zerobengali }, + { 0x09E7, glyph_onebengali }, + { 0x09E8, glyph_twobengali }, + { 0x09E9, glyph_threebengali }, + { 0x09EA, glyph_fourbengali }, + { 0x09EB, glyph_fivebengali }, + { 0x09EC, glyph_sixbengali }, + { 0x09ED, glyph_sevenbengali }, + { 0x09EE, glyph_eightbengali }, + { 0x09EF, glyph_ninebengali }, + { 0x09F0, glyph_ramiddlediagonalbengali }, + { 0x09F1, glyph_ralowerdiagonalbengali }, + { 0x09F2, glyph_rupeemarkbengali }, + { 0x09F3, glyph_rupeesignbengali }, + { 0x09F4, glyph_onenumeratorbengali }, + { 0x09F5, glyph_twonumeratorbengali }, + { 0x09F6, glyph_threenumeratorbengali }, + { 0x09F7, glyph_fournumeratorbengali }, + { 0x09F8, glyph_denominatorminusonenumeratorbengali }, + { 0x09F9, glyph_sixteencurrencydenominatorbengali }, + { 0x09FA, glyph_issharbengali }, + { 0x0A02, glyph_bindigurmukhi }, + { 0x0A05, glyph_agurmukhi }, + { 0x0A06, glyph_aagurmukhi }, + { 0x0A07, glyph_igurmukhi }, + { 0x0A08, glyph_iigurmukhi }, + { 0x0A09, glyph_ugurmukhi }, + { 0x0A0A, glyph_uugurmukhi }, + { 0x0A0F, glyph_eegurmukhi }, + { 0x0A10, glyph_aigurmukhi }, + { 0x0A13, glyph_oogurmukhi }, + { 0x0A14, glyph_augurmukhi }, + { 0x0A15, glyph_kagurmukhi }, + { 0x0A16, glyph_khagurmukhi }, + { 0x0A17, glyph_gagurmukhi }, + { 0x0A18, glyph_ghagurmukhi }, + { 0x0A19, glyph_ngagurmukhi }, + { 0x0A1A, glyph_cagurmukhi }, + { 0x0A1B, glyph_chagurmukhi }, + { 0x0A1C, glyph_jagurmukhi }, + { 0x0A1D, glyph_jhagurmukhi }, + { 0x0A1E, glyph_nyagurmukhi }, + { 0x0A1F, glyph_ttagurmukhi }, + { 0x0A20, glyph_tthagurmukhi }, + { 0x0A21, glyph_ddagurmukhi }, + { 0x0A22, glyph_ddhagurmukhi }, + { 0x0A23, glyph_nnagurmukhi }, + { 0x0A24, glyph_tagurmukhi }, + { 0x0A25, glyph_thagurmukhi }, + { 0x0A26, glyph_dagurmukhi }, + { 0x0A27, glyph_dhagurmukhi }, + { 0x0A28, glyph_nagurmukhi }, + { 0x0A2A, glyph_pagurmukhi }, + { 0x0A2B, glyph_phagurmukhi }, + { 0x0A2C, glyph_bagurmukhi }, + { 0x0A2D, glyph_bhagurmukhi }, + { 0x0A2E, glyph_magurmukhi }, + { 0x0A2F, glyph_yagurmukhi }, + { 0x0A30, glyph_ragurmukhi }, + { 0x0A32, glyph_lagurmukhi }, + { 0x0A35, glyph_vagurmukhi }, + { 0x0A36, glyph_shagurmukhi }, + { 0x0A38, glyph_sagurmukhi }, + { 0x0A39, glyph_hagurmukhi }, + { 0x0A3C, glyph_nuktagurmukhi }, + { 0x0A3E, glyph_aamatragurmukhi }, + { 0x0A3F, glyph_imatragurmukhi }, + { 0x0A40, glyph_iimatragurmukhi }, + { 0x0A41, glyph_umatragurmukhi }, + { 0x0A42, glyph_uumatragurmukhi }, + { 0x0A47, glyph_eematragurmukhi }, + { 0x0A48, glyph_aimatragurmukhi }, + { 0x0A4B, glyph_oomatragurmukhi }, + { 0x0A4C, glyph_aumatragurmukhi }, + { 0x0A4D, glyph_halantgurmukhi }, + { 0x0A59, glyph_khhagurmukhi }, + { 0x0A5A, glyph_ghhagurmukhi }, + { 0x0A5B, glyph_zagurmukhi }, + { 0x0A5C, glyph_rragurmukhi }, + { 0x0A5E, glyph_fagurmukhi }, + { 0x0A66, glyph_zerogurmukhi }, + { 0x0A67, glyph_onegurmukhi }, + { 0x0A68, glyph_twogurmukhi }, + { 0x0A69, glyph_threegurmukhi }, + { 0x0A6A, glyph_fourgurmukhi }, + { 0x0A6B, glyph_fivegurmukhi }, + { 0x0A6C, glyph_sixgurmukhi }, + { 0x0A6D, glyph_sevengurmukhi }, + { 0x0A6E, glyph_eightgurmukhi }, + { 0x0A6F, glyph_ninegurmukhi }, + { 0x0A70, glyph_tippigurmukhi }, + { 0x0A71, glyph_addakgurmukhi }, + { 0x0A72, glyph_irigurmukhi }, + { 0x0A73, glyph_uragurmukhi }, + { 0x0A74, glyph_ekonkargurmukhi }, + { 0x0A81, glyph_candrabindugujarati }, + { 0x0A82, glyph_anusvaragujarati }, + { 0x0A83, glyph_visargagujarati }, + { 0x0A85, glyph_agujarati }, + { 0x0A86, glyph_aagujarati }, + { 0x0A87, glyph_igujarati }, + { 0x0A88, glyph_iigujarati }, + { 0x0A89, glyph_ugujarati }, + { 0x0A8A, glyph_uugujarati }, + { 0x0A8B, glyph_rvocalicgujarati }, + { 0x0A8D, glyph_ecandragujarati }, + { 0x0A8F, glyph_egujarati }, + { 0x0A90, glyph_aigujarati }, + { 0x0A91, glyph_ocandragujarati }, + { 0x0A93, glyph_ogujarati }, + { 0x0A94, glyph_augujarati }, + { 0x0A95, glyph_kagujarati }, + { 0x0A96, glyph_khagujarati }, + { 0x0A97, glyph_gagujarati }, + { 0x0A98, glyph_ghagujarati }, + { 0x0A99, glyph_ngagujarati }, + { 0x0A9A, glyph_cagujarati }, + { 0x0A9B, glyph_chagujarati }, + { 0x0A9C, glyph_jagujarati }, + { 0x0A9D, glyph_jhagujarati }, + { 0x0A9E, glyph_nyagujarati }, + { 0x0A9F, glyph_ttagujarati }, + { 0x0AA0, glyph_tthagujarati }, + { 0x0AA1, glyph_ddagujarati }, + { 0x0AA2, glyph_ddhagujarati }, + { 0x0AA3, glyph_nnagujarati }, + { 0x0AA4, glyph_tagujarati }, + { 0x0AA5, glyph_thagujarati }, + { 0x0AA6, glyph_dagujarati }, + { 0x0AA7, glyph_dhagujarati }, + { 0x0AA8, glyph_nagujarati }, + { 0x0AAA, glyph_pagujarati }, + { 0x0AAB, glyph_phagujarati }, + { 0x0AAC, glyph_bagujarati }, + { 0x0AAD, glyph_bhagujarati }, + { 0x0AAE, glyph_magujarati }, + { 0x0AAF, glyph_yagujarati }, + { 0x0AB0, glyph_ragujarati }, + { 0x0AB2, glyph_lagujarati }, + { 0x0AB3, glyph_llagujarati }, + { 0x0AB5, glyph_vagujarati }, + { 0x0AB6, glyph_shagujarati }, + { 0x0AB7, glyph_ssagujarati }, + { 0x0AB8, glyph_sagujarati }, + { 0x0AB9, glyph_hagujarati }, + { 0x0ABC, glyph_nuktagujarati }, + { 0x0ABE, glyph_aavowelsigngujarati }, + { 0x0ABF, glyph_ivowelsigngujarati }, + { 0x0AC0, glyph_iivowelsigngujarati }, + { 0x0AC1, glyph_uvowelsigngujarati }, + { 0x0AC2, glyph_uuvowelsigngujarati }, + { 0x0AC3, glyph_rvocalicvowelsigngujarati }, + { 0x0AC4, glyph_rrvocalicvowelsigngujarati }, + { 0x0AC5, glyph_ecandravowelsigngujarati }, + { 0x0AC7, glyph_evowelsigngujarati }, + { 0x0AC8, glyph_aivowelsigngujarati }, + { 0x0AC9, glyph_ocandravowelsigngujarati }, + { 0x0ACB, glyph_ovowelsigngujarati }, + { 0x0ACC, glyph_auvowelsigngujarati }, + { 0x0ACD, glyph_viramagujarati }, + { 0x0AD0, glyph_omgujarati }, + { 0x0AE0, glyph_rrvocalicgujarati }, + { 0x0AE6, glyph_zerogujarati }, + { 0x0AE7, glyph_onegujarati }, + { 0x0AE8, glyph_twogujarati }, + { 0x0AE9, glyph_threegujarati }, + { 0x0AEA, glyph_fourgujarati }, + { 0x0AEB, glyph_fivegujarati }, + { 0x0AEC, glyph_sixgujarati }, + { 0x0AED, glyph_sevengujarati }, + { 0x0AEE, glyph_eightgujarati }, + { 0x0AEF, glyph_ninegujarati }, + { 0x0E01, glyph_kokaithai }, + { 0x0E02, glyph_khokhaithai }, + { 0x0E03, glyph_khokhuatthai }, + { 0x0E04, glyph_khokhwaithai }, + { 0x0E05, glyph_khokhonthai }, + { 0x0E06, glyph_khorakhangthai }, + { 0x0E07, glyph_ngonguthai }, + { 0x0E08, glyph_chochanthai }, + { 0x0E09, glyph_chochingthai }, + { 0x0E0A, glyph_chochangthai }, + { 0x0E0B, glyph_sosothai }, + { 0x0E0C, glyph_chochoethai }, + { 0x0E0D, glyph_yoyingthai }, + { 0x0E0E, glyph_dochadathai }, + { 0x0E0F, glyph_topatakthai }, + { 0x0E10, glyph_thothanthai }, + { 0x0E11, glyph_thonangmonthothai }, + { 0x0E12, glyph_thophuthaothai }, + { 0x0E13, glyph_nonenthai }, + { 0x0E14, glyph_dodekthai }, + { 0x0E15, glyph_totaothai }, + { 0x0E16, glyph_thothungthai }, + { 0x0E17, glyph_thothahanthai }, + { 0x0E18, glyph_thothongthai }, + { 0x0E19, glyph_nonuthai }, + { 0x0E1A, glyph_bobaimaithai }, + { 0x0E1B, glyph_poplathai }, + { 0x0E1C, glyph_phophungthai }, + { 0x0E1D, glyph_fofathai }, + { 0x0E1E, glyph_phophanthai }, + { 0x0E1F, glyph_fofanthai }, + { 0x0E20, glyph_phosamphaothai }, + { 0x0E21, glyph_momathai }, + { 0x0E22, glyph_yoyakthai }, + { 0x0E23, glyph_roruathai }, + { 0x0E24, glyph_ruthai }, + { 0x0E25, glyph_lolingthai }, + { 0x0E26, glyph_luthai }, + { 0x0E27, glyph_wowaenthai }, + { 0x0E28, glyph_sosalathai }, + { 0x0E29, glyph_sorusithai }, + { 0x0E2A, glyph_sosuathai }, + { 0x0E2B, glyph_hohipthai }, + { 0x0E2C, glyph_lochulathai }, + { 0x0E2D, glyph_oangthai }, + { 0x0E2E, glyph_honokhukthai }, + { 0x0E2F, glyph_paiyannoithai }, + { 0x0E30, glyph_saraathai }, + { 0x0E31, glyph_maihanakatthai }, + { 0x0E32, glyph_saraaathai }, + { 0x0E33, glyph_saraamthai }, + { 0x0E34, glyph_saraithai }, + { 0x0E35, glyph_saraiithai }, + { 0x0E36, glyph_sarauethai }, + { 0x0E37, glyph_saraueethai }, + { 0x0E38, glyph_sarauthai }, + { 0x0E39, glyph_sarauuthai }, + { 0x0E3A, glyph_phinthuthai }, + { 0x0E3F, glyph_bahtthai }, + { 0x0E40, glyph_saraethai }, + { 0x0E41, glyph_saraaethai }, + { 0x0E42, glyph_saraothai }, + { 0x0E43, glyph_saraaimaimuanthai }, + { 0x0E44, glyph_saraaimaimalaithai }, + { 0x0E45, glyph_lakkhangyaothai }, + { 0x0E46, glyph_maiyamokthai }, + { 0x0E47, glyph_maitaikhuthai }, + { 0x0E48, glyph_maiekthai }, + { 0x0E49, glyph_maithothai }, + { 0x0E4A, glyph_maitrithai }, + { 0x0E4B, glyph_maichattawathai }, + { 0x0E4C, glyph_thanthakhatthai }, + { 0x0E4D, glyph_nikhahitthai }, + { 0x0E4E, glyph_yamakkanthai }, + { 0x0E4F, glyph_fongmanthai }, + { 0x0E50, glyph_zerothai }, + { 0x0E51, glyph_onethai }, + { 0x0E52, glyph_twothai }, + { 0x0E53, glyph_threethai }, + { 0x0E54, glyph_fourthai }, + { 0x0E55, glyph_fivethai }, + { 0x0E56, glyph_sixthai }, + { 0x0E57, glyph_seventhai }, + { 0x0E58, glyph_eightthai }, + { 0x0E59, glyph_ninethai }, + { 0x0E5A, glyph_angkhankhuthai }, + { 0x0E5B, glyph_khomutthai }, + { 0x1E00, glyph_Aringbelow }, + { 0x1E01, glyph_aringbelow }, + { 0x1E02, glyph_Bdotaccent }, + { 0x1E03, glyph_bdotaccent }, + { 0x1E04, glyph_Bdotbelow }, + { 0x1E05, glyph_bdotbelow }, + { 0x1E06, glyph_Blinebelow }, + { 0x1E07, glyph_blinebelow }, + { 0x1E08, glyph_Ccedillaacute }, + { 0x1E09, glyph_ccedillaacute }, + { 0x1E0A, glyph_Ddotaccent }, + { 0x1E0B, glyph_ddotaccent }, + { 0x1E0C, glyph_Ddotbelow }, + { 0x1E0D, glyph_ddotbelow }, + { 0x1E0E, glyph_Dlinebelow }, + { 0x1E0F, glyph_dlinebelow }, + { 0x1E10, glyph_Dcedilla }, + { 0x1E11, glyph_dcedilla }, + { 0x1E12, glyph_Dcircumflexbelow }, + { 0x1E13, glyph_dcircumflexbelow }, + { 0x1E14, glyph_Emacrongrave }, + { 0x1E15, glyph_emacrongrave }, + { 0x1E16, glyph_Emacronacute }, + { 0x1E17, glyph_emacronacute }, + { 0x1E18, glyph_Ecircumflexbelow }, + { 0x1E19, glyph_ecircumflexbelow }, + { 0x1E1A, glyph_Etildebelow }, + { 0x1E1B, glyph_etildebelow }, + { 0x1E1C, glyph_Ecedillabreve }, + { 0x1E1D, glyph_ecedillabreve }, + { 0x1E1E, glyph_Fdotaccent }, + { 0x1E1F, glyph_fdotaccent }, + { 0x1E20, glyph_Gmacron }, + { 0x1E21, glyph_gmacron }, + { 0x1E22, glyph_Hdotaccent }, + { 0x1E23, glyph_hdotaccent }, + { 0x1E24, glyph_Hdotbelow }, + { 0x1E25, glyph_hdotbelow }, + { 0x1E26, glyph_Hdieresis }, + { 0x1E27, glyph_hdieresis }, + { 0x1E28, glyph_Hcedilla }, + { 0x1E29, glyph_hcedilla }, + { 0x1E2A, glyph_Hbrevebelow }, + { 0x1E2B, glyph_hbrevebelow }, + { 0x1E2C, glyph_Itildebelow }, + { 0x1E2D, glyph_itildebelow }, + { 0x1E2E, glyph_Idieresisacute }, + { 0x1E2F, glyph_idieresisacute }, + { 0x1E30, glyph_Kacute }, + { 0x1E31, glyph_kacute }, + { 0x1E32, glyph_Kdotbelow }, + { 0x1E33, glyph_kdotbelow }, + { 0x1E34, glyph_Klinebelow }, + { 0x1E35, glyph_klinebelow }, + { 0x1E36, glyph_Ldotbelow }, + { 0x1E37, glyph_ldotbelow }, + { 0x1E38, glyph_Ldotbelowmacron }, + { 0x1E39, glyph_ldotbelowmacron }, + { 0x1E3A, glyph_Llinebelow }, + { 0x1E3B, glyph_llinebelow }, + { 0x1E3C, glyph_Lcircumflexbelow }, + { 0x1E3D, glyph_lcircumflexbelow }, + { 0x1E3E, glyph_Macute }, + { 0x1E3F, glyph_macute }, + { 0x1E40, glyph_Mdotaccent }, + { 0x1E41, glyph_mdotaccent }, + { 0x1E42, glyph_Mdotbelow }, + { 0x1E43, glyph_mdotbelow }, + { 0x1E44, glyph_Ndotaccent }, + { 0x1E45, glyph_ndotaccent }, + { 0x1E46, glyph_Ndotbelow }, + { 0x1E47, glyph_ndotbelow }, + { 0x1E48, glyph_Nlinebelow }, + { 0x1E49, glyph_nlinebelow }, + { 0x1E4A, glyph_Ncircumflexbelow }, + { 0x1E4B, glyph_ncircumflexbelow }, + { 0x1E4C, glyph_Otildeacute }, + { 0x1E4D, glyph_otildeacute }, + { 0x1E4E, glyph_Otildedieresis }, + { 0x1E4F, glyph_otildedieresis }, + { 0x1E50, glyph_Omacrongrave }, + { 0x1E51, glyph_omacrongrave }, + { 0x1E52, glyph_Omacronacute }, + { 0x1E53, glyph_omacronacute }, + { 0x1E54, glyph_Pacute }, + { 0x1E55, glyph_pacute }, + { 0x1E56, glyph_Pdotaccent }, + { 0x1E57, glyph_pdotaccent }, + { 0x1E58, glyph_Rdotaccent }, + { 0x1E59, glyph_rdotaccent }, + { 0x1E5A, glyph_Rdotbelow }, + { 0x1E5B, glyph_rdotbelow }, + { 0x1E5C, glyph_Rdotbelowmacron }, + { 0x1E5D, glyph_rdotbelowmacron }, + { 0x1E5E, glyph_Rlinebelow }, + { 0x1E5F, glyph_rlinebelow }, + { 0x1E60, glyph_Sdotaccent }, + { 0x1E61, glyph_sdotaccent }, + { 0x1E62, glyph_Sdotbelow }, + { 0x1E63, glyph_sdotbelow }, + { 0x1E64, glyph_Sacutedotaccent }, + { 0x1E65, glyph_sacutedotaccent }, + { 0x1E66, glyph_Scarondotaccent }, + { 0x1E67, glyph_scarondotaccent }, + { 0x1E68, glyph_Sdotbelowdotaccent }, + { 0x1E69, glyph_sdotbelowdotaccent }, + { 0x1E6A, glyph_Tdotaccent }, + { 0x1E6B, glyph_tdotaccent }, + { 0x1E6C, glyph_Tdotbelow }, + { 0x1E6D, glyph_tdotbelow }, + { 0x1E6E, glyph_Tlinebelow }, + { 0x1E6F, glyph_tlinebelow }, + { 0x1E70, glyph_Tcircumflexbelow }, + { 0x1E71, glyph_tcircumflexbelow }, + { 0x1E72, glyph_Udieresisbelow }, + { 0x1E73, glyph_udieresisbelow }, + { 0x1E74, glyph_Utildebelow }, + { 0x1E75, glyph_utildebelow }, + { 0x1E76, glyph_Ucircumflexbelow }, + { 0x1E77, glyph_ucircumflexbelow }, + { 0x1E78, glyph_Utildeacute }, + { 0x1E79, glyph_utildeacute }, + { 0x1E7A, glyph_Umacrondieresis }, + { 0x1E7B, glyph_umacrondieresis }, + { 0x1E7C, glyph_Vtilde }, + { 0x1E7D, glyph_vtilde }, + { 0x1E7E, glyph_Vdotbelow }, + { 0x1E7F, glyph_vdotbelow }, + { 0x1E86, glyph_Wdotaccent }, + { 0x1E87, glyph_wdotaccent }, + { 0x1E88, glyph_Wdotbelow }, + { 0x1E89, glyph_wdotbelow }, + { 0x1E8A, glyph_Xdotaccent }, + { 0x1E8B, glyph_xdotaccent }, + { 0x1E8C, glyph_Xdieresis }, + { 0x1E8D, glyph_xdieresis }, + { 0x1E8E, glyph_Ydotaccent }, + { 0x1E8F, glyph_ydotaccent }, + { 0x1E90, glyph_Zcircumflex }, + { 0x1E91, glyph_zcircumflex }, + { 0x1E92, glyph_Zdotbelow }, + { 0x1E93, glyph_zdotbelow }, + { 0x1E94, glyph_Zlinebelow }, + { 0x1E95, glyph_zlinebelow }, + { 0x1E96, glyph_hlinebelow }, + { 0x1E97, glyph_tdieresis }, + { 0x1E98, glyph_wring }, + { 0x1E99, glyph_yring }, + { 0x1E9A, glyph_arighthalfring }, + { 0x1E9B, glyph_slongdotaccent }, + { 0x1EA0, glyph_Adotbelow }, + { 0x1EA1, glyph_adotbelow }, + { 0x1EA2, glyph_Ahookabove }, + { 0x1EA3, glyph_ahookabove }, + { 0x1EA4, glyph_Acircumflexacute }, + { 0x1EA5, glyph_acircumflexacute }, + { 0x1EA6, glyph_Acircumflexgrave }, + { 0x1EA7, glyph_acircumflexgrave }, + { 0x1EA8, glyph_Acircumflexhookabove }, + { 0x1EA9, glyph_acircumflexhookabove }, + { 0x1EAA, glyph_Acircumflextilde }, + { 0x1EAB, glyph_acircumflextilde }, + { 0x1EAC, glyph_Acircumflexdotbelow }, + { 0x1EAD, glyph_acircumflexdotbelow }, + { 0x1EAE, glyph_Abreveacute }, + { 0x1EAF, glyph_abreveacute }, + { 0x1EB0, glyph_Abrevegrave }, + { 0x1EB1, glyph_abrevegrave }, + { 0x1EB2, glyph_Abrevehookabove }, + { 0x1EB3, glyph_abrevehookabove }, + { 0x1EB4, glyph_Abrevetilde }, + { 0x1EB5, glyph_abrevetilde }, + { 0x1EB6, glyph_Abrevedotbelow }, + { 0x1EB7, glyph_abrevedotbelow }, + { 0x1EB8, glyph_Edotbelow }, + { 0x1EB9, glyph_edotbelow }, + { 0x1EBA, glyph_Ehookabove }, + { 0x1EBB, glyph_ehookabove }, + { 0x1EBC, glyph_Etilde }, + { 0x1EBD, glyph_etilde }, + { 0x1EBE, glyph_Ecircumflexacute }, + { 0x1EBF, glyph_ecircumflexacute }, + { 0x1EC0, glyph_Ecircumflexgrave }, + { 0x1EC1, glyph_ecircumflexgrave }, + { 0x1EC2, glyph_Ecircumflexhookabove }, + { 0x1EC3, glyph_ecircumflexhookabove }, + { 0x1EC4, glyph_Ecircumflextilde }, + { 0x1EC5, glyph_ecircumflextilde }, + { 0x1EC6, glyph_Ecircumflexdotbelow }, + { 0x1EC7, glyph_ecircumflexdotbelow }, + { 0x1EC8, glyph_Ihookabove }, + { 0x1EC9, glyph_ihookabove }, + { 0x1ECA, glyph_Idotbelow }, + { 0x1ECB, glyph_idotbelow }, + { 0x1ECC, glyph_Odotbelow }, + { 0x1ECD, glyph_odotbelow }, + { 0x1ECE, glyph_Ohookabove }, + { 0x1ECF, glyph_ohookabove }, + { 0x1ED0, glyph_Ocircumflexacute }, + { 0x1ED1, glyph_ocircumflexacute }, + { 0x1ED2, glyph_Ocircumflexgrave }, + { 0x1ED3, glyph_ocircumflexgrave }, + { 0x1ED4, glyph_Ocircumflexhookabove }, + { 0x1ED5, glyph_ocircumflexhookabove }, + { 0x1ED6, glyph_Ocircumflextilde }, + { 0x1ED7, glyph_ocircumflextilde }, + { 0x1ED8, glyph_Ocircumflexdotbelow }, + { 0x1ED9, glyph_ocircumflexdotbelow }, + { 0x1EDA, glyph_Ohornacute }, + { 0x1EDB, glyph_ohornacute }, + { 0x1EDC, glyph_Ohorngrave }, + { 0x1EDD, glyph_ohorngrave }, + { 0x1EDE, glyph_Ohornhookabove }, + { 0x1EDF, glyph_ohornhookabove }, + { 0x1EE0, glyph_Ohorntilde }, + { 0x1EE1, glyph_ohorntilde }, + { 0x1EE2, glyph_Ohorndotbelow }, + { 0x1EE3, glyph_ohorndotbelow }, + { 0x1EE4, glyph_Udotbelow }, + { 0x1EE5, glyph_udotbelow }, + { 0x1EE6, glyph_Uhookabove }, + { 0x1EE7, glyph_uhookabove }, + { 0x1EE8, glyph_Uhornacute }, + { 0x1EE9, glyph_uhornacute }, + { 0x1EEA, glyph_Uhorngrave }, + { 0x1EEB, glyph_uhorngrave }, + { 0x1EEC, glyph_Uhornhookabove }, + { 0x1EED, glyph_uhornhookabove }, + { 0x1EEE, glyph_Uhorntilde }, + { 0x1EEF, glyph_uhorntilde }, + { 0x1EF0, glyph_Uhorndotbelow }, + { 0x1EF1, glyph_uhorndotbelow }, + { 0x1EF4, glyph_Ydotbelow }, + { 0x1EF5, glyph_ydotbelow }, + { 0x1EF6, glyph_Yhookabove }, + { 0x1EF7, glyph_yhookabove }, + { 0x1EF8, glyph_Ytilde }, + { 0x1EF9, glyph_ytilde }, + { 0x2002, glyph_enspace }, + { 0x200B, glyph_zerowidthspace }, + { 0x200C, glyph_zerowidthnonjoiner }, + { 0x2010, glyph_hyphentwo }, + { 0x2015, glyph_horizontalbar }, + { 0x2016, glyph_dblverticalbar }, + { 0x2017, glyph_dbllowline }, + { 0x201B, glyph_quoteleftreversed }, + { 0x2025, glyph_twodotleader }, + { 0x2035, glyph_primereversed }, + { 0x203B, glyph_referencemark }, + { 0x203E, glyph_overline }, + { 0x2042, glyph_asterism }, + { 0x207A, glyph_plussuperior }, + { 0x207C, glyph_equalsuperior }, + { 0x20A1, glyph_colonsign }, + { 0x20A2, glyph_cruzeiro }, + { 0x20A4, glyph_afii08941 }, + { 0x20A9, glyph_won }, + { 0x20AC, glyph_euro }, + { 0x2103, glyph_centigrade }, + { 0x2105, glyph_careof }, + { 0x2109, glyph_fahrenheit }, + { 0x2113, glyph_lsquare }, + { 0x2116, glyph_numero }, + { 0x2121, glyph_telephone }, + { 0x2126, glyph_Ohm }, + { 0x212B, glyph_angstrom }, + { 0x2160, glyph_Oneroman }, + { 0x2161, glyph_Tworoman }, + { 0x2162, glyph_Threeroman }, + { 0x2163, glyph_Fourroman }, + { 0x2164, glyph_Fiveroman }, + { 0x2165, glyph_Sixroman }, + { 0x2166, glyph_Sevenroman }, + { 0x2167, glyph_Eightroman }, + { 0x2168, glyph_Nineroman }, + { 0x2169, glyph_Tenroman }, + { 0x216A, glyph_Elevenroman }, + { 0x216B, glyph_Twelveroman }, + { 0x2170, glyph_oneroman }, + { 0x2171, glyph_tworoman }, + { 0x2172, glyph_threeroman }, + { 0x2173, glyph_fourroman }, + { 0x2174, glyph_fiveroman }, + { 0x2175, glyph_sixroman }, + { 0x2176, glyph_sevenroman }, + { 0x2177, glyph_eightroman }, + { 0x2178, glyph_nineroman }, + { 0x2179, glyph_tenroman }, + { 0x217A, glyph_elevenroman }, + { 0x217B, glyph_twelveroman }, + { 0x2196, glyph_arrowupleft }, + { 0x2197, glyph_arrowupright }, + { 0x2198, glyph_arrowdownright }, + { 0x2199, glyph_arrowdownleft }, + { 0x21A8, glyph_arrowupdownbase }, + { 0x21BC, glyph_harpoonleftbarbup }, + { 0x21C0, glyph_harpoonrightbarbup }, + { 0x21C4, glyph_arrowrightoverleft }, + { 0x21C5, glyph_arrowupleftofdown }, + { 0x21C6, glyph_arrowleftoverright }, + { 0x21CD, glyph_arrowleftdblstroke }, + { 0x21CF, glyph_arrowrightdblstroke }, + { 0x21D0, glyph_arrowleftdbl }, + { 0x21D2, glyph_dblarrowright }, + { 0x21D4, glyph_dblarrowleft }, + { 0x21DE, glyph_pageup }, + { 0x21DF, glyph_pagedown }, + { 0x21E0, glyph_arrowdashleft }, + { 0x21E1, glyph_arrowdashup }, + { 0x21E2, glyph_arrowdashright }, + { 0x21E3, glyph_arrowdashdown }, + { 0x21E4, glyph_arrowtableft }, + { 0x21E5, glyph_arrowtabright }, + { 0x21E6, glyph_arrowleftwhite }, + { 0x21E7, glyph_arrowupwhite }, + { 0x21E8, glyph_arrowrightwhite }, + { 0x21E9, glyph_arrowdownwhite }, + { 0x21EA, glyph_capslock }, + { 0x2200, glyph_forall }, + { 0x2203, glyph_thereexists }, + { 0x2206, glyph_increment }, + { 0x2207, glyph_nabla }, + { 0x2209, glyph_notelementof }, + { 0x220C, glyph_notcontains }, + { 0x2213, glyph_minusplus }, + { 0x221F, glyph_rightangle }, + { 0x2223, glyph_divides }, + { 0x2225, glyph_parallel }, + { 0x2226, glyph_notparallel }, + { 0x222C, glyph_dblintegral }, + { 0x222E, glyph_contourintegral }, + { 0x2235, glyph_because }, + { 0x2236, glyph_ratio }, + { 0x2237, glyph_proportion }, + { 0x223C, glyph_tildeoperator }, + { 0x223D, glyph_reversedtilde }, + { 0x2243, glyph_asymptoticallyequal }, + { 0x2245, glyph_approximatelyequal }, + { 0x224C, glyph_allequal }, + { 0x2250, glyph_approaches }, + { 0x2251, glyph_geometricallyequal }, + { 0x2252, glyph_approxequalorimage }, + { 0x2253, glyph_imageorapproximatelyequal }, + { 0x2262, glyph_notidentical }, + { 0x2266, glyph_lessoverequal }, + { 0x2267, glyph_greateroverequal }, + { 0x226A, glyph_muchless }, + { 0x226B, glyph_muchgreater }, + { 0x226E, glyph_notless }, + { 0x226F, glyph_notgreater }, + { 0x2270, glyph_notlessnorequal }, + { 0x2271, glyph_notgreaternorequal }, + { 0x2272, glyph_lessorequivalent }, + { 0x2273, glyph_greaterorequivalent }, + { 0x2276, glyph_lessorgreater }, + { 0x2277, glyph_greaterorless }, + { 0x2279, glyph_notgreaternorless }, + { 0x227A, glyph_precedes }, + { 0x227B, glyph_succeeds }, + { 0x2280, glyph_notprecedes }, + { 0x2281, glyph_notsucceeds }, + { 0x2282, glyph_subset }, + { 0x2283, glyph_superset }, + { 0x2285, glyph_notsuperset }, + { 0x2286, glyph_subsetorequal }, + { 0x2287, glyph_supersetorequal }, + { 0x228A, glyph_subsetnotequal }, + { 0x228B, glyph_supersetnotequal }, + { 0x2295, glyph_pluscircle }, + { 0x2296, glyph_minuscircle }, + { 0x2297, glyph_timescircle }, + { 0x2299, glyph_circleot }, + { 0x22A3, glyph_tackleft }, + { 0x22A4, glyph_tackdown }, + { 0x22BF, glyph_righttriangle }, + { 0x22CE, glyph_curlyor }, + { 0x22CF, glyph_curlyand }, + { 0x22DA, glyph_lessequalorgreater }, + { 0x22DB, glyph_greaterequalorless }, + { 0x22EE, glyph_ellipsisvertical }, + { 0x2303, glyph_control }, + { 0x2305, glyph_projective }, + { 0x2310, glyph_logicalnotreversed }, + { 0x2312, glyph_arc }, + { 0x2318, glyph_propellor }, + { 0x2320, glyph_integraltop }, + { 0x2321, glyph_integralbottom }, + { 0x2325, glyph_option }, + { 0x2326, glyph_deleteright }, + { 0x2327, glyph_clear }, + { 0x232B, glyph_deleteleft }, + { 0x2423, glyph_blank }, + { 0x2460, glyph_onecircle }, + { 0x2461, glyph_twocircle }, + { 0x2462, glyph_threecircle }, + { 0x2463, glyph_fourcircle }, + { 0x2464, glyph_fivecircle }, + { 0x2465, glyph_sixcircle }, + { 0x2466, glyph_sevencircle }, + { 0x2467, glyph_eightcircle }, + { 0x2468, glyph_ninecircle }, + { 0x2469, glyph_tencircle }, + { 0x246A, glyph_elevencircle }, + { 0x246B, glyph_twelvecircle }, + { 0x246C, glyph_thirteencircle }, + { 0x246D, glyph_fourteencircle }, + { 0x246E, glyph_fifteencircle }, + { 0x246F, glyph_sixteencircle }, + { 0x2470, glyph_seventeencircle }, + { 0x2471, glyph_eighteencircle }, + { 0x2472, glyph_nineteencircle }, + { 0x2473, glyph_twentycircle }, + { 0x2474, glyph_oneparen }, + { 0x2475, glyph_twoparen }, + { 0x2476, glyph_threeparen }, + { 0x2477, glyph_fourparen }, + { 0x2478, glyph_fiveparen }, + { 0x2479, glyph_sixparen }, + { 0x247A, glyph_sevenparen }, + { 0x247B, glyph_eightparen }, + { 0x247C, glyph_nineparen }, + { 0x247D, glyph_tenparen }, + { 0x247E, glyph_elevenparen }, + { 0x247F, glyph_twelveparen }, + { 0x2480, glyph_thirteenparen }, + { 0x2481, glyph_fourteenparen }, + { 0x2482, glyph_fifteenparen }, + { 0x2483, glyph_sixteenparen }, + { 0x2484, glyph_seventeenparen }, + { 0x2485, glyph_eighteenparen }, + { 0x2486, glyph_nineteenparen }, + { 0x2487, glyph_twentyparen }, + { 0x2488, glyph_oneperiod }, + { 0x2489, glyph_twoperiod }, + { 0x248A, glyph_threeperiod }, + { 0x248B, glyph_fourperiod }, + { 0x248C, glyph_fiveperiod }, + { 0x248D, glyph_sixperiod }, + { 0x248E, glyph_sevenperiod }, + { 0x248F, glyph_eightperiod }, + { 0x2490, glyph_nineperiod }, + { 0x2491, glyph_tenperiod }, + { 0x2492, glyph_elevenperiod }, + { 0x2493, glyph_twelveperiod }, + { 0x2494, glyph_thirteenperiod }, + { 0x2495, glyph_fourteenperiod }, + { 0x2496, glyph_fifteenperiod }, + { 0x2497, glyph_sixteenperiod }, + { 0x2498, glyph_seventeenperiod }, + { 0x2499, glyph_eighteenperiod }, + { 0x249A, glyph_nineteenperiod }, + { 0x249B, glyph_twentyperiod }, + { 0x249C, glyph_aparen }, + { 0x249D, glyph_bparen }, + { 0x249E, glyph_cparen }, + { 0x249F, glyph_dparen }, + { 0x24A0, glyph_eparen }, + { 0x24A1, glyph_fparen }, + { 0x24A2, glyph_gparen }, + { 0x24A3, glyph_hparen }, + { 0x24A4, glyph_iparen }, + { 0x24A5, glyph_jparen }, + { 0x24A6, glyph_kparen }, + { 0x24A7, glyph_lparen }, + { 0x24A8, glyph_mparen }, + { 0x24A9, glyph_nparen }, + { 0x24AA, glyph_oparen }, + { 0x24AB, glyph_pparen }, + { 0x24AC, glyph_qparen }, + { 0x24AD, glyph_rparen }, + { 0x24AE, glyph_sparen }, + { 0x24AF, glyph_tparen }, + { 0x24B0, glyph_uparen }, + { 0x24B1, glyph_vparen }, + { 0x24B2, glyph_wparen }, + { 0x24B3, glyph_xparen }, + { 0x24B4, glyph_yparen }, + { 0x24B5, glyph_zparen }, + { 0x24B6, glyph_Acircle }, + { 0x24B7, glyph_Bcircle }, + { 0x24B8, glyph_Ccircle }, + { 0x24B9, glyph_Dcircle }, + { 0x24BA, glyph_Ecircle }, + { 0x24BB, glyph_Fcircle }, + { 0x24BC, glyph_Gcircle }, + { 0x24BD, glyph_Hcircle }, + { 0x24BE, glyph_Icircle }, + { 0x24BF, glyph_Jcircle }, + { 0x24C0, glyph_Kcircle }, + { 0x24C1, glyph_Lcircle }, + { 0x24C2, glyph_Mcircle }, + { 0x24C3, glyph_Ncircle }, + { 0x24C4, glyph_Ocircle }, + { 0x24C5, glyph_Pcircle }, + { 0x24C6, glyph_Qcircle }, + { 0x24C7, glyph_Rcircle }, + { 0x24C8, glyph_Scircle }, + { 0x24C9, glyph_Tcircle }, + { 0x24CA, glyph_Ucircle }, + { 0x24CB, glyph_Vcircle }, + { 0x24CC, glyph_Wcircle }, + { 0x24CD, glyph_Xcircle }, + { 0x24CE, glyph_Ycircle }, + { 0x24CF, glyph_Zcircle }, + { 0x24D0, glyph_acircle }, + { 0x24D1, glyph_bcircle }, + { 0x24D2, glyph_ccircle }, + { 0x24D3, glyph_dcircle }, + { 0x24D4, glyph_ecircle }, + { 0x24D5, glyph_fcircle }, + { 0x24D6, glyph_gcircle }, + { 0x24D7, glyph_hcircle }, + { 0x24D8, glyph_icircle }, + { 0x24D9, glyph_jcircle }, + { 0x24DA, glyph_kcircle }, + { 0x24DB, glyph_lcircle }, + { 0x24DC, glyph_mcircle }, + { 0x24DD, glyph_ncircle }, + { 0x24DE, glyph_ocircle }, + { 0x24DF, glyph_pcircle }, + { 0x24E0, glyph_qcircle }, + { 0x24E1, glyph_rcircle }, + { 0x24E2, glyph_scircle }, + { 0x24E3, glyph_tcircle }, + { 0x24E4, glyph_ucircle }, + { 0x24E5, glyph_vcircle }, + { 0x24E6, glyph_wcircle }, + { 0x24E7, glyph_xcircle }, + { 0x24E8, glyph_ycircle }, + { 0x24E9, glyph_zcircle }, + { 0x2591, glyph_shadelight }, + { 0x2592, glyph_shademedium }, + { 0x2593, glyph_shadedark }, + { 0x25A0, glyph_blacksquare }, + { 0x25A1, glyph_whitesquare }, + { 0x25A3, glyph_squarewhitewithsmallblack }, + { 0x25A4, glyph_squarehorizontalfill }, + { 0x25A5, glyph_squareverticalfill }, + { 0x25A6, glyph_squareorthogonalcrosshatchfill }, + { 0x25A7, glyph_squareupperlefttolowerrightfill }, + { 0x25A8, glyph_squareupperrighttolowerleftfill }, + { 0x25A9, glyph_squarediagonalcrosshatchfill }, + { 0x25AA, glyph_blacksmallsquare }, + { 0x25AB, glyph_whitesmallsquare }, + { 0x25AC, glyph_blackrectangle }, + { 0x25B2, glyph_blackuppointingtriangle }, + { 0x25B3, glyph_whiteuppointingtriangle }, + { 0x25B4, glyph_blackuppointingsmalltriangle }, + { 0x25B5, glyph_whiteuppointingsmalltriangle }, + { 0x25B6, glyph_blackrightpointingtriangle }, + { 0x25B7, glyph_whiterightpointingtriangle }, + { 0x25B9, glyph_whiterightpointingsmalltriangle }, + { 0x25BA, glyph_blackrightpointingpointer }, + { 0x25BC, glyph_blackdownpointingtriangle }, + { 0x25BD, glyph_whitedownpointingtriangle }, + { 0x25BF, glyph_whitedownpointingsmalltriangle }, + { 0x25C0, glyph_blackleftpointingtriangle }, + { 0x25C1, glyph_whiteleftpointingtriangle }, + { 0x25C3, glyph_whiteleftpointingsmalltriangle }, + { 0x25C4, glyph_blackleftpointingpointer }, + { 0x25C6, glyph_blackdiamond }, + { 0x25C7, glyph_whitediamond }, + { 0x25C8, glyph_whitediamondcontainingblacksmalldiamond }, + { 0x25C9, glyph_fisheye }, + { 0x25CB, glyph_whitecircle }, + { 0x25CC, glyph_dottedcircle }, + { 0x25CE, glyph_bullseye }, + { 0x25CF, glyph_blackcircle }, + { 0x25D0, glyph_circlewithlefthalfblack }, + { 0x25D1, glyph_circlewithrighthalfblack }, + { 0x25D8, glyph_bulletinverse }, + { 0x25D9, glyph_whitecircleinverse }, + { 0x25E2, glyph_blacklowerrighttriangle }, + { 0x25E3, glyph_blacklowerlefttriangle }, + { 0x25E4, glyph_blackupperlefttriangle }, + { 0x25E5, glyph_blackupperrighttriangle }, + { 0x25E6, glyph_whitebullet }, + { 0x25EF, glyph_largecircle }, + { 0x2605, glyph_blackstar }, + { 0x2606, glyph_whitestar }, + { 0x260E, glyph_telephoneblack }, + { 0x260F, glyph_whitetelephone }, + { 0x261C, glyph_pointingindexleftwhite }, + { 0x261D, glyph_pointingindexupwhite }, + { 0x261E, glyph_pointingindexrightwhite }, + { 0x261F, glyph_pointingindexdownwhite }, + { 0x262F, glyph_yinyang }, + { 0x263A, glyph_whitesmilingface }, + { 0x263B, glyph_blacksmilingface }, + { 0x263C, glyph_compass }, + { 0x2640, glyph_venus }, + { 0x2641, glyph_earth }, + { 0x2642, glyph_mars }, + { 0x2660, glyph_spadesuitblack }, + { 0x2661, glyph_heartsuitwhite }, + { 0x2662, glyph_diamondsuitwhite }, + { 0x2663, glyph_clubsuitblack }, + { 0x2664, glyph_spadesuitwhite }, + { 0x2665, glyph_heartsuitblack }, + { 0x2667, glyph_clubsuitwhite }, + { 0x2668, glyph_hotsprings }, + { 0x2669, glyph_quarternote }, + { 0x266B, glyph_eighthnotebeamed }, + { 0x266C, glyph_beamedsixteenthnotes }, + { 0x266D, glyph_musicflatsign }, + { 0x266F, glyph_musicsharpsign }, + { 0x2713, glyph_checkmark }, + { 0x278A, glyph_onecircleinversesansserif }, + { 0x278B, glyph_twocircleinversesansserif }, + { 0x278C, glyph_threecircleinversesansserif }, + { 0x278D, glyph_fourcircleinversesansserif }, + { 0x278E, glyph_fivecircleinversesansserif }, + { 0x278F, glyph_sixcircleinversesansserif }, + { 0x2790, glyph_sevencircleinversesansserif }, + { 0x2791, glyph_eightcircleinversesansserif }, + { 0x2792, glyph_ninecircleinversesansserif }, + { 0x279E, glyph_arrowrightheavy }, + { 0x3000, glyph_ideographicspace }, + { 0x3001, glyph_ideographiccomma }, + { 0x3002, glyph_ideographicperiod }, + { 0x3003, glyph_dittomark }, + { 0x3004, glyph_jis }, + { 0x3005, glyph_ideographiciterationmark }, + { 0x3006, glyph_ideographicclose }, + { 0x3007, glyph_ideographiczero }, + { 0x3008, glyph_anglebracketleft }, + { 0x3009, glyph_anglebracketright }, + { 0x300A, glyph_dblanglebracketleft }, + { 0x300B, glyph_dblanglebracketright }, + { 0x300C, glyph_cornerbracketleft }, + { 0x300D, glyph_cornerbracketright }, + { 0x300E, glyph_whitecornerbracketleft }, + { 0x300F, glyph_whitecornerbracketright }, + { 0x3010, glyph_blacklenticularbracketleft }, + { 0x3011, glyph_blacklenticularbracketright }, + { 0x3012, glyph_postalmark }, + { 0x3013, glyph_getamark }, + { 0x3014, glyph_tortoiseshellbracketleft }, + { 0x3015, glyph_tortoiseshellbracketright }, + { 0x3016, glyph_whitelenticularbracketleft }, + { 0x3017, glyph_whitelenticularbracketright }, + { 0x3018, glyph_whitetortoiseshellbracketleft }, + { 0x3019, glyph_whitetortoiseshellbracketright }, + { 0x301C, glyph_wavedash }, + { 0x301D, glyph_quotedblprimereversed }, + { 0x301E, glyph_quotedblprime }, + { 0x3020, glyph_postalmarkface }, + { 0x3021, glyph_onehangzhou }, + { 0x3022, glyph_twohangzhou }, + { 0x3023, glyph_threehangzhou }, + { 0x3024, glyph_fourhangzhou }, + { 0x3025, glyph_fivehangzhou }, + { 0x3026, glyph_sixhangzhou }, + { 0x3027, glyph_sevenhangzhou }, + { 0x3028, glyph_eighthangzhou }, + { 0x3029, glyph_ninehangzhou }, + { 0x3036, glyph_circlepostalmark }, + { 0x3041, glyph_asmallhiragana }, + { 0x3042, glyph_ahiragana }, + { 0x3043, glyph_ismallhiragana }, + { 0x3044, glyph_ihiragana }, + { 0x3045, glyph_usmallhiragana }, + { 0x3046, glyph_uhiragana }, + { 0x3047, glyph_esmallhiragana }, + { 0x3048, glyph_ehiragana }, + { 0x3049, glyph_osmallhiragana }, + { 0x304A, glyph_ohiragana }, + { 0x304B, glyph_kahiragana }, + { 0x304C, glyph_gahiragana }, + { 0x304D, glyph_kihiragana }, + { 0x304E, glyph_gihiragana }, + { 0x304F, glyph_kuhiragana }, + { 0x3050, glyph_guhiragana }, + { 0x3051, glyph_kehiragana }, + { 0x3052, glyph_gehiragana }, + { 0x3053, glyph_kohiragana }, + { 0x3054, glyph_gohiragana }, + { 0x3055, glyph_sahiragana }, + { 0x3056, glyph_zahiragana }, + { 0x3057, glyph_sihiragana }, + { 0x3058, glyph_zihiragana }, + { 0x3059, glyph_suhiragana }, + { 0x305A, glyph_zuhiragana }, + { 0x305B, glyph_sehiragana }, + { 0x305C, glyph_zehiragana }, + { 0x305D, glyph_sohiragana }, + { 0x305E, glyph_zohiragana }, + { 0x305F, glyph_tahiragana }, + { 0x3060, glyph_dahiragana }, + { 0x3061, glyph_tihiragana }, + { 0x3062, glyph_dihiragana }, + { 0x3063, glyph_tusmallhiragana }, + { 0x3064, glyph_tuhiragana }, + { 0x3065, glyph_duhiragana }, + { 0x3066, glyph_tehiragana }, + { 0x3067, glyph_dehiragana }, + { 0x3068, glyph_tohiragana }, + { 0x3069, glyph_dohiragana }, + { 0x306A, glyph_nahiragana }, + { 0x306B, glyph_nihiragana }, + { 0x306C, glyph_nuhiragana }, + { 0x306D, glyph_nehiragana }, + { 0x306E, glyph_nohiragana }, + { 0x306F, glyph_hahiragana }, + { 0x3070, glyph_bahiragana }, + { 0x3071, glyph_pahiragana }, + { 0x3072, glyph_hihiragana }, + { 0x3073, glyph_bihiragana }, + { 0x3074, glyph_pihiragana }, + { 0x3075, glyph_huhiragana }, + { 0x3076, glyph_buhiragana }, + { 0x3077, glyph_puhiragana }, + { 0x3078, glyph_hehiragana }, + { 0x3079, glyph_behiragana }, + { 0x307A, glyph_pehiragana }, + { 0x307B, glyph_hohiragana }, + { 0x307C, glyph_bohiragana }, + { 0x307D, glyph_pohiragana }, + { 0x307E, glyph_mahiragana }, + { 0x307F, glyph_mihiragana }, + { 0x3080, glyph_muhiragana }, + { 0x3081, glyph_mehiragana }, + { 0x3082, glyph_mohiragana }, + { 0x3083, glyph_yasmallhiragana }, + { 0x3084, glyph_yahiragana }, + { 0x3085, glyph_yusmallhiragana }, + { 0x3086, glyph_yuhiragana }, + { 0x3087, glyph_yosmallhiragana }, + { 0x3088, glyph_yohiragana }, + { 0x3089, glyph_rahiragana }, + { 0x308A, glyph_rihiragana }, + { 0x308B, glyph_ruhiragana }, + { 0x308C, glyph_rehiragana }, + { 0x308D, glyph_rohiragana }, + { 0x308E, glyph_wasmallhiragana }, + { 0x308F, glyph_wahiragana }, + { 0x3090, glyph_wihiragana }, + { 0x3091, glyph_wehiragana }, + { 0x3092, glyph_wohiragana }, + { 0x3093, glyph_nhiragana }, + { 0x3094, glyph_vuhiragana }, + { 0x309B, glyph_voicedmarkkana }, + { 0x309C, glyph_semivoicedmarkkana }, + { 0x309D, glyph_iterationhiragana }, + { 0x309E, glyph_voicediterationhiragana }, + { 0x30A1, glyph_asmallkatakana }, + { 0x30A2, glyph_akatakana }, + { 0x30A3, glyph_ismallkatakana }, + { 0x30A4, glyph_ikatakana }, + { 0x30A5, glyph_usmallkatakana }, + { 0x30A6, glyph_ukatakana }, + { 0x30A7, glyph_esmallkatakana }, + { 0x30A8, glyph_ekatakana }, + { 0x30A9, glyph_osmallkatakana }, + { 0x30AA, glyph_okatakana }, + { 0x30AB, glyph_kakatakana }, + { 0x30AC, glyph_gakatakana }, + { 0x30AD, glyph_kikatakana }, + { 0x30AE, glyph_gikatakana }, + { 0x30AF, glyph_kukatakana }, + { 0x30B0, glyph_gukatakana }, + { 0x30B1, glyph_kekatakana }, + { 0x30B2, glyph_gekatakana }, + { 0x30B3, glyph_kokatakana }, + { 0x30B4, glyph_gokatakana }, + { 0x30B5, glyph_sakatakana }, + { 0x30B6, glyph_zakatakana }, + { 0x30B7, glyph_sikatakana }, + { 0x30B8, glyph_zikatakana }, + { 0x30B9, glyph_sukatakana }, + { 0x30BA, glyph_zukatakana }, + { 0x30BB, glyph_sekatakana }, + { 0x30BC, glyph_zekatakana }, + { 0x30BD, glyph_sokatakana }, + { 0x30BE, glyph_zokatakana }, + { 0x30BF, glyph_takatakana }, + { 0x30C0, glyph_dakatakana }, + { 0x30C1, glyph_tikatakana }, + { 0x30C2, glyph_dikatakana }, + { 0x30C3, glyph_tusmallkatakana }, + { 0x30C4, glyph_tukatakana }, + { 0x30C5, glyph_dukatakana }, + { 0x30C6, glyph_tekatakana }, + { 0x30C7, glyph_dekatakana }, + { 0x30C8, glyph_tokatakana }, + { 0x30C9, glyph_dokatakana }, + { 0x30CA, glyph_nakatakana }, + { 0x30CB, glyph_nikatakana }, + { 0x30CC, glyph_nukatakana }, + { 0x30CD, glyph_nekatakana }, + { 0x30CE, glyph_nokatakana }, + { 0x30CF, glyph_hakatakana }, + { 0x30D0, glyph_bakatakana }, + { 0x30D1, glyph_pakatakana }, + { 0x30D2, glyph_hikatakana }, + { 0x30D3, glyph_bikatakana }, + { 0x30D4, glyph_pikatakana }, + { 0x30D5, glyph_hukatakana }, + { 0x30D6, glyph_bukatakana }, + { 0x30D7, glyph_pukatakana }, + { 0x30D8, glyph_hekatakana }, + { 0x30D9, glyph_bekatakana }, + { 0x30DA, glyph_pekatakana }, + { 0x30DB, glyph_hokatakana }, + { 0x30DC, glyph_bokatakana }, + { 0x30DD, glyph_pokatakana }, + { 0x30DE, glyph_makatakana }, + { 0x30DF, glyph_mikatakana }, + { 0x30E0, glyph_mukatakana }, + { 0x30E1, glyph_mekatakana }, + { 0x30E2, glyph_mokatakana }, + { 0x30E3, glyph_yasmallkatakana }, + { 0x30E4, glyph_yakatakana }, + { 0x30E5, glyph_yusmallkatakana }, + { 0x30E6, glyph_yukatakana }, + { 0x30E7, glyph_yosmallkatakana }, + { 0x30E8, glyph_yokatakana }, + { 0x30E9, glyph_rakatakana }, + { 0x30EA, glyph_rikatakana }, + { 0x30EB, glyph_rukatakana }, + { 0x30EC, glyph_rekatakana }, + { 0x30ED, glyph_rokatakana }, + { 0x30EE, glyph_wasmallkatakana }, + { 0x30EF, glyph_wakatakana }, + { 0x30F0, glyph_wikatakana }, + { 0x30F1, glyph_wekatakana }, + { 0x30F2, glyph_wokatakana }, + { 0x30F3, glyph_nkatakana }, + { 0x30F4, glyph_vukatakana }, + { 0x30F5, glyph_kasmallkatakana }, + { 0x30F6, glyph_kesmallkatakana }, + { 0x30F7, glyph_vakatakana }, + { 0x30F8, glyph_vikatakana }, + { 0x30F9, glyph_vekatakana }, + { 0x30FA, glyph_vokatakana }, + { 0x30FB, glyph_dotkatakana }, + { 0x30FC, glyph_prolongedkana }, + { 0x30FD, glyph_iterationkatakana }, + { 0x30FE, glyph_voicediterationkatakana }, + { 0x3105, glyph_bbopomofo }, + { 0x3106, glyph_pbopomofo }, + { 0x3107, glyph_mbopomofo }, + { 0x3108, glyph_fbopomofo }, + { 0x3109, glyph_dbopomofo }, + { 0x310A, glyph_tbopomofo }, + { 0x310B, glyph_nbopomofo }, + { 0x310C, glyph_lbopomofo }, + { 0x310D, glyph_gbopomofo }, + { 0x310E, glyph_kbopomofo }, + { 0x310F, glyph_hbopomofo }, + { 0x3110, glyph_jbopomofo }, + { 0x3111, glyph_qbopomofo }, + { 0x3112, glyph_xbopomofo }, + { 0x3113, glyph_zhbopomofo }, + { 0x3114, glyph_chbopomofo }, + { 0x3115, glyph_shbopomofo }, + { 0x3116, glyph_rbopomofo }, + { 0x3117, glyph_zbopomofo }, + { 0x3118, glyph_cbopomofo }, + { 0x3119, glyph_sbopomofo }, + { 0x311A, glyph_abopomofo }, + { 0x311B, glyph_obopomofo }, + { 0x311C, glyph_ebopomofo }, + { 0x311D, glyph_ehbopomofo }, + { 0x311E, glyph_aibopomofo }, + { 0x311F, glyph_eibopomofo }, + { 0x3120, glyph_aubopomofo }, + { 0x3121, glyph_oubopomofo }, + { 0x3122, glyph_anbopomofo }, + { 0x3123, glyph_enbopomofo }, + { 0x3124, glyph_angbopomofo }, + { 0x3125, glyph_engbopomofo }, + { 0x3126, glyph_erbopomofo }, + { 0x3127, glyph_ibopomofo }, + { 0x3128, glyph_ubopomofo }, + { 0x3129, glyph_iubopomofo }, + { 0x3131, glyph_kiyeokkorean }, + { 0x3132, glyph_ssangkiyeokkorean }, + { 0x3133, glyph_kiyeoksioskorean }, + { 0x3134, glyph_nieunkorean }, + { 0x3135, glyph_nieuncieuckorean }, + { 0x3136, glyph_nieunhieuhkorean }, + { 0x3137, glyph_tikeutkorean }, + { 0x3138, glyph_ssangtikeutkorean }, + { 0x3139, glyph_rieulkorean }, + { 0x313A, glyph_rieulkiyeokkorean }, + { 0x313B, glyph_rieulmieumkorean }, + { 0x313C, glyph_rieulpieupkorean }, + { 0x313D, glyph_rieulsioskorean }, + { 0x313E, glyph_rieulthieuthkorean }, + { 0x313F, glyph_rieulphieuphkorean }, + { 0x3140, glyph_rieulhieuhkorean }, + { 0x3141, glyph_mieumkorean }, + { 0x3142, glyph_pieupkorean }, + { 0x3143, glyph_ssangpieupkorean }, + { 0x3144, glyph_pieupsioskorean }, + { 0x3145, glyph_sioskorean }, + { 0x3146, glyph_ssangsioskorean }, + { 0x3147, glyph_ieungkorean }, + { 0x3148, glyph_cieuckorean }, + { 0x3149, glyph_ssangcieuckorean }, + { 0x314A, glyph_chieuchkorean }, + { 0x314B, glyph_khieukhkorean }, + { 0x314C, glyph_thieuthkorean }, + { 0x314D, glyph_phieuphkorean }, + { 0x314E, glyph_hieuhkorean }, + { 0x314F, glyph_akorean }, + { 0x3150, glyph_aekorean }, + { 0x3151, glyph_yakorean }, + { 0x3152, glyph_yaekorean }, + { 0x3153, glyph_eokorean }, + { 0x3154, glyph_ekorean }, + { 0x3155, glyph_yeokorean }, + { 0x3156, glyph_yekorean }, + { 0x3157, glyph_okorean }, + { 0x3158, glyph_wakorean }, + { 0x3159, glyph_waekorean }, + { 0x315A, glyph_oekorean }, + { 0x315B, glyph_yokorean }, + { 0x315C, glyph_ukorean }, + { 0x315D, glyph_weokorean }, + { 0x315E, glyph_wekorean }, + { 0x315F, glyph_wikorean }, + { 0x3160, glyph_yukorean }, + { 0x3161, glyph_eukorean }, + { 0x3162, glyph_yikorean }, + { 0x3163, glyph_ikorean }, + { 0x3164, glyph_hangulfiller }, + { 0x3165, glyph_ssangnieunkorean }, + { 0x3166, glyph_nieuntikeutkorean }, + { 0x3167, glyph_nieunsioskorean }, + { 0x3168, glyph_nieunpansioskorean }, + { 0x3169, glyph_rieulkiyeoksioskorean }, + { 0x316A, glyph_rieultikeutkorean }, + { 0x316B, glyph_rieulpieupsioskorean }, + { 0x316C, glyph_rieulpansioskorean }, + { 0x316D, glyph_rieulyeorinhieuhkorean }, + { 0x316E, glyph_mieumpieupkorean }, + { 0x316F, glyph_mieumsioskorean }, + { 0x3170, glyph_mieumpansioskorean }, + { 0x3171, glyph_kapyeounmieumkorean }, + { 0x3172, glyph_pieupkiyeokkorean }, + { 0x3173, glyph_pieuptikeutkorean }, + { 0x3174, glyph_pieupsioskiyeokkorean }, + { 0x3175, glyph_pieupsiostikeutkorean }, + { 0x3176, glyph_pieupcieuckorean }, + { 0x3177, glyph_pieupthieuthkorean }, + { 0x3178, glyph_kapyeounpieupkorean }, + { 0x3179, glyph_kapyeounssangpieupkorean }, + { 0x317A, glyph_sioskiyeokkorean }, + { 0x317B, glyph_siosnieunkorean }, + { 0x317C, glyph_siostikeutkorean }, + { 0x317D, glyph_siospieupkorean }, + { 0x317E, glyph_sioscieuckorean }, + { 0x317F, glyph_pansioskorean }, + { 0x3180, glyph_ssangieungkorean }, + { 0x3181, glyph_yesieungkorean }, + { 0x3182, glyph_yesieungsioskorean }, + { 0x3183, glyph_yesieungpansioskorean }, + { 0x3184, glyph_kapyeounphieuphkorean }, + { 0x3185, glyph_ssanghieuhkorean }, + { 0x3186, glyph_yeorinhieuhkorean }, + { 0x3187, glyph_yoyakorean }, + { 0x3188, glyph_yoyaekorean }, + { 0x3189, glyph_yoikorean }, + { 0x318A, glyph_yuyeokorean }, + { 0x318B, glyph_yuyekorean }, + { 0x318C, glyph_yuikorean }, + { 0x318D, glyph_araeakorean }, + { 0x318E, glyph_araeaekorean }, + { 0x3200, glyph_kiyeokparenkorean }, + { 0x3201, glyph_nieunparenkorean }, + { 0x3202, glyph_tikeutparenkorean }, + { 0x3203, glyph_rieulparenkorean }, + { 0x3204, glyph_mieumparenkorean }, + { 0x3205, glyph_pieupparenkorean }, + { 0x3206, glyph_siosparenkorean }, + { 0x3207, glyph_ieungparenkorean }, + { 0x3208, glyph_cieucparenkorean }, + { 0x3209, glyph_chieuchparenkorean }, + { 0x320A, glyph_khieukhparenkorean }, + { 0x320B, glyph_thieuthparenkorean }, + { 0x320C, glyph_phieuphparenkorean }, + { 0x320D, glyph_hieuhparenkorean }, + { 0x320E, glyph_kiyeokaparenkorean }, + { 0x320F, glyph_nieunaparenkorean }, + { 0x3210, glyph_tikeutaparenkorean }, + { 0x3211, glyph_rieulaparenkorean }, + { 0x3212, glyph_mieumaparenkorean }, + { 0x3213, glyph_pieupaparenkorean }, + { 0x3214, glyph_siosaparenkorean }, + { 0x3215, glyph_ieungaparenkorean }, + { 0x3216, glyph_cieucaparenkorean }, + { 0x3217, glyph_chieuchaparenkorean }, + { 0x3218, glyph_khieukhaparenkorean }, + { 0x3219, glyph_thieuthaparenkorean }, + { 0x321A, glyph_phieuphaparenkorean }, + { 0x321B, glyph_hieuhaparenkorean }, + { 0x321C, glyph_cieucuparenkorean }, + { 0x3220, glyph_oneideographicparen }, + { 0x3221, glyph_twoideographicparen }, + { 0x3222, glyph_threeideographicparen }, + { 0x3223, glyph_fourideographicparen }, + { 0x3224, glyph_fiveideographicparen }, + { 0x3225, glyph_sixideographicparen }, + { 0x3226, glyph_sevenideographicparen }, + { 0x3227, glyph_eightideographicparen }, + { 0x3228, glyph_nineideographicparen }, + { 0x3229, glyph_tenideographicparen }, + { 0x322A, glyph_ideographicmoonparen }, + { 0x322B, glyph_ideographicfireparen }, + { 0x322C, glyph_ideographicwaterparen }, + { 0x322D, glyph_ideographicwoodparen }, + { 0x322E, glyph_ideographicmetalparen }, + { 0x322F, glyph_ideographicearthparen }, + { 0x3230, glyph_ideographicsunparen }, + { 0x3231, glyph_ideographicstockparen }, + { 0x3232, glyph_ideographichaveparen }, + { 0x3233, glyph_ideographicsocietyparen }, + { 0x3234, glyph_ideographicnameparen }, + { 0x3235, glyph_ideographicspecialparen }, + { 0x3236, glyph_ideographicfinancialparen }, + { 0x3237, glyph_ideographiccongratulationparen }, + { 0x3238, glyph_ideographiclaborparen }, + { 0x3239, glyph_ideographicrepresentparen }, + { 0x323A, glyph_ideographiccallparen }, + { 0x323B, glyph_ideographicstudyparen }, + { 0x323C, glyph_ideographicsuperviseparen }, + { 0x323D, glyph_ideographicenterpriseparen }, + { 0x323E, glyph_ideographicresourceparen }, + { 0x323F, glyph_ideographicallianceparen }, + { 0x3240, glyph_ideographicfestivalparen }, + { 0x3242, glyph_ideographicselfparen }, + { 0x3243, glyph_ideographicreachparen }, + { 0x3260, glyph_kiyeokcirclekorean }, + { 0x3261, glyph_nieuncirclekorean }, + { 0x3262, glyph_tikeutcirclekorean }, + { 0x3263, glyph_rieulcirclekorean }, + { 0x3264, glyph_mieumcirclekorean }, + { 0x3265, glyph_pieupcirclekorean }, + { 0x3266, glyph_sioscirclekorean }, + { 0x3267, glyph_ieungcirclekorean }, + { 0x3268, glyph_cieuccirclekorean }, + { 0x3269, glyph_chieuchcirclekorean }, + { 0x326A, glyph_khieukhcirclekorean }, + { 0x326B, glyph_thieuthcirclekorean }, + { 0x326C, glyph_phieuphcirclekorean }, + { 0x326D, glyph_hieuhcirclekorean }, + { 0x326E, glyph_kiyeokacirclekorean }, + { 0x326F, glyph_nieunacirclekorean }, + { 0x3270, glyph_tikeutacirclekorean }, + { 0x3271, glyph_rieulacirclekorean }, + { 0x3272, glyph_mieumacirclekorean }, + { 0x3273, glyph_pieupacirclekorean }, + { 0x3274, glyph_siosacirclekorean }, + { 0x3275, glyph_ieungacirclekorean }, + { 0x3276, glyph_cieucacirclekorean }, + { 0x3277, glyph_chieuchacirclekorean }, + { 0x3278, glyph_khieukhacirclekorean }, + { 0x3279, glyph_thieuthacirclekorean }, + { 0x327A, glyph_phieuphacirclekorean }, + { 0x327B, glyph_hieuhacirclekorean }, + { 0x327F, glyph_koreanstandardsymbol }, + { 0x328A, glyph_ideographmooncircle }, + { 0x328B, glyph_ideographfirecircle }, + { 0x328C, glyph_ideographwatercircle }, + { 0x328D, glyph_ideographwoodcircle }, + { 0x328E, glyph_ideographmetalcircle }, + { 0x328F, glyph_ideographearthcircle }, + { 0x3290, glyph_ideographsuncircle }, + { 0x3294, glyph_ideographnamecircle }, + { 0x3296, glyph_ideographicfinancialcircle }, + { 0x3298, glyph_ideographiclaborcircle }, + { 0x3299, glyph_ideographicsecretcircle }, + { 0x329D, glyph_ideographicexcellentcircle }, + { 0x329E, glyph_ideographicprintcircle }, + { 0x32A3, glyph_ideographiccorrectcircle }, + { 0x32A4, glyph_ideographichighcircle }, + { 0x32A5, glyph_ideographiccentrecircle }, + { 0x32A6, glyph_ideographiclowcircle }, + { 0x32A7, glyph_ideographicleftcircle }, + { 0x32A8, glyph_ideographicrightcircle }, + { 0x32A9, glyph_ideographicmedicinecircle }, + { 0x3300, glyph_apaatosquare }, + { 0x3303, glyph_aarusquare }, + { 0x3305, glyph_intisquare }, + { 0x330D, glyph_karoriisquare }, + { 0x3314, glyph_kirosquare }, + { 0x3315, glyph_kiroguramusquare }, + { 0x3316, glyph_kiromeetorusquare }, + { 0x3318, glyph_guramusquare }, + { 0x331E, glyph_kooposquare }, + { 0x3322, glyph_sentisquare }, + { 0x3323, glyph_sentosquare }, + { 0x3326, glyph_dorusquare }, + { 0x3327, glyph_tonsquare }, + { 0x332A, glyph_haitusquare }, + { 0x332B, glyph_paasentosquare }, + { 0x3331, glyph_birusquare }, + { 0x3333, glyph_huiitosquare }, + { 0x3336, glyph_hekutaarusquare }, + { 0x3339, glyph_herutusquare }, + { 0x333B, glyph_peezisquare }, + { 0x3342, glyph_hoonsquare }, + { 0x3347, glyph_mansyonsquare }, + { 0x3349, glyph_mirisquare }, + { 0x334A, glyph_miribaarusquare }, + { 0x334D, glyph_meetorusquare }, + { 0x334E, glyph_yaadosquare }, + { 0x3351, glyph_rittorusquare }, + { 0x3357, glyph_wattosquare }, + { 0x337B, glyph_heiseierasquare }, + { 0x337C, glyph_syouwaerasquare }, + { 0x337D, glyph_taisyouerasquare }, + { 0x337E, glyph_meizierasquare }, + { 0x337F, glyph_corporationsquare }, + { 0x3380, glyph_paampssquare }, + { 0x3381, glyph_nasquare }, + { 0x3382, glyph_muasquare }, + { 0x3383, glyph_masquare }, + { 0x3384, glyph_kasquare }, + { 0x3385, glyph_KBsquare }, + { 0x3386, glyph_MBsquare }, + { 0x3387, glyph_GBsquare }, + { 0x3388, glyph_calsquare }, + { 0x3389, glyph_kcalsquare }, + { 0x338A, glyph_pfsquare }, + { 0x338B, glyph_nfsquare }, + { 0x338C, glyph_mufsquare }, + { 0x338D, glyph_mugsquare }, + { 0x338E, glyph_squaremg }, + { 0x338F, glyph_squarekg }, + { 0x3390, glyph_Hzsquare }, + { 0x3391, glyph_khzsquare }, + { 0x3392, glyph_mhzsquare }, + { 0x3393, glyph_ghzsquare }, + { 0x3394, glyph_thzsquare }, + { 0x3395, glyph_mulsquare }, + { 0x3396, glyph_mlsquare }, + { 0x3397, glyph_dlsquare }, + { 0x3398, glyph_klsquare }, + { 0x3399, glyph_fmsquare }, + { 0x339A, glyph_nmsquare }, + { 0x339B, glyph_mumsquare }, + { 0x339C, glyph_squaremm }, + { 0x339D, glyph_squarecm }, + { 0x339E, glyph_squarekm }, + { 0x339F, glyph_mmsquaredsquare }, + { 0x33A0, glyph_cmsquaredsquare }, + { 0x33A1, glyph_squaremsquared }, + { 0x33A2, glyph_kmsquaredsquare }, + { 0x33A3, glyph_mmcubedsquare }, + { 0x33A4, glyph_cmcubedsquare }, + { 0x33A5, glyph_mcubedsquare }, + { 0x33A6, glyph_kmcubedsquare }, + { 0x33A7, glyph_moverssquare }, + { 0x33A8, glyph_moverssquaredsquare }, + { 0x33A9, glyph_pasquare }, + { 0x33AA, glyph_kpasquare }, + { 0x33AB, glyph_mpasquare }, + { 0x33AC, glyph_gpasquare }, + { 0x33AD, glyph_radsquare }, + { 0x33AE, glyph_radoverssquare }, + { 0x33AF, glyph_radoverssquaredsquare }, + { 0x33B0, glyph_pssquare }, + { 0x33B1, glyph_nssquare }, + { 0x33B2, glyph_mussquare }, + { 0x33B3, glyph_mssquare }, + { 0x33B4, glyph_pvsquare }, + { 0x33B5, glyph_nvsquare }, + { 0x33B6, glyph_muvsquare }, + { 0x33B7, glyph_mvsquare }, + { 0x33B8, glyph_kvsquare }, + { 0x33B9, glyph_mvmegasquare }, + { 0x33BA, glyph_pwsquare }, + { 0x33BB, glyph_nwsquare }, + { 0x33BC, glyph_muwsquare }, + { 0x33BD, glyph_mwsquare }, + { 0x33BE, glyph_kwsquare }, + { 0x33BF, glyph_mwmegasquare }, + { 0x33C0, glyph_kohmsquare }, + { 0x33C1, glyph_mohmsquare }, + { 0x33C2, glyph_amsquare }, + { 0x33C3, glyph_bqsquare }, + { 0x33C4, glyph_squarecc }, + { 0x33C5, glyph_cdsquare }, + { 0x33C6, glyph_coverkgsquare }, + { 0x33C7, glyph_cosquare }, + { 0x33C8, glyph_dbsquare }, + { 0x33C9, glyph_gysquare }, + { 0x33CA, glyph_hasquare }, + { 0x33CB, glyph_HPsquare }, + { 0x33CD, glyph_KKsquare }, + { 0x33CE, glyph_squarekmcapital }, + { 0x33CF, glyph_ktsquare }, + { 0x33D0, glyph_lmsquare }, + { 0x33D1, glyph_squareln }, + { 0x33D2, glyph_squarelog }, + { 0x33D3, glyph_lxsquare }, + { 0x33D4, glyph_mbsquare }, + { 0x33D5, glyph_squaremil }, + { 0x33D6, glyph_molsquare }, + { 0x33D8, glyph_pmsquare }, + { 0x33DB, glyph_srsquare }, + { 0x33DC, glyph_svsquare }, + { 0x33DD, glyph_wbsquare }, + { 0x5344, glyph_twentyhangzhou }, + { 0xF884, glyph_maihanakatleftthai }, + { 0xF885, glyph_saraileftthai }, + { 0xF886, glyph_saraiileftthai }, + { 0xF887, glyph_saraueleftthai }, + { 0xF888, glyph_saraueeleftthai }, + { 0xF889, glyph_maitaikhuleftthai }, + { 0xF88A, glyph_maiekupperleftthai }, + { 0xF88B, glyph_maieklowrightthai }, + { 0xF88C, glyph_maieklowleftthai }, + { 0xF88D, glyph_maithoupperleftthai }, + { 0xF88E, glyph_maitholowrightthai }, + { 0xF88F, glyph_maitholowleftthai }, + { 0xF890, glyph_maitriupperleftthai }, + { 0xF891, glyph_maitrilowrightthai }, + { 0xF892, glyph_maitrilowleftthai }, + { 0xF893, glyph_maichattawaupperleftthai }, + { 0xF894, glyph_maichattawalowrightthai }, + { 0xF895, glyph_maichattawalowleftthai }, + { 0xF896, glyph_thanthakhatupperleftthai }, + { 0xF897, glyph_thanthakhatlowrightthai }, + { 0xF898, glyph_thanthakhatlowleftthai }, + { 0xF899, glyph_nikhahitleftthai }, + { 0xFB20, glyph_ayinaltonehebrew }, + { 0xFB2E, glyph_alefpatahhebrew }, + { 0xFB2F, glyph_alefqamatshebrew }, + { 0xFB30, glyph_alefdageshhebrew }, + { 0xFB43, glyph_pefinaldageshhebrew }, + { 0xFB48, glyph_reshdageshhebrew }, + { 0xFB4C, glyph_betrafehebrew }, + { 0xFB4D, glyph_kafrafehebrew }, + { 0xFB4E, glyph_perafehebrew }, + { 0xFB4F, glyph_aleflamedhebrew }, + { 0xFB57, glyph_pehfinalarabic }, + { 0xFB58, glyph_pehinitialarabic }, + { 0xFB59, glyph_pehmedialarabic }, + { 0xFB67, glyph_ttehfinalarabic }, + { 0xFB68, glyph_ttehinitialarabic }, + { 0xFB69, glyph_ttehmedialarabic }, + { 0xFB6B, glyph_vehfinalarabic }, + { 0xFB6C, glyph_vehinitialarabic }, + { 0xFB6D, glyph_vehmedialarabic }, + { 0xFB7B, glyph_tchehfinalarabic }, + { 0xFB7C, glyph_tchehinitialarabic }, + { 0xFB7D, glyph_tchehmedialarabic }, + { 0xFB89, glyph_ddalfinalarabic }, + { 0xFB8B, glyph_jehfinalarabic }, + { 0xFB8D, glyph_rrehfinalarabic }, + { 0xFB93, glyph_gaffinalarabic }, + { 0xFB94, glyph_gafinitialarabic }, + { 0xFB95, glyph_gafmedialarabic }, + { 0xFB9F, glyph_noonghunnafinalarabic }, + { 0xFBA4, glyph_hehhamzaaboveisolatedarabic }, + { 0xFBA5, glyph_hehhamzaabovefinalarabic }, + { 0xFBA7, glyph_hehfinalaltonearabic }, + { 0xFBA8, glyph_hehinitialaltonearabic }, + { 0xFBA9, glyph_hehmedialaltonearabic }, + { 0xFBAF, glyph_yehbarreefinalarabic }, + { 0xFC08, glyph_behmeemisolatedarabic }, + { 0xFC0B, glyph_tehjeemisolatedarabic }, + { 0xFC0C, glyph_tehhahisolatedarabic }, + { 0xFC0E, glyph_tehmeemisolatedarabic }, + { 0xFC48, glyph_meemmeemisolatedarabic }, + { 0xFC4B, glyph_noonjeemisolatedarabic }, + { 0xFC4E, glyph_noonmeemisolatedarabic }, + { 0xFC58, glyph_yehmeemisolatedarabic }, + { 0xFC5E, glyph_shaddadammatanarabic }, + { 0xFC5F, glyph_shaddakasratanarabic }, + { 0xFC60, glyph_shaddafathaarabic }, + { 0xFC61, glyph_shaddadammaarabic }, + { 0xFC62, glyph_shaddakasraarabic }, + { 0xFC6D, glyph_behnoonfinalarabic }, + { 0xFC73, glyph_tehnoonfinalarabic }, + { 0xFC8D, glyph_noonnoonfinalarabic }, + { 0xFC94, glyph_yehnoonfinalarabic }, + { 0xFC9F, glyph_behmeeminitialarabic }, + { 0xFCA1, glyph_tehjeeminitialarabic }, + { 0xFCA2, glyph_tehhahinitialarabic }, + { 0xFCA4, glyph_tehmeeminitialarabic }, + { 0xFCC9, glyph_lamjeeminitialarabic }, + { 0xFCCA, glyph_lamhahinitialarabic }, + { 0xFCCB, glyph_lamkhahinitialarabic }, + { 0xFCCC, glyph_lammeeminitialarabic }, + { 0xFCD1, glyph_meemmeeminitialarabic }, + { 0xFCD2, glyph_noonjeeminitialarabic }, + { 0xFCD5, glyph_noonmeeminitialarabic }, + { 0xFCDD, glyph_yehmeeminitialarabic }, + { 0xFD3E, glyph_parenleftaltonearabic }, + { 0xFD3F, glyph_parenrightaltonearabic }, + { 0xFD88, glyph_lammeemhahinitialarabic }, + { 0xFDF2, glyph_lamlamhehisolatedarabic }, + { 0xFDFA, glyph_sallallahoualayhewasallamarabic }, + { 0xFE30, glyph_twodotleadervertical }, + { 0xFE31, glyph_emdashvertical }, + { 0xFE32, glyph_endashvertical }, + { 0xFE33, glyph_underscorevertical }, + { 0xFE34, glyph_wavyunderscorevertical }, + { 0xFE35, glyph_parenleftvertical }, + { 0xFE36, glyph_parenrightvertical }, + { 0xFE37, glyph_braceleftvertical }, + { 0xFE38, glyph_bracerightvertical }, + { 0xFE39, glyph_tortoiseshellbracketleftvertical }, + { 0xFE3A, glyph_tortoiseshellbracketrightvertical }, + { 0xFE3B, glyph_blacklenticularbracketleftvertical }, + { 0xFE3C, glyph_blacklenticularbracketrightvertical }, + { 0xFE3D, glyph_dblanglebracketleftvertical }, + { 0xFE3E, glyph_dblanglebracketrightvertical }, + { 0xFE3F, glyph_anglebracketleftvertical }, + { 0xFE40, glyph_anglebracketrightvertical }, + { 0xFE41, glyph_cornerbracketleftvertical }, + { 0xFE42, glyph_cornerbracketrightvertical }, + { 0xFE43, glyph_whitecornerbracketleftvertical }, + { 0xFE44, glyph_whitecornerbracketrightvertical }, + { 0xFE49, glyph_overlinedashed }, + { 0xFE4A, glyph_overlinecenterline }, + { 0xFE4B, glyph_overlinewavy }, + { 0xFE4C, glyph_overlinedblwavy }, + { 0xFE4D, glyph_lowlinedashed }, + { 0xFE4E, glyph_lowlinecenterline }, + { 0xFE4F, glyph_underscorewavy }, + { 0xFE50, glyph_commasmall }, + { 0xFE52, glyph_periodsmall }, + { 0xFE54, glyph_semicolonsmall }, + { 0xFE55, glyph_colonsmall }, + { 0xFE59, glyph_parenleftsmall }, + { 0xFE5A, glyph_parenrightsmall }, + { 0xFE5B, glyph_braceleftsmall }, + { 0xFE5C, glyph_bracerightsmall }, + { 0xFE5D, glyph_tortoiseshellbracketleftsmall }, + { 0xFE5E, glyph_tortoiseshellbracketrightsmall }, + { 0xFE5F, glyph_numbersignsmall }, + { 0xFE61, glyph_asterisksmall }, + { 0xFE62, glyph_plussmall }, + { 0xFE63, glyph_hyphensmall }, + { 0xFE64, glyph_lesssmall }, + { 0xFE65, glyph_greatersmall }, + { 0xFE66, glyph_equalsmall }, + { 0xFE69, glyph_dollarsmall }, + { 0xFE6A, glyph_percentsmall }, + { 0xFE6B, glyph_atsmall }, + { 0xFE82, glyph_alefmaddaabovefinalarabic }, + { 0xFE84, glyph_alefhamzaabovefinalarabic }, + { 0xFE86, glyph_wawhamzaabovefinalarabic }, + { 0xFE88, glyph_alefhamzabelowfinalarabic }, + { 0xFE8A, glyph_yehhamzaabovefinalarabic }, + { 0xFE8B, glyph_yehhamzaaboveinitialarabic }, + { 0xFE8C, glyph_yehhamzaabovemedialarabic }, + { 0xFE8E, glyph_aleffinalarabic }, + { 0xFE90, glyph_behfinalarabic }, + { 0xFE91, glyph_behinitialarabic }, + { 0xFE92, glyph_behmedialarabic }, + { 0xFE94, glyph_tehmarbutafinalarabic }, + { 0xFE96, glyph_tehfinalarabic }, + { 0xFE97, glyph_tehinitialarabic }, + { 0xFE98, glyph_tehmedialarabic }, + { 0xFE9A, glyph_thehfinalarabic }, + { 0xFE9B, glyph_thehinitialarabic }, + { 0xFE9C, glyph_thehmedialarabic }, + { 0xFE9E, glyph_jeemfinalarabic }, + { 0xFE9F, glyph_jeeminitialarabic }, + { 0xFEA0, glyph_jeemmedialarabic }, + { 0xFEA2, glyph_hahfinalarabic }, + { 0xFEA3, glyph_hahinitialarabic }, + { 0xFEA4, glyph_hahmedialarabic }, + { 0xFEA6, glyph_khahfinalarabic }, + { 0xFEA7, glyph_khahinitialarabic }, + { 0xFEA8, glyph_khahmedialarabic }, + { 0xFEAA, glyph_dalfinalarabic }, + { 0xFEAC, glyph_thalfinalarabic }, + { 0xFEAE, glyph_rehfinalarabic }, + { 0xFEB0, glyph_zainfinalarabic }, + { 0xFEB2, glyph_seenfinalarabic }, + { 0xFEB3, glyph_seeninitialarabic }, + { 0xFEB4, glyph_seenmedialarabic }, + { 0xFEB6, glyph_sheenfinalarabic }, + { 0xFEB7, glyph_sheeninitialarabic }, + { 0xFEB8, glyph_sheenmedialarabic }, + { 0xFEBA, glyph_sadfinalarabic }, + { 0xFEBB, glyph_sadinitialarabic }, + { 0xFEBC, glyph_sadmedialarabic }, + { 0xFEBE, glyph_dadfinalarabic }, + { 0xFEBF, glyph_dadinitialarabic }, + { 0xFEC0, glyph_dadmedialarabic }, + { 0xFEC2, glyph_tahfinalarabic }, + { 0xFEC3, glyph_tahinitialarabic }, + { 0xFEC4, glyph_tahmedialarabic }, + { 0xFEC6, glyph_zahfinalarabic }, + { 0xFEC7, glyph_zahinitialarabic }, + { 0xFEC8, glyph_zahmedialarabic }, + { 0xFECA, glyph_ainfinalarabic }, + { 0xFECB, glyph_aininitialarabic }, + { 0xFECC, glyph_ainmedialarabic }, + { 0xFECE, glyph_ghainfinalarabic }, + { 0xFECF, glyph_ghaininitialarabic }, + { 0xFED0, glyph_ghainmedialarabic }, + { 0xFED2, glyph_fehfinalarabic }, + { 0xFED3, glyph_fehinitialarabic }, + { 0xFED4, glyph_fehmedialarabic }, + { 0xFED6, glyph_qaffinalarabic }, + { 0xFED7, glyph_qafinitialarabic }, + { 0xFED8, glyph_qafmedialarabic }, + { 0xFEDA, glyph_kaffinalarabic }, + { 0xFEDB, glyph_kafinitialarabic }, + { 0xFEDC, glyph_kafmedialarabic }, + { 0xFEDE, glyph_lamfinalarabic }, + { 0xFEDF, glyph_laminitialarabic }, + { 0xFEE0, glyph_lammedialarabic }, + { 0xFEE2, glyph_meemfinalarabic }, + { 0xFEE3, glyph_meeminitialarabic }, + { 0xFEE4, glyph_meemmedialarabic }, + { 0xFEE6, glyph_noonfinalarabic }, + { 0xFEE7, glyph_nooninitialarabic }, + { 0xFEE8, glyph_noonmedialarabic }, + { 0xFEEB, glyph_hehinitialarabic }, + { 0xFEEC, glyph_hehmedialarabic }, + { 0xFEEE, glyph_wawfinalarabic }, + { 0xFEF0, glyph_alefmaksurafinalarabic }, + { 0xFEF2, glyph_yehfinalarabic }, + { 0xFEF5, glyph_lamalefmaddaaboveisolatedarabic }, + { 0xFEF6, glyph_lamalefmaddaabovefinalarabic }, + { 0xFEF7, glyph_lamalefhamzaaboveisolatedarabic }, + { 0xFEF8, glyph_lamalefhamzaabovefinalarabic }, + { 0xFEF9, glyph_lamalefhamzabelowisolatedarabic }, + { 0xFEFA, glyph_lamalefhamzabelowfinalarabic }, + { 0xFEFB, glyph_lamalefisolatedarabic }, + { 0xFEFC, glyph_lamaleffinalarabic }, + { 0xFEFF, glyph_zerowidthjoiner }, + { 0xFF01, glyph_exclammonospace }, + { 0xFF02, glyph_quotedblmonospace }, + { 0xFF03, glyph_numbersignmonospace }, + { 0xFF04, glyph_dollarmonospace }, + { 0xFF05, glyph_percentmonospace }, + { 0xFF06, glyph_ampersandmonospace }, + { 0xFF07, glyph_quotesinglemonospace }, + { 0xFF08, glyph_parenleftmonospace }, + { 0xFF09, glyph_parenrightmonospace }, + { 0xFF0A, glyph_asteriskmonospace }, + { 0xFF0B, glyph_plusmonospace }, + { 0xFF0C, glyph_commamonospace }, + { 0xFF0D, glyph_hyphenmonospace }, + { 0xFF0E, glyph_periodmonospace }, + { 0xFF0F, glyph_slashmonospace }, + { 0xFF10, glyph_zeromonospace }, + { 0xFF11, glyph_onemonospace }, + { 0xFF12, glyph_twomonospace }, + { 0xFF13, glyph_threemonospace }, + { 0xFF14, glyph_fourmonospace }, + { 0xFF15, glyph_fivemonospace }, + { 0xFF16, glyph_sixmonospace }, + { 0xFF17, glyph_sevenmonospace }, + { 0xFF18, glyph_eightmonospace }, + { 0xFF19, glyph_ninemonospace }, + { 0xFF1A, glyph_colonmonospace }, + { 0xFF1B, glyph_semicolonmonospace }, + { 0xFF1C, glyph_lessmonospace }, + { 0xFF1D, glyph_equalmonospace }, + { 0xFF1E, glyph_greatermonospace }, + { 0xFF1F, glyph_questionmonospace }, + { 0xFF20, glyph_atmonospace }, + { 0xFF21, glyph_Amonospace }, + { 0xFF22, glyph_Bmonospace }, + { 0xFF23, glyph_Cmonospace }, + { 0xFF24, glyph_Dmonospace }, + { 0xFF25, glyph_Emonospace }, + { 0xFF26, glyph_Fmonospace }, + { 0xFF27, glyph_Gmonospace }, + { 0xFF28, glyph_Hmonospace }, + { 0xFF29, glyph_Imonospace }, + { 0xFF2A, glyph_Jmonospace }, + { 0xFF2B, glyph_Kmonospace }, + { 0xFF2C, glyph_Lmonospace }, + { 0xFF2D, glyph_Mmonospace }, + { 0xFF2E, glyph_Nmonospace }, + { 0xFF2F, glyph_Omonospace }, + { 0xFF30, glyph_Pmonospace }, + { 0xFF31, glyph_Qmonospace }, + { 0xFF32, glyph_Rmonospace }, + { 0xFF33, glyph_Smonospace }, + { 0xFF34, glyph_Tmonospace }, + { 0xFF35, glyph_Umonospace }, + { 0xFF36, glyph_Vmonospace }, + { 0xFF37, glyph_Wmonospace }, + { 0xFF38, glyph_Xmonospace }, + { 0xFF39, glyph_Ymonospace }, + { 0xFF3A, glyph_Zmonospace }, + { 0xFF3B, glyph_bracketleftmonospace }, + { 0xFF3C, glyph_backslashmonospace }, + { 0xFF3D, glyph_bracketrightmonospace }, + { 0xFF3E, glyph_asciicircummonospace }, + { 0xFF3F, glyph_underscoremonospace }, + { 0xFF40, glyph_gravemonospace }, + { 0xFF41, glyph_amonospace }, + { 0xFF42, glyph_bmonospace }, + { 0xFF43, glyph_cmonospace }, + { 0xFF44, glyph_dmonospace }, + { 0xFF45, glyph_emonospace }, + { 0xFF46, glyph_fmonospace }, + { 0xFF47, glyph_gmonospace }, + { 0xFF48, glyph_hmonospace }, + { 0xFF49, glyph_imonospace }, + { 0xFF4A, glyph_jmonospace }, + { 0xFF4B, glyph_kmonospace }, + { 0xFF4C, glyph_lmonospace }, + { 0xFF4D, glyph_mmonospace }, + { 0xFF4E, glyph_nmonospace }, + { 0xFF4F, glyph_omonospace }, + { 0xFF50, glyph_pmonospace }, + { 0xFF51, glyph_qmonospace }, + { 0xFF52, glyph_rmonospace }, + { 0xFF53, glyph_smonospace }, + { 0xFF54, glyph_tmonospace }, + { 0xFF55, glyph_umonospace }, + { 0xFF56, glyph_vmonospace }, + { 0xFF57, glyph_wmonospace }, + { 0xFF58, glyph_xmonospace }, + { 0xFF59, glyph_ymonospace }, + { 0xFF5A, glyph_zmonospace }, + { 0xFF5B, glyph_braceleftmonospace }, + { 0xFF5C, glyph_barmonospace }, + { 0xFF5D, glyph_bracerightmonospace }, + { 0xFF5E, glyph_asciitildemonospace }, + { 0xFF61, glyph_periodhalfwidth }, + { 0xFF62, glyph_cornerbracketlefthalfwidth }, + { 0xFF63, glyph_cornerbracketrighthalfwidth }, + { 0xFF64, glyph_ideographiccommaleft }, + { 0xFF65, glyph_middledotkatakanahalfwidth }, + { 0xFF66, glyph_wokatakanahalfwidth }, + { 0xFF67, glyph_asmallkatakanahalfwidth }, + { 0xFF68, glyph_ismallkatakanahalfwidth }, + { 0xFF69, glyph_usmallkatakanahalfwidth }, + { 0xFF6A, glyph_esmallkatakanahalfwidth }, + { 0xFF6B, glyph_osmallkatakanahalfwidth }, + { 0xFF6C, glyph_yasmallkatakanahalfwidth }, + { 0xFF6D, glyph_yusmallkatakanahalfwidth }, + { 0xFF6E, glyph_yosmallkatakanahalfwidth }, + { 0xFF6F, glyph_tusmallkatakanahalfwidth }, + { 0xFF70, glyph_katahiraprolongmarkhalfwidth }, + { 0xFF71, glyph_akatakanahalfwidth }, + { 0xFF72, glyph_ikatakanahalfwidth }, + { 0xFF73, glyph_ukatakanahalfwidth }, + { 0xFF74, glyph_ekatakanahalfwidth }, + { 0xFF75, glyph_okatakanahalfwidth }, + { 0xFF76, glyph_kakatakanahalfwidth }, + { 0xFF77, glyph_kikatakanahalfwidth }, + { 0xFF78, glyph_kukatakanahalfwidth }, + { 0xFF79, glyph_kekatakanahalfwidth }, + { 0xFF7A, glyph_kokatakanahalfwidth }, + { 0xFF7B, glyph_sakatakanahalfwidth }, + { 0xFF7C, glyph_sikatakanahalfwidth }, + { 0xFF7D, glyph_sukatakanahalfwidth }, + { 0xFF7E, glyph_sekatakanahalfwidth }, + { 0xFF7F, glyph_sokatakanahalfwidth }, + { 0xFF80, glyph_takatakanahalfwidth }, + { 0xFF81, glyph_tikatakanahalfwidth }, + { 0xFF82, glyph_tukatakanahalfwidth }, + { 0xFF83, glyph_tekatakanahalfwidth }, + { 0xFF84, glyph_tokatakanahalfwidth }, + { 0xFF85, glyph_nakatakanahalfwidth }, + { 0xFF86, glyph_nikatakanahalfwidth }, + { 0xFF87, glyph_nukatakanahalfwidth }, + { 0xFF88, glyph_nekatakanahalfwidth }, + { 0xFF89, glyph_nokatakanahalfwidth }, + { 0xFF8A, glyph_hakatakanahalfwidth }, + { 0xFF8B, glyph_hikatakanahalfwidth }, + { 0xFF8C, glyph_hukatakanahalfwidth }, + { 0xFF8D, glyph_hekatakanahalfwidth }, + { 0xFF8E, glyph_hokatakanahalfwidth }, + { 0xFF8F, glyph_makatakanahalfwidth }, + { 0xFF90, glyph_mikatakanahalfwidth }, + { 0xFF91, glyph_mukatakanahalfwidth }, + { 0xFF92, glyph_mekatakanahalfwidth }, + { 0xFF93, glyph_mokatakanahalfwidth }, + { 0xFF94, glyph_yakatakanahalfwidth }, + { 0xFF95, glyph_yukatakanahalfwidth }, + { 0xFF96, glyph_yokatakanahalfwidth }, + { 0xFF97, glyph_rakatakanahalfwidth }, + { 0xFF98, glyph_rikatakanahalfwidth }, + { 0xFF99, glyph_rukatakanahalfwidth }, + { 0xFF9A, glyph_rekatakanahalfwidth }, + { 0xFF9B, glyph_rokatakanahalfwidth }, + { 0xFF9C, glyph_wakatakanahalfwidth }, + { 0xFF9D, glyph_nkatakanahalfwidth }, + { 0xFF9E, glyph_voicedmarkkanahalfwidth }, + { 0xFF9F, glyph_semivoicedmarkkanahalfwidth }, + { 0xFFE0, glyph_centmonospace }, + { 0xFFE1, glyph_sterlingmonospace }, + { 0xFFE3, glyph_macronmonospace }, + { 0xFFE5, glyph_yenmonospace }, + { 0xFFE6, glyph_wonmonospace }, +}; /* tab_uni2diffagl */ + +/* List of all ambiguous AGL version 1.2 glyph names + * (see chapter 4.c. Double-mappings in + * http://partners.adobe.com/asn/tech/type/unicodegn-old.jsp) + */ + +static const pdc_glyph_tab tab_double_mappping[] = +{ +#ifndef PDFLIB_EBCDIC + { 0x0394, glyph_Delta }, /* Deltagreek */ + { 0x03A9, glyph_Omega }, /* Omegagreek */ + { 0xF6C1, glyph_Scedilla }, /* (CUS) */ + { 0x0162, glyph_Tcommaaccent }, /* (wrong mapping) */ + { 0x2215, glyph_fraction }, /* divisionslash */ + { 0x00AD, glyph_hyphen }, /* sfthyphen */ + { 0x02C9, glyph_macron }, /* firsttonechinese */ + { 0x03BC, glyph_mu }, /* mugreek */ + { 0x2219, glyph_periodcentered }, /* bulletoperator */ + { 0xF6C2, glyph_scedilla }, /* (CUS) */ + { 0x00A0, glyph_space }, /* nbspace */ + { 0x0163, glyph_tcommaaccent }, /* (wrong mapping) */ +#else +#endif +}; + + +/* This is the list of all character names of the Adobe + * standard Latin character set and the set of named characters + * in the Symbol font, documented in Appendix D of PDF Reference. + */ + +static const char *pc_standard_latin_charset[] = +{ +#ifndef PDFLIB_EBCDIC + glyph_A, + glyph_AE, + glyph_Aacute, + glyph_Acircumflex, + glyph_Adieresis, + glyph_Agrave, + glyph_Alpha, + glyph_Aring, + glyph_Atilde, + glyph_B, + glyph_Beta, + glyph_C, + glyph_Ccedilla, + glyph_Chi, + glyph_D, + glyph_Delta, + glyph_E, + glyph_Eacute, + glyph_Ecircumflex, + glyph_Edieresis, + glyph_Egrave, + glyph_Epsilon, + glyph_Eta, + glyph_Eth, + glyph_Euro, + glyph_F, + glyph_G, + glyph_Gamma, + glyph_H, + glyph_I, + glyph_Iacute, + glyph_Icircumflex, + glyph_Idieresis, + glyph_Ifraktur, + glyph_Igrave, + glyph_Iota, + glyph_J, + glyph_K, + glyph_Kappa, + glyph_L, + glyph_Lambda, + glyph_Lslash, + glyph_M, + glyph_Mu, + glyph_N, + glyph_Ntilde, + glyph_Nu, + glyph_O, + glyph_OE, + glyph_Oacute, + glyph_Ocircumflex, + glyph_Odieresis, + glyph_Ograve, + glyph_Omega, + glyph_Omicron, + glyph_Oslash, + glyph_Otilde, + glyph_P, + glyph_Phi, + glyph_Pi, + glyph_Psi, + glyph_Q, + glyph_R, + glyph_Rfraktur, + glyph_Rho, + glyph_S, + glyph_Scaron, + glyph_Sigma, + glyph_T, + glyph_Tau, + glyph_Theta, + glyph_Thorn, + glyph_U, + glyph_Uacute, + glyph_Ucircumflex, + glyph_Udieresis, + glyph_Ugrave, + glyph_Upsilon, + glyph_Upsilon1, + glyph_V, + glyph_W, + glyph_X, + glyph_Xi, + glyph_Y, + glyph_Yacute, + glyph_Ydieresis, + glyph_Z, + glyph_Zcaron, + glyph_Zeta, + glyph_a, + glyph_aacute, + glyph_acircumflex, + glyph_acute, + glyph_adieresis, + glyph_ae, + glyph_agrave, + glyph_aleph, + glyph_alpha, + glyph_ampersand, + glyph_angle, + glyph_angleleft, + glyph_angleright, + glyph_approxequal, + glyph_aring, + glyph_arrowboth, + glyph_arrowdblboth, + glyph_arrowdbldown, + glyph_arrowdblleft, + glyph_arrowdblright, + glyph_arrowdblup, + glyph_arrowdown, + glyph_arrowhorizex, + glyph_arrowleft, + glyph_arrowright, + glyph_arrowup, + glyph_arrowvertex, + glyph_asciicircum, + glyph_asciitilde, + glyph_asterisk, + glyph_asteriskmath, + glyph_at, + glyph_atilde, + glyph_b, + glyph_backslash, + glyph_bar, + glyph_beta, + glyph_braceex, + glyph_braceleft, + glyph_braceleftbt, + glyph_braceleftmid, + glyph_bracelefttp, + glyph_braceright, + glyph_bracerightbt, + glyph_bracerightmid, + glyph_bracerighttp, + glyph_bracketleft, + glyph_bracketleftbt, + glyph_bracketleftex, + glyph_bracketlefttp, + glyph_bracketright, + glyph_bracketrightbt, + glyph_bracketrightex, + glyph_bracketrighttp, + glyph_breve, + glyph_brokenbar, + glyph_bullet, + glyph_c, + glyph_caron, + glyph_carriagereturn, + glyph_ccedilla, + glyph_cedilla, + glyph_cent, + glyph_chi, + glyph_circlemultiply, + glyph_circleplus, + glyph_circumflex, + glyph_club, + glyph_colon, + glyph_comma, + glyph_congruent, + glyph_copyright, + glyph_copyrightsans, + glyph_copyrightserif, + glyph_currency, + glyph_d, + glyph_dagger, + glyph_daggerdbl, + glyph_degree, + glyph_delta, + glyph_diamond, + glyph_dieresis, + glyph_divide, + glyph_dollar, + glyph_dotaccent, + glyph_dotlessi, + glyph_dotmath, + glyph_e, + glyph_eacute, + glyph_ecircumflex, + glyph_edieresis, + glyph_egrave, + glyph_eight, + glyph_element, + glyph_ellipsis, + glyph_emdash, + glyph_emptyset, + glyph_endash, + glyph_epsilon, + glyph_equal, + glyph_equivalence, + glyph_eta, + glyph_eth, + glyph_exclam, + glyph_exclamdown, + glyph_existential, + glyph_f, + glyph_fi, + glyph_five, + glyph_fl, + glyph_florin, + glyph_four, + glyph_fraction, + glyph_g, + glyph_gamma, + glyph_germandbls, + glyph_gradient, + glyph_grave, + glyph_greater, + glyph_greaterequal, + glyph_guillemotleft, + glyph_guillemotright, + glyph_guilsinglleft, + glyph_guilsinglright, + glyph_h, + glyph_heart, + glyph_hungarumlaut, + glyph_hyphen, + glyph_i, + glyph_iacute, + glyph_icircumflex, + glyph_idieresis, + glyph_igrave, + glyph_infinity, + glyph_integral, + glyph_integralbt, + glyph_integralex, + glyph_integraltp, + glyph_intersection, + glyph_iota, + glyph_j, + glyph_k, + glyph_kappa, + glyph_l, + glyph_lambda, + glyph_less, + glyph_lessequal, + glyph_logicaland, + glyph_logicalnot, + glyph_logicalor, + glyph_lozenge, + glyph_lslash, + glyph_m, + glyph_macron, + glyph_minus, + glyph_minute, + glyph_mu, + glyph_multiply, + glyph_n, + glyph_nine, + glyph_notelement, + glyph_notequal, + glyph_notsubset, + glyph_ntilde, + glyph_nu, + glyph_numbersign, + glyph_o, + glyph_oacute, + glyph_ocircumflex, + glyph_odieresis, + glyph_oe, + glyph_ogonek, + glyph_ograve, + glyph_omega, + glyph_omega1, + glyph_omicron, + glyph_one, + glyph_onehalf, + glyph_onequarter, + glyph_onesuperior, + glyph_ordfeminine, + glyph_ordmasculine, + glyph_oslash, + glyph_otilde, + glyph_p, + glyph_paragraph, + glyph_parenleft, + glyph_parenleftbt, + glyph_parenleftex, + glyph_parenlefttp, + glyph_parenright, + glyph_parenrightbt, + glyph_parenrightex, + glyph_parenrighttp, + glyph_partialdiff, + glyph_percent, + glyph_period, + glyph_periodcentered, + glyph_perpendicular, + glyph_perthousand, + glyph_phi, + glyph_phi1, + glyph_pi, + glyph_plus, + glyph_plusminus, + glyph_product, + glyph_propersubset, + glyph_propersuperset, + glyph_proportional, + glyph_psi, + glyph_q, + glyph_question, + glyph_questiondown, + glyph_quotedbl, + glyph_quotedblbase, + glyph_quotedblleft, + glyph_quotedblright, + glyph_quoteleft, + glyph_quoteright, + glyph_quotesinglbase, + glyph_quotesingle, + glyph_r, + glyph_radical, + glyph_radicalex, + glyph_reflexsubset, + glyph_reflexsuperset, + glyph_registered, + glyph_registersans, + glyph_registerserif, + glyph_rho, + glyph_ring, + glyph_s, + glyph_scaron, + glyph_second, + glyph_section, + glyph_semicolon, + glyph_seven, + glyph_sigma, + glyph_sigma1, + glyph_similar, + glyph_six, + glyph_slash, + glyph_space, + glyph_spade, + glyph_sterling, + glyph_suchthat, + glyph_summation, + glyph_t, + glyph_tau, + glyph_therefore, + glyph_theta, + glyph_theta1, + glyph_thorn, + glyph_three, + glyph_threequarters, + glyph_threesuperior, + glyph_tilde, + glyph_trademark, + glyph_trademarksans, + glyph_trademarkserif, + glyph_two, + glyph_twosuperior, + glyph_u, + glyph_uacute, + glyph_ucircumflex, + glyph_udieresis, + glyph_ugrave, + glyph_underscore, + glyph_union, + glyph_universal, + glyph_upsilon, + glyph_v, + glyph_w, + glyph_weierstrass, + glyph_x, + glyph_xi, + glyph_y, + glyph_yacute, + glyph_ydieresis, + glyph_yen, + glyph_z, + glyph_zcaron, + glyph_zero, + glyph_zeta, +#else +#endif +}; + + +/* --------------------------------- TET tables ---------------------------- */ + + +#endif /* PC_CHARTABS_H */ diff --git a/src/pdflib/pdcore/pc_classic.h b/src/pdflib/pdcore/pc_classic.h new file mode 100644 index 0000000..cd6c22c --- /dev/null +++ b/src/pdflib/pdcore/pc_classic.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_classic.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Header for CodeWarrior to activate Classic builds (without CarbonLib). + * + */ + +/* + * This must only be set for Classic builds. It is not used for the + * standard build which is based on CarbonLib. + */ + +#define PDF_TARGET_API_MAC_CLASSIC diff --git a/src/pdflib/pdcore/pc_config.h b/src/pdflib/pdcore/pc_config.h new file mode 100644 index 0000000..945c9d1 --- /dev/null +++ b/src/pdflib/pdcore/pc_config.h @@ -0,0 +1,388 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_config.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib portability and configuration definitions + * + */ + +#ifndef PC_CONFIG_H +#define PC_CONFIG_H + +/* ------------------------ feature configuration ------------------- */ + +/* zlib compression support */ +#define HAVE_LIBZ + +/* ---------------------------- platform definitions ------------------------ */ + +/* #undef this if your platform doesn't support environment variables */ +#define HAVE_ENVVARS + +/* Compilers which are not strictly ANSI conforming can set PDF_VOLATILE + * to an empty value. + */ +#ifndef PDF_VOLATILE +#define PDF_VOLATILE volatile +#endif + +/* + * Byte order + * WORDS_BIGENDIAN will be set by the configure script on most platforms. + * Only on platforms where there is no configure script we must set the + * endianness explicitly (most importantly CodeWarrior on the Mac) + */ +#undef PDC_ISBIGENDIAN +#if defined(WORDS_BIGENDIAN) || defined(__POWERPC__) || defined(__MC68K__) +#define PDC_ISBIGENDIAN 1 +#if !defined(WORDS_BIGENDIAN) +#define WORDS_BIGENDIAN +#endif +#else +#define PDC_ISBIGENDIAN 0 +#endif + +/* + * Define for compiler supporting file open function _wfopen + * for Unicode filenames. + */ +#undef PDC_UNICODE_FILENAME + +/* + * Define whether function char *strerror(int errnum) + * is available in the C runtime system + */ +#define PDC_HAS_STRERROR + + +/* ---------------------------------- WIN32 -------------------------------- */ + +/* try to identify Windows compilers */ + +#if (defined _WIN32 || defined __WATCOMC__ || defined __BORLANDC__ || \ + (defined(__MWERKS__) && defined(__INTEL__))) && !defined WIN32 +#define WIN32 +#endif /* <Windows compiler> && !defined WIN32 */ + +#ifdef WIN32 +#define WRITEMODE "wb" +#define APPENDMODE "ab" + +#ifdef _MSC_VER +#define _LARGEFILE_SOURCE +#endif + +#undef PDC_PATHSEP +#define PDC_PATHSEP "\\" + +#if defined(_WIN32_WCE) && (_WIN32_WCE >= 300) +#define PDF_PLATFORM "Windows CE" +#define WINCE +#undef HAVE_SETLOCALE +#undef HAVE_ENVVARS +#else +#if defined(WIN64) +#define PDF_PLATFORM "Win64" +#else +#define PDF_PLATFORM "Win32" +#endif +#endif + +#define PDC_TMPDIR_ENV "TMP" + +/* file open function "_wfopen" for Unicode filenames is available. +**/ +#if defined(_MSC_VER) && !defined(PDF_WIN98) +#define PDC_UNICODE_FILENAME +#endif + +#endif /* WIN32 */ + +/* some standard C library functions (eg. localtime()) are not reentrant +** and must be replaced with their "_r" equivalent (eg. localtime_r()). +*/ +#if !defined(WIN32) && !defined(__MVS__) && !defined(OS_ZOS_SASC) &&\ + !(defined(__MWERKS__) && (defined(__POWERPC__) || defined(__MC68K__))) +#define PDC_NEEDS_R_FUNCTIONS +#endif + +/* --------------------------------- Cygnus -------------------------------- */ + +#ifdef __CYGWIN__ +#define WRITEMODE "wb" +#define APPENDMODE "ab" +#ifdef DLL_EXPORT + #define PDFLIB_EXPORTS +#endif + +#endif /* __CYGWIN__ */ + +/* ---------------------------------- DJGPP -------------------------------- */ + +#ifdef __DJGPP__ +#define WRITEMODE "wb" +#define APPENDMODE "ab" +#define PDF_PLATFORM "Win32/DJGPP" +#endif /* __DJGPP__ */ + +/* ----------------------------------- OS/2 -------------------------------- */ + +/* + * Try to identify OS/2 compilers. + */ + +#if (defined __OS2__ || defined __EMX__) && !defined OS2 +#define OS2 +#endif + +#ifdef OS2 +#define WRITEMODE "wb" +#define APPENDMODE "ab" +#define PDF_PLATFORM "OS/2" +#endif /* OS2 */ + +/* --------------------------------- Mac OS X ------------------------------- */ + +/* try to identify the Mac OS X command line compiler */ + +#if (defined(__ppc__) && defined(__APPLE__)) \ + || (defined(__i386__) && defined(__APPLE__)) + +/* #define MACOSX CDPDF */ + +/* Mac OS X 10.2 (Jaguar) defines this, but we use it for Mac OS 9 below */ +#undef MAC + +#ifndef PDF_PLATFORM +#define PDF_PLATFORM "Mac OS X" +#endif +#endif /* Mac OS X */ + +/* --------------------------------- Mac OS 9 ------------------------------- */ + +/* try to identify Mac OS 9 compilers */ + +#if (defined macintosh || defined __POWERPC__ || defined __CFM68K__) && \ + !defined MAC && !defined MACOSX && !defined __BEOS__ +#define MAC +#endif + +#undef MAC /* CDPDF */ +#undef MACOSX /* CDPDF */ + +#ifdef MAC +#define WRITEMODE "wb" +#define APPENDMODE "ab" +#define PDC_PATHSEP ":" + +#undef HAVE_ENVVARS + +#define PDF_PLATFORM "Mac OS 9" +#endif /* MAC */ + +/* ------------------ Carbon Handling for both Mac OS 9 and X --------------- */ + +#if defined(MAC) || defined(MACOSX) +/* + * By default we always build a carbonized version of the library, + * but allow non-Carbon builds to be triggered by setting the + * PDF_TARGET_API_MAC_CLASSIC symbol externally. + */ + +#ifdef PDF_TARGET_API_MAC_CLASSIC +#undef PDF_TYPE1_HOSTFONT_SUPPORTED +#else +#define PDF_TARGET_API_MAC_CARBON +#endif + +#if defined(PDF_TARGET_API_MAC_CARBON) && !defined(TARGET_API_MAC_CARBON) +#define TARGET_API_MAC_CARBON 1 +#endif + +#endif /* MAC */ + +/* ----------------------------------- BeOS --------------------------------- */ + +#ifdef __BEOS__ +#define PDF_PLATFORM "BeOS" +#endif /* __BEOS__ */ + +/* --------------------------------- AS/400 --------------------------------- */ + +/* try to identify the AS/400 compiler */ + +#if defined __ILEC400__ && !defined AS400 +#define AS400 +#endif + +#ifdef AS400 + +#pragma comment(copyright, \ + "(C) PDFlib GmbH, Muenchen, Germany (www.pdflib.com)") + +#if (_OS400_TGTVRM__>440) +# ifndef _LARGE_FILE_API + #error You need to compile this module with DEFINE(_LARGE_FILE_API) +# endif +# ifndef __TERASPACE__ + #error You need to compile this module with TERASPACE(*YES *TSIFC) +STGMDL(*TERASPACE) +# endif +#endif + +#define READTMODE "rb" +#define WRITEMODE "wb" +#define APPENDMODE "ab" + +#define PDF_PLATFORM "iSeries" + +#define WORDS_BIGENDIAN +#undef PDC_ISBIGENDIAN +#define PDC_ISBIGENDIAN 1 + +#endif /* AS400 */ + +/* --------------------- S/390 with Unix System Services -------------------- */ + +#ifdef OS390 + +#define WRITEMODE "wb" +#define APPENDMODE "ab" + +#undef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#undef PDC_ISBIGENDIAN +#define PDC_ISBIGENDIAN 1 + +#define PDC_NO_VSNPRINTF + +#endif /* OS390 */ + +/* -------------------------------- S/390 with MVS -------------------------- */ + +/* try to identify MVS (__MVS__ is #defined on USS and MVS!) + * I370 is used by SAS C + */ + +#if !defined(OS390) && (defined __MVS__ || defined I370) && !defined MVS +#define MVS +#endif + +#ifdef MVS + +#if defined(I370) +#define PDC_FILEQUOT "" +#else +#define READBMODE "rb,byteseek" +#define READBMODE_PLUS "rb+,byteseek" +#define PDC_FILEQUOT "'" +#endif +#define WRITEMODE "wb" +#define WRITEMODE_V "wb,recfm=v" +#define APPENDMODE "ab" + +#undef PDC_PATHSEP +#define PDC_PATHSEP "(" + +#undef PDC_PATHTERM +#define PDC_PATHTERM ")" + +#define PDF_PLATFORM "zSeries MVS" +#define PDF_OS390_MVS_RESOURCE + +#define WORDS_BIGENDIAN +#undef PDC_ISBIGENDIAN +#define PDC_ISBIGENDIAN 1 + +#define PDC_NO_VSNPRINTF + +#endif /* MVS */ + +/* ------------------------------------ VMS --------------------------------- */ + +/* No special handling required */ + +#ifdef VMS +/* Usually this will come from the build process */ +#ifndef PDF_PLATFORM +#define PDF_PLATFORM "VMS" +#endif +#define PDC_TMPDIR_ENV "SYS$SCRATCH" +#define PDC_PATHSEP_LOG ":" + +#define PDC_NO_VSNPRINTF + +#endif /* VMS */ + +/* --------------------------------- Defaults ------------------------------- */ + +/* CDPDF */ +#ifndef PDF_PLATFORM +#define PDF_PLATFORM "Default" +#endif /* !PDF_PLATFORM */ + +/* boolean for function fileno() exists +*/ +#ifndef PDC_FILENO_EXISTS +#define PDC_FILENO_EXISTS 1 +#endif /* !PDC_FILENO_EXISTS */ + +#ifndef READTMODE +#define READTMODE "r" +#endif /* !READTMODE */ + +#ifndef READBMODE +#define READBMODE "rb" +#endif /* !READBMODE */ + +#ifndef READBMODE_PLUS +#define READBMODE_PLUS "rb+" +#endif /* !READBMODE_PLUS */ + +#ifndef WRITEMODE +#define WRITEMODE "wb" +#endif /* !WRITEMODE */ + +#ifndef APPENDMODE +#define APPENDMODE "ab" +#endif /* !APPENDMODE */ + +#ifndef PDC_PATHSEP +#define PDC_PATHSEP "/" +#endif /* !PDC_PATHSEP */ + +#ifndef PDC_TMPDIR_ENV +#define PDC_TMPDIR_ENV "TMPDIR" +#endif /* !PDC_TMPDIR_ENV */ + +#ifdef _DEBUG +#define DEBUG +#endif /* _DEBUG */ + +#ifdef DEBUG +#define PDC_DEBUG +#endif /* DEBUG */ + +#define PDC_SCHAR_MIN (-128) +#define PDC_SCHAR_MAX 127 +#define PDC_UCHAR_MAX 255 +#define PDC_SHRT_MIN (-32768) +#define PDC_SHRT_MAX 32767 +#define PDC_USHRT_MAX 65535 +#define PDC_INT_MIN (-PDC_INT_MAX - 1) +#define PDC_INT_MAX 2147483647 +#define PDC_UINT_MAX 4294967295U + +#define PDC_OFFSET(type, field) ((unsigned int) &(((type *)NULL)->field)) + +#endif /* PC_CONFIG_H */ diff --git a/src/pdflib/pdcore/pc_contain.c b/src/pdflib/pdcore/pc_contain.c new file mode 100644 index 0000000..6a3cdfc --- /dev/null +++ b/src/pdflib/pdcore/pc_contain.c @@ -0,0 +1,518 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_contain.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib generic container classes + * + */ + +#include "pc_util.h" +#include "pc_contain.h" + + +/**************************** avl tree class ****************************/ + +typedef struct avl_node_s avl_node; + +struct avl_node_s +{ + const char *name; + int balance; + avl_node * left; + avl_node * right; +}; + +#undef COMMENT +#ifdef COMMENT + +before single rotate right; after insertion of X. + + root(-2) + + / \ + + lc(-1) +------+ + | rc | + / \ | | + | | + +------+ +------+ | | + | llc | | rlc | | n | + | | | | +------+ + | | | | + | | | | + | n | | n | + +------+ +------+ + + | + + X + + +after single rotate right. + + lc(0) + + / \ + + +------+ root(0) + | llc | + | | / \ + | | + | | +------+ +------+ + | n | | rlc | | rc | + +------+ | | | | + | | | | + | | | | | + | n | | n | + X +------+ +------+ + + + +before double rotate right; after insertion of X/Y. + + root(-2) + + / \ + + lc(+1) +------+ + | rc | + / \ | | + | | + +------+ rlc(-1/+1) | | + | llc | | | + | | / \ | | + | | | | + | | +------+ +------+ | n | + | | | lrlc | | rrlc | +------+ + | | | | | | + | | | | | | + | n | | n-1 | | n-1 | + +------+ +------+ +------+ + + | | + + X Y + + +after double rotate right: + + rlc(0) + + / \ + + lc(0/-1) root(+1/0) + + / \ / \ + + +------+ +------+ +------+ +------+ + | llc | | lrlc | | rrlc | | rc | + | | | | | | | | + | | | | | | | | + | | | n-1 | | n-1 | | | + | | +------+ +------+ | | + | | | | + | | | | | | + | n | | n | + +------+ X Y +------+ + + +avl_node * +avl_insert(avl_node *root, const char *name, pdc_bool *change_parent_balance) +{ + pdc_bool change_balance = pdc_false; + + if (root == 0) + { + avl_node *result = (avl_node *) malloc(sizeof (avl_node)); + + result->name = name; + result->balance = 0; + result->left = (avl_node *) 0; + result->right = (avl_node *) 0; + *change_parent_balance = pdc_true; + return result; + } + + if (strcmp(name, root->name) < 0) + { + root->left = avl_insert(root->left, name, &change_balance); + + if (change_balance && --root->balance < 0) + { + if (root->balance == -1) + { + *change_parent_balance = pdc_true; + } + else /* root->balance == -2 */ + { + avl_node *lc = root->left; /* left child */ + avl_node *rlc = lc->right; /* right of left child */ + + if (lc->balance == -1) /* single rotate right */ + { + root->left = rlc; + lc->right = root; + lc->balance = root->balance = 0; + return lc; + } + else /* double rotate right */ + { + root->balance = (rlc->balance == -1) ? +1 : 0; + lc->balance = (rlc->balance == +1) ? -1 : 0; + rlc->balance = 0; + lc->right = rlc->left; + rlc->left = lc; + root->left = rlc->right; + rlc->right = root; + return rlc; + } + } + } + } + else + { + root->right = avl_insert(root->right, name, &change_balance); + + if (change_balance && ++root->balance > 0) + { + if (root->balance == +1) + { + *change_parent_balance = pdc_true; + } + else /* root->balance == +2 */ + { + avl_node *rc = root->right; /* right child */ + avl_node *lrc = rc->left; /* left of right child */ + + if (rc->balance == +1) /* single rotate left */ + { + root->right = lrc; + rc->left = root; + rc->balance = root->balance = 0; + return rc; + } + else /* double rotate left */ + { + root->balance = (lrc->balance == +1) ? -1 : 0; + rc->balance = (lrc->balance == -1) ? +1 : 0; + lrc->balance = 0; + rc->left = lrc->right; + lrc->right = rc; + root->right = lrc->left; + lrc->left = root; + return lrc; + } + } + } + } + + return root; +} + +#endif /* COMMENT */ + +/***************************** vector class *****************************/ + +struct pdc_vtr_s +{ + pdc_core * pdc; + + pdc_ced ced; /* container entry descriptor */ + void * context; /* client context */ + + char ** ctab; /* chunk table */ + int ctab_size; /* current # of slots */ + int ctab_incr; + int chunk_size; /* # of items per chunk */ + int size; /* current # of items total */ +}; + + +static const pdc_vtr_parms vtr_dflt_parms = +{ + 0, /* init_size */ + 100, /* chunk_size */ + 10 /* ctab_incr */ +}; + +void +pdc_vtr_dflt_parms(pdc_vtr_parms *vp) +{ + *vp = vtr_dflt_parms; +} + + +static void +pdc_vtr_grow_ctab(pdc_vtr *v, int new_size) +{ + static const char fn[] = "pdc_vtr_grow_ctab"; + + int i; + + v->ctab = (char **) + pdc_realloc(v->pdc, v->ctab, (size_t) (new_size * sizeof (char *)), fn); + + for (i = v->ctab_size; i < new_size; ++i) + v->ctab[i] = (char *) 0; + + v->ctab_size = new_size; +} /* pdc_vtr_grow_ctab */ + + +pdc_vtr * +pdc_vtr_new( + pdc_core *pdc, + const pdc_ced *ced, + void *context, + const pdc_vtr_parms *parms) +{ + static const char fn[] = "pdc_vtr_new"; + + pdc_vtr *v = (pdc_vtr *) pdc_malloc(pdc, sizeof (pdc_vtr), fn); + + if (!parms) + parms = &vtr_dflt_parms; + + v->pdc = pdc; + v->ced = *ced; + v->context = context ? context : pdc; + + v->ctab = (char **) 0; + v->ctab_size = 0; + v->ctab_incr = parms->ctab_incr; + v->chunk_size = parms->chunk_size; + v->size = 0; + + if (parms->init_size != 0) + { + PDC_TRY (pdc) + { + pdc_vtr_resize(v, parms->init_size); + } + PDC_CATCH (pdc) + { + pdc_vtr_delete(v); + PDC_RETHROW(pdc); + } + } + + return v; +} /* pdc_vtr_new */ + + +void +pdc_vtr_delete(pdc_vtr *v) +{ + int cs = v->chunk_size; + int i; + + if (v->size != 0 && v->ced.release) + { + for (i = 0; i < v->size; ++i) + { + v->ced.release(v->context, (void *) + &v->ctab[i / cs][(i % cs) * v->ced.size]); + } + } + + for (i = 0; i < v->ctab_size && v->ctab[i] != (char *) 0; ++i) + { + pdc_free(v->pdc, v->ctab[i]); + } + + if (v->ctab) + pdc_free(v->pdc, v->ctab); + + pdc_free(v->pdc, v); +} /* pdc_vtr_delete */ + + +int +pdc_vtr_size(const pdc_vtr *v) +{ + return (int) v->size; +} /* pdc_vtr_size */ + + +void +pdc_vtr_resize(pdc_vtr *v, int new_size) +{ + static const char fn[] = "pdc_vtr_resize"; + + int cs = v->chunk_size; + + PDC_ASSERT(v->pdc, 0 <= new_size); + + if (new_size < v->size) + { + if (!v->ced.release) + { + v->size = new_size; + } + else + { + do + { + --v->size; + + v->ced.release(v->context, (void *) + &v->ctab[v->size / cs][(v->size % cs) * v->ced.size]); + } while (new_size < v->size); + } + + /* TODO: free chunks if possible? */ + } + else if (new_size > v->size) + { + int curr_slot = v->size / cs; + int new_ctsize = (new_size + cs - 1) / cs; + int i; + + if (v->ctab_size < new_ctsize) + pdc_vtr_grow_ctab(v, new_ctsize); + + for (i = curr_slot; i < new_ctsize; ++i) + { + if (v->ctab[i] == (char *) 0) + { + v->ctab[i] = (char *) + pdc_malloc(v->pdc, (size_t) (cs * v->ced.size), fn); + } + } + + if (v->ced.reclaim) + { + for (i = v->size; i < new_size; ++i) + { + v->ced.reclaim((void *) &v->ctab[i/cs][(i%cs) * v->ced.size]); + } + } + + v->size = new_size; + } +} /* pdc_vtr_resize */ + + +void * +pdc__vtr_at(const pdc_vtr *v, int idx) +{ + static const char fn[] = "pdc__vtr_at"; + + int cs = v->chunk_size; + + if (idx < 0 || v->size <= idx) + pdc_error(v->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(v->pdc, "%d", idx), fn, 0, 0); + /* TODO: "%u" */ + + return (void *) (&v->ctab[idx / cs][(idx % cs) * v->ced.size]); +} /* pdc__vtr_at */ + + +#if 0 +const void * +pdc__vtr_at_c(const pdc_vtr *v, int idx) +{ + static const char fn[] = "pdc__vtr_at_c"; + + int cs = v->chunk_size; + + if (idx < 0 || v->size <= idx) + pdc_error(v->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(v->pdc, "%d", idx), fn, 0, 0); + /* TODO: "%u" */ + + return (const void *) (&v->ctab[idx / cs][(idx % cs) * v->ced.size]); +} /* pdc__vtr_at_c */ +#endif + + +void * +pdc__vtr_top(const pdc_vtr *v) +{ + int cs = v->chunk_size; + int idx; + + if (v->size == 0) + return (void *) 0; + + idx = v->size - 1; + return (void *) (&v->ctab[idx / cs][(idx % cs) * v->ced.size]); +} /* pdc__vtr_top */ + + +#if 0 +const void * +pdc__vtr_top_c(const pdc_vtr *v) +{ + int cs = v->chunk_size; + int idx; + + if (v->size == 0) + return (void *) 0; + + idx = v->size - 1; + return (const void *) (&v->ctab[idx / cs][(idx % cs) * v->ced.size]); +} /* pdc__vtr_top_c */ +#endif + + +void * +pdc__vtr_push(pdc_vtr *v) +{ + static char fn[] = "pdc__vtr_push"; + + int cs = v->chunk_size; + int idx = v->size; + int slot = idx / cs; + char *target; + + if (v->ctab_size <= slot) + pdc_vtr_grow_ctab(v, v->ctab_size + v->ctab_incr); + + if (v->ctab[slot] == (char *) 0) + { + v->ctab[slot] = (char *) + pdc_malloc(v->pdc, (size_t) (cs * v->ced.size), fn); + } + + ++v->size; + target = &v->ctab[slot][(idx % cs) * v->ced.size]; + + if (v->ced.reclaim) + { + v->ced.reclaim((void *) target); + } + + return (void *) target; +} /* pdc__vtr_push */ + + +void +pdc_vtr_pop(pdc_vtr *v) +{ + static char fn[] = "pdc_vtr_pop"; + + int cs = v->chunk_size; + + if (v->size == 0) + pdc_error(v->pdc, PDC_E_INT_STACK_UNDER, fn, 0, 0, 0); + + --v->size; + + if (v->ced.release) + { + v->ced.release(v->context, (void *) + &v->ctab[v->size / cs][(v->size % cs) * v->ced.size]); + } +} /* pdc_vtr_pop */ diff --git a/src/pdflib/pdcore/pc_contain.h b/src/pdflib/pdcore/pc_contain.h new file mode 100644 index 0000000..007bfd0 --- /dev/null +++ b/src/pdflib/pdcore/pc_contain.h @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_contain.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib generic container classes + * + */ + +#ifndef PC_CONTAIN_H +#define PC_CONTAIN_H + +/* container entry descriptor +*/ +typedef struct +{ + size_t size; + + void (*reclaim)(void *item); + void (*release)(void *context, void *item); + int (*compare)(const void *lhs, const void *rhs); +} pdc_ced; + + +/* callback functions for the "for_each" methods +*/ +typedef void (*pdc_for_each_cb)(void *context, void *item); + + +/**************************** avl tree class ****************************/ + +typedef struct pdc_avl_s pdc_avl; + +pdc_avl * pdc_avl_new(pdc_core *pdc, const pdc_ced *ced, void *context); +void pdc_avl_delete(pdc_avl *t); +int pdc_avl_size(const pdc_avl *t); +void * pdc_avl_insert(pdc_avl *t, const void *item); +void pdc_avl_for_each(const pdc_avl *t, pdc_for_each_cb cb); + + +/***************************** vector class *****************************/ + +typedef struct pdc_vtr_s pdc_vtr; + +typedef struct +{ + int init_size; + int chunk_size; + int ctab_incr; +} pdc_vtr_parms; + +void pdc_vtr_dflt_parms(pdc_vtr_parms *vp); + +pdc_vtr * pdc_vtr_new(pdc_core *pdc, const pdc_ced *ced, void *context, + const pdc_vtr_parms *parms); + +void pdc_vtr_delete(pdc_vtr *v); +int pdc_vtr_size(const pdc_vtr *v); +void pdc_vtr_resize(pdc_vtr *v, int size); +void pdc_vtr_pop(pdc_vtr *v); + +/* don't use the pdc__vtr_xxx() functions directly. +** use the respective pdc_vtr_xxx() macros below. +*/ +void * pdc__vtr_at(const pdc_vtr *v, int idx); +void * pdc__vtr_top(const pdc_vtr *v); +void * pdc__vtr_push(pdc_vtr *v); + + +/* <type> pdc_vtr_at(const pdc_vtr *v, int idx, <type>); +** +** (<type>) v[idx] +*/ +#define pdc_vtr_at(v, idx, type) \ + (*((type *) pdc__vtr_at(v, idx))) + + +/* <type> pdc_vtr_top(const pdc_vtr *v, <type>); +** +** (<type>) v[vsize-1] +*/ +#define pdc_vtr_top(v, type) \ + (*((type *) pdc__vtr_top(v))) + + +/* void pdc_vtr_push(pdc_vtr *v, item, <type>); +** +** (<type>) v[vsize++] = item +*/ +#define pdc_vtr_push(v, item, type) \ + (*((type *) pdc__vtr_push(v)) = item) + + +/* <type> * pdc_vtr_incr(pdc_vtr *v, <type>); +** +** (<type> *) &v[vsize++] +*/ +#define pdc_vtr_incr(v, type) \ + ((type *) pdc__vtr_push(v)) + +#endif /* PC_CONTAIN_H */ diff --git a/src/pdflib/pdcore/pc_core.c b/src/pdflib/pdcore/pc_core.c new file mode 100644 index 0000000..4617aec --- /dev/null +++ b/src/pdflib/pdcore/pc_core.c @@ -0,0 +1,1190 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_core.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib core services + * + */ + +#include "pc_util.h" +#include "pc_string.h" +#include "pc_ctype.h" + +#define PDF_UnknownError 12 + +#if defined(__ia64__) && defined (__linux__) +#define PDC_ALIGN16 +#endif + +/* TODO: how to make this dynamic? +** exception during pdc_core_init(): +** - out of memory in pdc_bs_new() +*/ +#define PDC_ERRPARM_SIZE 2048 +#define PDC_ERRBUF_SIZE (5 * PDC_ERRPARM_SIZE) +#define PDC_XSTACK_INISIZE 10 + +#define PDC_CLASSLIST_SIZE 32 + +#define N_ERRTABS (PDC_ET_LAST / 1000) + +/* temporary free store. +*/ +typedef struct +{ + void * mem; + pdc_destructor destr; + void * opaque; +} pdc_tmpmem; + +typedef struct +{ + pdc_tmpmem * tmpmem; + int capacity; + int size; +} pdc_tmpmem_list; + + +/* exception handling frame. +*/ +typedef struct +{ + pdc_jmpbuf jbuf; +} pdc_xframe; + +typedef struct +{ + const pdc_error_info * ei; + int n_entries; +} error_table; + + +/* ------------------------ the core private structure ---------------------- */ + +struct pdc_core_priv_s +{ + /* ------------ try/catch ------------ */ + pdc_xframe * x_stack; +#ifdef PDC_ALIGN16 + char * x_alias; +#endif + int x_ssize; + int x_sp; /* exception stack pointer */ + int x_sp0; /* exception stack pointer at */ + /* the time of pdc_enter_api() */ + + /* ------------ error handling ------------ */ + pdc_bool in_error; + char * premsg; + char errbuf[PDC_ERRBUF_SIZE]; + char errparms[4][PDC_ERRPARM_SIZE]; + int epcount; + int errnum; + pdc_bool x_thrown; /* exception thrown and not caught */ + char apiname[32]; + pdc_error_fp errorhandler; /* client error handler */ + void * opaque; /* client specific, opaque data */ + + error_table err_tables[N_ERRTABS]; + +#ifdef PDC_DEBUG + pdc_bool hexdump; /* hexdump feature enabled? */ +#endif /* PDC_DEBUG */ + + /* ------------ memory management ------------ */ + pdc_alloc_fp allocproc; + pdc_realloc_fp reallocproc; + pdc_free_fp freeproc; + pdc_tmpmem_list tm_list; +}; + + +/* ----------- default memory management & error handling ----------- */ + +static void * +default_malloc(void *opaque, size_t size, const char *caller) +{ + (void) opaque; + (void) caller; + + return malloc(size); +} + +static void * +default_realloc(void *opaque, void *mem, size_t size, const char *caller) +{ + (void) opaque; + (void) caller; + + return realloc(mem, size); +} + +static void +default_free(void *opaque, void *mem) +{ + (void) opaque; + + free(mem); +} + +static void +default_errorhandler(void *opaque, int errnum, const char *msg) +{ + (void) opaque; + (void) errnum; + + fprintf(stderr, "fatal exception: %s\n", msg); + exit(99); +} + +pdc_bool +pdc_enter_api(pdc_core *pdc, const char *apiname) +{ + char *name = NULL; + + if (pdc->pr->in_error) + return pdc_false; + + if (pdc->objorient) + name = (char *) strchr(apiname, '_'); + if (name) + name++; + else + name = (char *) apiname; + if (name[0] == '\n') + name++; + + strcpy(pdc->pr->apiname, name); + + if (pdc->binding != NULL) + { + size_t len = strlen(pdc->pr->apiname); + len--; + if (len && pdc->pr->apiname[len] == '2') + pdc->pr->apiname[len] = 0; + } + + pdc->pr->errnum = 0; + pdc->pr->x_sp0 = pdc->pr->x_sp; + return pdc_true; +} + +pdc_bool +pdc_in_error(pdc_core *pdc) +{ + return pdc->pr->in_error; +} + + +/* --------------------- error table management --------------------- */ + +static pdc_error_info core_errors[] = +{ +#define pdc_genInfo 1 +#include "pc_generr.h" +}; + +#define N_CORE_ERRORS (sizeof core_errors / sizeof (pdc_error_info)) + + +static void +pdc_panic(pdc_core *pdc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pdc_vsnprintf(pdc->pr->errbuf, PDC_ERRPARM_SIZE, fmt, ap); + va_end(ap); + + (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, + pdc->pr->errbuf); +} /* pdc_panic */ + + +static void +check_parms(pdc_core *pdc, const pdc_error_info *ei) +{ + const char *msg = ei->errmsg; + const char *dollar; + + while ((dollar = strchr(msg, '$')) != (char *) 0) + { + if (pdc_isdigit(dollar[1])) + { + int n = dollar[1] - '0'; + + if (ei->nparms < n || n < 1) + pdc_panic(pdc, "illegal parameter '$%d' in error message %d", + n, ei->errnum); + } + else if (dollar[1] != '$') + { + pdc_panic(pdc, + "illegal '$' in error message %d", ei->errnum); + } + + msg = dollar + 1; + } +} /* check_parms */ + + +void +pdc_register_errtab( + pdc_core *pdc, + int et, + const pdc_error_info *ei, + int n_entries) +{ + int i; + int n = (et / 1000) - 1; + + if (n < 0 || N_ERRTABS <= n || et % 1000 != 0) + pdc_panic(pdc, "tried to register unknown error table %d", et); + + /* ignore multiple registrations of the same table. + */ + if (pdc->pr->err_tables[n].ei != (pdc_error_info *) 0) + return; + + pdc->pr->err_tables[n].ei = ei; + pdc->pr->err_tables[n].n_entries = n_entries; + + check_parms(pdc, &ei[0]); + + for (i = 1; i < n_entries; ++i) + { + if (ei[i].errnum <= ei[i-1].errnum) + { + pdc_panic(pdc, + "duplicate or misplaced error number %d", ei[i].errnum); + } + + /* an error table may span several blocks. + */ + if ((ei[i].errnum / 1000) - 1 > n) + { + pdc->pr->err_tables[n].n_entries = i; /* correct old block size */ + + n = (ei[i].errnum / 1000) - 1; /* new block number */ + + if (N_ERRTABS <= n) + pdc_panic(pdc, "invalid error number %d", ei[i].errnum); + + ei += i; /* start of new block */ + n_entries -= i; /* size of new block */ + i = 0; + pdc->pr->err_tables[n].ei = ei; + pdc->pr->err_tables[n].n_entries = n_entries; + } + + check_parms(pdc, &ei[i]); + } +} /* pdc_register_errtab */ + + +/* pdc_new_core() never throws exceptions. +** it returns NULL if there's not enough memory. +*/ +pdc_core * +pdc_new_core( + pdc_error_fp errorhandler, + pdc_alloc_fp allocproc, + pdc_realloc_fp reallocproc, + pdc_free_fp freeproc, + void *opaque, + const char *prodname, + const char *version) +{ + static const char fn[] = "pdc_new_core"; + + pdc_core_priv *pdc_pr; + pdc_core *pdc; + int i; + + /* if allocproc is NULL, we use pdc's default memory handling. + */ + if (allocproc == (pdc_alloc_fp) 0) + { + allocproc = default_malloc; + reallocproc = default_realloc; + freeproc = default_free; + } + + if (errorhandler == (pdc_error_fp) 0) + errorhandler = default_errorhandler; + + pdc_pr = (pdc_core_priv *) + (*allocproc)(opaque, sizeof (pdc_core_priv), fn); + + if (pdc_pr == (pdc_core_priv *) 0) + return (pdc_core *) 0; + + pdc = (pdc_core *) + (*allocproc)(opaque, sizeof (pdc_core), fn); + + if (pdc == (pdc_core *) 0) + return (pdc_core *) 0; + + pdc->pr = pdc_pr; + + /* initialize client members + */ + pdc->reslist = NULL; + pdc->filesystem = NULL; + pdc->logg = NULL; + pdc->loggenv = pdc_false; + pdc->encstack = NULL; + pdc->pglyphtab = NULL; + pdc->bstr_pool = NULL; + pdc->ustr_pool = NULL; + pdc->last_rand = 1; + pdc->prodname = prodname; + pdc->version = version; + pdc->binding = NULL; + pdc->unicaplang = pdc_false; + pdc->objorient = pdc_false; + pdc->hastobepos = pdc_false; + pdc->ptfrun = pdc_false; + pdc->smokerun = pdc_false; + pdc->charref = pdc_false; + pdc->escapesequ = pdc_false; + pdc->honorlang = pdc_false; + pdc->compatibility = PDC_X_X_LAST; + pdc->floatdigits = 4; + pdc->uniqueno = 0; + + +#ifdef PDC_DEBUG + pdc->pr->hexdump = pdc_true; +#endif + + /* set diverse handlers + */ + pdc->pr->errorhandler = errorhandler; + pdc->pr->allocproc = allocproc; + pdc->pr->reallocproc = reallocproc; + pdc->pr->freeproc = freeproc; + pdc->pr->opaque = opaque; + + /* initialize error & exception handling. + */ + pdc->pr->in_error = pdc_false; + pdc->pr->x_thrown = pdc_false; + pdc->pr->epcount = 0; + pdc->pr->errnum = 0; + pdc->pr->premsg = NULL; + pdc->pr->apiname[0] = 0; + pdc->pr->x_sp = -1; + pdc->pr->x_ssize = PDC_XSTACK_INISIZE; + +#ifdef PDC_ALIGN16 + pdc->pr->x_alias = (char *) + (*allocproc)(opaque, 16 + pdc->pr->x_ssize * sizeof (pdc_xframe), fn); + + if (pdc->pr->x_alias == (char *) 0) + pdc->pr->x_stack = (pdc_xframe *) 0; + else + pdc->pr->x_stack = (pdc_xframe *) + (((unsigned long) pdc->pr->x_alias + 16) & 0xFFFFFFFFFFFFFFF0); +#else + pdc->pr->x_stack = (pdc_xframe *) + (*allocproc)(opaque, pdc->pr->x_ssize * sizeof (pdc_xframe), fn); +#endif + + if (pdc->pr->x_stack == (pdc_xframe *) 0) + { + (*freeproc)(opaque, pdc); + return (pdc_core *) 0; + } + + pdc_tmlist_init(pdc); + + /* initialize error tables. + */ + for (i = 0; i < N_ERRTABS; ++i) + pdc->pr->err_tables[i].ei = (pdc_error_info *) 0; + + pdc_register_errtab(pdc, PDC_ET_CORE, core_errors, N_CORE_ERRORS); + pdc_init_strings(pdc); + + return pdc; +} + +void +pdc_delete_core(pdc_core *pdc) +{ + pdc_free_fp freeproc = pdc->pr->freeproc; + void *opaque = pdc->pr->opaque; + pdc_time ltime; + + pdc_localtime(<ime); + pdc_logg(pdc, "[%04d-%02d-%02d %02d:%02d:%02d]\n", + ltime.year + 1900, ltime.month + 1, ltime.mday, + ltime.hour, ltime.minute, ltime.second); + + pdc_delete_reslist(pdc); + pdc_delete_filesystem(pdc); + pdc_delete_encodingstack(pdc); + pdc_delete_pglyphtab(pdc); + + pdc_cleanup_strings(pdc); + + if (pdc->binding) + pdc_free(pdc, pdc->binding); + + pdc_pop_errmsg(pdc); + + pdc_tmlist_cleanup(pdc); + + if (pdc->pr->tm_list.capacity != 0) + pdc_free(pdc, pdc->pr->tm_list.tmpmem); + +#ifdef PDC_ALIGN16 + pdc_free(pdc, pdc->pr->x_alias); +#else + pdc_free(pdc, pdc->pr->x_stack); +#endif + + pdc_delete_logg(pdc); + + (*freeproc)(opaque, pdc->pr); + (*freeproc)(opaque, pdc); +} + +/* --------------------------- memory management --------------------------- */ + +void * +pdc_malloc(pdc_core *pdc, size_t size, const char *caller) +{ + void *ret; + pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory); + + if (logg1) + pdc_logg(pdc, "\ttry to malloc %ld bytes\n", size); + + + /* the behavior of malloc(0) is undefined in ANSI C, and may + * result in a NULL pointer return value which makes PDFlib bail out. + */ + if (size == (size_t) 0 || (long) size < 0L) { + size = (size_t) 1; + pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); + } + + if ((ret = (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller)) == + (void *) 0) + { + pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); + } + + if (logg1) + pdc_logg(pdc, "\t%p malloced, size=%ld, called from \"%s\"\n", + ret, size, caller); + + return ret; +} + +/* We cook up our own calloc routine, using the caller-supplied + * malloc and memset. + */ +void * +pdc_calloc(pdc_core *pdc, size_t size, const char *caller) +{ + void *ret; + pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory); + + if (logg1) + pdc_logg(pdc, "\ttry to calloc %ld bytes\n", size); + + if (size == (size_t) 0 || (long) size < 0L) { + size = (size_t) 1; + pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); + } + + if ((ret = (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller)) == + (void *) 0) + { + pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); + } + + if (logg1) + pdc_logg(pdc, "\t%p calloced, size=%ld, called from \"%s\"\n", + ret, size, caller); + + memset(ret, 0, size); + return ret; +} + +void * +pdc_realloc(pdc_core *pdc, void *mem, size_t size, const char *caller) +{ + void *ret; + pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory); + + if (logg1) + pdc_logg(pdc, "\ttry to realloc %p to %ld bytes\n", mem, size); + + if (size == (size_t) 0 || (long) size < 0L) { + size = (size_t) 1; + pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); + } + + ret = (mem == (void *) 0) ? + (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller) : + (*pdc->pr->reallocproc)(pdc->pr->opaque, mem, size, caller); + + if (ret == (void *) 0) + pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); + + pdc_logg_cond(pdc, 1, trc_memory, + "\t%p realloced to\n" + "\t%p new, size=%ld, called from \"%s\"\n", + mem, ret, size, caller); + + return ret; +} + +void +pdc_free(pdc_core *pdc, void *mem) +{ + pdc_logg_cond(pdc, 1, trc_memory, "\t%p freed\n", mem); + + /* just in case the freeproc() isn't that ANSI compatible... + */ + if (mem != NULL) + (*pdc->pr->freeproc)(pdc->pr->opaque, mem); +} + +/* -------------------- temporary free store management -------------------- */ + +void +pdc_tmlist_init(pdc_core *pdc) +{ + pdc->pr->tm_list.size = pdc->pr->tm_list.capacity = 0; +} + +static void +pdc_tmlist_grow(pdc_core *pdc) +{ + static const char fn[] = "pdc_tmlist_grow"; + pdc_tmpmem_list *tm_list = &pdc->pr->tm_list; + static const int chunksize = 20; + + if (tm_list->capacity == 0) + { + tm_list->capacity = chunksize; + tm_list->tmpmem = (pdc_tmpmem *) pdc_malloc(pdc, + (size_t) (tm_list->capacity * sizeof (pdc_tmpmem)), fn); + } + else + { + tm_list->capacity += chunksize; + tm_list->tmpmem = (pdc_tmpmem *) pdc_realloc(pdc, tm_list->tmpmem, + (size_t) (tm_list->capacity * sizeof (pdc_tmpmem)), fn); + } +} + +void +pdc_tmlist_cleanup(pdc_core *pdc) +{ + pdc_tmpmem_list *tm_list = &pdc->pr->tm_list; + int i; + + for (i = 0; i < tm_list->size; ++i) + { + if (tm_list->tmpmem[i].destr) + tm_list->tmpmem[i].destr(tm_list->tmpmem[i].opaque, + tm_list->tmpmem[i].mem); + + pdc_free(pdc, tm_list->tmpmem[i].mem); + } + + tm_list->size = 0; +} + +void +pdc_insert_mem_tmp( + pdc_core * pdc, + void * memory, + void * opaque, + pdc_destructor destr) +{ + pdc_tmpmem_list *tm_list = &pdc->pr->tm_list; + + if (tm_list->size == tm_list->capacity) + pdc_tmlist_grow(pdc); + + pdc_logg_cond(pdc, 2, trc_memory, + "\tTemporary memory %p was created\n", memory); + + tm_list->tmpmem[tm_list->size].mem = memory; + tm_list->tmpmem[tm_list->size].destr = destr; + tm_list->tmpmem[tm_list->size].opaque = opaque; + ++tm_list->size; +} + +void * +pdc_malloc_tmp( + pdc_core * pdc, + size_t size, + const char * caller, + void * opaque, + pdc_destructor destr) +{ + void *memory = pdc_malloc(pdc, size, caller); + + pdc_insert_mem_tmp(pdc, memory, opaque, destr); + + return memory; +} + +void * +pdc_calloc_tmp( + pdc_core * pdc, + size_t size, + const char * caller, + void * opaque, + pdc_destructor destr) +{ + void *memory = pdc_calloc(pdc, size, caller); + + pdc_insert_mem_tmp(pdc, memory, opaque, destr); + + return memory; +} + +void * +pdc_realloc_tmp(pdc_core *pdc, void *mem, size_t size, const char *caller) +{ + pdc_tmpmem_list *tm_list = &pdc->pr->tm_list; + int i; + + for (i = tm_list->size - 1; 0 <= i; --i) + if (tm_list->tmpmem[i].mem == mem) + return tm_list->tmpmem[i].mem = pdc_realloc(pdc, mem, size, caller); + + pdc_error(pdc, PDC_E_INT_REALLOC_TMP, caller, 0, 0, 0); + return (void *) 0; +} + +void +pdc_free_tmp(pdc_core *pdc, void *mem) +{ + pdc_tmpmem_list *tm_list = &pdc->pr->tm_list; + int i, j; + + pdc_logg_cond(pdc, 2, trc_memory, + "\tTemporary memory %p to be freed\n", mem); + + /* we search the list backwards since chances are good + ** that the most recently allocated items are freed first. + */ + for (i = tm_list->size - 1; 0 <= i; --i) + { + if (tm_list->tmpmem[i].mem == mem) + { + if (tm_list->tmpmem[i].destr) + tm_list->tmpmem[i].destr( + tm_list->tmpmem[i].opaque, tm_list->tmpmem[i].mem); + + pdc_free(pdc, tm_list->tmpmem[i].mem); + tm_list->tmpmem[i].mem = (void *) 0; + + --tm_list->size; + for (j = i; j < tm_list->size; j++) + tm_list->tmpmem[j] = tm_list->tmpmem[j + 1]; + + return; + } + } + + pdc_error(pdc, PDC_E_INT_FREE_TMP, 0, 0, 0, 0); +} + + +/* --------------------------- exception handling --------------------------- */ + +const char *pdc_errprintf(pdc_core *pdc, const char *fmt, ...) +{ + va_list ap; + + if (pdc->pr->epcount < 0 || pdc->pr->epcount > 3) + pdc->pr->epcount = 0; + + va_start(ap, fmt); + pdc_vsnprintf(pdc->pr->errparms[pdc->pr->epcount], PDC_ERRPARM_SIZE, + fmt, ap); + va_end(ap); + + return pdc->pr->errparms[pdc->pr->epcount++]; +} + +static const pdc_error_info * +get_error_info(pdc_core *pdc, int errnum) +{ + int n = (errnum / 1000) - 1; + + if (0 <= n && n < N_ERRTABS && pdc->pr->err_tables[n].ei != 0) + { + error_table *etab = &pdc->pr->err_tables[n]; + int i; + + /* LATER: binary search. */ + for (i = 0; i < etab->n_entries; ++i) + { + if (etab->ei[i].errnum == errnum) + return &etab->ei[i]; + } + } + + pdc_panic(pdc, "Internal error: unknown error number %d", errnum); + + return (pdc_error_info *) 0; /* for the compiler */ +} /* get_error_info */ + + +static void +make_errmsg( + pdc_core * pdc, + const pdc_error_info *ei, + const char * parm1, + const char * parm2, + const char * parm3, + const char * parm4, + pdc_bool popmsg) +{ + const char *src = ei->ce_msg ? ei->ce_msg : ei->errmsg; + char * dst = pdc->pr->errbuf; + const char *dollar; + + if (pdc->pr->premsg != NULL) + { + strcpy(dst, pdc->pr->premsg); + dst += strlen(pdc->pr->premsg); + if (popmsg) + pdc_pop_errmsg(pdc); + } + + pdc->pr->epcount = 0; + + /* copy *src to *dst, replacing "$N" with *parmN. + */ + while ((dollar = strchr(src, '$')) != (char *) 0) + { + const char *parm = (const char *) 0; + + memcpy(dst, src, (size_t) (dollar - src)); + dst += dollar - src; + src = dollar + 1; + + switch (*src) + { + case '1': parm = (parm1 ? parm1 : "?"); break; + case '2': parm = (parm2 ? parm2 : "?"); break; + case '3': parm = (parm3 ? parm3 : "?"); break; + case '4': parm = (parm4 ? parm4 : "?"); break; + + case 0: break; + + default: *(dst++) = *(src++); + break; + } + + if (parm != (const char *) 0) + { + ++src; + strcpy(dst, parm); + dst += strlen(parm); + } + } + + strcpy(dst, src); + +} /* make_errmsg */ + +void +pdc_pop_errmsg(pdc_core *pdc) +{ + if (pdc->pr->premsg) + { + pdc_free(pdc, pdc->pr->premsg); + pdc->pr->premsg = NULL; + } +} /* pdc_pop_errmsg */ + +void +pdc_push_errmsg( + pdc_core * pdc, + int errnum, + const char *parm1, + const char *parm2, + const char *parm3, + const char *parm4) +{ + static const char fn[] = "pdc_push_errmsg"; + const pdc_error_info *ei = get_error_info(pdc, errnum); + + pdc_pop_errmsg(pdc); + + make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false); + + pdc->pr->premsg = pdc_strdup_ext(pdc, pdc->pr->errbuf, 0, fn); + +} /* pdc_push_errmsg */ + +void +pdc_set_errmsg( + pdc_core * pdc, + int errnum, + const char *parm1, + const char *parm2, + const char *parm3, + const char *parm4) +{ + const pdc_error_info *ei = get_error_info(pdc, errnum); + + make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false); + + pdc->pr->errnum = errnum; + + pdc_logg_cond(pdc, 2, trc_warning, + "[Reason for error message %d: \"%s\"]\n", + pdc->pr->errnum, pdc->pr->errbuf); + +} /* pdc_set_errmsg */ + +void +pdc_set_warnmsg( + pdc_core * pdc, + int errnum, + const char *parm1, + const char *parm2, + const char *parm3, + const char *parm4) +{ + char errbuf[PDC_ERRBUF_SIZE]; + + strcpy(errbuf, pdc->pr->errbuf); + + if (errnum != -1) + { + const pdc_error_info *ei = get_error_info(pdc, errnum); + + make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false); + } + + pdc_logg_cond(pdc, 1, trc_warning, + "\n[Warning message %d: \"%s\"]\n", + errnum, pdc->pr->errbuf); + + strcpy(pdc->pr->errbuf, errbuf); + +} /* pdc_set_warnmsg */ + + +void +pdc_error( + pdc_core * pdc, + int errnum, + const char *parm1, + const char *parm2, + const char *parm3, + const char *parm4) +{ + const char *logmsg; + + /* avoid recursive errors, but allow rethrow. + */ + if (errnum != -1 && pdc->pr->in_error) + return; + + pdc->pr->in_error = pdc_true; + pdc->pr->x_thrown = pdc_true; + + if (errnum != -1) + { + const pdc_error_info *ei = get_error_info(pdc, errnum); + + make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_true); + pdc->pr->errnum = errnum; + } + + if (pdc->pr->x_sp > pdc->pr->x_sp0) + { + logmsg = "\n[/// Exception %d in %s ]"; + } + else + { + logmsg = "\n[+++ Exception %d in %s ]"; + } + + pdc_logg(pdc, logmsg, pdc->pr->errnum, + (pdc->pr->errnum == 0 || !pdc->pr->apiname) ? "" : pdc->pr->apiname, + pdc->pr->x_sp0 + 1, pdc->pr->x_sp - pdc->pr->x_sp0); + + pdc_logg(pdc, "[\"%s\"]\n\n", pdc->pr->errbuf); + + if (pdc->pr->x_sp == -1) + { + char errbuf[PDC_ERRBUF_SIZE]; + const char *apiname = pdc_get_apiname(pdc); + const char *errmsg = pdc->pr->errbuf; + + if (strlen(apiname)) + { + sprintf(errbuf, "[%d] %s: %s", pdc->pr->errnum, apiname, errmsg); + errmsg = errbuf; + } + + (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, errmsg); + + /* + * The error handler must never return. If it does, it is severely + * broken. We cannot remedy this, so we exit. + */ + exit(99); + + } + else + { + longjmp(pdc->pr->x_stack[pdc->pr->x_sp].jbuf.jbuf, 1); + } + +} /* pdc_error */ + +pdc_jmpbuf * +pdc_jbuf(pdc_core *pdc) +{ + static const char fn[] = "pdc_jbuf"; + + if (++pdc->pr->x_sp == pdc->pr->x_ssize) + { + pdc_xframe *aux; + +#ifdef PDC_ALIGN16 + char *cp = (char *) (*pdc->pr->allocproc)(pdc->pr->opaque, + 16 + 2 * pdc->pr->x_ssize * sizeof (pdc_xframe), fn); + + if (cp == (char *) 0) + { + aux = (pdc_xframe *) 0; + } + else + { + /* remember the pointer in order to free it only after the memcpy + * below, as pdc->pr->x_stack points into the memory allocated + * to pdc->pr->x_alias + */ + char *free_me_later = pdc->pr->x_alias; + pdc->pr->x_alias = cp; + aux = (pdc_xframe *) + (((unsigned long) cp + 16) & 0xFFFFFFFFFFFFFFF0); + + memcpy(aux, pdc->pr->x_stack, + pdc->pr->x_ssize * sizeof (pdc_xframe)); + pdc_free(pdc, free_me_later); + } +#else + aux = (pdc_xframe *) (*pdc->pr->reallocproc)( + pdc->pr->opaque, pdc->pr->x_stack, + 2 * pdc->pr->x_ssize * sizeof (pdc_xframe), fn); +#endif + + if (aux == (pdc_xframe *) 0) + { + --pdc->pr->x_sp; + pdc->pr->x_thrown = pdc_true; + pdc->pr->in_error = pdc_true; + + pdc->pr->errnum = PDC_E_MEM_OUT; + pdc->pr->apiname[0] = 0; + sprintf(pdc->pr->errbuf, + "Out of memory in TRY function (nesting level: %d)", + pdc->pr->x_sp + 1); + + longjmp(pdc->pr->x_stack[pdc->pr->x_sp].jbuf.jbuf, 1); + } + + pdc->pr->x_stack = aux; + pdc->pr->x_ssize *= 2; + } + + pdc->pr->x_thrown = pdc_false; + return &pdc->pr->x_stack[pdc->pr->x_sp].jbuf; +} /* pdc_jbuf */ + +void +pdc_exit_try(pdc_core *pdc) +{ + if (pdc->pr->x_sp == -1) + { + strcpy(pdc->pr->errbuf, "exception stack underflow"); + pdc->pr->errnum = PDC_E_INT_XSTACK; + (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, + pdc->pr->errbuf); + } + else + --pdc->pr->x_sp; +} /* pdc_exit_try */ + +int +pdc_catch_intern(pdc_core *pdc) +{ + pdc_bool result; + + if (pdc->pr->x_sp == -1) + { + strcpy(pdc->pr->errbuf, "exception stack underflow"); + pdc->pr->errnum = PDC_E_INT_XSTACK; + (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, + pdc->pr->errbuf); + } + else + --pdc->pr->x_sp; + + result = pdc->pr->x_thrown; + pdc->pr->in_error = pdc_false; + pdc->pr->x_thrown = pdc_false; + + return result; +} /* pdc_catch_intern */ + +int +pdc_catch_extern(pdc_core *pdc) +{ + pdc_bool result; + + if (pdc->pr->x_sp == -1) + { + strcpy(pdc->pr->errbuf, "exception stack underflow"); + pdc->pr->errnum = PDC_E_INT_XSTACK; + (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, + pdc->pr->errbuf); + } + else + --pdc->pr->x_sp; + + result = pdc->pr->x_thrown; + pdc->pr->x_thrown = pdc_false; + + return result; +} /* pdc_catch_extern */ + +void +pdc_rethrow(pdc_core *pdc) +{ + pdc_error(pdc, -1, 0, 0, 0, 0); +} /* pdc_rethrow */ + + +/* this function should be called in the PDC_CATCH branch of +** a function before it returns -1. +*/ +void +pdc_check_rethrow(pdc_core *pdc) +{ + if (pdc->pr->errnum == PDC_E_MEM_OUT) + pdc_error(pdc, -1, 0, 0, 0, 0); +} /* pdc_check_rethrow */ + + +int +pdc_get_errnum(pdc_core *pdc) +{ + return pdc->pr->errnum; +} + +const char * +pdc_get_errmsg(pdc_core *pdc) +{ + return (pdc->pr->errnum == 0) ? "" : pdc->pr->errbuf; +} + +const char * +pdc_get_apiname(pdc_core *pdc) +{ + return pdc->pr->apiname; +} + +const char * +pdc_get_errpref(pdc_core *pdc) +{ + return pdc->pr->premsg; +} + +/* ----------- service function to get PDF version string -------------- */ + +const char * +pdc_get_pdfversion(pdc_core *pdc, int compatibility) +{ + return pdc_errprintf(pdc, "%d.%d", compatibility / 10, compatibility % 10); +} + + +#ifdef PDC_DEBUG + +/* --------------------------- debug hexdump --------------------------- */ +void +pdc_enable_hexdump(pdc_core *pdc) +{ + pdc->pr->hexdump = pdc_true; +} + +void +pdc_disable_hexdump(pdc_core *pdc) +{ + pdc->pr->hexdump = pdc_false; +} + +void +pdc_hexdump(pdc_core *pdc, const char *msg, const char *text, int tlen) +{ + if (pdc->pr->hexdump) + { + int i, k; + + if (tlen == 1) + { + printf("%s: %02X '%c'\n", msg, + (unsigned char) text[0], + pdc_isprint(text[0]) ? text[0] : '.'); + } + else + { + printf("%s:\n", msg); + + for (i = 0; i < tlen; i += 16) + { + for (k = 0; k < 16; ++k) + if (i + k < tlen) + printf("%02X ", (unsigned char) text[i + k]); + else + printf(" "); + + printf(" "); + for (k = 0; k < 16; ++k) + if (i + k < tlen) + { + printf("%c", + pdc_isprint(text[i + k]) ? text[i + k] : '.'); + } + else + printf(" "); + + printf("\n"); + } + } + } +} + +#endif /* PDC_DEBUG */ diff --git a/src/pdflib/pdcore/pc_core.h b/src/pdflib/pdcore/pc_core.h new file mode 100644 index 0000000..c758789 --- /dev/null +++ b/src/pdflib/pdcore/pc_core.h @@ -0,0 +1,270 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_core.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib core services: + * - memory management + * - exception handling + * - internal try/catch + */ + +#ifndef PC_CORE_H +#define PC_CORE_H + +/* Built-in metric support */ +#define PDF_BUILTINMETRIC_SUPPORTED + +/* Built-in encoding support */ +#define PDF_BUILTINENCODING_SUPPORTED + +/* TrueType font support */ +#define PDF_TRUETYPE_SUPPORTED + +/* Proportional widths for the standard CJK fonts support */ +#define PDF_CJKFONTWIDTHS_SUPPORTED + + +#define PDF_FEATURE_NOT_PUBLIC + + +/* ------------------------- general ------------------------- */ + +typedef struct pdc_core_priv_s pdc_core_priv; +typedef struct pdc_core_s pdc_core; + +typedef int pdc_bool; +typedef long pdc_id; +typedef char pdc_char; +typedef unsigned char pdc_byte; +typedef unsigned char pdc_uchar; +typedef short pdc_short; +typedef unsigned short pdc_ushort; +typedef long pdc_long; +typedef unsigned long pdc_ulong; +typedef unsigned int pdc_uint; + +typedef unsigned short pdc_ucval; /* unicode value */ + +typedef short pdc_sint16; +typedef unsigned short pdc_uint16; +typedef int pdc_sint32; +typedef unsigned int pdc_uint32; + +/* TODO2GB: this is the signed 64-bit integer type for >2GB files. +** must be platform & compiler specific. +*/ +#if defined(_LARGEFILE_SOURCE) + #if defined(WIN32) + typedef __int64 pdc_off_t; + #else +#include <sys/types.h> + typedef off_t pdc_off_t; + #endif +#else + typedef long pdc_off_t; +#endif + +/* use this one for casts from "off_t" to "long" - so we can "grep" +** for critical places. +*/ +typedef long pdc_off_t1; + + +#define pdc_undef -1 +#define pdc_false 0 +#define pdc_true 1 + +#define PDC_1_1 11 /* PDF 1.1 = Acrobat 2 */ +#define PDC_1_2 12 /* PDF 1.2 = Acrobat 3 */ +#define PDC_1_3 13 /* PDF 1.3 = Acrobat 4 */ +#define PDC_1_4 14 /* PDF 1.4 = Acrobat 5 */ +#define PDC_1_5 15 /* PDF 1.5 = Acrobat 6 */ +#define PDC_1_6 16 /* PDF 1.6 = Acrobat 7 */ +#define PDC_1_7 17 /* PDF 1.7 = Acrobat 8 */ +#define PDC_X_X_LAST 17 + +/* Acrobat limit for page dimensions */ +#define PDF_ACRO_MINPAGE (3.0) /* 1/24 inch = 0.106 cm */ +#define PDF_ACRO_MAXPAGE (14400.0) /* 200 inch = 508 cm */ + + + +typedef void (*pdc_error_fp)(void *opaque, int type, const char *msg); +typedef void* (*pdc_alloc_fp)(void *opaque, size_t size, const char *caller); +typedef void* (*pdc_realloc_fp)(void *opaque, void *mem, size_t size, + const char *caller); +typedef void (*pdc_free_fp)(void *opaque, void *mem); + +pdc_core *pdc_new_core(pdc_error_fp errorhandler, pdc_alloc_fp allocproc, + pdc_realloc_fp reallocproc, pdc_free_fp freeproc, void *opaque, + const char *appname, const char *version); + +void pdc_delete_core(pdc_core *pdc); + +typedef enum +{ + pdc_pbox_none, + pdc_pbox_art, + pdc_pbox_bleed, + pdc_pbox_crop, + pdc_pbox_media, + pdc_pbox_trim +} pdc_pagebox; + +/* ------------------------- memory management ------------------------- */ + +void *pdc_malloc(pdc_core *pdc, size_t size, const char *caller); +void *pdc_realloc(pdc_core *pdc, void *mem, size_t size, const char *caller); +void *pdc_calloc(pdc_core *pdc, size_t size, const char *caller); +void pdc_free(pdc_core *pdc, void *mem); + +#define PDC_TMPMEM 1 + +typedef void (*pdc_destructor)(void *opaque, void *mem); + +void pdc_insert_mem_tmp(pdc_core *pdc, void *memory, void *opaque, + pdc_destructor destr); +void *pdc_malloc_tmp(pdc_core *pdc, size_t size, const char *caller, + void *opaque, pdc_destructor destr); +void *pdc_realloc_tmp(pdc_core *pdc, void *mem, size_t size, + const char *caller); +void *pdc_calloc_tmp(pdc_core *pdc, size_t size, const char *caller, + void *opaque, pdc_destructor destr); +void pdc_free_tmp(pdc_core *pdc, void *mem); + +void pdc_tmlist_init(pdc_core *pdc); +void pdc_tmlist_cleanup(pdc_core *pdc); + + +/* --------------------------- exception handling --------------------------- */ + +#define PDC_ASSERT(pdc, expr) \ + ((expr) ? (void) 0 : pdc_error((pdc), PDC_E_INT_ASSERT, \ + __FILE__, pdc_errprintf((pdc), "%d", __LINE__), 0, 0)) + +/* maximal length of strings for %.*s in pdc_errprintf format +*/ +#define PDC_ERR_MAXSTRLEN 256 + +/* per-library error table base numbers. +*/ +#define PDC_ET_CORE 1000 +#define PDC_ET_PDFLIB 2000 +#define PDC_ET_PDI 4000 +#define PDC_ET_PLOP 5000 +#define PDC_ET_PDPAGE 6000 +#define PDC_ET_FONT 7000 +#define PDC_ET_TET 8000 +#define PDC_ET_PCOS 9000 + +#define PDC_ET_LAST 9000 + +/* core error numbers. +*/ +enum +{ +#define pdc_genNames 1 +#include "pc_generr.h" + + PDC_E_dummy +}; + +typedef struct +{ + int nparms; /* number of error parameters */ + int errnum; /* error number */ + const char *errmsg; /* default error message */ + const char *ce_msg; /* custom error message */ +} pdc_error_info; + +void pdc_register_errtab(pdc_core *pdc, int et, + const pdc_error_info *ei, int n_entries); + +pdc_bool pdc_enter_api(pdc_core *pdc, const char *apiname); +pdc_bool pdc_in_error(pdc_core *pdc); + +const char * pdc_errprintf(pdc_core *pdc, const char *format, ...); + +void pdc_pop_errmsg(pdc_core *pdc); + +void pdc_push_errmsg(pdc_core *pdc, int errnum, const char *parm1, + const char *parm2, const char *parm3, const char *parm4); + +void pdc_set_errmsg(pdc_core *pdc, int errnum, const char *parm1, + const char *parm2, const char *parm3, const char *parm4); + +void pdc_set_warnmsg(pdc_core *pdc, int errnum, const char *parm1, + const char *parm2, const char *parm3, const char *parm4); + +void pdc_error(pdc_core *pdc, int errnum, const char *parm1, + const char *parm2, const char *parm3, const char *parm4); + +int pdc_get_errnum(pdc_core *pdc); +const char * pdc_get_errmsg(pdc_core *pdc); +const char * pdc_get_apiname(pdc_core *pdc); +const char * pdc_get_errpref(pdc_core *pdc); + +/* ----------------------------- try/catch ---------------------------- */ + +#include <setjmp.h> + +typedef struct +{ + jmp_buf jbuf; +} pdc_jmpbuf; + +pdc_jmpbuf * pdc_jbuf(pdc_core *pdc); +void pdc_exit_try(pdc_core *pdc); +int pdc_catch_intern(pdc_core *pdc); +int pdc_catch_extern(pdc_core *pdc); +void pdc_check_rethrow(pdc_core *pdc); +void pdc_rethrow(pdc_core *pdc); + +#define PDC_TRY(pdc) if (setjmp(pdc_jbuf(pdc)->jbuf) == 0) + +#define PDC_EXIT_TRY(pdc) pdc_exit_try(pdc) + +#define PDC_CATCH(pdc) if (pdc_catch_intern(pdc)) + +#define PDC_RETHROW(pdc) pdc_rethrow(pdc) + + +/* ----------- service function to get PDF version string -------------- */ + +const char *pdc_get_pdfversion(pdc_core *pdc, int compatibility); + + +/* --------------------------- debug hexdump --------------------------- */ + +#ifdef PDC_DEBUG +void pdc_enable_hexdump(pdc_core *pdc); +void pdc_disable_hexdump(pdc_core *pdc); +void pdc_hexdump(pdc_core *pdc, const char *msg, const char *text, int tlen); +#endif /* PDC_DEBUG */ + +/* --------------------------- scope --------------------------- */ + +/* + * An arbitrary number used for sanity checks. + * Actually, we use the hex representation of pi in order to avoid + * the more common patterns. + */ + +#define PDC_MAGIC ((unsigned long) 0x126960A1) + +/* environment variable name for license file +*/ +#define PDC_LICFILE_ENV "PDFLIBLICENSEFILE" + + +#endif /* PC_CORE_H */ diff --git a/src/pdflib/pdcore/pc_crypt.c b/src/pdflib/pdcore/pc_crypt.c new file mode 100644 index 0000000..bcc404b --- /dev/null +++ b/src/pdflib/pdcore/pc_crypt.c @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_crypt.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Routines for PDF encryption and decryption + * + */ + +#include "time.h" + +#include "pc_util.h" +#include "pc_md5.h" +#include "pc_crypt.h" + + +static void pdc_pd_crypt_c(void) {} + diff --git a/src/pdflib/pdcore/pc_crypt.h b/src/pdflib/pdcore/pc_crypt.h new file mode 100644 index 0000000..585f22c --- /dev/null +++ b/src/pdflib/pdcore/pc_crypt.h @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_crypt.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Crypto routines + * + */ + +#ifndef PC_CRYPT_H +#define PC_CRYPT_H + +#include "pc_util.h" +#include "pc_arc4.h" +#include "pc_aes.h" + + +#endif /* PC_CRYPT_H */ diff --git a/src/pdflib/pdcore/pc_ctype.c b/src/pdflib/pdcore/pc_ctype.c new file mode 100644 index 0000000..658f82f --- /dev/null +++ b/src/pdflib/pdcore/pc_ctype.c @@ -0,0 +1,309 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 PDFlib GmbH. All rights reserved. | + *---------------------------------------------------------------------------* + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_ctype.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ */ + +#include "pc_ctype.h" + + +#undef LOWER +#undef UPPER +#undef DIGIT +#undef PUNCT +#undef SPACE + +#undef OCT +#undef HEX +#undef DELIM +#undef NUM0 +#undef PDFSP + +#define LOWER 0x0001 +#define UPPER 0x0002 +#define DIGIT 0x0004 +#define PUNCT 0x0008 +#define SPACE 0x0010 + +#define OCT 0x0100 +#define HEX 0x0200 +#define DELIM 0x0400 +#define NUM0 0x0800 /* '+' '-' '.' '0'..'9' */ +#define PDFSP 0x1000 /* ' ' NUL HT NL CR FF */ + + +static const unsigned short pdc_ctype[256] = +{ + PDFSP, /* 0x00 = NUL */ + + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x01 .. 0x08 */ + + SPACE | PDFSP, /* 0x09 = HT */ + SPACE | PDFSP, /* 0x0A = NL */ + SPACE, /* 0x0B = VT */ + SPACE | PDFSP, /* 0x0C = FF */ + SPACE | PDFSP, /* 0x0D = CR */ + 0, /* 0x0E */ + 0, /* 0x0F */ + + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 .. 0x17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18 .. 0x1F */ + + SPACE | PDFSP, /* 0x20 = ' ' */ + PUNCT, /* 0x21 = '!' */ + PUNCT, /* 0x22 = '"' */ + PUNCT, /* 0x23 = '#' */ + PUNCT, /* 0x24 = '$' */ + PUNCT | DELIM, /* 0x25 = '%' */ + PUNCT, /* 0x26 = '&' */ + PUNCT, /* 0x27 = ''' */ + PUNCT | DELIM, /* 0x28 = '(' */ + PUNCT | DELIM, /* 0x29 = ')' */ + PUNCT, /* 0x2A = '*' */ + PUNCT | NUM0, /* 0x2B = '+' */ + PUNCT, /* 0x2C = ',' */ + PUNCT | NUM0, /* 0x2D = '-' */ + PUNCT | NUM0, /* 0x2E = '.' */ + PUNCT | DELIM, /* 0x2F = '/' */ + + DIGIT | NUM0 | HEX | OCT, /* 0x30 = '0' */ + DIGIT | NUM0 | HEX | OCT, /* 0x31 = '1' */ + DIGIT | NUM0 | HEX | OCT, /* 0x32 = '2' */ + DIGIT | NUM0 | HEX | OCT, /* 0x33 = '3' */ + DIGIT | NUM0 | HEX | OCT, /* 0x34 = '4' */ + DIGIT | NUM0 | HEX | OCT, /* 0x35 = '5' */ + DIGIT | NUM0 | HEX | OCT, /* 0x36 = '6' */ + DIGIT | NUM0 | HEX | OCT, /* 0x37 = '7' */ + DIGIT | NUM0 | HEX, /* 0x38 = '8' */ + DIGIT | NUM0 | HEX, /* 0x39 = '9' */ + + PUNCT, /* 0x3A = ':' */ + PUNCT, /* 0x3B = ';' */ + PUNCT | DELIM, /* 0x3C = '<' */ + PUNCT, /* 0x3D = '=' */ + PUNCT | DELIM, /* 0x3E = '>' */ + PUNCT, /* 0x3F = '?' */ + PUNCT, /* 0x40 = '@' */ + + UPPER | HEX, /* 0x41 = 'A' */ + UPPER | HEX, /* 0x42 = 'B' */ + UPPER | HEX, /* 0x43 = 'C' */ + UPPER | HEX, /* 0x44 = 'D' */ + UPPER | HEX, /* 0x45 = 'E' */ + UPPER | HEX, /* 0x46 = 'F' */ + UPPER, /* 0x47 = 'G' */ + UPPER, /* 0x48 = 'H' */ + UPPER, /* 0x49 = 'I' */ + UPPER, /* 0x4A = 'J' */ + UPPER, /* 0x4B = 'K' */ + UPPER, /* 0x4C = 'L' */ + UPPER, /* 0x4D = 'M' */ + UPPER, /* 0x4E = 'N' */ + UPPER, /* 0x4F = 'O' */ + + UPPER, /* 0x50 = 'P' */ + UPPER, /* 0x51 = 'Q' */ + UPPER, /* 0x52 = 'R' */ + UPPER, /* 0x53 = 'S' */ + UPPER, /* 0x54 = 'T' */ + UPPER, /* 0x55 = 'U' */ + UPPER, /* 0x56 = 'V' */ + UPPER, /* 0x57 = 'W' */ + UPPER, /* 0x58 = 'X' */ + UPPER, /* 0x59 = 'Y' */ + UPPER, /* 0x5A = 'Z' */ + + PUNCT | DELIM, /* 0x5B = '[' */ + PUNCT, /* 0x5C = '\' */ + PUNCT | DELIM, /* 0x5D = ']' */ + PUNCT, /* 0x5E = '^' */ + PUNCT, /* 0x5F = '_' */ + PUNCT, /* 0x60 = '`' */ + + LOWER | HEX, /* 0x61 = 'a' */ + LOWER | HEX, /* 0x62 = 'b' */ + LOWER | HEX, /* 0x63 = 'c' */ + LOWER | HEX, /* 0x64 = 'd' */ + LOWER | HEX, /* 0x65 = 'e' */ + LOWER | HEX, /* 0x66 = 'f' */ + LOWER, /* 0x67 = 'g' */ + LOWER, /* 0x68 = 'h' */ + LOWER, /* 0x69 = 'i' */ + LOWER, /* 0x6A = 'j' */ + LOWER, /* 0x6B = 'k' */ + LOWER, /* 0x6C = 'l' */ + LOWER, /* 0x6D = 'm' */ + LOWER, /* 0x6E = 'n' */ + LOWER, /* 0x6F = 'o' */ + + LOWER, /* 0x70 = 'p' */ + LOWER, /* 0x71 = 'q' */ + LOWER, /* 0x72 = 'r' */ + LOWER, /* 0x73 = 's' */ + LOWER, /* 0x74 = 't' */ + LOWER, /* 0x75 = 'u' */ + LOWER, /* 0x76 = 'v' */ + LOWER, /* 0x77 = 'w' */ + LOWER, /* 0x78 = 'x' */ + LOWER, /* 0x79 = 'y' */ + LOWER, /* 0x7A = 'z' */ + + PUNCT | DELIM, /* 0x7B = '{' */ + PUNCT, /* 0x7C = '|' */ + PUNCT | DELIM, /* 0x7D = '}' */ + PUNCT, /* 0x7E = '~' */ + 0, /* 0x7F */ + + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 .. 0x87 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88 .. 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 .. 0x97 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x98 .. 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 .. 0xA7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA8 .. 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 .. 0xB7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB8 .. 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 .. 0xC7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC8 .. 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 .. 0xD7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD8 .. 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 .. 0xE7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE8 .. 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 .. 0xF7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF8 .. 0xFF */ +}; /* pdc_ctype */ + + +pdc_bool pdc__isalnum(pdc_byte c) +{ + + return (pdc_ctype[c] & (LOWER | UPPER | DIGIT)) != 0; +} + +pdc_bool pdc__isalpha(pdc_byte c) +{ + + return (pdc_ctype[c] & (LOWER | UPPER)) != 0; +} + +pdc_bool pdc__isdigit(pdc_byte c) +{ + + return (pdc_ctype[c] & DIGIT) != 0; +} + +pdc_bool pdc__islower(pdc_byte c) +{ + + return (pdc_ctype[c] & LOWER) != 0; +} + +pdc_bool pdc__isprint(pdc_byte c) +{ + + if (c == 0x20) + return pdc_true; + + return (pdc_ctype[c] & (LOWER | UPPER | DIGIT | PUNCT)) != 0; +} + +pdc_bool pdc__ispunct(pdc_byte c) +{ + + return (pdc_ctype[c] & PUNCT) != 0; +} + +pdc_bool pdc__isspace(pdc_byte c) +{ + + return (pdc_ctype[c] & SPACE) != 0; +} + +pdc_bool pdc__isupper(pdc_byte c) +{ + + return (pdc_ctype[c] & UPPER) != 0; +} + +pdc_bool pdc__isxdigit(pdc_byte c) +{ + + return (pdc_ctype[c] & HEX) != 0; +} + +pdc_byte pdc__tolower(pdc_byte c) +{ + if (!pdc_isupper(c)) + { + return c; + } + else + { + return (pdc_byte) (c + 0x20); + } +} + +pdc_byte pdc__toupper(pdc_byte c) +{ + if (!pdc_islower(c)) + { + return c; + } + else + { + return (pdc_byte) (c - 0x20); + } +} + +pdc_bool pdc__isalpha_a(pdc_byte c) +{ + return (pdc_ctype[c] & (LOWER | UPPER)) != 0; +} + +pdc_bool pdc__isdecdt_a(pdc_byte c) +{ + return (pdc_ctype[c] & DIGIT) != 0; +} + +pdc_bool pdc__isdelim_a(pdc_byte c) +{ + return (pdc_ctype[c] & DELIM) != 0; +} + +pdc_bool pdc__ishexdt_a(pdc_byte c) +{ + return (pdc_ctype[c] & HEX) != 0; +} + +pdc_bool pdc__islower_a(pdc_byte c) +{ + return (pdc_ctype[c] & LOWER) != 0; +} + +pdc_bool pdc__isnum0_a(pdc_byte c) +{ + return (pdc_ctype[c] & NUM0) != 0; +} + +pdc_bool pdc__isoctdt_a(pdc_byte c) +{ + return (pdc_ctype[c] & OCT) != 0; +} + +pdc_bool pdc__isspace_a(pdc_byte c) +{ + return (pdc_ctype[c] & PDFSP) != 0; +} + +pdc_bool pdc__isspecial_a(pdc_byte c) +{ + return (pdc_ctype[c] & (PDFSP | DELIM)) != 0; +} + +pdc_bool pdc__isupper_a(pdc_byte c) +{ + return (pdc_ctype[c] & UPPER) != 0; +} diff --git a/src/pdflib/pdcore/pc_ctype.h b/src/pdflib/pdcore/pc_ctype.h new file mode 100644 index 0000000..5aebcb4 --- /dev/null +++ b/src/pdflib/pdcore/pc_ctype.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 PDFlib GmbH. All rights reserved. | + *---------------------------------------------------------------------------* + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_ctype.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ */ + +#ifndef PC_CTYPE_H_INCLUDED +#define PC_CTYPE_H_INCLUDED + +#include "pc_util.h" + +/* these are the locale-free replacements for the standard library +** isXXX() functions. use the macros below, DO NOT use the pdc__isXXX() +** functions directly. +*/ +#define pdc_isalnum(c) pdc__isalnum((pdc_byte) (c)) +#define pdc_isalpha(c) pdc__isalpha((pdc_byte) (c)) +#define pdc_isdigit(c) pdc__isdigit((pdc_byte) (c)) +#define pdc_islower(c) pdc__islower((pdc_byte) (c)) +#define pdc_isprint(c) pdc__isprint((pdc_byte) (c)) +#define pdc_ispunct(c) pdc__ispunct((pdc_byte) (c)) +#define pdc_isspace(c) pdc__isspace((pdc_byte) (c)) +#define pdc_isupper(c) pdc__isupper((pdc_byte) (c)) +#define pdc_isxdigit(c) pdc__isxdigit((pdc_byte) (c)) + +#define pdc_tolower(c) pdc__tolower((pdc_byte) (c)) +#define pdc_toupper(c) pdc__toupper((pdc_byte) (c)) + +pdc_bool pdc__isalnum(pdc_byte c); +pdc_bool pdc__isalpha(pdc_byte c); +pdc_bool pdc__isdigit(pdc_byte c); +pdc_bool pdc__islower(pdc_byte c); +pdc_bool pdc__isprint(pdc_byte c); +pdc_bool pdc__ispunct(pdc_byte c); +pdc_bool pdc__isspace(pdc_byte c); +pdc_bool pdc__isupper(pdc_byte c); +pdc_bool pdc__isxdigit(pdc_byte c); + +pdc_byte pdc__tolower(pdc_byte c); +pdc_byte pdc__toupper(pdc_byte c); + + +/* these macros are for the various flavors of the token scanner. they +** expect ASCII input even on EBCDIC platforms (thus the "_a" suffix), +** and they implement special rules for PDF character classification. +*/ +#define pdc_isalpha_a(c) pdc__isalpha_a((pdc_byte) (c)) +#define pdc_isdecdt_a(c) pdc__isdecdt_a((pdc_byte) (c)) +#define pdc_isdelim_a(c) pdc__isdelim_a((pdc_byte) (c)) +#define pdc_ishexdt_a(c) pdc__ishexdt_a((pdc_byte) (c)) +#define pdc_islower_a(c) pdc__islower_a((pdc_byte) (c)) +#define pdc_isnum0_a(c) pdc__isnum0_a((pdc_byte) (c)) +#define pdc_isoctdt_a(c) pdc__isoctdt_a((pdc_byte) (c)) + +#define pdc_isregular_a(c) \ + ((c) != -1 && !pdc__isspecial_a((pdc_byte) (c))) + +#define pdc_isspace_a(c) pdc__isspace_a((pdc_byte) (c)) +#define pdc_isspecial_a(c) pdc__isspecial_a((pdc_byte) (c)) +#define pdc_isupper_a(c) pdc__isupper_a((pdc_byte) (c)) + +pdc_bool pdc__isalpha_a(pdc_byte c); +pdc_bool pdc__isdecdt_a(pdc_byte c); +pdc_bool pdc__isdelim_a(pdc_byte c); +pdc_bool pdc__ishexdt_a(pdc_byte c); +pdc_bool pdc__islower_a(pdc_byte c); +pdc_bool pdc__isnum0_a(pdc_byte c); +pdc_bool pdc__isoctdt_a(pdc_byte c); +pdc_bool pdc__isspace_a(pdc_byte c); +pdc_bool pdc__isspecial_a(pdc_byte c); +pdc_bool pdc__isupper_a(pdc_byte c); + +#endif /* PC_CTYPE_H_INCLUDED */ diff --git a/src/pdflib/pdcore/pc_digsig.c b/src/pdflib/pdcore/pc_digsig.c new file mode 100644 index 0000000..de2916e --- /dev/null +++ b/src/pdflib/pdcore/pc_digsig.c @@ -0,0 +1,20 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 2006 PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_digsig.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + */ + + +/* ANSI C forbids an empty source file */ +void pdc_dummy_digsig_c(void); +void pdc_dummy_digsig_c() {} + diff --git a/src/pdflib/pdcore/pc_digsig.h b/src/pdflib/pdcore/pc_digsig.h new file mode 100644 index 0000000..caaa3c7 --- /dev/null +++ b/src/pdflib/pdcore/pc_digsig.h @@ -0,0 +1,17 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 2006 PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_digsig.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Digital Signature hashing/signing routines + * + */ diff --git a/src/pdflib/pdcore/pc_ebcdic.c b/src/pdflib/pdcore/pc_ebcdic.c new file mode 100644 index 0000000..cf87c5d --- /dev/null +++ b/src/pdflib/pdcore/pc_ebcdic.c @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_ebcdic.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * EBCDIC conversion routines + * + */ + +#include "pc_util.h" + + +void +pdc_ebcdic2ascii(char *s) +{ + (void) s; +} + diff --git a/src/pdflib/pdcore/pc_ebcdic.h b/src/pdflib/pdcore/pc_ebcdic.h new file mode 100644 index 0000000..5f8993f --- /dev/null +++ b/src/pdflib/pdcore/pc_ebcdic.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_ebcdic.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * EBCDIC conversion routines + * + */ + +#ifndef PC_EBCDIC_H +#define PC_EBCDIC_H + + +void pdc_ebcdic2ascii(char *s); +void pdc_ebcdic2ascii_len(char *s, size_t len); +void pdc_ascii2ebcdic_len(char *s, size_t len); +void pdc_ascii2ebcdic(char *s); +void pdc_ascii2ebcdic_char(char *c); +void pdc_ascii2ebcdic_int(int *i); +void pdc_ebcdic2ascii_int(int *i); +void pdc_ebcdic2ascii_byte(pdc_byte *c); +void pdc_ebcdic2pdfascii(char *s); +void pdc_ebcdic2pdfascii_len(char *s, size_t len); + +#endif /* PC_EBCDIC_H */ + diff --git a/src/pdflib/pdcore/pc_encoding.c b/src/pdflib/pdcore/pc_encoding.c new file mode 100644 index 0000000..3dfa390 --- /dev/null +++ b/src/pdflib/pdcore/pc_encoding.c @@ -0,0 +1,2549 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_encoding.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib in-core encodings and basic encoding functions + * + */ + +#define PC_ENCODING_C + +#include "pc_util.h" +#include "pc_file.h" +#include "pc_ctype.h" + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif /* WIN32 */ + + +typedef struct pdc_unicodeslot_s +{ + pdc_ushort code; /* unicode value */ + pdc_ushort slot; /* slot for this value */ +} +pdc_unicodeslot; + +typedef struct pdc_core_encvector_s +{ + char *apiname; /* PDFlib's name of the encoding at the API */ + int isstdlatin; /* character names are all Adobe standard */ + pdc_ushort codes[256]; /* unicode values */ +} +pdc_core_encvector; + +static const pdc_core_encvector pdc_core_enc_winansi = +{ + "winansi", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_macroman = +{ + "macroman", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x0000, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x0000, 0x00C6, 0x00D8, + 0x0000, 0x00B1, 0x0000, 0x0000, 0x00A5, 0x00B5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x00AA, 0x00BA, 0x0000, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x0000, 0x0192, 0x0000, 0x0000, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x0000, + 0x00FF, 0x0178, 0x2044, 0x00A4, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0x0000, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7, + } +}; + +static const pdc_core_encvector pdc_core_enc_macroman_apple = +{ + "macroman_apple", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x0000, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x2126, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7, + } +}; + +static const pdc_core_encvector pdc_core_enc_ebcdic = +{ + "ebcdic", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x000A, 0x0008, 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, + 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, + 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E, + 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, + 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, + 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, + 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4, + 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x005B, 0x00DE, 0x00AE, + 0x00AC, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, + 0x00BD, 0x00BE, 0x00DD, 0x00A8, 0x00AF, 0x005D, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, + 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F, + } +}; + +static const pdc_core_encvector pdc_core_enc_ebcdic_37 = +{ + "ebcdic_37", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, + 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, + 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC, + 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, + 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, + 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, + 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4, + 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE, + 0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, + 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, + 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F, + } +}; + +static const pdc_core_encvector pdc_core_enc_ebcdic_winansi = +{ + "ebcdic_winansi", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0153, 0x0009, 0x2020, 0x007F, + 0x2014, 0x0000, 0x017D, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0000, 0x000A, 0x0008, 0x2021, + 0x0018, 0x0019, 0x2019, 0x0000, 0x001C, 0x001D, 0x001E, 0x001F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x0017, 0x001B, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0005, 0x0006, 0x0007, + 0x0000, 0x2018, 0x0016, 0x201C, 0x201D, 0x2022, 0x2013, 0x0004, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0014, 0x0015, 0x017E, 0x001A, + 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, + 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, + 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E, + 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, + 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, + 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, + 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4, + 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x005B, 0x00DE, 0x00AE, + 0x00AC, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, + 0x00BD, 0x00BE, 0x00DD, 0x00A8, 0x00AF, 0x005D, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, + 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x0178, + } +}; + +static const pdc_core_encvector pdc_core_enc_pdfdoc = +{ + "pdfdoc", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x02D8, 0x02C7, 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x0000, + 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, + 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, + 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x0141, 0x0152, 0x0160, + 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0x0000, + 0x20AC, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x0000, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_stdenc = +{ + "stdenc", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x0000, 0x00A1, 0x00A2, 0x00A3, 0x2044, 0x00A5, 0x0192, 0x00A7, + 0x00A4, 0x0027, 0x201C, 0x00AB, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x0000, 0x2013, 0x2020, 0x2021, 0x00B7, 0x0000, 0x00B6, 0x2022, + 0x201A, 0x201E, 0x201D, 0x00BB, 0x2026, 0x2030, 0x0000, 0x00BF, + 0x0000, 0x0060, 0x00B4, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, + 0x00A8, 0x0000, 0x02DA, 0x00B8, 0x0000, 0x02DD, 0x02DB, 0x02C7, + 0x2014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x00C6, 0x0000, 0x00AA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0141, 0x00D8, 0x0152, 0x00BA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x00E6, 0x0000, 0x0000, 0x0000, 0x0131, 0x0000, 0x0000, + 0x0142, 0x00F8, 0x0153, 0x00DF, 0x0000, 0x0000, 0x0000, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_macexpert = +{ + "macexpert", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0xF721, 0xF6F8, 0xF7A2, 0xF724, 0xF6E4, 0xF726, 0xF7B4, + 0x207D, 0x207E, 0x2025, 0x2024, 0x002C, 0x002D, 0x002E, 0x2044, + 0xF730, 0xF731, 0xF732, 0xF733, 0xF734, 0xF735, 0xF736, 0xF737, + 0xF738, 0xF739, 0x003A, 0x003B, 0x0000, 0xF6DE, 0x0000, 0xF73F, + 0x0000, 0x0000, 0x0000, 0x0000, 0xF7F0, 0x0000, 0x0000, 0x00BC, + 0x00BD, 0x00BE, 0x215B, 0x215C, 0x215D, 0x215E, 0x2153, 0x2154, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFB00, 0xFB01, + 0xFB02, 0xFB03, 0xFB04, 0x208D, 0x0000, 0x208E, 0xF6F6, 0xF6E5, + 0xF760, 0xF761, 0xF762, 0xF763, 0xF764, 0xF765, 0xF766, 0xF767, + 0xF768, 0xF769, 0xF76A, 0xF76B, 0xF76C, 0xF76D, 0xF76E, 0xF76F, + 0xF770, 0xF771, 0xF772, 0xF773, 0xF774, 0xF775, 0xF776, 0xF777, + 0xF778, 0xF779, 0xF77A, 0x20A1, 0xF6DC, 0xF6DD, 0xF6FE, 0x0000, + 0x0000, 0xF6E9, 0xF6E0, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7E1, + 0xF7E0, 0xF7E2, 0xF7E4, 0xF7E3, 0xF7E5, 0xF7E7, 0xF7E9, 0xF7E8, + 0xF7EA, 0xF7EB, 0xF7ED, 0xF7EC, 0xF7EE, 0xF7EF, 0xF7F1, 0xF7F3, + 0xF7F2, 0xF7F4, 0xF7F6, 0xF7F5, 0xF7FA, 0xF7F9, 0xF7FB, 0xF7FC, + 0x0000, 0x2078, 0x2084, 0x2083, 0x2086, 0x2088, 0x2087, 0xF6FD, + 0x0000, 0xF6DF, 0x2082, 0x0000, 0xF7A8, 0x0000, 0xF6F5, 0xF6F0, + 0x2085, 0x0000, 0xF6E1, 0xF6E7, 0xF7FD, 0x0000, 0xF6E3, 0x0000, + 0x0000, 0xF7FE, 0x0000, 0x2089, 0x2080, 0xF6FF, 0xF7E6, 0xF7F8, + 0xF7BF, 0x2081, 0xF6F9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xF7B8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF6FA, + 0x2012, 0xF6E6, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7A1, 0x0000, + 0xF7FF, 0x0000, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2076, + 0x2077, 0x2079, 0x2070, 0x0000, 0xF6EC, 0xF6F1, 0xF6F3, 0x0000, + 0x0000, 0xF6ED, 0xF6F2, 0xF6EB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xF6EE, 0xF6FB, 0xF6F4, 0xF7AF, 0xF6EA, 0x207F, 0xF6EF, + 0xF6E2, 0xF6E8, 0xF6F7, 0xF6FC, 0x0000, 0x0000, 0x0000, 0x0000, + } +}; + +#ifdef PDF_BUILTINENCODING_SUPPORTED + +static const pdc_core_encvector pdc_core_enc_iso8859_2 = +{ + "iso8859-2", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x00D0, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_3 = +{ + "iso8859-3", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0000, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x0000, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x0000, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0000, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0000, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0000, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_4 = +{ + "iso8859-4", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_5 = +{ + "iso8859-5", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_6 = +{ + "iso8859-6", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, + 0x0668, 0x0669, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0000, 0x0000, 0x0000, 0x00A4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x060C, 0x00AD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x061B, 0x0000, 0x0000, 0x0000, 0x061F, + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_7 = +{ + "iso8859-7", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, 0x0000, 0x0000, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x0000, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_8 = +{ + "iso8859-8", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_9 = +{ + "iso8859-9", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_10 = +{ + "iso8859-10", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_13 = +{ + "iso8859-13", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_14 = +{ + "iso8859-14", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_15 = +{ + "iso8859-15", 1, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x2022, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_iso8859_16 = +{ + "iso8859-16", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B, + 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7, + 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A, + 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, + 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1250 = +{ + "cp1250", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1251 = +{ + "cp1251", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1253 = +{ + "cp1253", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1254 = +{ + "cp1254", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1255 = +{ + "cp1255", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1256 = +{ + "cp1256", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1257 = +{ + "cp1257", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9, + } +}; + +static const pdc_core_encvector pdc_core_enc_cp1258 = +{ + "cp1258", 0, + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF, + } +}; + +#endif /* PDF_BUILTINENCODING_SUPPORTED */ + +static const pdc_core_encvector *pdc_core_encodings[] = { + &pdc_core_enc_winansi, + &pdc_core_enc_macroman, + &pdc_core_enc_macroman_apple, + &pdc_core_enc_ebcdic, + &pdc_core_enc_ebcdic_37, + &pdc_core_enc_ebcdic_winansi, + &pdc_core_enc_pdfdoc, + &pdc_core_enc_stdenc, + &pdc_core_enc_macexpert, +#ifdef PDF_BUILTINENCODING_SUPPORTED + &pdc_core_enc_iso8859_2, + &pdc_core_enc_iso8859_3, + &pdc_core_enc_iso8859_4, + &pdc_core_enc_iso8859_5, + &pdc_core_enc_iso8859_6, + &pdc_core_enc_iso8859_7, + &pdc_core_enc_iso8859_8, + &pdc_core_enc_iso8859_9, + &pdc_core_enc_iso8859_10, + &pdc_core_enc_iso8859_13, + &pdc_core_enc_iso8859_14, + &pdc_core_enc_iso8859_15, + &pdc_core_enc_iso8859_16, + &pdc_core_enc_cp1250, + &pdc_core_enc_cp1251, + &pdc_core_enc_cp1253, + &pdc_core_enc_cp1254, + &pdc_core_enc_cp1255, + &pdc_core_enc_cp1256, + &pdc_core_enc_cp1257, + &pdc_core_enc_cp1258, +#endif /* PDF_BUILTINENCODING_SUPPORTED */ +}; + +static int pdc_enc_numbuiltin = + (int)(sizeof(pdc_core_encodings)/sizeof(pdc_core_encodings[0])); + +pdc_encodingvector * +pdc_copy_core_encoding(pdc_core *pdc, const char *name) +{ + static const char fn[] = "pdc_copy_core_encoding"; + const char *tmpname = name; + const pdc_core_encvector *ev_ic; + pdc_encodingvector *ev = NULL; + int i, slot; + + /* MacRoman encoding with euro sign */ + if (!strcmp(name, "macroman_euro")) + tmpname = "macroman_apple"; + + /* iso8859-1 encoding */ + if (!strcmp(name, "iso8859-1")) + tmpname = "winansi"; + + for (slot = 0; slot < pdc_enc_numbuiltin; slot++) + { + ev_ic = pdc_core_encodings[slot]; + if (!strcmp(tmpname, ev_ic->apiname)) + { + ev = (pdc_encodingvector *) + pdc_malloc(pdc, sizeof(pdc_encodingvector), fn); + + ev->apiname = pdc_strdup(pdc, name); + + for (i = 0; i < 256; i++) + { + ev->codes[i] = ev_ic->codes[i]; + ev->chars[i] = (char *)pdc_unicode2adobe(ev->codes[i]); + ev->given[i] = 1; + } + + if (!strcmp(name, "iso8859-1")) + { + for (i = 0x7E; i < 0xA0; i++) + { + ev->codes[i] = (pdc_ushort) i; + ev->chars[i] = (char *)pdc_unicode2adobe(ev->codes[i]); + } + } + + ev->sortedslots = NULL; + ev->nslots = 0; + ev->flags = PDC_ENC_INCORE; + ev->flags |= PDC_ENC_SETNAMES; + if (ev_ic->isstdlatin) + ev->flags |= PDC_ENC_STDNAMES; + break; + } + } + return ev; +} + + +void +pdc_init_encoding(pdc_core *pdc, pdc_encodingvector *ev, const char *name) +{ + int slot; + + ev->apiname = pdc_strdup(pdc, name); + for (slot = 0; slot < 256; slot++) + { + ev->codes[slot] = 0; + ev->chars[slot] = NULL; + ev->given[slot] = 0; + } + ev->sortedslots = NULL; + ev->nslots = 0; + ev->flags = 0; +} + + +pdc_encodingvector * +pdc_new_encoding(pdc_core *pdc, const char *name) +{ + static const char fn[] = "pdc_new_encoding"; + + pdc_encodingvector *ev = (pdc_encodingvector *) + pdc_malloc(pdc, sizeof(pdc_encodingvector), fn); + if (ev != NULL) + pdc_init_encoding(pdc, ev, name); + return(ev); +} + + +void +pdc_cleanup_encoding(pdc_core *pdc, pdc_encodingvector *ev) +{ + int slot; + + if (ev->apiname) + pdc_free(pdc, ev->apiname); + + if (ev->flags & PDC_ENC_ALLOCCHARS) + { + for (slot = 0; slot < 256; slot++) + if (ev->chars[slot]) + pdc_free(pdc, ev->chars[slot]); + } + + if (ev->sortedslots) + pdc_free(pdc, ev->sortedslots); + + pdc_free(pdc, ev); +} + +pdc_encodingvector * +pdc_copy_encoding(pdc_core *pdc, pdc_encodingvector *evfrom, const char *name) +{ + static const char fn[] = "pdc_copy_encoding"; + + pdc_encodingvector *evto = (pdc_encodingvector *) + pdc_malloc(pdc, sizeof(pdc_encodingvector), fn); + int slot; + + evto->apiname = pdc_strdup(pdc, name); + for (slot = 0; slot < 256; slot++) + { + evto->codes[slot] = evfrom->codes[slot]; + evto->chars[slot] = evfrom->chars[slot]; + evto->given[slot] = 1; + } + evto->sortedslots = NULL; + evto->nslots = 0; + evto->flags = PDC_ENC_SETNAMES; + + return(evto); +} + + +static int +pdc_unicode_compare(const void *a, const void *b) +{ + pdc_unicodeslot *sssa = (pdc_unicodeslot *) a; + pdc_unicodeslot *sssb = (pdc_unicodeslot *) b; + pdc_ushort uva = sssa->code; + pdc_ushort uvb = sssb->code; + return (uva < uvb ? -1 : (uva > uvb ? 1 : 0 )); +} + +int +pdc_get_encoding_bytecode(pdc_core *pdc, pdc_encodingvector *ev, pdc_ushort uv) +{ + static const char fn[] = "pdc_get_encoding_bytecode"; + + if (uv <= PDC_UNICODE_MAXLATIN1 && ev->codes[uv] == uv) + return (int) uv; + + if (uv) + { + pdc_ushort slot; + int i, j, lo, hi; + + if (!ev->sortedslots) + { + int nslots = 1; + pdc_unicodeslot sss[256]; + + sss[0].code = 0; + sss[0].slot = 0; + for (slot = 1; slot < 256; slot++) + { + if (ev->codes[slot]) + { + sss[nslots].code = ev->codes[slot]; + sss[nslots].slot = slot; + nslots++; + } + } + + /* sort unicode values */ + qsort((void *)sss, (size_t) nslots, sizeof(pdc_unicodeslot), + pdc_unicode_compare); + + /* copy slot values */ + ev->sortedslots = + (pdc_byte*)pdc_malloc(pdc, nslots * sizeof(char), fn); + j = 0; + for (i = 0; i < nslots; i++) + { + /* If pairs are identical in unicode values, + * we take the pair with the smaller 8-bit code */ + if (i && sss[i].code == sss[i-1].code) + { + if (sss[i].slot > sss[i-1].slot) + continue; + j--; + } + ev->sortedslots[j] = (pdc_byte) sss[i].slot; + j++; + } + ev->nslots = j; + } + + lo = 0; + hi = ev->nslots; + while (lo < hi) + { + i = (lo + hi) / 2; + slot = (pdc_ushort) ev->sortedslots[i]; + + if (uv == ev->codes[slot]) + return slot; + + if (uv < ev->codes[slot]) + hi = i; + else + lo = i + 1; + } + } + + return -1; +} + +pdc_byte +pdc_transform_bytecode(pdc_core *pdc, pdc_encodingvector *evto, + pdc_encodingvector *evfrom, pdc_byte code) +{ + int tocode = pdc_get_encoding_bytecode(pdc, evto, evfrom->codes[code]); + if (tocode == -1) + tocode = 0; + + return (pdc_byte) tocode; +} + +static const pdc_keyconn pdc_encoding_keytable[] = +{ + {"glyphid", pdc_glyphid}, + {"unicode", pdc_unicode}, + {"builtin", pdc_builtin}, + {"cid", pdc_cid}, + {"winansi", pdc_winansi}, + {"macroman", pdc_macroman}, + {"macroman_apple", pdc_macroman_apple}, + {"ebcdic", pdc_ebcdic}, + {"ebcdic_37", pdc_ebcdic_37}, + {"ebcdic_winansi", pdc_ebcdic_winansi}, + {"pdfdoc", pdc_pdfdoc}, + {"stdenc", pdc_stdenc}, + {"macexpert", pdc_macexpert}, + {NULL, 0}, +}; + +const char * +pdc_get_fixed_encoding_name(pdc_encoding enc) +{ + const char *encname = pdc_get_keyword(enc, pdc_encoding_keytable); + if (encname) + return encname; + return ""; +} + +static const char * +pdc_subst_encoding_name(pdc_core *pdc, const char *encoding, char *buffer) +{ + (void) pdc; + (void) buffer; + + /* special case for the platform-specific host encoding */ + if (!strcmp(encoding, "host") || !strcmp(encoding, "auto")) + { + +#if defined(PDFLIB_EBCDIC) + return PDC_EBCDIC_NAME; + +#elif defined(MAC) + return "macroman"; + +#elif defined(WIN32) + UINT cpident = GetACP(); + if (!strcmp(encoding, "auto")) + { + if (cpident == 10000) + strcpy(buffer, "macroman"); + else if (cpident == 20924) + strcpy(buffer, "ebcdic"); + else if (cpident >= 28590 && cpident <= 28599) + sprintf(buffer, "iso8859-%d", cpident-28590); + else if (cpident >= 28600 && cpident <= 28609) + sprintf(buffer, "iso8859-%d", cpident-28600+10); + else if (cpident == 1200 || cpident == 1201) + strcpy(buffer, "unicode"); + else + sprintf(buffer, "cp%d", cpident); + encoding = buffer; + } + else + { + return "winansi"; + } +#else + return "iso8859-1"; +#endif + } + + /* These encodings will be mapped to winansi */ + if (!strcmp(encoding, "host") || + !strcmp(encoding, "auto") || + !strcmp(encoding, "cp1252")) + return "winansi"; + + return encoding; +} + + +/* + * Try to read an encoding from file. + * + */ + +pdc_encodingvector * +pdc_read_encoding(pdc_core *pdc, const char *encoding, const char *filename, + pdc_bool verbose) +{ + pdc_encodingvector *ev = NULL; + pdc_file *fp; + char **linelist = NULL, **itemlist = NULL; + char *line, *item; + const char *stemp; + int nlines = 0, l, nitems; + pdc_bool isenc = pdc_undef; + pdc_byte code; + pdc_ushort uv; + + fp = pdc_fsearch_fopen(pdc, filename, NULL, "encoding ", PDC_FILE_TEXT); + if (fp == NULL) + { + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + } + else + { + nlines = pdc_read_textfile(pdc, fp, PDC_FILE_BSSUBST, &linelist); + pdc_fclose(fp); + } + if (!nlines) + return NULL; + + ev = pdc_new_encoding(pdc, encoding); + + for (l = 0; l < nlines; l++) + { + line = linelist[l]; + nitems = pdc_split_stringlist(pdc, line, NULL, 0, &itemlist); + if (!nitems) continue; + + /* Glyphname or Unicode value */ + item = itemlist[0]; + if (isenc == pdc_undef) + { + if (!strncmp(item, "0x", 2) || !strncmp(item, "0X", 2)) + isenc = pdc_false; + else + isenc = pdc_true; + } + if (isenc) + { + uv = pdc_insert_glyphname(pdc, item); + if (nitems == 3 && !pdc_str2integer(itemlist[2], + PDC_INT_UNICODE, (pdc_ushort *) &uv)) + goto PDC_ENC_ERROR; + } + else if (!pdc_str2integer(item, PDC_INT_UNICODE, (pdc_ushort *) &uv)) + { + goto PDC_ENC_ERROR; + } + if (nitems < 2) + goto PDC_ENC_ERROR; + + /* Code value */ + if (!pdc_str2integer(itemlist[1], PDC_INT_UNSIGNED | PDC_INT_CHAR, + (pdc_byte *) &code)) + { + if (!pdc_str2integer(itemlist[1], PDC_INT_CODE, (pdc_byte *) &code)) + goto PDC_ENC_ERROR; + } + + /* Saving */ + ev->codes[code] = uv; + if (isenc) + { + ev->chars[code] = pdc_strdup(pdc, item); + ev->given[code] = 1; + } + else + { + ev->chars[code] = (char *) pdc_insert_unicode(pdc, uv); + } + + pdc_cleanup_stringlist(pdc, itemlist); + itemlist = NULL; + } + pdc_cleanup_stringlist(pdc, linelist); + linelist = NULL; + + ev->flags |= PDC_ENC_FILE; + ev->flags |= PDC_ENC_SETNAMES; + if (isenc) + ev->flags |= PDC_ENC_ALLOCCHARS; + + return ev; + + PDC_ENC_ERROR: + stemp = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, line); + pdc_cleanup_stringlist(pdc, itemlist); + pdc_cleanup_stringlist(pdc, linelist); + pdc_cleanup_encoding(pdc, ev); + if (verbose) + pdc_error(pdc, PDC_E_ENC_BADLINE, filename, stemp, 0, 0); + return NULL; +} + +/* + * Try to generate an encoding from a Unicode code page. + * + * Return value: allocated encoding struct + * NULL: error + */ + +pdc_encodingvector * +pdc_generate_encoding(pdc_core *pdc, const char *encoding) +{ + pdc_encodingvector *ev = NULL; + char **itemlist = NULL, *item; + pdc_ushort uv, uv1 = 0xFFFF, uv2 = 0xFFFF; + int nitems, slot; + + nitems = pdc_split_stringlist(pdc, encoding, " U", 0, &itemlist); + if (nitems && nitems <= 2 && !strncmp(encoding, "U+", 2)) + { + /* first unicode offset */ + item = itemlist[0]; + if (pdc_str2integer(item, PDC_INT_UNICODE, (pdc_ushort *) &uv1)) + { + if (nitems == 2) + { + /* second unicode offset */ + item = itemlist[1]; + if (!pdc_str2integer(item, PDC_INT_UNICODE, + (pdc_ushort *) &uv2)) + uv2 = 0xFFFF; + } + if ((nitems == 1 && uv1 <= 0xFF00) || + (nitems == 2 && uv1 <= 0xFF80 && uv2 <= 0xFF80)) + { + uv = uv1; + ev = pdc_new_encoding(pdc, encoding); + for (slot = 0; slot < 256; slot++) + { + if (slot == 128 && nitems == 2) uv = uv2; + ev->codes[slot] = uv; + ev->chars[slot] = (char *) pdc_insert_unicode(pdc, uv); + uv++; + } + ev->flags |= PDC_ENC_GENERATE; + ev->flags |= PDC_ENC_SETNAMES; + } + } + } + + pdc_cleanup_stringlist(pdc, itemlist); + return ev; +} + + +/* ---------------------- encoding stack ---------------------- */ + +struct pdc_encoding_stack_s +{ + pdc_encoding_info *info; /* all encodings in document */ + int capacity; /* currently allocated size */ + int number; /* next available encoding info slot */ +}; + +pdc_encoding_stack * +pdc_new_encodingstack(pdc_core *pdc) +{ + static const char fn[] = "pdc_new_encodingstack"; + + pdc_encoding_stack *est = + (pdc_encoding_stack *) pdc_malloc(pdc, sizeof(pdc_encoding_stack), fn); + + est->info = NULL; + est->capacity = 0; + est->number = 0; + + pdc->encstack = est; + + return est; +} + +void +pdc_delete_encodingstack(pdc_core *pdc) +{ + pdc_encoding_stack *est = pdc->encstack; + int slot; + + if (est != NULL) + { + for (slot = 0; slot < est->number; slot++) + { + if (est->info != NULL && est->info[slot].ev != NULL) + pdc_cleanup_encoding(pdc, est->info[slot].ev); + } + + if (est->info) + pdc_free(pdc, est->info); + + pdc_free(pdc, est); + pdc->encstack = NULL; + } +} + +static pdc_encoding_stack * +pdc_get_encodingstack(pdc_core *pdc) +{ + pdc_encoding_stack *est = pdc->encstack; + + if (est == NULL) + est = pdc_new_encodingstack(pdc); + + return est; +} + +int +pdc_get_encodingstack_number(pdc_core *pdc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + return est->number; +} + +static void +pdc_init_encoding_info_mem(pdc_encoding_info *info, pdc_bool withev) +{ + if (withev) + info->ev = NULL; + info->id = PDC_BAD_ID; + info->tounicode_id = PDC_BAD_ID; + info->used_in_formfield = pdc_false; + info->stored = pdc_false; +} + +void +pdc_init_encoding_info_ids(pdc_core *pdc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + int slot; + + for (slot = 0; slot < est->capacity; slot++) + pdc_init_encoding_info_mem(&est->info[slot], pdc_false); +} + +static void +pdc_init_encoding_info(pdc_core *pdc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + int slot; + + for (slot = est->number; slot < est->capacity; slot++) + pdc_init_encoding_info_mem(&est->info[slot], pdc_true); +} + +pdc_encoding +pdc_insert_encoding_vector(pdc_core *pdc, pdc_encodingvector *ev) +{ + static const char fn[] = "pdc_insert_encoding_vector"; + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + int slot; + + if (est->number == 0) + { + est->capacity = pdc_firstvarenc + 1; + est->info = (pdc_encoding_info *) pdc_malloc(pdc, + sizeof(pdc_encoding_info) * est->capacity, fn); + + pdc_init_encoding_info(pdc); + + /* we must reserve the first pdc_firstvarenc slots for standard + * encodings, because the program identify their by index of + * encoding stack! (see pdc_find_encoding) + */ + est->number = (int) pdc_firstvarenc; + } + + /* search for free slot */ + for (slot = pdc_firstvarenc; slot < est->capacity; slot++) + if (est->info[slot].ev == NULL) + break; + + if (slot == est->capacity) + { + est->capacity *= 2; + est->info = (pdc_encoding_info *) pdc_realloc(pdc, est->info, + sizeof(pdc_encoding_info) * est->capacity, fn); + + pdc_init_encoding_info(pdc); + } + + if (ev != NULL) + { + est->info[slot].ev = ev; + if (slot == est->number) + (est->number)++; + } + + return (pdc_encoding) slot; +} + +void +pdc_remove_encoding_vector(pdc_core *pdc, int slot) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + + if (est && slot >= 0 && slot < est->number) + { + pdc_encoding_info *info = &est->info[slot]; + + if (info->ev != NULL) + { + pdc_cleanup_encoding(pdc, info->ev); + pdc_init_encoding_info_mem(info, pdc_true); + } + } +} + +pdc_encoding +pdc_find_encoding(pdc_core *pdc, const char *encoding) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + pdc_encodingvector *ev = NULL; + char buffer[PDC_ENCNAME_LEN]; + pdc_encoding_info *info; + int slot; + + /* substituting encoding name */ + encoding = pdc_subst_encoding_name(pdc, encoding, buffer); + + /* search for a fixed encoding */ + for (slot = (pdc_encoding) pdc_invalidenc + 1; + slot < (pdc_encoding) pdc_firstvarenc; slot++) + { + if (!strcmp(encoding, pdc_get_fixed_encoding_name((pdc_encoding) slot))) + { + /* copy in-core encoding at fixed slots */ + if (slot >= 0) + { + if (est->number == 0) + pdc_insert_encoding_vector(pdc, NULL); + info = &est->info[slot]; + if (info->ev == NULL) + info->ev = pdc_copy_core_encoding(pdc, encoding); + } + return((pdc_encoding) slot); + } + } + + /* search for a user defined encoding */ + for (slot = (pdc_encoding) pdc_firstvarenc; + slot < est->number; slot++) + { + info = &est->info[slot]; + if (info->ev != NULL && info->ev->apiname != NULL && + !strcmp(encoding, info->ev->apiname)) + return((pdc_encoding) slot); + } + + /* search for an in-core encoding */ + ev = pdc_copy_core_encoding(pdc, encoding); + if (ev != NULL) + return pdc_insert_encoding_vector(pdc, ev); + + return (pdc_invalidenc); +} + + +pdc_encoding +pdc_insert_encoding(pdc_core *pdc, const char *encoding, int *codepage, + pdc_bool verbose) +{ + const char *filename; + char buffer[PDC_ENCNAME_LEN]; + pdc_encodingvector *ev = NULL; + pdc_encoding enc = pdc_invalidenc; + pdc_bool logg = pdc_true; + + *codepage = 0; + + /* substituting encoding name */ + encoding = pdc_subst_encoding_name(pdc, encoding, buffer); + + /* check for an user-defined encoding */ + filename = pdc_find_resource(pdc, "Encoding", encoding); + if (filename) + ev = pdc_read_encoding(pdc, encoding, filename, verbose); + if (ev == NULL) + { + /* check for a generate encoding */ + ev = pdc_generate_encoding(pdc, encoding); + if (ev == NULL) + { + { + if (!strcmp(encoding, PDC_ENC_TEMPNAME)) + { + ev = pdc_new_encoding(pdc, encoding); + ev->flags |= PDC_ENC_TEMP; + logg = pdc_false; + } + else + { + pdc_set_errmsg(pdc, PDC_E_ENC_NOTFOUND, + encoding, 0, 0, 0); + + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + + return pdc_invalidenc; + } + } + } + } + + if (*codepage) + enc = pdc_unicode; + else + enc = pdc_insert_encoding_vector(pdc, ev); + + if (logg) + pdc_encoding_logg_protocol(pdc, ev); + + return enc; +} + +pdc_encoding +pdc_get_encoding(pdc_core *pdc, const char *encoding, int *codepage, + pdc_bool verbose) +{ + pdc_encoding enc = pdc_invalidenc; + + *codepage = 0; + enc = pdc_find_encoding(pdc, encoding); + if (enc == pdc_invalidenc) + enc = pdc_insert_encoding(pdc, encoding, codepage, verbose); + if (enc == pdc_invalidenc && verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + + return enc; +} + +pdc_encoding_info * +pdc_get_encoding_info(pdc_core *pdc, pdc_encoding enc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + pdc_encoding_info *info = NULL; + + if (est) + { + if (est->number == 0) + pdc_insert_encoding_vector(pdc, NULL); + if (enc >= 0 && enc < est->number) + { + info = &est->info[enc]; + if (info->ev == NULL) + { + const char *encoding = pdc_get_fixed_encoding_name(enc); + + if (encoding[0] != 0) + { + pdc_find_encoding(pdc, encoding); + info = &est->info[enc]; + } + } + } + } + + return info; +} + +const char * +pdc_get_user_encoding(pdc_core *pdc, pdc_encoding enc) +{ + const char *encoding = pdc_get_fixed_encoding_name(enc); + + if (!encoding[0] && enc >= 0) + { + pdc_encoding_info *info = pdc_get_encoding_info(pdc, enc); + if (info->ev != NULL) + encoding = info->ev->apiname; + } + + return encoding; +} + +pdc_encodingvector * +pdc_get_encoding_vector(pdc_core *pdc, pdc_encoding enc) +{ + pdc_encoding_info *info = pdc_get_encoding_info(pdc, enc); + + return info ? info->ev : NULL; +} + + +pdc_encodingvector * +pdc_get_encoding_vector_direct(pdc_core *pdc, pdc_encoding enc) +{ + return pdc->encstack->info[enc].ev; +} + +void +pdc_set_encoding_glyphnames(pdc_core *pdc, pdc_encoding enc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + pdc_encodingvector *ev = est->info[enc].ev; + int slot; + pdc_ushort uv; + + if (ev != NULL && !(ev->flags & PDC_ENC_SETNAMES)) + { + ev->flags |= PDC_ENC_SETNAMES; + for (slot = 0; slot < 256; slot++) + { + uv = ev->codes[slot]; + ev->chars[slot] = (char *)pdc_unicode2glyphname(pdc, uv); + } + } +} + +pdc_bool +pdc_get_encoding_isstdflag(pdc_core *pdc, pdc_encoding enc) +{ + pdc_encoding_stack *est = pdc_get_encodingstack(pdc); + pdc_encodingvector *ev = est->info[enc].ev; + int slot; + pdc_bool isstd = pdc_true; + + if (ev != NULL && + !(ev->flags & PDC_ENC_INCORE) && !(ev->flags & PDC_ENC_STDNAMES)) + { + for (slot = 0; slot < 256; slot++) + { + if (!(ev->flags & PDC_ENC_SETNAMES)) + ev->chars[slot] = + (char *) pdc_unicode2glyphname(pdc, ev->codes[slot]); + if (isstd == pdc_true && ev->chars[slot]) + { + isstd = pdc_is_std_charname((char *) ev->chars[slot]); + if (isstd == pdc_false && (ev->flags & PDC_ENC_SETNAMES)) + break; + } + } + ev->flags |= PDC_ENC_SETNAMES; + if (isstd == pdc_true) + ev->flags |= PDC_ENC_STDNAMES; + } + + return (ev->flags & PDC_ENC_STDNAMES) ? pdc_true : pdc_false; +} + +pdc_bool +pdc_is_encoding_subset(pdc_core *pdc, pdc_encodingvector *testev, + pdc_encodingvector *refev) +{ + pdc_ushort uv; + int code; + + for (code = 0; code < 256; code++) + { + uv = testev->codes[code]; + if (pdc_get_encoding_bytecode(pdc, refev, uv) == -1) + { + const char *glyphname = pdc_unicode2adobe(uv); + if (glyphname && strcmp(glyphname, pdc_get_notdef_glyphname())) + { + break; + } + } + } + + return (code == 256) ? pdc_true : pdc_false; +} + +/* ------------------------- PDF encodings ------------------------ */ + +static const pdc_keyconn pdc_pdfencoding_keytable[] = +{ + {"WinAnsiEncoding", pdc_winansi}, + {"MacRomanEncoding", pdc_macroman}, + {"PDFDocEncoding", pdc_pdfdoc}, + {"StandardEncoding", pdc_stdenc}, + {"MacExpertEncoding", pdc_macexpert}, + {NULL, 0}, +}; + +const char * +pdc_get_pdf_encoding_name(int enc) +{ + const char *encname = pdc_get_keyword(enc, pdc_pdfencoding_keytable); + + return encname ? encname : ""; +} + +int +pdc_get_pdf_encoding_code(const char *encname) +{ + int enc = pdc_get_keycode(encname, pdc_pdfencoding_keytable); + + return (enc != PDC_KEY_NOTFOUND) ? enc : pdc_invalidenc; +} + +/* ---------------------- private glyph table ---------------------- */ + +#define PRIVGLYPHS_CHUNKSIZE 256 + + +struct pdc_priv_glyphtab_s +{ + pdc_glyph_tab *unicode2name; /* private unicode to glyphname table */ + pdc_glyph_tab *name2unicode; /* private glyphname to unicode table */ + int glyph_tab_capacity; /* currently allocated size */ + int glyph_tab_size; /* size of glyph tables */ + pdc_ushort next_unicode; /* next available unicode number */ +}; + +pdc_priv_glyphtab * +pdc_new_pglyphtab(pdc_core *pdc) +{ + static const char fn[] = "pdc_new_pglyphtab"; + + pdc_priv_glyphtab *pgt = (pdc_priv_glyphtab *) pdc_malloc(pdc, + sizeof(pdc_priv_glyphtab), fn); + + pgt->next_unicode = (pdc_ushort) PDC_UNICODE_PDFPUA; + pgt->unicode2name = NULL; + pgt->name2unicode = NULL; + pgt->glyph_tab_capacity = 0; + pgt->glyph_tab_size = 0; + + pdc->pglyphtab = pgt; + + return pgt; +} + +void +pdc_delete_pglyphtab(pdc_core *pdc) +{ + pdc_priv_glyphtab *pgt = pdc->pglyphtab; + + if (pgt) + { + int slot; + + if (pgt->unicode2name) + { + for (slot = 0; slot < pgt->glyph_tab_size; slot++) + pdc_free(pdc, (char *)pgt->unicode2name[slot].name); + + if (pgt->unicode2name) + pdc_free(pdc, pgt->unicode2name); + pgt->unicode2name = NULL; + } + + if (pgt->name2unicode) + pdc_free(pdc, pgt->name2unicode); + pgt->name2unicode = NULL; + + + pdc_free(pdc, pgt); + pdc->pglyphtab = NULL; + } +} + +static pdc_priv_glyphtab * +pdc_get_glyphtab(pdc_core *pdc) +{ + pdc_priv_glyphtab *pgt = pdc->pglyphtab; + + if (pgt == NULL) + pgt = pdc_new_pglyphtab(pdc); + + return pgt; +} + +pdc_ushort +pdc_register_glyphname(pdc_core *pdc, const char *glyphname, + pdc_ushort uv, pdc_bool forcepua) +{ + static const char fn[] = "pdc_register_glyphname"; + pdc_priv_glyphtab *pgt = pdc_get_glyphtab(pdc); + char buf[16]; + int i, n, slot, slotname, slotuv; + + /* Re-allocate private glyphname tables */ + if (pgt->glyph_tab_size == pgt->glyph_tab_capacity) + { + if (pgt->glyph_tab_capacity == 0) + { + pgt->glyph_tab_size = 0; + pgt->glyph_tab_capacity = PRIVGLYPHS_CHUNKSIZE; + pgt->unicode2name = (pdc_glyph_tab *) pdc_malloc(pdc, + sizeof(pdc_glyph_tab) * pgt->glyph_tab_capacity, fn); + pgt->name2unicode = (pdc_glyph_tab *) pdc_malloc(pdc, + sizeof(pdc_glyph_tab) * pgt->glyph_tab_capacity, fn); + } + else + { + n = pgt->glyph_tab_capacity + PRIVGLYPHS_CHUNKSIZE; + pgt->unicode2name = (pdc_glyph_tab *) pdc_realloc(pdc, + pgt->unicode2name, n * sizeof(pdc_glyph_tab), fn); + pgt->name2unicode = (pdc_glyph_tab *) pdc_realloc(pdc, + pgt->name2unicode, n * sizeof(pdc_glyph_tab), fn); + pgt->glyph_tab_capacity = n; + } + } + + /* Set reasonable glyph name "unixxxx" */ + if (!glyphname) + { + sprintf(buf, "uni%04X", uv); + glyphname = buf; + } + + /* Set reasonable unicode value in the case of "unixxxx" glyph names. + * Otherwise the next free PDFlib PUA value + */ + if (!uv) + { + if (!forcepua && !strncmp(glyphname, "uni", 3) && + pdc_str2integer(&glyphname[3], PDC_INT_HEXADEC, &i)) + uv = (pdc_ushort) i; + if (!uv) + { + uv = pgt->next_unicode; + pgt->next_unicode = (pdc_ushort) (uv + 1); + } + } + + /* Find slot so that new glyphname is sorted in to name table */ + slotname = pgt->glyph_tab_size; + if (slotname > 0 && + strcmp(glyphname, pgt->name2unicode[slotname-1].name) < 0) + { + for (slot = 0; slot < pgt->glyph_tab_size; slot++) + { + if (strcmp(glyphname, pgt->name2unicode[slot].name) < 0) + break; + } + slotname = slot; + if (slot < pgt->glyph_tab_size) + { + for (slot = pgt->glyph_tab_size; slot > slotname; slot--) + { + pgt->name2unicode[slot].code = pgt->name2unicode[slot-1].code; + pgt->name2unicode[slot].name = pgt->name2unicode[slot-1].name; + } + } + } + + /* Find slot so that new unicode is sorted in to unicode table */ + slotuv = pgt->glyph_tab_size; + if (slotuv > 0 && + uv > pgt->unicode2name[slotuv-1].code) + { + for (slot = 0; slot < pgt->glyph_tab_size; slot++) + { + if (uv < pgt->unicode2name[slot].code) + break; + } + + slotuv = slot; + if (slot < pgt->glyph_tab_size) + { + for (slot = pgt->glyph_tab_size; slot > slotuv; slot--) + { + pgt->unicode2name[slot].code = pgt->unicode2name[slot-1].code; + pgt->unicode2name[slot].name = pgt->unicode2name[slot-1].name; + } + } + } + + pgt->name2unicode[slotname].code = uv; + pgt->name2unicode[slotname].name = pdc_strdup(pdc, glyphname); + pgt->unicode2name[slotuv].code = uv; + pgt->unicode2name[slotuv].name = pgt->name2unicode[slotname].name; + + pgt->glyph_tab_size += 1; + + return uv; +} + +int +pdc_privglyphname2unicode(pdc_core *pdc, const char *glyphname) +{ + pdc_priv_glyphtab *pgt = pdc_get_glyphtab(pdc); + + if (pgt && pgt->glyph_tab_size) + return pdc_glyphname2code(glyphname, pgt->name2unicode, + pgt->glyph_tab_size); + return -1; +} + +int +pdc_glyphname2unicodelist(pdc_core *pdc, const char *glyphname, + pdc_ushort *uvlist) +{ + int nv = 0, retval = -1; + + /* private glyph names */ + retval = pdc_privglyphname2unicode(pdc, glyphname); + if (retval > -1) + { + nv = 1; + uvlist[0] = (pdc_ushort) retval; + } + + if (!nv) + { + /* .notdef */ + if (glyphname == NULL) + glyphname = pdc_get_notdef_glyphname(); + if (!strcmp(glyphname, pdc_get_notdef_glyphname())) + { + nv = 1; + uvlist[0] = 0; + } + else + { + /* Searching for glyph name in AGL, + * ZapfDingbats and misnamed table + */ + retval = pdc_adobe2unicode(glyphname); + if (retval > -1) + { + nv = 1; + uvlist[0] = (pdc_ushort) retval; + } + else + { + nv = pdc_newadobe2unicodelist(glyphname, uvlist); + if (!nv) + { + retval = pdc_zadb2unicode(glyphname); + if (retval > -1) + { + nv = 1; + uvlist[0] = (pdc_ushort) retval; + } + } + } + } + } + + return nv; +} + +int +pdc_glyphname2unicode(pdc_core *pdc, const char *glyphname) +{ + pdc_ushort uvlist[PDC_MAX_UVLIST]; + int nv = pdc_glyphname2unicodelist(pdc, glyphname, uvlist); + + switch (nv) + { + case 0: + return -1; + + case 1: + return (int) uvlist[0]; + + /* we doesn't support glyph names + * with multiple Unicode values */ + default: + return 0; + } +} + +int +pdc_glyphname2utf32(pdc_core *pdc, const char *glyphname) +{ + pdc_ushort uvlist[PDC_MAX_UVLIST]; + int ic = 0, nv, usv; + + nv = pdc_glyphname2unicodelist(pdc, glyphname, uvlist); + usv = pdc_char16_to_char32(pdc, uvlist, &ic, 2, pdc_false); + if (nv <= 2 && usv > -1) + return usv; + + return -1; +} + +const char * +pdc_glyphname2privglyphname(pdc_core *pdc, const char *glyphname) +{ + pdc_priv_glyphtab *pgt = pdc_get_glyphtab(pdc); + + if (pgt && pgt->glyph_tab_size) + return pdc_glyphname2glyphname(glyphname, pgt->name2unicode, + pgt->glyph_tab_size); + return NULL; +} + +const char * +pdc_unicode2glyphname(pdc_core *pdc, pdc_ushort uv) +{ + pdc_priv_glyphtab *pgt = pdc_get_glyphtab(pdc); + const char *retval = NULL; + + /* Private unicode table available */ + if (pgt && pgt->glyph_tab_size) + retval = pdc_code2glyphname(uv, pgt->unicode2name, + pgt->glyph_tab_size); + + /* Searching for unicode value in AGL, ZapfDingbats and misnamed table */ + if (retval == NULL) + { + retval = pdc_unicode2adobe(uv); + if (retval == NULL) + { + retval = pdc_unicode2newadobe(uv); + if (retval == NULL) + { + retval = pdc_unicode2zadb(uv); + } + } + } + return retval; +} + +pdc_ushort +pdc_insert_glyphname(pdc_core *pdc, const char *glyphname) +{ + pdc_ushort uv; + int retval; + + retval = pdc_glyphname2unicode(pdc, glyphname); + if (retval == -1) + uv = pdc_register_glyphname(pdc, glyphname, 0, pdc_false); + else + uv = (pdc_ushort) retval; + return uv; +} + +const char * +pdc_insert_unicode(pdc_core *pdc, pdc_ushort uv) +{ + const char *glyphname; + + glyphname = pdc_unicode2glyphname(pdc, uv); + if (!glyphname) + { + pdc_register_glyphname(pdc, NULL, uv, pdc_false); + glyphname = pdc_unicode2glyphname(pdc, uv); + } + return glyphname; +} + + + +void +pdc_encoding_logg_protocol(pdc_core *pdc, pdc_encodingvector *ev) +{ + if (ev != NULL && + pdc_logg_is_enabled(pdc, 2, trc_encoding)) + { + int slot; + + pdc_logg(pdc, + "\n\t\tEncoding name: \"%s\"\n" + "\t\tCode Unicode Name\n", + ev->apiname); + + for (slot = 0; slot < 256; slot++) + { + pdc_ushort uv = ev->codes[slot]; + + if (!(ev->flags & PDC_ENC_SETNAMES)) + ev->chars[slot] = (char *)pdc_unicode2glyphname(pdc, uv); + + if (uv != 0) + { + pdc_logg(pdc, + "\t\t%4d U+%04X \"%s\"", + slot, uv, ev->chars[slot] ? ev->chars[slot] : ""); + + + pdc_logg(pdc, "\n"); + } + } + + ev->flags |= PDC_ENC_SETNAMES; + } +} diff --git a/src/pdflib/pdcore/pc_encoding.h b/src/pdflib/pdcore/pc_encoding.h new file mode 100644 index 0000000..633e1a7 --- /dev/null +++ b/src/pdflib/pdcore/pc_encoding.h @@ -0,0 +1,295 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_encoding.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Encoding data structures and routines + * + */ + +#ifndef PC_ENCODING_H +#define PC_ENCODING_H + +/* + * Symbolic names for predefined font encodings. 0 and above are used + * as indices in the pdc_encodingvector array. The encodings starting at + * pdc_firstvarenc have no enumeration name, because they are loaded + * dynamically. + * The predefined encodings must not be changed or rearranged. + * The order of encodings here must match that of pdc_core_encodings + * and pdc_fixed_encoding_names in pc_encoding.c. + */ +typedef enum +{ + pdc_invalidenc = -5, + pdc_glyphid = -4, + pdc_unicode = -3, + pdc_builtin = -2, + pdc_cid = -1, + + pdc_winansi = 0, + pdc_macroman = 1, + pdc_macroman_apple = 2, + pdc_ebcdic = 3, + pdc_ebcdic_37 = 4, + pdc_ebcdic_winansi = 5, + pdc_pdfdoc = 6, + pdc_stdenc = 7, + pdc_macexpert = 8, + pdc_firstvarenc = 9, + + pdc_encmax = PDC_INT_MAX +} +pdc_encoding; + +/* Predefined character collections */ +typedef enum +{ + cc_none = 0, + cc_japanese, + cc_simplified_chinese, + cc_traditional_chinese, + cc_korean, + cc_identity, + cc_unknown +} +pdc_charcoll; + +#define PDC_NUMCHARCOLL 4 + +/* treatment of non-resolvable character references */ +typedef enum +{ + text_nocheck = -2, + text_error = -1, + text_replace = 0 +} +pdc_glyphcheck; + + + +#define PDC_EBCDIC_NAME "ebcdic" +#define PDC_EBCDIC_ENC pdc_ebcdic + +typedef struct pdc_charclass_tab_s pdc_charclass_tab; +typedef struct pdc_code_map_s pdc_code_map; +typedef struct pdc_encoding_info_s pdc_encoding_info; +typedef struct pdc_encoding_stack_s pdc_encoding_stack; +typedef struct pdc_encodingvector_s pdc_encodingvector; +typedef struct pdc_priv_glyphtab_s pdc_priv_glyphtab; +typedef struct pdc_glyph_tab_s pdc_glyph_tab; + +struct pdc_encodingvector_s +{ + char *apiname; /* PDFlib's name of the encoding at the API */ + pdc_ushort codes[256]; /* unicode values */ + char *chars[256]; /* character names */ + char given[256]; /* flags for kind of given character name */ + pdc_byte *sortedslots; /* slots for sorted unicode values */ + int nslots; /* number of sorted slots */ + unsigned long flags; /* flags, see PDC_ENC_... */ +}; + +struct pdc_encoding_info_s +{ + pdc_encodingvector *ev; /* encoding vector */ + pdc_id id; /* encoding object id */ + pdc_id tounicode_id; /* tounicode object ids */ + pdc_bool used_in_formfield; /* encoding is in use in form field */ + pdc_bool stored; /* encoding is stored in PDF */ +}; + +struct pdc_code_map_s +{ + pdc_ushort src; /* source code */ + pdc_ushort dst; /* destination code */ +}; + +struct pdc_glyph_tab_s +{ + pdc_ushort code; + const char *name; +}; + + +#define PDC_ENC_INCORE (1L<<0) /* encoding from in-core */ +#define PDC_ENC_FILE (1L<<1) /* encoding from file */ +#define PDC_ENC_HOST (1L<<2) /* encoding from host system */ +#define PDC_ENC_USER (1L<<3) /* encoding from user */ +#define PDC_ENC_FONT (1L<<4) /* encoding from font resp. for a font*/ +#define PDC_ENC_GENERATE (1L<<5) /* encoding generated from Unicode page */ +#define PDC_ENC_USED (1L<<6) /* encoding already used */ +#define PDC_ENC_SETNAMES (1L<<7) /* character names are set */ +#define PDC_ENC_ALLOCCHARS (1L<<8) /* character names are allocated */ +#define PDC_ENC_STDNAMES (1L<<9) /* character names are all Adobe standard */ +#define PDC_ENC_TEMP (1L<<10) /* temporary generated encoding */ + +#define PDC_ENC_MODSEPAR "_" /* separator of modified encoding */ +#define PDC_ENC_MODWINANSI "winansi_" /* prefix of modified winansi enc */ +#define PDC_ENC_MODMACROMAN "macroman_" /* prefix of modified macroman enc */ +#define PDC_ENC_MODEBCDIC "ebcdic_" /* prefix of modified ebcdic enc */ +#define PDC_ENC_ISO8859 "iso8859-" /* begin of iso8859 enc name */ +#define PDC_ENC_CP125 "cp125" /* begin of ANSI enc name */ + +#define PDC_ENC_TEMPNAME "__temp__enc__" /* name of temporary encoding */ + +#define PDC_ENCNAME_LEN PDC_FILENAMELEN + +/* Adobe glyph names can have maximal 7 components */ +#define PDC_MAX_UVLIST 8 + +/* maximal length of glyph names */ +#define PDC_CHARREF_MAXNAMLEN 64 + +/* types of glyph names */ +#define PDC_GLF_ISUNDEF (1<<0) /* is undefined (unknown Unicode(s) */ +#define PDC_GLF_ISAGL12NAME (1<<1) /* is AGL 1.2' name (without ambiguity) */ +#define PDC_GLF_ISAGL20NAME (1<<2) /* is AGL 2.0 and not AGL 1.2' */ +#define PDC_GLF_ISZADBNAME (1<<3) /* is ZapfDingbats name */ +#define PDC_GLF_ISUNINAME (1<<4) /* is a "uni" name (with single Unicode) */ +#define PDC_GLF_ISAMBIG (1<<5) /* is ambiguous name (double mapping) */ +#define PDC_GLF_ISVARIANT (1<<6) /* is glyphic variant (contains period) */ +#define PDC_GLF_ISDECOMP (1<<7) /* is decomposed glyph (contains underscores + * or more than one Unicode values) */ +#define PDC_GLF_ISCUS (1<<8) /* is a glyph from Unicode's Corporate + * Use Subarea (CUS) used by Adobe + * (U+F600 - U+F8FF) */ +#define PDC_GLF_ISLIGATURE (1<<9) /* is a Latin or Armenian ligature glyph */ +#define PDC_GLF_ISSURROGAT (1<<10) /* is a surrogate glyph */ +#define PDC_GLF_ISMISNAMED (1<<11) /* is misnamed (see tab_misnamed2uni) */ +#define PDC_GLF_ISINCORE (1<<12) /* is incore (AGL, ZapfDingabts, misnamed)*/ +#define PDC_GLF_ISPRIVATE (1<<13) /* is private glyph (in supplied glyphtab) + * or a heuristic determined character */ + +#define PDC_GLF_REDVARIANT (1<<0) /* reduce glyphic variant */ +#define PDC_GLF_DECOMPNAME (1<<1) /* decompose glyph name */ +#define PDC_GLF_CONVUNINAME (1<<2) /* convert unixxxx name */ +#define PDC_GLF_RESOLCUS (1<<3) /* resolve CUS value */ +#define PDC_GLF_RESOLLIGAT (1<<4) /* resolve ligature value */ +#define PDC_GLF_ALTGREEKMAP (1<<5) /* take alternative greek mapping */ +#define PDC_GLF_ALTMAPPING (1<<6) /* take alternative mapping */ +#define PDC_GLF_STDTYPE3MAP (1<<7) /* standard Type3 glyph name mapping */ + +/* standard flags */ +#define PDC_GLF_STANDARD1 (PDC_GLF_REDVARIANT | PDC_GLF_DECOMPNAME | \ + PDC_GLF_CONVUNINAME | PDC_GLF_RESOLCUS | \ + PDC_GLF_RESOLLIGAT) + +/* standard flags with keeping standard ligatures and CUS values */ +#define PDC_GLF_STANDARD2 (PDC_GLF_REDVARIANT | PDC_GLF_DECOMPNAME | \ + PDC_GLF_CONVUNINAME) + +/* pc_chartabs.c */ +int pdc_glyphname2codelist(const char *glyphname, const pdc_glyph_tab *glyphtab, + int tabsize, pdc_ushort *codelist); +int pdc_glyphname2code(const char *glyphname, const pdc_glyph_tab *glyphtab, + int tabsize); +const char *pdc_code2glyphname(pdc_ushort code, const pdc_glyph_tab *glyphtab, + int tabsize); +int pdc_code2codelist(pdc_core *pdc, pdc_ushort code, + const pdc_code_map *codemap, int tabsize, pdc_ushort *codelist, + int listsize); +const char *pdc_glyphname2glyphname(const char *glyphname, + const pdc_glyph_tab *glyphtab, int tabsize); + +int pdc_adobe2unicode(const char *glyphname); +const char *pdc_unicode2adobe(pdc_ushort uv); +const char *pdc_get_notdef_glyphname(void); +int pdc_zadb2unicode(const char *glyphname); +const char *pdc_unicode2zadb(pdc_ushort uv); +int pdc_newadobe2unicodelist(const char *glyphname, pdc_ushort *uvlist); +const char *pdc_unicode2newadobe(pdc_ushort uv); +const char *pdc_get_newadobe_glyphname(const char *glyphname); +int pdc_glyphname2altunicode(const char *glyphname); + +pdc_bool pdc_is_std_charname(const char *glyphname); +void pdc_delete_missingglyph_bit(pdc_ushort uv, pdc_ulong *bmask); +pdc_ushort pdc_get_alter_glyphname(pdc_ushort uv, pdc_ulong bmask, + char **glyphname); +int pdc_string2unicode(pdc_core *pdc, const char *text, int i_flags, + const pdc_keyconn *keyconn, pdc_bool verbose); +pdc_bool pdc_is_linebreaking_relchar(pdc_ushort uv); + + + +/* pc_core.c */ +void pdc_set_encodingstack_ptr(pdc_core *pdc, pdc_encoding_stack *encstack); +pdc_encoding_stack *pdc_get_encodingstack_ptr(pdc_core *pdc); +void pdc_set_pglyphtab_ptr(pdc_core *pdc, pdc_priv_glyphtab *pglyphtab); +pdc_priv_glyphtab *pdc_get_pglyphtab_ptr(pdc_core *pdc); + +/* pc_encoding.c */ +void pdc_init_encoding(pdc_core *pdc, pdc_encodingvector *ev, + const char *name); +pdc_encodingvector *pdc_new_encoding(pdc_core *pdc, const char *name); +void pdc_cleanup_encoding(pdc_core *pdc, pdc_encodingvector *ev); +pdc_encodingvector *pdc_copy_encoding(pdc_core *pdc, pdc_encodingvector *evfrom, + const char *name); +int pdc_get_encoding_bytecode(pdc_core *pdc, pdc_encodingvector *ev, + pdc_ushort uv); +pdc_byte pdc_transform_bytecode(pdc_core *pdc, pdc_encodingvector *evto, + pdc_encodingvector *evfrom, pdc_byte code); +pdc_encodingvector *pdc_copy_core_encoding(pdc_core *pdc, const char *encoding); +const char *pdc_get_fixed_encoding_name(pdc_encoding enc); + + +pdc_encodingvector *pdc_read_encoding(pdc_core *pdc, const char *encoding, + const char *filename, pdc_bool verbose); +pdc_encodingvector *pdc_generate_encoding(pdc_core *pdc, const char *encoding); +void pdc_encoding_logg_protocol(pdc_core *pdc, pdc_encodingvector *ev); + +pdc_encoding_stack *pdc_new_encodingstack(pdc_core *pdc); +void pdc_delete_encodingstack(pdc_core *pdc); +pdc_encoding pdc_insert_encoding_vector(pdc_core *pdc, + pdc_encodingvector *ev); +pdc_encoding pdc_get_encoding(pdc_core *pdc, const char *encoding, + int *codepage, pdc_bool verbose); +pdc_encoding pdc_insert_encoding(pdc_core *pdc, const char *encoding, + int *codepage, pdc_bool verbose); +void pdc_remove_encoding_vector(pdc_core *pdc, int slot); +pdc_encoding pdc_find_encoding(pdc_core *pdc, const char *encoding); +void pdc_set_encoding_glyphnames(pdc_core *pdc, pdc_encoding enc); +pdc_bool pdc_get_encoding_isstdflag(pdc_core *pdc, pdc_encoding enc); +pdc_bool pdc_is_encoding_subset(pdc_core *pdc, pdc_encodingvector *testev, + pdc_encodingvector *refev); + +int pdc_get_encodingstack_number(pdc_core *pdc); +pdc_encoding_info *pdc_get_encoding_info(pdc_core *pdc, + pdc_encoding enc); +pdc_encodingvector *pdc_get_encoding_vector(pdc_core *pdc, + pdc_encoding enc); +pdc_encodingvector *pdc_get_encoding_vector_direct(pdc_core *pdc, + pdc_encoding enc); +const char *pdc_get_user_encoding(pdc_core *pdc, pdc_encoding enc); +void pdc_init_encoding_info_ids(pdc_core *pdc); + +const char *pdc_get_pdf_encoding_name(int enc); +int pdc_get_pdf_encoding_code(const char *encname); +pdc_encodingvector *pdc_generate_pdfencoding(pdc_core *pdc, + const char *pdfname); + +pdc_priv_glyphtab *pdc_new_pglyphtab(pdc_core *pdc); +void pdc_delete_pglyphtab(pdc_core *pdc); +pdc_ushort pdc_register_glyphname(pdc_core *pdc, + const char *glyphname, pdc_ushort uv, pdc_bool forcepua); +int pdc_privglyphname2unicode(pdc_core *pdc, const char *glyphname); +int pdc_glyphname2unicodelist(pdc_core *pdc, const char *glyphname, + pdc_ushort *uvlist); +int pdc_glyphname2unicode(pdc_core *pdc, const char *glyphname); +int pdc_glyphname2utf32(pdc_core *pdc, const char *glyphname); +const char *pdc_glyphname2privglyphname(pdc_core *pdc, const char *glyphname); +const char *pdc_unicode2glyphname(pdc_core *pdc, pdc_ushort uv); +pdc_ushort pdc_insert_glyphname(pdc_core *pdc, const char *glyphname); +const char *pdc_insert_unicode(pdc_core *pdc, pdc_ushort uv); + + +#endif /* PC_ENCODING_H */ diff --git a/src/pdflib/pdcore/pc_exports.h b/src/pdflib/pdcore/pc_exports.h new file mode 100644 index 0000000..c062d70 --- /dev/null +++ b/src/pdflib/pdcore/pc_exports.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_exports.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Header for CodeWarrior to create a PDFlib DLL + * + */ + +/* + * Force a DLL to be built. + * This is useful as a prefix file when building a DLL with CodeWarrior. + */ + +#define PDFLIB_EXPORTS diff --git a/src/pdflib/pdcore/pc_file.c b/src/pdflib/pdcore/pc_file.c new file mode 100644 index 0000000..35c67ed --- /dev/null +++ b/src/pdflib/pdcore/pc_file.c @@ -0,0 +1,1548 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_file.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Various file routines + * + */ + +#include <errno.h> + +#include "pc_util.h" +#include "pc_md5.h" +#include "pc_file.h" + + +/* headers for getpid() or _getpid(). +*/ +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <process.h> +#include <io.h> +#else +#if defined(MAC) +#include <MacErrors.h> +#else +#include <sys/types.h> +#include <unistd.h> +#endif +#endif + +#ifndef WINCE +#include <time.h> +#else +#include <winbase.h> +#endif + +#ifdef VMS +#include <errno.h> +#include <descrip.h> +#include <ssdef.h> +#endif + +/* platform independent wrapper functions for 64-bit file handling. +*/ +int +pdc__fseek(FILE *fp, pdc_off_t offset, int whence) +{ +#if defined(_LARGEFILE_SOURCE) + #if defined(WIN32) + switch (whence) + { + case SEEK_SET: + return fsetpos(fp, &offset); + + case SEEK_CUR: + { + pdc_off_t pos; + + fgetpos(fp, &pos); + pos += offset; + return fsetpos(fp, &pos); + } + + case SEEK_END: + { + pdc_off_t pos, len; + + pos = _telli64(fileno(fp)); + _lseeki64(fileno(fp), 0, SEEK_END); + len = _telli64(fileno(fp)); + _lseeki64(fileno(fp), pos, SEEK_SET); + + len += offset; + return fsetpos(fp, &len); + } + + default: + return -1; + } + #else + return fseeko(fp, offset, whence); + #endif +#else + return fseek(fp, offset, whence); +#endif +} + +pdc_off_t +pdc__ftell(FILE *fp) +{ +#if defined(_LARGEFILE_SOURCE) + #if defined(WIN32) + pdc_off_t pos; + + fgetpos(fp, &pos); + return pos; + #else + return ftello(fp); + #endif +#else + return ftell(fp); +#endif +} + +size_t +pdc__fread(void *ptr, size_t size, size_t nmemb, FILE *fp) +{ + return fread(ptr, size, nmemb, fp); +} + +size_t +pdc__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp) +{ + return fwrite(ptr, size, nmemb, fp); +} + +int +pdc__fgetc(FILE *fp) +{ + return fgetc(fp); +} + +int +pdc__feof(FILE *fp) +{ + return feof(fp); +} + +struct pdc_file_s +{ + pdc_core *pdc; /* pdcore struct */ + char *filename; /* file name */ + FILE *fp; /* file struct or NULL. Then data != NULL: */ + pdc_bool wrmode; /* writing mode */ + pdc_byte *data; /* file data or NULL. Then fp != NULL */ + pdc_byte *end; /* first byte above data buffer */ + pdc_byte *pos; /* current file position in data buffer */ + pdc_byte *limit; /* limit of file buffer in writing mode */ +}; + +FILE * +pdc_get_fileptr(pdc_file *sfp) +{ + return sfp->fp; +} + +pdc_core * +pdc_get_pdcptr(pdc_file *sfp) +{ + return sfp->pdc; +} + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +int +pdc_get_fopen_errnum(pdc_core *pdc, int errnum) +{ + int outnum = errnum, isread; + + (void) pdc; + + isread = (errnum == PDC_E_IO_RDOPEN); + +#if defined(VMS) + /* + * On the vms system, when a system error occurs which is not + * mapped into the unix styled errno values, errno is set EVMSERR + * and a VMS error code is set in vaxc$errno. + */ + switch (errno) + { + case EVMSERR: + { + /* unmapped VMS runtime error - check vaxc$errno */ + switch (vaxc$errno) + { + case 100052: /* old style RMS file specification syntax error */ + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; + } + } + return outnum; + } +#endif /* VMS */ + +#if defined(MVS) + + switch (errno) + { + case 49: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; + } + return outnum; + +#elif defined(WIN32) + { + DWORD lasterror = GetLastError(); + switch (lasterror) + { + case ERROR_FILE_NOT_FOUND: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; + break; + + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_PASSWORD: + case ERROR_NETWORK_ACCESS_DENIED: + outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; + break; + + case ERROR_INVALID_NAME: + outnum = isread ? PDC_E_IO_RDOPEN_IS : PDC_E_IO_WROPEN_IS; + break; + + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_BAD_NETPATH: + case ERROR_BAD_UNIT: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NP; + break; + + case ERROR_TOO_MANY_OPEN_FILES: + case ERROR_SHARING_BUFFER_EXCEEDED: + outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; + break; + + case ERROR_BAD_COMMAND: + outnum = isread ? PDC_E_IO_RDOPEN_BC : PDC_E_IO_WROPEN_BC; + break; + + case ERROR_FILE_EXISTS: + outnum = PDC_E_IO_WROPEN_AE; + break; + + case ERROR_BUFFER_OVERFLOW: + outnum = PDC_E_IO_WROPEN_TL; + break; + + case ERROR_WRITE_FAULT: + case ERROR_CANNOT_MAKE: + outnum = PDC_E_IO_WROPEN_NC; + break; + + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + outnum = PDC_E_IO_WROPEN_NS; + break; + + case ERROR_SHARING_VIOLATION: + outnum = isread ? PDC_E_IO_RDOPEN_SV : PDC_E_IO_WROPEN_SV; + break; + + /* This code arises after opening a existing PDF or log file. + * Because the file could be opened, we can ignore this code. + */ + case ERROR_ALREADY_EXISTS: + lasterror = 0; + outnum = 0; + break; + } + + if (lasterror) + { + errno = (int) lasterror; + return outnum; + } + + /* if lasterror == 0 we must look for errno (see .NET) */ + } + +#endif /* WIN32 */ + + switch (errno) + { +#ifdef EACCES + case EACCES: + outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; + break; +#endif +#ifdef EMACOSERR + case EMACOSERR: +#if defined(MAC) + + switch (__MacOSErrNo) + { + case fnfErr: + case dirNFErr: + case resFNotFound: + case afpDirNotFound: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; + break; + + case permErr: + case wrPermErr: + case wPrErr: + case afpAccessDenied: + case afpVolLocked: + outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; + break; + + case nsvErr: + case afpObjectTypeErr: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_IS; + break; + + case tmfoErr: + case afpTooManyFilesOpen: + outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; + break; + + case opWrErr: + outnum = PDC_E_IO_WROPEN_AE; + break; + + case dirFulErr: + case dskFulErr: + case afpDiskFull: + outnum = PDC_E_IO_WROPEN_NS; + break; + + case fLckdErr: + case afpLockErr: + outnum = isread ? PDC_E_IO_RDOPEN_SV : PDC_E_IO_WROPEN_SV; + break; + + default: + break; + } + + if (__MacOSErrNo) + { + return outnum; + } +#endif + break; +#endif +#ifdef ENOENT + case ENOENT: + outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; + break; +#endif +#ifdef EMFILE + case EMFILE: + outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; + break; +#endif +#ifdef ENFILE + case ENFILE: + outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; + break; +#endif +#ifdef EISDIR + case EISDIR: + outnum = isread ? PDC_E_IO_RDOPEN_ID : PDC_E_IO_WROPEN_ID; + break; +#endif +#ifdef EDQUOT + case EDQUOT: + outnum = isread ? PDC_E_IO_RDOPEN_QU : PDC_E_IO_WROPEN_QU; + break; +#endif +#ifdef EEXIST + case EEXIST: + outnum = PDC_E_IO_WROPEN_AE; + break; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: + outnum = PDC_E_IO_WROPEN_TL; + break; +#endif +#ifdef ENOSPC + case ENOSPC: + outnum = PDC_E_IO_WROPEN_NS; + break; +#endif + default: + + /* observed on Solaris */ + if (errno == 0) + pdc_error(pdc, PDC_E_INT_BADERRNO, 0, 0, 0, 0); + + outnum = errnum; + break; + } + + return outnum; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + +void +pdc_set_fopen_errmsg(pdc_core *pdc, int errnum, const char *qualifier, + const char *filename) +{ + const char *stemp1 = NULL; + const char *stemp2 = NULL; + int errno1 = errno; + +#if defined(EMACOSERR) && defined(MAC) + errno1 = (int) __MacOSErrNo; +#endif + + errnum = pdc_get_fopen_errnum(pdc, errnum); + if (errnum == PDC_E_IO_RDOPEN) + errnum = PDC_E_IO_RDOPEN_CODE; + else if (errnum == PDC_E_IO_WROPEN) + errnum = PDC_E_IO_WROPEN_CODE; + if (errnum == PDC_E_IO_RDOPEN_CODE || errnum == PDC_E_IO_WROPEN_CODE) + { + stemp1 = pdc_errprintf(pdc, "%d", errno1); + +#ifdef PDC_HAS_STRERROR + stemp2 = strerror(errno1); + if (stemp2 != NULL) + { + if (errnum == PDC_E_IO_RDOPEN_CODE) + errnum = PDC_E_IO_RDOPEN_CODETEXT; + else if (errnum == PDC_E_IO_WROPEN_CODE) + errnum = PDC_E_IO_WROPEN_CODETEXT; + } +#endif + } + + pdc_set_errmsg(pdc, errnum, qualifier, filename, stemp1, stemp2); +} + +pdc_bool +pdc_check_fopen_errmsg(pdc_core *pdc, pdc_bool requested) +{ + return (requested || pdc_get_errnum(pdc) != PDC_E_IO_RDOPEN_NF) ? + pdc_false : pdc_undef; +} + +static void +pdc_logg_openclose(pdc_core *pdc, FILE *fp, pdc_bool opened) +{ + int errno1 = errno, errno2 = 0; + + if (pdc_logg_is_enabled(pdc, 3, trc_filesearch)) + { +#if defined(WIN32) + errno2 = (int) GetLastError(); +#elif defined(MAC) + errno2 = __MacOSErrNo; +#endif + pdc_logg(pdc, "\t%p", fp); + if (opened) + pdc_logg(pdc, " opened"); + else + pdc_logg(pdc, " closed"); +#if PDC_FILENO_EXISTS + if (fp != NULL && opened) + pdc_logg(pdc, ", fileno=%d", fileno(fp)); +#endif + pdc_logg(pdc, ", errno=%d", errno1); + if (errno2 != 0) + pdc_logg(pdc, ", errno2=%d", errno2); + pdc_logg(pdc, "\n"); + + /* because of logfile IO */ + if (errno != errno1) + errno = errno1; + } +} + +void * +pdc_read_file(pdc_core *pdc, FILE *fp, pdc_off_t *o_filelen, int incore) +{ + static const char fn[] = "pdc_read_file"; + pdc_off_t filelen = 0, len = 0; + char *content = NULL; + + +#if !defined(MVS) || !defined(I370) + + pdc__fseek(fp, 0, SEEK_END); + filelen = pdc__ftell(fp); + pdc__fseek(fp, 0, SEEK_SET); + + if (incore && filelen) + { + content = (char *) pdc_malloc(pdc, (size_t) (filelen + 1), fn); + len = (pdc_off_t) pdc__fread(content, 1, (size_t) filelen, fp); + +/* because pdc__ftell lies! */ +filelen = len; + if (!filelen) + { + pdc_free(pdc, content); + filelen = 0; + content = NULL; + } + } + +#endif + + if (content) content[filelen] = 0; + *o_filelen = filelen; + return (void *) content; +} + + +/* + * In the case of systems which are not capable of Unicode file names: + * + * File name can be converted to Latin-1: The incoming char pointer + * will be deleted and a new char pointer to the Latin-1 string will + * be returned. Otherwise an execption will be thrown. + * + */ +char * +pdc_check_filename(pdc_core *pdc, char *filename) +{ +#if !defined(PDC_UNICODE_FILENAME) + char *ffname = pdc_utf8_to_hostbytes(pdc, pdc->honorlang, filename); + + pdc_free(pdc, filename); + if (ffname == NULL) + pdc_error(pdc, PDC_E_IO_UNSUPP_UNINAME, 0, 0, 0, 0); + filename = (char *) ffname; +#endif + + return filename; +} + +char * +pdc_get_filename(pdc_core *pdc, char *filename) +{ + char *ffname; + +#if defined(PDC_UNICODE_FILENAME) + static const char fn[] = "pdc_get_filename"; + + ffname = pdc_strdup_ext(pdc, filename, 0, fn); +#else + ffname = pdc_hostbytes_to_utf8(pdc, pdc->honorlang, filename); +#endif + + return ffname; +} + +/* + * pdc_convert_filename_ext converts a file name as string of name type + * (see function pdc_convert_name) to a [EBCDIC-]UTF-8 string with or + * without a BOM. If the compiler doesn't allow Unicode filenames + * (see define PDC_UNICODE_FILENAME) the filename is Latin-1 encoded + * if possible or an exception will be thrown. + * + */ +const char * +pdc_convert_filename_ext(pdc_core *pdc, const char *filename, int len, + const char *paramname, pdc_encoding enc, int codepage, + int flags) +{ + char *fname = NULL; + const char *outfilename = NULL; + int i = 0; + + if (filename == NULL) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, paramname, 0, 0, 0); + + fname = pdc_convert_name_ext(pdc, filename, len, enc, codepage, flags); + + if (fname == NULL || *fname == '\0') + pdc_error(pdc, PDC_E_ILLARG_EMPTY, paramname, 0, 0, 0); + + if (pdc_is_utf8_bytecode(fname)) + { +#if defined(PDC_UNICODE_FILENAME) + i = 3; +#else + fname = pdc_check_filename(pdc, fname); +#endif + } + + outfilename = pdc_errprintf(pdc, "%s", &fname[i]); + pdc_free(pdc, fname); + + return outfilename; +} + +const char * +pdc_convert_filename(pdc_core *pdc, const char *filename, int len, + const char *paramname, pdc_bool withbom) +{ + int flags = PDC_CONV_EBCDIC; + + if (withbom) + flags |= PDC_CONV_WITHBOM; + + return pdc_convert_filename_ext(pdc, filename, len, paramname, + pdc_invalidenc, 0, flags); +} + +/* + * pdc_fopen_logg opens a file. The function expects a UTF-8 encoded file name. + * (see function pdc_convert_filename), if define PDC_UNICODE_FILENAME is set. + * + */ +FILE * +pdc_fopen_logg(pdc_core *pdc, const char *filename, const char *mode) +{ + FILE *fp = NULL; + +#if defined(PDC_UNICODE_FILENAME) + + pdc_byte *outfilename = NULL; + pdc_text_format nameformat = PDC_UTF8; + pdc_text_format targetnameformat = pdc_utf16; + int len = (int) strlen(filename); + int outlen = 0; + + /* convert filename from UTF-8 to UTF-16 or Latin-1 */ + pdc_convert_string(pdc, nameformat, 0, NULL, (pdc_byte *) filename, len, + &targetnameformat, NULL, &outfilename, &outlen, + PDC_CONV_TRYBYTES | PDC_CONV_NOBOM, pdc_true); + + if (targetnameformat == pdc_bytes) + { + fp = fopen((const char *) outfilename, mode); + } + else + { + wchar_t wmode[8]; + int i; + + len = (int) strlen(mode); + for (i = 0; i < len; i++) + wmode[i] = (wchar_t) mode[i]; + wmode[len] = 0; + + fp = _wfopen((wchar_t *) outfilename, wmode); + } + + pdc_free(pdc, outfilename); + +#else + (void) pdc; + + fp = fopen(filename, mode); +#endif + + pdc_logg_openclose(pdc, fp, pdc_true); + + return fp; +} + +pdc_file * +pdc_fopen(pdc_core *pdc, const char *filename, const char *qualifier, + const pdc_byte *data, size_t size, int flags) +{ + static const char fn[] = "pdc_fopen"; + pdc_file *sfp; + + sfp = (pdc_file *) pdc_calloc(pdc, sizeof(pdc_file), fn); + + /* initialize */ + sfp->pdc = pdc; + sfp->filename = pdc_strdup_ext(pdc, filename, 0, fn); + + if (flags & PDC_FILE_WRITEMODE || flags & PDC_FILE_APPENDMODE) + sfp->wrmode = pdc_true; + + + if (data != NULL || size > 0) + { + /* virtual file */ + if (sfp->wrmode) + { + sfp->data = (pdc_byte *) pdc_calloc(pdc, size, fn); + if (data != NULL) + { + /* append mode */ + memcpy(sfp->data, data, size); + sfp->pos = sfp->data + size; + } + else + { + sfp->pos = sfp->data; + } + sfp->end = sfp->pos; + sfp->limit = sfp->data + size; + } + else + { + sfp->data = (pdc_byte *) data; + sfp->pos = sfp->data; + sfp->end = sfp->data + size; + } + } + else + { + const char *mode; + + + /* disk file */ + if (flags & PDC_FILE_BINARY) + mode = READBMODE; + else + mode = READTMODE; + if (flags & PDC_FILE_APPENDMODE) + mode = APPENDMODE; + else if (flags & PDC_FILE_WRITEMODE) + mode = WRITEMODE; + + sfp->fp = pdc_fopen_logg(pdc, filename, mode); + if (sfp->fp == NULL) + { + pdc_fclose(sfp); + + if (qualifier == NULL) + qualifier = ""; + pdc_set_fopen_errmsg(pdc, PDC_E_IO_RDOPEN, qualifier, filename); + return NULL; + } + } + + return sfp; +} + +pdc_bool +pdc_file_isvirtual(pdc_file *sfp) +{ + return sfp->fp ? pdc_false : pdc_true; +} + +char * +pdc_file_name(pdc_file *sfp) +{ + return sfp->filename; +} + +pdc_core * +pdc_file_getpdc(pdc_file *sfp) +{ + return sfp->pdc; +} + +pdc_off_t +pdc_file_size(pdc_file *sfp) +{ + pdc_off_t filelen; + + if (sfp->fp) + { + pdc_off_t pos = pdc__ftell(sfp->fp); + + pdc_read_file(sfp->pdc, sfp->fp, &filelen, 0); + pdc__fseek(sfp->fp, pos, SEEK_SET); + } + else + filelen = (pdc_off_t) (sfp->end - sfp->data); + + return filelen; +} + +const void * +pdc_freadall(pdc_file *sfp, size_t *filelen, pdc_bool *ismem) +{ + const void *result = NULL; + + *filelen = 0; + + pdc_logg_cond(sfp->pdc, 1, trc_filesearch, + "\tAttempting to read whole file \"%s\"\n", sfp->filename); + + if (sfp->fp) + { + pdc_off_t flen; /* TODO2GB: >2GB on 32-bit platforms? */ + + result = pdc_read_file(sfp->pdc, sfp->fp, &flen, 1); + + if (ismem) + *ismem = pdc_false; + *filelen = (size_t) flen; + } + else + { + result = sfp->data; + + if (ismem) + *ismem = pdc_true; + *filelen = (size_t) (sfp->end - sfp->data); + } + + pdc_logg_cond(sfp->pdc, 1, trc_filesearch, + "\t%d bytes read from %s file, contents=%p\n", + (int) (*filelen), + (sfp->fp) ? "disk" : "memory", + result); + + return result; +} + +static int +pdc_fgetc_e(pdc_file *sfp) +{ + int c = pdc_fgetc(sfp); + return c; +} + +char * +pdc_fgetline(char *s, int size, pdc_file *sfp) +{ + int i, c; + + c = pdc_fgetc_e(sfp); + if (c == EOF) + return NULL; + + size--; + for (i = 0; i < size; i++) + { + if (c == '\n' || c == '\r' || c == EOF) break; + s[i] = (char) c; + c = pdc_fgetc_e(sfp); + } + s[i] = 0; + + /* Skip windows line end \r\n */ + if (c == '\r') + { + c = pdc_fgetc_e(sfp); + + if (c != '\n' && c != EOF) + { + if (sfp->fp) + ungetc(c, sfp->fp); + else + pdc_fseek(sfp, -1, SEEK_CUR); + } + } + return s; +} + +/* + * Emulation of C file functions - relevant for PDFlib + */ + +pdc_off_t +pdc_ftell(pdc_file *sfp) +{ + if (sfp->fp) + return pdc__ftell(sfp->fp); + + return (pdc_off_t) (sfp->pos - sfp->data); +} + +int +pdc_fseek(pdc_file *sfp, pdc_off_t offset, int whence) +{ + static const char fn[] = "pdc_fseek"; + + if (sfp->fp) + return pdc__fseek(sfp->fp, offset, whence); + + switch (whence) + { + case SEEK_SET: + sfp->pos = sfp->data + offset; + break; + + case SEEK_CUR: + sfp->pos += offset; + break; + + case SEEK_END: + sfp->pos = sfp->end; + break; + } + + if (sfp->pos > sfp->end) + { + /* extend file in writing mode */ + if (sfp->wrmode) + { + size_t nbytes = (size_t) (sfp->pos - sfp->end); + + if (sfp->pos > sfp->limit) + { + size_t size = (size_t) (sfp->pos - sfp->data); + + sfp->data = (pdc_byte *) pdc_realloc(sfp->pdc, sfp->data, size, + fn); + sfp->end = sfp->data + size; + sfp->pos = sfp->end; + sfp->limit = sfp->end; + } + + memset(sfp->pos - nbytes, 0, nbytes); + } + else + { + return -1; + } + } + else if (sfp->pos < sfp->data) + { + return -1; + } + + return 0; +} + +size_t +pdc_fread(void *ptr, size_t size, size_t nmemb, pdc_file *sfp) +{ + size_t nbytes = 0; + + if (sfp->fp) + return pdc__fread(ptr, size, nmemb, sfp->fp); + + nbytes = size * nmemb; + if (sfp->pos + nbytes > sfp->end) + { + nbytes = (size_t) (sfp->end - sfp->pos); + nmemb = nbytes / size; + nbytes = nmemb *size; + } + + if (nbytes) + memcpy(ptr, sfp->pos, nbytes); + sfp->pos += nbytes; + + return nmemb; +} + +size_t +pdc_fwrite(const void *ptr, size_t size, size_t nmemb, pdc_file *sfp) +{ + static const char fn[] = "pdc_fwrite"; + + if (sfp->wrmode) + { + size_t poslen, nbytes = 0; + + if (sfp->fp) + return pdc__fwrite(ptr, size, nmemb, sfp->fp); + + nbytes = size * nmemb; + if (sfp->pos + nbytes > sfp->limit) + { + poslen = (size_t) (sfp->pos - sfp->data); + size = poslen + nbytes; + + sfp->data = (pdc_byte *) pdc_realloc(sfp->pdc, sfp->data, size, fn); + sfp->pos = sfp->data + poslen; + sfp->end = sfp->data + size; + sfp->limit = sfp->end; + } + memcpy(sfp->pos, ptr, nbytes); + sfp->pos += nbytes; + if (sfp->pos > sfp->end) + sfp->end = sfp->pos; + } + else + { + nmemb = 0; + } + + return nmemb; +} + +void +pdc_freset(pdc_file *sfp, size_t size) +{ + static const char fn[] = "pdc_freset"; + + if (sfp->wrmode && !sfp->fp) + { + if (size > (size_t) (sfp->limit - sfp->data)) + { + sfp->data = (pdc_byte *) pdc_realloc(sfp->pdc, sfp->data, size, fn); + sfp->limit = sfp->data + size; + } + + sfp->pos = sfp->data; + sfp->end = sfp->data; + } +} + +int +pdc_fgetc(pdc_file *sfp) +{ + int ch = 0; + + if (sfp->fp) + return pdc__fgetc(sfp->fp); + + if (sfp->pos < sfp->end) + { + ch = (int) *sfp->pos; + sfp->pos++; + } + else + { + ch = EOF; + } + + return ch; +} + +int +pdc_feof(pdc_file *sfp) +{ + if (sfp->fp) + return pdc__feof(sfp->fp); + + return (sfp->pos >= sfp->end) ? 1 : 0; +} + +void +pdc_fclose_logg(pdc_core *pdc, FILE *fp) +{ + fclose(fp); + pdc_logg_openclose(pdc, fp, pdc_false); +} + +void +pdc_fclose(pdc_file *sfp) +{ + if (sfp) + { + if (sfp->fp) + { + pdc_fclose_logg(sfp->pdc, sfp->fp); + sfp->fp = NULL; + } + else if (sfp->wrmode) + { + if (sfp->data) + { + pdc_free(sfp->pdc, sfp->data); + sfp->data = NULL; + } + } + + if (sfp->filename) + { + pdc_free(sfp->pdc, sfp->filename); + sfp->filename = NULL; + } + + pdc_free(sfp->pdc, sfp); + } +} + +/* + * Concatenating a directory name with a file base name to a full valid + * file name. On MVS platforms an extension at the end of basename + * will be discarded. + */ +void +pdc_file_fullname(const char *dirname, const char *basename, char *fullname) +{ + const char *pathsep = PDC_PATHSEP; + +#ifdef MVS + pdc_bool lastterm = pdc_false; +#endif + + if (!dirname || !dirname[0]) + { + strcpy(fullname, basename); + } + else + { + fullname[0] = 0; + +#ifdef MVS + if (strncmp(dirname, PDC_FILEQUOT, 1)) + strcat(fullname, PDC_FILEQUOT); +#endif + + strcat(fullname, dirname); + +#ifdef VMS + /* look for logical name or whose result */ + if(getenv(dirname)) + pathsep = PDC_PATHSEP_LOG; + else if (fullname[strlen(fullname)-1] == ']') + pathsep = ""; +#endif + + strcat(fullname, pathsep); + strcat(fullname, basename); + +#ifdef MVS + lastterm = pdc_true; +#endif + } + +#ifdef MVS + { + int ie, len; + + len = strlen(fullname); + for (ie = len - 1; ie >= 0; ie--) + { + if (fullname[ie] == pathsep[0]) + break; + + if (fullname[ie] == '.') + { + fullname[ie] = 0; + break; + } + } + if (lastterm) + { + strcat(fullname, PDC_PATHTERM); + strcat(fullname, PDC_FILEQUOT); + } + } +#endif +} + +#define EXTRA_SPACE 32 /* extra space for separators, FILEQUOT etc. */ + +char * +pdc_file_fullname_mem(pdc_core *pdc, const char *dirname, const char *basename) +{ + static const char fn[] = "pdc_file_fullname_mem"; + char *fullname; + size_t len; + + len = strlen(basename); + if (dirname && dirname[0]) + len += strlen(dirname); + len += EXTRA_SPACE; + fullname = (char *) pdc_malloc(pdc, len, fn); + + pdc_file_fullname(dirname, basename, fullname); + + return fullname; +} + +/* + * Returns the full specified path name in a new memory. + * The full path name can be concatened by a path name, + * file name and extension (incl. dot). + */ +char * +pdc_file_concat(pdc_core *pdc, const char *dirname, const char *basename, + const char *extension) +{ + static const char fn[] = "pdc_file_concat"; + char *pathname = pdc_file_fullname_mem(pdc, dirname, basename); + size_t len = strlen(pathname) + 1; + + if (extension != NULL) + len += strlen(extension); + + pathname = (char *) pdc_realloc(pdc, pathname, len, fn); + + if (extension != NULL) + strcat(pathname, extension); + + return pathname; +} + +/* + * Returns the file basename of a full specified path name in the same memory. + */ +const char * +pdc_file_strip_dirs(const char *pathname) +{ + const char *scan = pathname + strlen(pathname); + char charsep = PDC_PATHSEP[0]; + + while (pathname <= --scan) + { + if (*scan == charsep) + return scan + 1; + } + + return pathname; +} + + +/* + * Returns the file path of a full specified path name in the same memory. + */ +char * +pdc_file_strip_name(char *pathname) +{ + char *scan = pathname + strlen(pathname); + char charsep = PDC_PATHSEP[0]; + + while (pathname <= --scan) + { + if (*scan == charsep) + { + *scan = 0; + break; + } + } + + return pathname; +} + + +/* + * Returns the file extension of a path name in the same memory. + */ +char * +pdc_file_strip_ext(char *pathname) +{ + char *scan = pathname + strlen(pathname); + + while (pathname <= --scan) + { + if (*scan == '.') + { + *scan = 0; + break; + } + } + + return pathname; +} + + +/* + * Function reads a text file and creates a string list + * of all no-empty and no-comment lines. The strings are stripped + * by leading and trailing white space characters. + * + * The caller is responsible for freeing the resultated string list + * by calling the function pdc_cleanup_stringlist. + * + * Not for unicode strings. + * + * Return value: Number of strings + */ + +#define PDC_ARGV_CHUNKSIZE 256 + +int +pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, int flags, char ***linelist) +{ + static const char fn[] = "pdc_read_textfile"; + char buf[PDC_BUFSIZE]; + char *content = NULL; + char **strlist = NULL; + int nlines = 0; + pdc_off_t filelen; + size_t len = 0, sumlen = 0, maxl = 0; + pdc_bool tocont = pdc_false; + int i, nbs, is = -1; + + /* get file length */ + filelen = pdc_file_size(sfp); + if (filelen) + { + /* allocate content array */ + content = (char *) pdc_calloc(pdc, (size_t) filelen, fn); + + /* read loop */ + while (pdc_fgetline(buf, PDC_BUFSIZE, sfp) != NULL) + { + /* trim white spaces */ + if (tocont) + pdc_strtrim(buf); + else + pdc_str2trim(buf); + + /* skip blank and comment lines */ + if (buf[0] == 0 || buf[0] == '%') + { + tocont = pdc_false; + continue; + } + + /* register new line */ + if (!tocont) + { + if (nlines) + pdc_logg_cond(pdc, 2, trc_filesearch, + "\t\tLine %d; \"%s\"\n", nlines, strlist[nlines - 1]); + + if (nlines >= (int) maxl) + { + maxl += PDC_ARGV_CHUNKSIZE; + strlist = (strlist == NULL) ? + (char **)pdc_malloc(pdc, maxl * sizeof(char *), fn): + (char **)pdc_realloc(pdc, strlist, maxl * + sizeof(char *), fn); + } + + is += sumlen + 1; + strlist[nlines] = &content[is]; + nlines++; + sumlen = 0; + } + + /* process new line */ + nbs = 0; + len = strlen(buf); + for (i = 0; i < (int) len; i++) + { + /* backslash found */ + if (buf[i] == '\\') + { + nbs++; + } + else + { + /* comment sign found */ + if (buf[i] == '%') + { + if (nbs % 2) + { + /* masked */ + memmove(&buf[i-1], &buf[i], (size_t) (len-i)); + len--; + buf[len] = 0; + } + else + { + buf[i] = 0; + len = strlen(buf); + } + } + nbs = 0; + } + } + + /* continuation line */ + tocont = (nbs % 2) ? pdc_true : pdc_false; + if (tocont) + { + if (flags & PDC_FILE_KEEPLF) + buf[len - 1] = '\n'; + else + len--; + } + buf[len] = '\0'; + + /* backslash substitution */ + if (flags & PDC_FILE_BSSUBST) + { + len = (size_t) pdc_subst_backslash(pdc, (pdc_byte *) buf, + (int) len, NULL, pdc_bytes, pdc_true); + } + + /* concatenate line */ + strcat(&content[is], buf); + + sumlen += len; + } + + if (!strlist) pdc_free(pdc, content); + } + + if (nlines) + pdc_logg_cond(pdc, 2, trc_filesearch, + "\t\tLine %d; \"%s\"\n", nlines, strlist[nlines - 1]); + + *linelist = strlist; + return nlines; +} + + +/* generate a temporary file name from the current time, pid, 'dirname', +** and the data in 'inbuf' using MD5. prepend 'dirname' to the file name. +** the result is written to 'outbuf'. if 'outbuf' is NULL, memory will be +** allocated and must be freed by the caller. otherwise, 'pdc' can be set +** to NULL. +** +** if 'dirname' isn't specified the function looks for an environment +** variable via the define PDC_TMPDIR_ENV. This define is set in +** pc_config.h. If the environment variable has a value and if the +** directory exists (check with the temporary file together) the +** directory will be used. +*/ + +#ifdef MVS +#define TMP_NAME_LEN 9 +#define TMP_SUFFIX "" +#define TMP_SUFF_LEN 0 +#else +#define TMP_NAME_LEN 14 +#define TMP_SUFFIX ".TMP" +#define TMP_SUFF_LEN 4 +#endif + +char * +pdc_temppath( + pdc_core *pdc, + char *outbuf, + const char *inbuf, + size_t inlen, + const char *dirname) +{ + char name[TMP_NAME_LEN + TMP_SUFF_LEN + 1]; + MD5_CTX md5; + time_t timer; + unsigned char digest[MD5_DIGEST_LENGTH]; + int i; + size_t dirlen; +#ifdef VMS + char *tmpdir = NULL; +#endif /* VMS */ + +#if defined(WIN32) +#if defined(__BORLANDC__) + int pid = getpid(); +#else + int pid = _getpid(); +#endif +#else +#if !defined(MAC) + pid_t pid = getpid(); +#endif +#endif + +#ifdef PDC_TMPDIR_ENV + if (!dirname) + { + dirname = (char *) getenv(PDC_TMPDIR_ENV); + } +#endif /* !PDC_TMPDIR_ENV */ + + time(&timer); + + MD5_Init(&md5); +#if !defined(MAC) + MD5_Update(&md5, (unsigned char *) &pid, sizeof pid); +#endif + MD5_Update(&md5, (unsigned char *) &timer, sizeof timer); + + if (inlen == 0 && inbuf != (const char *) 0) + inlen = strlen(inbuf); + + if (inlen != 0) + MD5_Update(&md5, (unsigned char *) inbuf, inlen); + + dirlen = dirname ? strlen(dirname) : 0; + if (dirlen) + MD5_Update(&md5, (const unsigned char *) dirname, dirlen); + + MD5_Final(digest, &md5); + + for (i = 0; i < TMP_NAME_LEN - 1; ++i) + name[i] = (char) (PDF_A + digest[i % MD5_DIGEST_LENGTH] % 26); + + name[i] = 0; + strcat(name, TMP_SUFFIX); + + if (!outbuf) + outbuf = pdc_file_fullname_mem(pdc, dirname, name); + else + pdc_file_fullname(dirname, name, outbuf); + return outbuf; +} + +/* Write function depending on pdc->asciifile. + */ +size_t +pdc_fwrite_ascii(pdc_core *pdc, const char *str, size_t len, FILE *fp) +{ + + (void) pdc; + len = fwrite(str, 1, len, fp); + + + return len; +} + +/* Creates a file depending on PDC_FILE_ASCII and pdc->asciifile. +*/ +size_t +pdc_write_file( + pdc_core *pdc, + const char *filename, + const char *qualifier, + const char *content, + size_t len, + int flags) +{ + size_t wlen = 0; + pdc_file *sfp; + + + sfp = pdc_fopen(pdc, filename, qualifier, NULL, 0, flags); + if (sfp != NULL) + { + wlen = pdc_fwrite_ascii(pdc, content, len, sfp->fp); + pdc_fclose(sfp); + if (wlen != len) + { + pdc_set_errmsg(pdc, PDC_E_IO_WRITE, filename, 0, 0, 0); + } + } + + + return wlen; +} + + + +#if defined(MAC) || defined(MACOSX) + +#ifdef PDF_TARGET_API_MAC_CARBON + +/* Construct an FSSpec from a Posix path name. Only required for + * Carbon (host font support and file type/creator). + */ + +OSStatus +FSPathMakeFSSpec(const UInt8 *path, FSSpec *spec) +{ + OSStatus result; + FSRef ref; + + /* convert the POSIX path to an FSRef */ + result = FSPathMakeRef(path, &ref, NULL); + + if (result != noErr) + return result; + + /* and then convert the FSRef to an FSSpec */ + result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + + return result; +} + + +#else + + +#endif /* !PDF_TARGET_API_MAC_CARBON */ + +#endif /* (defined(MAC) || defined(MACOSX)) */ + diff --git a/src/pdflib/pdcore/pc_file.h b/src/pdflib/pdcore/pc_file.h new file mode 100644 index 0000000..d1a6163 --- /dev/null +++ b/src/pdflib/pdcore/pc_file.h @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_file.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Definitions for file routines + * + */ + +#ifndef PC_FILE_H +#define PC_FILE_H + +#if (defined(MAC) || defined(MACOSX)) + +#include <Files.h> + +#ifdef PDF_TARGET_API_MAC_CARBON + +OSStatus FSMakePath(SInt16 volRefNum, SInt32 dirID, ConstStr255Param name, + UInt8 *path, UInt32 maxPathSize); + +OSStatus FSPathMakeFSSpec(const UInt8 *path, FSSpec *spec); + +#else + +#include <Aliases.h> + +OSErr FSpGetFullPath(const FSSpec *spec, short *fullPathLength, + Handle *fullPath); + +OSErr FSpLocationFromFullPath(short fullPathLength, + const void *fullPath, FSSpec *spec); + +#endif /* !PDF_TARGET_API_MAC_CARBON */ +#endif /* (defined(MAC) || defined(MACOSX)) */ + +#define PDC_FILENAMELEN 1024 /* maximum file name length */ + +#define PDC_FILE_TEXT (1L<<0) /* text file - whether ASCII file or not + * depends on pdc->asciifile */ + +#define PDC_FILE_ASCII (1L<<1) /* treat text or binary file as ASCII file + * even on EBCDIC platforms */ + +#define PDC_FILE_BINARY (1L<<2) /* open as binary file, + * otherwise as text file */ + +#define PDC_FILE_WRITEMODE (1L<<10) /* open file in writing mode, + * otherwise in reading mode */ + +#define PDC_FILE_APPENDMODE (1L<<11) /* open file in appending mode */ + + +/* flags for pdc_read_textfile() */ + +#define PDC_FILE_BSSUBST (1<<0) /* backslash substitution */ +#define PDC_FILE_KEEPLF (1<<1) /* keep linefeed at line continuation */ + +#define PDC_BUFSIZE 1024 + +#define PDC_OK_FREAD(file, buffer, len) \ + (pdc_fread(buffer, 1, len, file) == len) + +typedef struct pdc_file_s pdc_file; + +/* pc_file.c */ + +int pdc__fseek(FILE *fp, pdc_off_t offset, int whence); +pdc_off_t pdc__ftell(FILE *fp); +size_t pdc__fread(void *ptr, size_t size, size_t nmemb, FILE *fp); +size_t pdc__fwrite(const void *ptr, size_t size, size_t nmemb, + FILE *fp); +int pdc__fgetc(FILE *fp); +int pdc__feof(FILE *fp); + +FILE *pdc_get_fileptr(pdc_file *sfp); +pdc_core *pdc_get_pdcptr(pdc_file *sfp); +int pdc_get_fopen_errnum(pdc_core *pdc, int errnum); +void pdc_set_fopen_errmsg(pdc_core *pdc, int errnum, const char *qualifier, + const char *filename); +pdc_bool pdc_check_fopen_errmsg(pdc_core *pdc, pdc_bool requested); + +void *pdc_read_file(pdc_core *pdc, FILE *fp, pdc_off_t *o_filelen, + int incore); +int pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, int flags, + char ***linelist); +char * pdc_temppath(pdc_core *pdc, char *outbuf, const char *inbuf, + size_t inlen, const char *dirname); + +char *pdc_check_filename(pdc_core *pdc, char *filename); +char *pdc_get_filename(pdc_core *pdc, char *filename); +const char *pdc_convert_filename_ext(pdc_core *pdc, const char *filename, + int len, const char *paramname, pdc_encoding enc, int codepage, + int flags); +const char *pdc_convert_filename(pdc_core *pdc, const char *filename, int len, + const char *paramname, pdc_bool withbom); +FILE *pdc_fopen_logg(pdc_core *pdc, const char *filename, const char *mode); + +pdc_file * pdc_fopen(pdc_core *pdc, const char *filename, + const char *qualifier, const pdc_byte *data, + size_t size, int flags); +pdc_core * pdc_file_getpdc(pdc_file *sfp); +char * pdc_file_name(pdc_file *sfp); +pdc_off_t pdc_file_size(pdc_file *sfp); +pdc_bool pdc_file_isvirtual(pdc_file *sfp); +char * pdc_fgetline(char *s, int size, pdc_file *sfp); +pdc_off_t pdc_ftell(pdc_file *sfp); +int pdc_fseek(pdc_file *sfp, pdc_off_t offset, int whence); +size_t pdc_fread(void *ptr, size_t size, size_t nmemb, pdc_file *sfp); +const void * pdc_freadall(pdc_file *sfp, size_t *filelen, + pdc_bool *ismem); +size_t pdc_fwrite(const void *ptr, size_t size, size_t nmemb, + pdc_file *sfp); +void pdc_freset(pdc_file *sfp, size_t size); + +int pdc_ungetc(int c, pdc_file *sfp); +int pdc_fgetc(pdc_file *sfp); +int pdc_feof(pdc_file *sfp); +void pdc_fclose(pdc_file *sfp); +void pdc_fclose_logg(pdc_core *pdc, FILE *fp); +void pdc_file_fullname(const char *dirname, const char *basename, + char *fullname); +char *pdc_file_fullname_mem(pdc_core *pdc, const char *dirname, + const char *basename); +char *pdc_file_concat(pdc_core *pdc, const char *dirname, const char *basename, + const char *extension); +const char *pdc_file_strip_dirs(const char *pathname); +char *pdc_file_strip_name(char *pathname); +char *pdc_file_strip_ext(char *pathname); + +size_t pdc_fwrite_ascii(pdc_core *pdc, const char *str, size_t len, FILE *fp); +size_t pdc_write_file(pdc_core *pdc, const char *filename, + const char *qualifier, const char *content, size_t len, int flags); + + +/* pc_resource.c */ + +pdc_file *pdc_fsearch_fopen(pdc_core *pdc, const char *filename, char *fullname, + const char *qualifier, int flags); + +#endif /* PC_FILE_H */ diff --git a/src/pdflib/pdcore/pc_generr.h b/src/pdflib/pdcore/pc_generr.h new file mode 100644 index 0000000..b1651ff --- /dev/null +++ b/src/pdflib/pdcore/pc_generr.h @@ -0,0 +1,444 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_generr.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDCORE error messages + * + */ + +#if pdc_genNames +#define gen(n, num, nam, msg) PDC_E_##nam = num, +#elif pdc_genInfo +#define gen(n, num, nam, msg) { n, num, msg, (const char *) 0 }, + +#else +#error invalid inclusion of generator file +#endif + +/* -------------------------------------------------------------------- */ +/* Configuration, memory, and I/O (10xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 1000, MEM_OUT, "Out of memory in function $1") + +gen(1, 1008, IO_ILLFILENAME, "Bad file name '$1'") + +gen(4, 1009, IO_RDOPEN_CODETEXT, + "Couldn't open $1file '$2' for reading (system error code $3: $4)") + +gen(2, 1010, IO_RDOPEN, "Couldn't open $1file '$2' for reading") + +gen(3, 1011, IO_RDOPEN_CODE, + "Couldn't open $1file '$2' for reading (system error code $3)") + +gen(2, 1012, IO_WROPEN, "Couldn't open $1file '$2' for writing") + +gen(3, 1013, IO_WROPEN_CODE, + "Couldn't open $1file '$2' for writing (system error code $3)") + +gen(0, 1014, IO_NOWRITE, "Couldn't write output") + +gen(4, 1015, IO_WROPEN_CODETEXT, + "Couldn't open $1file '$2' for writing (system error code $3: $4)") + +gen(2, 1016, IO_RDOPEN_NF, + "Couldn't open $1file '$2' for reading (file not found)") + +gen(2, 1017, IO_RDOPEN_BC, + "Couldn't open $1file '$2' for reading (device (e.g. URL) not supported)") + +gen(2, 1018, IO_WROPEN_NF, + "Couldn't open $1file '$2' for writing (no such directory)") + +gen(2, 1019, IO_WROPEN_BC, + "Couldn't open $1file '$2' for writing (device (e.g. URL) not supported)") + +gen(2, 1020, IO_RDOPEN_PD, + "Couldn't open $1file '$2' for reading (permission denied)") + +gen(2, 1022, IO_WROPEN_PD, + "Couldn't open $1file '$2' for writing (permission denied)") + +gen(2, 1024, IO_RDOPEN_TM, + "Couldn't open $1file '$2' for reading (too many open files)") + +gen(2, 1026, IO_WROPEN_TM, + "Couldn't open $1file '$2' for writing (too many open files)") + +gen(2, 1028, IO_RDOPEN_ID, + "Couldn't open $1file '$2' for reading (is a directory)") + +gen(2, 1030, IO_WROPEN_ID, + "Couldn't open $1file '$2' for writing (is a directory)") + +gen(2, 1032, IO_WROPEN_AE, + "Couldn't open $1file '$2' for writing (file already exists)") + +gen(2, 1034, IO_WROPEN_TL, + "Couldn't open $1file '$2' for writing (file name too long)") + +gen(2, 1036, IO_WROPEN_NS, + "Couldn't open $1file '$2' for writing (no space left on device)") + +gen(2, 1037, IO_RDOPEN_IS, + "Couldn't open $1file '$2' for reading (file name syntax incorrect)") + +gen(2, 1038, IO_WROPEN_IS, + "Couldn't open $1file '$2' for writing (file name syntax incorrect)") + +gen(2, 1040, IO_WROPEN_NC, + "Couldn't open $1file '$2' for writing (file cannot be created)") + +gen(2, 1042, IO_WROPEN_NP, + "Couldn't open $1file '$2' for writing (path not found)") + +gen(2, 1044, IO_RDOPEN_SV, + "Couldn't open $1file '$2' for reading (used by another process)") + +gen(2, 1046, IO_WROPEN_SV, + "Couldn't open $1file '$2' for writing (used by another process)") + +gen(0, 1048, IO_UNSUPP_UNINAME, + "Unicode file names are not supported on this platform") + +gen(1, 1050, IO_COMPRESS, "Compression error ($1)") + +gen(0, 1052, IO_NOBUFFER, "Don't fetch buffer contents when writing to file") + +gen(2, 1054, IO_BADFORMAT, "'$1' does not appear to be a $2 file") + +gen(1, 1056, IO_READ, "Error reading data from file '$1'") + +gen(1, 1057, IO_WRITE, "Error writing data to file '$1'") + +gen(3, 1058, IO_ILLSYNTAX, "$1file '$2': Syntax error in line $3") + +gen(1, 1060, PVF_NAMEEXISTS, + "Couldn't create virtual file '$1' (name already exists)") + +gen(2, 1062, IO_FILE_EMPTY, "$1file '$2' is empty") + +gen(2, 1064, IO_RDOPEN_QU, + "Couldn't open $1file '$2' for reading (quota exceeded)") + +gen(2, 1066, IO_WROPEN_QU, + "Couldn't open $1file '$2' for writing (quota exceeded)") + + + + +/* -------------------------------------------------------------------- */ +/* Invalid arguments (11xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 1100, ILLARG_EMPTY, "Parameter '$1' is empty") + +gen(2, 1101, ILLARG_FLOAT_ZERO, + "Floating point parameter '$1' has bad value $2 (too close to 0)") + +/* Unused. See 1107 +gen(1, 1102, ILLARG_POSITIVE, "Parameter '$1' must be positive") +*/ + +gen(2, 1104, ILLARG_BOOL, "Boolean parameter '$1' has bad value '$2'") + +gen(2, 1106, ILLARG_INT, "Integer parameter '$1' has bad value $2") + +gen(3, 1107, ILLARG_FLOAT_TOOSMALL, + "Floating point parameter '$1' has bad value $2 (minimum $3)") + +gen(2, 1108, ILLARG_FLOAT, "Floating-point parameter '$1' has bad value $2") + +gen(3, 1109, ILLARG_FLOAT_TOOLARGE, + "Floating point parameter '$1' has bad value $2 (maximum $3)") + +gen(2, 1110, ILLARG_STRING, "String parameter '$1' has bad value '$2'") + +gen(1, 1111, ILLARG_FLOAT_NAN, + "Floating point parameter '$1' has bad value (not a number)") + +/* Unused. See 1504 +gen(1, 1112, ILLARG_UTF, "Illegal UTF-$1 sequence in string") +*/ + +gen(2, 1114, ILLARG_MATRIX, "Matrix [$1] is degenerate") + +gen(2, 1116, ILLARG_TOOLONG, + "String parameter '$1' is limited to $2 characters") + +gen(2, 1118, ILLARG_HANDLE, + "Handle parameter or option of type '$1' has bad value $2") + +/* Unused. See 1107 +gen(1, 1120, ILLARG_NONNEG, "Parameter '$1' must not be negative") +*/ + +gen(1, 1122, ILLARG_LANG_CODE, "Unsupported language code '$1'") + + +/* -------------------------------------------------------------------- */ +/* Parameters and values (12xx) */ +/* -------------------------------------------------------------------- */ + +gen(0, 1200, PAR_EMPTYKEY, "Empty key") + +gen(1, 1202, PAR_UNKNOWNKEY, "Unknown key '$1'") + +gen(0, 1204, PAR_EMPTYVALUE, "Empty parameter value") + +gen(2, 1206, PAR_ILLPARAM, "Bad parameter '$1' for key '$2'") + +gen(2, 1208, PAR_ILLVALUE, "Bad value $1 for key '$2'") + +gen(2, 1210, PAR_SCOPE_GET, "Can't get parameter '$1' in scope '$2'") + +gen(2, 1212, PAR_SCOPE_SET, "Can't set parameter '$1' in scope '$2'") + +gen(2, 1214, PAR_VERSION, "Parameter '$1' requires PDF $2 or above") + +gen(1, 1216, PAR_ILLKEY, "Illegal attempt to set parameter '$1'") + +gen(1, 1217, RES_BADCAT, "Bad resource category '$1'") + +gen(2, 1218, RES_BADRES, "Bad resource specification '$1' for category '$2'") + +gen(3, 1219, RES_BADRES2, + "Bad resource specification '$1 = $2' for category '$3'") + +gen(1, 1220, PAR_UNSUPPKEY, "Unknown or unsupported key '$1'") + +gen(1, 1250, PAR_ILLSECT, "Illegal section '$1'") + + + + +/* -------------------------------------------------------------------- */ +/* Options and values (14xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 1400, OPT_UNKNOWNKEY, "Unknown option '$1'") + +gen(2, 1402, OPT_TOOFEWVALUES, "Option '$1' has too few values (< $2)") + +gen(2, 1404, OPT_TOOMANYVALUES, "Option '$1' has too many values (> $2)") + +gen(1, 1406, OPT_NOVALUES, "Option '$1' doesn't have a value") + +gen(2, 1408, OPT_ILLBOOLEAN, "Option '$1' has bad boolean value '$2'") + +gen(2, 1410, OPT_ILLINTEGER, "Option '$1' has bad integer value '$2'") + +gen(2, 1412, OPT_ILLNUMBER, "Option '$1' has bad number value '$2'") + +gen(2, 1414, OPT_ILLKEYWORD, "Option '$1' has bad keyword '$2'") + +gen(2, 1415, OPT_ILLCHAR, + "Option '$1' has bad Unicode value or character name '$2'") + +gen(3, 1416, OPT_TOOSMALLVAL, + "Value $2 for option '$1' is too small (minimum $3)") + +gen(2, 1417, OPT_TOOSMALLPERCVAL, + "Value $2% for option '$1' is too small (minimum 0%)") + +gen(3, 1418, OPT_TOOBIGVAL, + "Value $2 for option '$1' is too large (maximum $3)") + +gen(2, 1419, OPT_TOOBIGPERCVAL, + "Value $2% for option '$1' is too large (maximum 100%)") + +gen(2, 1420, OPT_ZEROVAL, "Option '$1' has bad value $2") + +gen(3, 1422, OPT_TOOSHORTSTR, + "String value '$2' for option '$1' is too short (minimum $3)") + +gen(3, 1424, OPT_TOOLONGSTR, + "String value '$2' for option '$1' is too long (maximum $3)") + +gen(2, 1426, OPT_ILLSPACES, + "Option '$1' has bad string value '$2' (contains whitespace)") + +gen(1, 1428, OPT_NOTFOUND, "Required option '$1' is missing") + +gen(1, 1430, OPT_IGNORED, "Option '$1' ignored") + +gen(2, 1432, OPT_VERSION, "Option '$1' is not supported in PDF $2") + +gen(3, 1434, OPT_ILLHANDLE, "Option '$1' has bad $3 handle $2") + +gen(2, 1436, OPT_IGNORE, + "Option '$1' will be ignored (specified option '$2' is dominant)") + +gen(1, 1438, OPT_UNSUPP, "Option '$1' not supported in PDFlib Lite") + +gen(1, 1439, OPT_UNSUPP_CONFIG, + "Option '$1' not supported in this configuration") + +gen(1, 1440, OPT_NOTBAL, "Braces aren't balanced in option list '$1'") + +gen(1, 1442, OPT_ODDNUM, "Option '$1' has odd number of values") + +gen(1, 1444, OPT_EVENNUM, "Option '$1' has even number of values") + +gen(1, 1446, OPT_ILLCOMB, "Option '$1' contains a bad combination of keywords") + +gen(1, 1448, OPT_ILL7BITASCII, "Option '$1' contains bad 7-bit ASCII string") + +gen(2, 1450, OPT_COMBINE, "Option '$1' must not be combined with option '$2'") + +gen(2, 1452, OPT_ILLBOX, "Option '$1' has bad box '$2'") + +gen(2, 1454, OPT_ILLEXP, "Option '$1' has bad expression '$2'") + +gen(1, 1456, OPT_TOOMANYPERCVALS, + "Option '$1' contains too many percentage values (> 32)") + +gen(2, 1458, OPT_ILLPOLYLINE, + "Option '$1' has bad polyline '$2' (too few vertices <= 2)") + + +/* -------------------------------------------------------------------- */ +/* String conversion and encoding functions (15xx) */ +/* -------------------------------------------------------------------- */ + +gen(0, 1500, CONV_ILLUTF16, "Invalid UTF-16 string (odd byte count)") + +gen(2, 1501, CONV_ILLUTF16SUR, "Invalid UTF-16 surrogate pair <U+$1,U+$2>") + +gen(0, 1502, CONV_MEMOVERFLOW, "Out of memory in UTF string conversion") + +gen(1, 1504, CONV_ILLUTF, "Invalid UTF-$1 string") + +gen(1, 1505, CONV_ILLUTF32, "Invalid UTF-32 character U+$1") + +gen(1, 1506, CONV_ILL_MBTEXTSTRING, + "Invalid text string according to the current codepage '$1'") + +gen(1, 1508, CONV_UNSUPP_MBTEXTFORM, + "Multi byte text format (codepage $1) not supported on this platform") + +gen(0, 1510, CONV_LIST_MEMOVERFLOW, + "Buffer overflow while converting code to destination code list") + +gen(1, 1520, CONV_CHARREF_TOOLONG, + "Illegal character reference '$1' (too long)") + +gen(1, 1521, CONV_HTML_ILLCODE, + "Illegal HTML character entity '$1' (illegal character code)") + +gen(1, 1522, CONV_HTML_ILLNAME, + "Illegal HTML character entity '$1' (illegal character name)") + +gen(1, 1523, CONV_CHARREF_MISSDELIMIT, + "Illegal character reference '$1' (delimiter ';' missing)") + +gen(1, 1524, CONV_CHARREF_UNKNOWN, + "Illegal character reference '$1' (unknown glyph name)") + +gen(1, 1525, CONV_CHARREF_NOTUNIQUE, + "Illegal character reference '$1' (more than one Unicode value)") + +gen(2, 1550, ENC_TOOLONG, "Encoding name '$1' too long (max. $2)") + +gen(2, 1551, ENC_BADLINE, "Syntax error in encoding file '$1' (line '$2')") + +gen(1, 1552, ENC_NOTFOUND, "Couldn't find encoding '$1'") + +gen(2, 1554, ENC_NOTDEF_UNICODE, "Unicode U+$1 not defined in encoding '$2'") + +gen(2, 1556, ENC_NOTDEF_CODE, "Code $1 has no Unicode value in encoding '$2'") + +gen(1, 1558, ENC_UNSUPP_LANG, + "Codeset '$1' in LANG environment variable not supported") + +gen(2, 1570, GLL_BADLINE, "Syntax error in glyph list file '$1' (line '$2')") + +gen(2, 1572, CDL_BADLINE, "Syntax error in code list file '$1' (line '$2')") + +gen(1, 1574, STR_ILL_ESCSEQ, "Illegal escape sequence '$1'") + +gen(1, 1576, STR_ILL_UNIESCSEQ, + "Illegal UTF-16 escape sequence (character U+$1 > U+00FF)") + + + + + + +/* -------------------------------------------------------------------- */ +/* Internal (19xx) */ +/* -------------------------------------------------------------------- */ + +/* Unused. +gen(1, 1900, INT_NULLARG, "Invalid NULL argument in function $1") +*/ + +gen(0, 1902, INT_XSTACK, "Exception stack underflow") + +gen(1, 1904, INT_UNUSEDOBJ, "Object $1 allocated but not used") + +gen(1, 1906, INT_FLOATTOOLARGE, "Floating point number $1 too large for PDF") + +gen(0, 1907, INT_ILLFLOAT, "Bad floating point number for PDF") + +gen(2, 1908, INT_BADFORMAT, "Unknown vsprintf() format '$1' ($2)") + +gen(1, 1910, INT_ALLOC0, + "Tried to allocate 0 or negative number of bytes in function $1") + +/* Unused. See 1502 +gen(1, 1912, INT_UNICODEMEM, "Too few bytes allocated in Unicode function $1") + */ + +gen(1, 1914, INT_INVMATRIX, "Matrix [$1] not invertible") + +gen(1, 1916, INT_REALLOC_TMP, "Illegal call to realloc_tmp() in function $1") + +gen(0, 1918, INT_FREE_TMP, "Illegal call to free_tmp()") + +gen(2, 1920, INT_ILLSWITCH, "Unexpected switch value $1 in function $2") + +gen(2, 1922, INT_ARRIDX, "Illegal array index $1 in function $2") + +gen(1, 1924, INT_ILLARG, "Invalid argument(s) in function $1") + +gen(2, 1926, INT_ASSERT, + "Internal error: assertion failed in file '$1', line $2") + +gen(1, 1928, INT_STACK_UNDER, "Stack underflow in function $1") + +gen(0, 1930, INT_TOOMUCH_SARE, "Too many save/restore operations") + +gen(1, 1932, INT_TOOMUCH_INDOBJS, "Too many indirect objects (> $1)") + +gen(1, 1934, INT_TOOLONG_TEXTSTR, "Text string too long (> $1)") + +gen(1, 1940, INT_BADERRNO, + "System IO error (file pointer = NULL, errno = 0); " + "contact support@pdflib.com") + +gen(1, 1950, INT_LONGNAME_MISSING, "Long name is missing at index $1") + + + + +#undef gen +#undef pdc_genNames +#undef pdc_genInfo + + + + + + + diff --git a/src/pdflib/pdcore/pc_geom.c b/src/pdflib/pdcore/pc_geom.c new file mode 100644 index 0000000..c52cdf4 --- /dev/null +++ b/src/pdflib/pdcore/pc_geom.c @@ -0,0 +1,681 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_geom.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Various geometry routines + * + */ + +#include "pc_util.h" +#include "pc_geom.h" + + +/* ---------------------- matrix functions ----------------------------- */ + +pdc_bool +pdc_is_identity_matrix(pdc_matrix *m) +{ + return PDC_FLOAT_ISNULL(m->a - 1) && + PDC_FLOAT_ISNULL(m->b) && + PDC_FLOAT_ISNULL(m->c) && + PDC_FLOAT_ISNULL(m->d - 1) && + PDC_FLOAT_ISNULL(m->e) && + PDC_FLOAT_ISNULL(m->f); +} + +/* identity matrix */ +void +pdc_identity_matrix(pdc_matrix *M) +{ + M->a = 1; + M->b = 0; + M->c = 0; + M->d = 1; + M->e = 0; + M->f = 0; +} + +/* translation matrix */ +void +pdc_translation_matrix(pdc_scalar tx, pdc_scalar ty, pdc_matrix *M) +{ + M->a = 1; + M->b = 0; + M->c = 0; + M->d = 1; + M->e = tx; + M->f = ty; +} + +/* scale matrix */ +void +pdc_scale_matrix(pdc_scalar sx, pdc_scalar sy, pdc_matrix *M) +{ + M->a = sx; + M->b = 0; + M->c = 0; + M->d = sy; + M->e = 0; + M->f = 0; +} + +/* rotation matrix */ +void +pdc_rotation_matrix(pdc_scalar alpha, pdc_matrix *M) +{ + pdc_scalar phi, c, s; + + phi = alpha * PDC_DEG2RAD; + c = cos(phi); + s = sin(phi); + + M->a = c; + M->b = s; + M->c = -s; + M->d = c; + M->e = 0; + M->f = 0; +} + +/* skew matrix */ +void +pdc_skew_matrix(pdc_scalar alpha, pdc_scalar beta, pdc_matrix *M) +{ + M->a = 1; + M->b = tan(alpha * PDC_DEG2RAD); + M->c = tan(beta * PDC_DEG2RAD); + M->d = 1; + M->e = 0; + M->f = 0; +} + +/* N = M * N */ +void +pdc_multiply_matrix(const pdc_matrix *M, pdc_matrix *N) +{ + pdc_matrix result; + + result.a = M->a * N->a + M->b * N->c; + result.b = M->a * N->b + M->b * N->d; + result.c = M->c * N->a + M->d * N->c; + result.d = M->c * N->b + M->d * N->d; + + result.e = M->e * N->a + M->f * N->c + N->e; + result.f = M->e * N->b + M->f * N->d + N->f; + + *N = result; +} + +/* L = M * N */ +void +pdc_multiply_matrix3(pdc_matrix *L, const pdc_matrix *M, const pdc_matrix *N) +{ + L->a = M->a * N->a + M->b * N->c; + L->b = M->a * N->b + M->b * N->d; + L->c = M->c * N->a + M->d * N->c; + L->d = M->c * N->b + M->d * N->d; + L->e = M->e * N->a + M->f * N->c + N->e; + L->f = M->e * N->b + M->f * N->d + N->f; +} + +/* M = [a b c d e f] * M; */ +void +pdc_multiply_6s_matrix(pdc_matrix *M, pdc_scalar a, pdc_scalar b, pdc_scalar c, + pdc_scalar d, pdc_scalar e, pdc_scalar f) +{ + pdc_matrix result; + + result.a = a * M->a + b * M->c; + result.b = a * M->b + b * M->d; + result.c = c * M->a + d * M->c; + result.d = c * M->b + d * M->d; + + result.e = e * M->a + f * M->c + M->e; + result.f = e * M->b + f * M->d + M->f; + + *M = result; +} + + +/* invert M and store the result in N */ +void +pdc_invert_matrix(pdc_core *pdc, pdc_matrix *N, pdc_matrix *M) +{ + pdc_scalar det = M->a * M->d - M->b * M->c; + + if (fabs(det) < PDC_SMALLREAL * PDC_SMALLREAL) + pdc_error(pdc, PDC_E_INT_INVMATRIX, + pdc_errprintf(pdc, "%f %f %f %f %f %f", + M->a, M->b, M->c, M->d, M->e, M->f), + 0, 0, 0); + + N->a = M->d/det; + N->b = -M->b/det; + N->c = -M->c/det; + N->d = M->a/det; + N->e = -(M->e * N->a + M->f * N->c); + N->f = -(M->e * N->b + M->f * N->d); +} + +/* debug print */ +void +pdc_print_matrix(const char *name, const pdc_matrix *M) +{ + printf("%s: a=%g, b=%g, c=%g, d=%g, e=%g, f=%g\n", + name, M->a, M->b, M->c, M->d, M->e, M->f); +} + +/* transform scalar */ +pdc_scalar +pdc_transform_scalar(const pdc_matrix *M, pdc_scalar s) +{ + pdc_scalar det = M->a * M->d - M->b * M->c; + + return sqrt(fabs(det)) * s; +} + +/* transform point */ +void +pdc_transform_point(const pdc_matrix *M, pdc_scalar x, pdc_scalar y, + pdc_scalar *tx, pdc_scalar *ty) +{ + *tx = M->a * x + M->c * y + M->e; + *ty = M->b * x + M->d * y + M->f; +} + +/* transform vector */ +void +pdc_transform_vector(const pdc_matrix *M, pdc_vector *v, pdc_vector *tv) +{ + pdc_scalar tx = M->a * v->x + M->c * v->y + M->e; + pdc_scalar ty = M->b * v->x + M->d * v->y + M->f; + if (tv) + { + tv->x = tx; + tv->y = ty; + } + else + { + v->x = tx; + v->y = ty; + } +} + +/* transform relative vector */ +void +pdc_transform_rvector(const pdc_matrix *M, pdc_vector *v, pdc_vector *tv) +{ + pdc_scalar tx = M->a * v->x + M->c * v->y; + pdc_scalar ty = M->b * v->x + M->d * v->y; + if (tv) + { + tv->x = tx; + tv->y = ty; + } + else + { + v->x = tx; + v->y = ty; + } +} + +/* get length of vector */ +pdc_scalar +pdc_get_vector_length(pdc_vector *start, pdc_vector *end) +{ + pdc_scalar dx = end->x - start->x; + pdc_scalar dy = end->y - start->y; + + return sqrt(dx * dx + dy * dy); +} + + +/* ---------------------- utility functions ----------------------------- */ + +void +pdc_place_element(pdc_fitmethod method, pdc_scalar minfscale, + const pdc_box *fitbox, const pdc_vector *fitrelpos, + const pdc_vector *elemsize, const pdc_vector *elemrelpos, + pdc_box *elembox, pdc_vector *scale) +{ + pdc_vector refpos; + pdc_scalar width, height, det, fscale = 1.0; + pdc_bool xscaling = pdc_false; + + /* reference position in fitbox */ + width = fitbox->ur.x - fitbox->ll.x; + height = fitbox->ur.y - fitbox->ll.y; + refpos.x = fitbox->ll.x + fitrelpos->x * width; + refpos.y = fitbox->ll.y + fitrelpos->y * height; + + /* first check */ + switch (method) + { + case pdc_entire: + case pdc_slice: + case pdc_meet: + case pdc_tauto: + if (fabs(width) > PDC_FLOAT_PREC && fabs(height) > PDC_FLOAT_PREC) + { + if (method != pdc_entire) + { + det = elemsize->x * height - elemsize->y * width; + xscaling = (method == pdc_slice && det <= 0) || + ((method == pdc_meet || method == pdc_tauto) && + det > 0) ? pdc_true : pdc_false; + if (xscaling) + fscale = width / elemsize->x; + else + fscale = height / elemsize->y; + } + + if (method == pdc_tauto) + { + if(fscale >= 1.0) + { + method = pdc_nofit; + } + else if (fscale < minfscale) + { + method = pdc_meet; + } + } + } + else + { + method = pdc_nofit; + } + break; + + default: + break; + } + + /* calculation */ + switch (method) + { + /* entire box is covered by entire element */ + case pdc_entire: + *elembox = *fitbox; + scale->x = width / elemsize->x; + scale->y = height / elemsize->y; + return; + + /* fit into and preserve aspect ratio */ + case pdc_slice: + case pdc_meet: + if (xscaling) + height = fscale * elemsize->y; + else + width = fscale * elemsize->x; + scale->x = fscale; + scale->y = fscale; + break; + + /* fit into and doesn't preserve aspect ratio */ + case pdc_tauto: + if (xscaling) + { + height = elemsize->y; + scale->x = fscale; + scale->y = 1.0; + } + else + { + width = elemsize->x; + scale->x = 1.0; + scale->y = fscale; + } + break; + + /* only positioning */ + case pdc_nofit: + case pdc_clip: + width = elemsize->x; + height = elemsize->y; + scale->x = 1.0; + scale->y = 1.0; + break; + } + + /* placed element box */ + elembox->ll.x = refpos.x - elemrelpos->x * width; + elembox->ll.y = refpos.y - elemrelpos->y * height; + elembox->ur.x = refpos.x + (1.0 - elemrelpos->x) * width; + elembox->ur.y = refpos.y + (1.0 - elemrelpos->y) * height; +} + + +void +pdc_box2polyline(const pdc_matrix *M, const pdc_box *box, pdc_vector *polyline) +{ + pdc_scalar x[4], y[4]; + + /* counterclockwise order */ + if (M != NULL) + { + pdc_transform_point(M, box->ll.x, box->ll.y, &x[0], &y[0]); + pdc_transform_point(M, box->ur.x, box->ll.y, &x[1], &y[1]); + pdc_transform_point(M, box->ur.x, box->ur.y, &x[2], &y[2]); + pdc_transform_point(M, box->ll.x, box->ur.y, &x[3], &y[3]); + + polyline[0].x = x[0]; + polyline[0].y = y[0]; + polyline[1].x = x[1]; + polyline[1].y = y[1]; + polyline[2].x = x[2]; + polyline[2].y = y[2]; + polyline[3].x = x[3]; + polyline[3].y = y[3]; + polyline[4] = polyline[0]; + } + else + { + polyline[0].x = box->ll.x; + polyline[0].y = box->ll.y; + polyline[1].x = box->ur.x; + polyline[1].y = box->ll.y; + polyline[2].x = box->ur.x; + polyline[2].y = box->ur.y; + polyline[3].x = box->ll.x; + polyline[3].y = box->ur.y; + polyline[4] = polyline[0]; + } +} + +void * +pdc_delete_polylinelist(pdc_core *pdc, pdc_polyline *polylinelist, int nplines) +{ + int i; + + if (polylinelist != NULL) + { + for (i = 0; i < nplines; i++) + pdc_free(pdc, polylinelist[i].p); + pdc_free(pdc, polylinelist); + } + + return NULL; +} + +void +pdc_init_box(pdc_box *box) +{ + box->ll.x = PDC_FLOAT_MAX; + box->ll.y = PDC_FLOAT_MAX; + box->ur.x = PDC_FLOAT_MIN; + box->ur.y = PDC_FLOAT_MIN; +} + +void +pdc_adapt_box(pdc_box *box, const pdc_vector *v) +{ + if (v->x < box->ll.x) + box->ll.x = v->x; + if (v->y < box->ll.y) + box->ll.y = v->y; + + if (v->x > box->ur.x) + box->ur.x = v->x; + if (v->y > box->ur.y) + box->ur.y = v->y; +} + +void +pdc_normalize_box(pdc_box *box, pdc_scalar ydir) +{ + pdc_scalar sxy; + + if (box->ll.x > box->ur.x) + { + sxy = box->ll.x; + box->ll.x = box->ur.x; + box->ur.x = sxy; + } + + if (ydir * box->ll.y > ydir * box->ur.y) + { + sxy = box->ll.y; + box->ll.y = box->ur.y; + box->ur.y = sxy; + } +} + +void +pdc_transform_box(const pdc_matrix *M, pdc_box *box, pdc_box *tbox) +{ + pdc_vector polyline[5]; + pdc_box tmpbox; + int i; + + pdc_box2polyline(NULL, box, polyline); + + pdc_init_box(&tmpbox); + + for (i = 0; i < 4; i++) + { + pdc_transform_vector(M, &polyline[i], NULL); + pdc_adapt_box(&tmpbox, &polyline[i]); + } + + if (tbox) + *tbox = tmpbox; + else + *box = tmpbox; +} + +/* --------------------------- rectangles --------------------------- */ +pdc_bool +pdc_rect_isnull(const pdc_rectangle *r) +{ + if (!r) + return pdc_true; + + return + (r->llx == 0 && r->lly == 0 && + r->urx == 0 && r->ury == 0); +} + +pdc_bool +pdc_rect_contains(const pdc_rectangle *r1, const pdc_rectangle *r2) +{ + return + (r1->llx <= r2->llx && r1->lly <= r2->lly && + r1->urx >= r2->urx && r1->ury >= r2->ury); +} + +void +pdc_rect_copy(pdc_rectangle *r1, const pdc_rectangle *r2) +{ + r1->llx = r2->llx; + r1->lly = r2->lly; + r1->urx = r2->urx; + r1->ury = r2->ury; +} + +void +pdc_rect_init(pdc_rectangle *r, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury) +{ + r->llx = llx; + r->lly = lly; + r->urx = urx; + r->ury = ury; +} + +pdc_bool +pdc_rect_intersect( + pdc_rectangle *result, + const pdc_rectangle *r1, + const pdc_rectangle *r2) +{ + if (r1->urx <= r2->llx || + r2->urx <= r1->llx || + r1->ury <= r2->lly || + r2->ury <= r1->lly) + { + if (result) + { + result->llx = result->lly = result->urx = result->ury = 0; + } + + return pdc_false; + } + + if (result) + { + result->llx = MAX(r1->llx, r2->llx); + result->urx = MIN(r1->urx, r2->urx); + result->lly = MAX(r1->lly, r2->lly); + result->ury = MIN(r1->ury, r2->ury); + } + + return pdc_true; +} + +void +pdc_rect_transform(const pdc_matrix *M, const pdc_rectangle *r1, + pdc_rectangle *r2) +{ + pdc_scalar x[4], y[4]; + int i; + + pdc_transform_point(M, r1->llx, r1->lly, &x[0], &y[0]); + pdc_transform_point(M, r1->urx, r1->lly, &x[1], &y[1]); + pdc_transform_point(M, r1->urx, r1->ury, &x[2], &y[2]); + pdc_transform_point(M, r1->llx, r1->ury, &x[3], &y[3]); + + pdc_rect_init(r2, PDC_FLOAT_MAX, PDC_FLOAT_MAX, + PDC_FLOAT_MIN, PDC_FLOAT_MIN); + + for (i = 0; i < 4; i++) + { + if (x[i] < r2->llx) + r2->llx = x[i]; + if (y[i] < r2->lly) + r2->lly = y[i]; + + if (x[i] > r2->urx) + r2->urx = x[i]; + if (y[i] > r2->ury) + r2->ury = y[i]; + } +} + +void pdc_rect_normalize(pdc_rectangle *r) +{ + double aux; + + if (r->urx < r->llx) + { + aux = r->llx; r->llx = r->urx; r->urx = aux; + } + + if (r->ury < r->lly) + { + aux = r->lly; r->lly = r->ury; r->ury = aux; + } +} + +void pdc_rect_normalize2(pdc_rectangle *dst, const pdc_rectangle *src) +{ + if (src->llx < src->urx) + { + dst->llx = src->llx; + dst->urx = src->urx; + } + else + { + dst->llx = src->urx; + dst->urx = src->llx; + } + + if (src->lly < src->ury) + { + dst->lly = src->lly; + dst->ury = src->ury; + } + else + { + dst->lly = src->ury; + dst->ury = src->lly; + } +} + +void +pdc_polyline2rect(const pdc_vector *polyline, int np, pdc_rectangle *r) +{ + int i; + + pdc_rect_init(r, PDC_FLOAT_MAX, PDC_FLOAT_MAX, + PDC_FLOAT_MIN, PDC_FLOAT_MIN); + + for (i = 0; i < np; i++) + { + if (polyline[i].x < r->llx) + r->llx = polyline[i].x; + if (polyline[i].y < r->lly) + r->lly = polyline[i].y; + + if (polyline[i].x > r->urx) + r->urx = polyline[i].x; + if (polyline[i].y > r->ury) + r->ury = polyline[i].y; + } +} + +void +pdc_rect2polyline(const pdc_matrix *M, const pdc_rectangle *r, + pdc_vector *polyline) +{ + pdc_scalar x[4], y[4]; + + /* counterclockwise order */ + if (M != NULL) + { + pdc_transform_point(M, r->llx, r->lly, &x[0], &y[0]); + pdc_transform_point(M, r->urx, r->lly, &x[1], &y[1]); + pdc_transform_point(M, r->urx, r->ury, &x[2], &y[2]); + pdc_transform_point(M, r->llx, r->ury, &x[3], &y[3]); + + polyline[0].x = x[0]; + polyline[0].y = y[0]; + polyline[1].x = x[1]; + polyline[1].y = y[1]; + polyline[2].x = x[2]; + polyline[2].y = y[2]; + polyline[3].x = x[3]; + polyline[3].y = y[3]; + polyline[4] = polyline[0]; + } + else + { + polyline[0].x = r->llx; + polyline[0].y = r->lly; + polyline[1].x = r->urx; + polyline[1].y = r->lly; + polyline[2].x = r->urx; + polyline[2].y = r->ury; + polyline[3].x = r->llx; + polyline[3].y = r->ury; + polyline[4] = polyline[0]; + } +} + +/* debug print */ +void +pdc_print_rectangle(const char *name, const pdc_rectangle *r) +{ + printf("%s: llx=%g, lly=%g, urx=%g, ury=%g\n", + name, r->llx, r->lly, r->urx, r->ury); +} diff --git a/src/pdflib/pdcore/pc_geom.h b/src/pdflib/pdcore/pc_geom.h new file mode 100644 index 0000000..629157d --- /dev/null +++ b/src/pdflib/pdcore/pc_geom.h @@ -0,0 +1,116 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_geom.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib core geometry utilities + * + */ + +#ifndef PC_GEOM_H +#define PC_GEOM_H + +/* Unfortunately M_PI causes porting woes, so we use a private name */ +#define PDC_M_PI 3.14159265358979323846 /* pi */ +#define PDC_DEG2RAD 0.0174532925199433 +#define PDC_RAD2DEG 57.2957795130823070 + +/* Conversion factors */ +#define PDC_INCH2METER 0.0254 +#define PDC_METER2INCH 39.3701 + +/* same as PDF_SMALLREAL */ +#define PDC_SMALLREAL (0.000015) + +typedef double pdc_scalar; +typedef struct { pdc_scalar x, y; } pdc_vector; +typedef struct { pdc_vector ll, ur; } pdc_box; +typedef struct { pdc_scalar llx, lly, urx, ury; } pdc_rectangle; +typedef struct { int np; pdc_vector *p; } pdc_polyline; +typedef struct { pdc_scalar a, b, c, d, e, f; } pdc_matrix; + +/* methods for fitting rectangle elements into a box */ +typedef enum +{ + pdc_nofit = 0, /* no fit, only positioning */ + pdc_clip, /* no fit, only positioning with following condition: + * - the parts of element beyond the bounds of box + * are clipped */ + pdc_slice, /* fit into the box with following conditions: + * - aspect ratio of element is preserved + * - entire box is covered by the element + * - the parts of element beyond the bounds of box + * are clipped */ + pdc_meet, /* fit into the box with following conditions: + * - aspect ratio of element is preserved + * - entire element is visible in the box */ + pdc_entire, /* fit into the box with following conditions: + * - entire box is covered by the element + * - entire element is visible in the box */ + pdc_tauto /* automatic fitting. If element extends fit box in + * length, then element is shrinked, if shrink + * factor is greater than a specified value. Otherwise + * pdc_meet is applied. */ +} +pdc_fitmethod; + +pdc_bool pdc_is_identity_matrix(pdc_matrix *m); +void pdc_identity_matrix(pdc_matrix *M); +void pdc_translation_matrix(pdc_scalar tx, pdc_scalar ty, pdc_matrix *M); +void pdc_scale_matrix(pdc_scalar sx, pdc_scalar sy, pdc_matrix *M); +void pdc_rotation_matrix(pdc_scalar angle, pdc_matrix *M); +void pdc_skew_matrix(pdc_scalar alpha, pdc_scalar beta, pdc_matrix *M); +void pdc_multiply_matrix(const pdc_matrix *M, pdc_matrix *N); +void pdc_multiply_matrix3(pdc_matrix *L, const pdc_matrix *M, + const pdc_matrix *N); +void pdc_multiply_6s_matrix(pdc_matrix *M, pdc_scalar a, pdc_scalar b, + pdc_scalar c, pdc_scalar d, pdc_scalar e, pdc_scalar f); +void pdc_invert_matrix(pdc_core *pdc, pdc_matrix *N, pdc_matrix *M); +void pdc_print_matrix(const char *name, const pdc_matrix *M); +pdc_scalar pdc_transform_scalar(const pdc_matrix *M, pdc_scalar s); +void pdc_transform_point(const pdc_matrix *M, + pdc_scalar x, pdc_scalar y, pdc_scalar *tx, pdc_scalar *ty); +void pdc_transform_vector(const pdc_matrix *M, pdc_vector *v, pdc_vector *tv); +void pdc_transform_rvector(const pdc_matrix *M, pdc_vector *v, pdc_vector *tv); +pdc_scalar pdc_get_vector_length(pdc_vector *start, pdc_vector *end); + +void pdc_place_element(pdc_fitmethod method, pdc_scalar minfscale, + const pdc_box *fitbox, const pdc_vector *fitrelpos, + const pdc_vector *elemsize, const pdc_vector *elemrelpos, + pdc_box *elembox, pdc_vector *scale); +void pdc_box2polyline(const pdc_matrix *M, const pdc_box *box, + pdc_vector *polyline); +void *pdc_delete_polylinelist(pdc_core *pdc, pdc_polyline *polylinelist, + int nplines); +void pdc_init_box(pdc_box *box); +void pdc_adapt_box(pdc_box *box, const pdc_vector *v); +void pdc_normalize_box(pdc_box *box, pdc_scalar ydir); +void pdc_transform_box(const pdc_matrix *M, pdc_box *box, pdc_box *tbox); + +pdc_bool pdc_rect_isnull(const pdc_rectangle *r); +pdc_bool pdc_rect_contains(const pdc_rectangle *r1, const pdc_rectangle *r2); +void pdc_rect_copy(pdc_rectangle *r1, const pdc_rectangle *r2); +void pdc_rect_init(pdc_rectangle *r, + pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury); +pdc_bool pdc_rect_intersect(pdc_rectangle *result, + const pdc_rectangle *r1, const pdc_rectangle *r2); +void pdc_rect_transform(const pdc_matrix *M, + const pdc_rectangle *r1, pdc_rectangle *r2); +void pdc_rect_normalize(pdc_rectangle *r); +void pdc_rect_normalize2(pdc_rectangle *dst, const pdc_rectangle *src); +void pdc_rect2polyline(const pdc_matrix *M, const pdc_rectangle *r, + pdc_vector *polyline); +void pdc_polyline2rect(const pdc_vector *polyline, int np, pdc_rectangle *r); +void pdc_print_rectangle(const char *name, const pdc_rectangle *r); + +#endif /* PC_GEOM_H */ + diff --git a/src/pdflib/pdcore/pc_md5.c b/src/pdflib/pdcore/pc_md5.c new file mode 100644 index 0000000..a9d209a --- /dev/null +++ b/src/pdflib/pdcore/pc_md5.c @@ -0,0 +1,307 @@ +/* $Id: pc_md5.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib MD5 message digest routines + * + */ + +/* This is a slightly modified version of the RSA reference + * implementation for MD5, which originally contained + * the following copyright notice: + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. +*/ + +#include <string.h> + +#include "pc_util.h" +#include "pc_md5.h" + +/* Constants for MD5_Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (MD5_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (MD5_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (MD5_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (MD5_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + + +/* Encodes input (MD5_UINT4) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void Encode(unsigned char *output, MD5_UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char) (input[i] & 0xff); + output[j+1] = (unsigned char) ((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char) ((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char) ((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (MD5_UINT4). Assumes len is + * a multiple of 4. + */ +static void Decode( + MD5_UINT4 *output, + const unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((MD5_UINT4) input[j]) | + (((MD5_UINT4) input[j+1]) << 8) | + (((MD5_UINT4) input[j+2]) << 16) | + (((MD5_UINT4) input[j+3]) << 24); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5_Transform(MD5_UINT4 state[4], const unsigned char block[64]) +{ + MD5_UINT4 a = state[0]; + MD5_UINT4 b = state[1]; + MD5_UINT4 c = state[2]; + MD5_UINT4 d = state[3]; + MD5_UINT4 x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + memset (x, 0, sizeof (x)); +} + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5_Init(MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +void MD5_Update( + MD5_CTX *context, + const unsigned char *input, + unsigned int inputLen) +{ + unsigned int i, idx, partLen; + + /* Compute number of bytes mod 64 */ + idx = (unsigned int) ((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((MD5_UINT4) inputLen << 3)) + < ((MD5_UINT4) inputLen << 3)) + context->count[1]++; + + context->count[1] += ((MD5_UINT4) inputLen >> 29); + + partLen = 64 - idx; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + MD5_Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5_Transform (context->state, &input[i]); + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int idx, padLen; + + /* Save number of bits */ + Encode(bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + idx = (unsigned int) ((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + MD5_Update(context, PADDING, padLen); + + /* Append length (before padding) */ + MD5_Update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* Zeroize sensitive information. + */ + memset(context, 0, sizeof (*context)); +} diff --git a/src/pdflib/pdcore/pc_md5.h b/src/pdflib/pdcore/pc_md5.h new file mode 100644 index 0000000..619b47d --- /dev/null +++ b/src/pdflib/pdcore/pc_md5.h @@ -0,0 +1,59 @@ +/* $Id: pc_md5.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Header file for the PDFlib MD5 message digest routines + * + */ + +/* This is a slightly modified version of the RSA reference + * implementation for MD5, which originally contained + * the following copyright notice: + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + + +/* we prefix our MD5 function and structure names with "pdc_", so you can + * link your program with another MD5 lib without troubles. + */ +#define MD5_Init pdc_MD5_Init +#define MD5_Update pdc_MD5_Update +#define MD5_Final pdc_MD5_Final + +#define MD5_CTX pdc_MD5_CTX + +typedef unsigned int MD5_UINT4; + +#define MD5_DIGEST_LENGTH 16 + + +/* MD5 context. */ +typedef struct { + MD5_UINT4 state[4]; /* state (ABCD) */ + MD5_UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5_Init(MD5_CTX *context); +void MD5_Update( + MD5_CTX *context, const unsigned char *input, unsigned int inputLen); +void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *context); diff --git a/src/pdflib/pdcore/pc_optparse.c b/src/pdflib/pdcore/pc_optparse.c new file mode 100644 index 0000000..dee18ad --- /dev/null +++ b/src/pdflib/pdcore/pc_optparse.c @@ -0,0 +1,1383 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_optparse.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Parser options routines + * + */ + +#include "pc_util.h" +#include "pc_geom.h" +#include "pc_ctype.h" + +/* result of an option */ +struct pdc_resopt_s +{ + int numdef; /* number of definitions */ + const pdc_defopt *defopt; /* pointer to option definition */ + int num; /* number of parsed values */ + void *val; /* list of parsed values */ + char *origval; /* original value as string */ + int flags; /* flags */ + int pcmask; /* percentage mask */ + int currind; /* index of current option */ + int lastind; /* index of last option */ + pdc_bool isutf8; /* optionlist UTF-8 encoded */ +}; + +/* sizes of option types. must be parallel to pdc_opttype */ +static const size_t pdc_typesizes[] = +{ + sizeof (pdc_bool), + sizeof (char *), + sizeof (int), + sizeof (int), + sizeof (float), + sizeof (double), + sizeof (pdc_scalar), + sizeof (int), + sizeof (pdc_polyline), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), + sizeof (int), +}; + +static const pdc_keyconn pdc_handletypes[] = +{ + {"3ddata", pdc_3ddatahandle}, + {"3dview", pdc_3dviewhandle}, + {"action", pdc_actionhandle}, + {"bookmark", pdc_bookmarkhandle}, + {"color", pdc_colorhandle}, + {"document", pdc_documenthandle}, + {"font", pdc_fonthandle}, + {"gstate", pdc_gstatehandle}, + {"iccprofile", pdc_iccprofilehandle}, + {"image", pdc_imagehandle}, + {"layer", pdc_layerhandle}, + {"page", pdc_pagehandle}, + {"pattern", pdc_patternhandle}, + {"shading", pdc_shadinghandle}, + {"table", pdc_tablehandle}, + {"template", pdc_templatehandle}, + {"textflow", pdc_textflowhandle}, + {"string", pdc_stringhandle}, + {NULL, 0} +}; + +int +pdc_get_keycode(const char *keyword, const pdc_keyconn *keyconn) +{ + int i; + for (i = 0; keyconn[i].word != 0; i++) + { + if (!strcmp(keyword, keyconn[i].word)) + return keyconn[i].code; + } + return PDC_KEY_NOTFOUND; +} + +int +pdc_get_keycode_ci(const char *keyword, const pdc_keyconn *keyconn) +{ + int i; + for (i = 0; keyconn[i].word != 0; i++) + { + if (!pdc_stricmp(keyword, keyconn[i].word)) + return keyconn[i].code; + } + return PDC_KEY_NOTFOUND; +} + +int +pdc_get_keycode_unique(const char *keyword, const pdc_keyconn *keyconn) +{ + int i, j; + size_t len = strlen(keyword); + + for (i = 0; keyconn[i].word != 0; i++) + { + if (!strncmp(keyword, keyconn[i].word, len)) + { + for (j = i + 1; keyconn[j].word != 0; j++) + if (!strncmp(keyword, keyconn[j].word, len)) + return PDC_KEY_NOTUNIQUE; + return keyconn[i].code; + } + } + return PDC_KEY_NOTFOUND; +} + +int +pdc_get_keymask_ci(pdc_core *pdc, const char *option, + const char *keywordlist, const pdc_keyconn *keyconn) +{ + char **keys = NULL; + int nkeys, i, j, k = 0; + + nkeys = pdc_split_stringlist(pdc, keywordlist, NULL, 0, &keys); + + for (j = 0; j < nkeys; j++) + { + for (i = 0; keyconn[i].word != NULL; i++) + if (!pdc_stricmp(keys[j], keyconn[i].word)) + break; + + if (keyconn[i].word == NULL) + { + const char *stemp = pdc_errprintf(pdc, "%.*s", + PDC_ERR_MAXSTRLEN, keys[j]); + pdc_cleanup_stringlist(pdc, keys); + pdc_set_errmsg(pdc, PDC_E_OPT_ILLKEYWORD, option, stemp, 0, 0); + return PDC_KEY_NOTFOUND; + } + + k |= keyconn[i].code; + } + + pdc_cleanup_stringlist(pdc, keys); + return k; +} + +/* + * flags: PDC_INT_HEXADEC, PDC_INT_CASESENS + */ +int +pdc_get_keycode_num(pdc_core *pdc, const char *option, const char *i_keyword, + int flags, const pdc_keyconn *keyconn, int *o_num) +{ + static const char *fn = "pdc_get_keycode_num"; + char *keyword; + int i, len, keycode; + + keyword = pdc_strdup_ext(pdc, i_keyword, 0, fn); + len = (int) strlen(keyword); + *o_num = -1; + + /* parse number */ + for (i = 0; i < len; i++) + { + if (pdc_isdigit(keyword[i])) + { + if (pdc_str2integer(&keyword[i], flags, o_num)) + { + keyword[i] = 0; + } + else + { + pdc_set_errmsg(pdc, PDC_E_OPT_ILLINTEGER, option, &keyword[i], + 0, 0); + } + break; + } + } + + if (flags & PDC_INT_CASESENS) + keycode = pdc_get_keycode(keyword, keyconn); + else + keycode = pdc_get_keycode_ci(keyword, keyconn); + + if (keycode == PDC_KEY_NOTFOUND) + pdc_set_errmsg(pdc, PDC_E_OPT_ILLKEYWORD, option, keyword, 0, 0); + + pdc_free(pdc, keyword); + + return keycode; +} + +const char * +pdc_get_keyword(int keycode, const pdc_keyconn *keyconn) +{ + int i; + for (i = 0; keyconn[i].word != 0; i++) + { + if (keycode == keyconn[i].code) + return keyconn[i].word; + } + return NULL; +} + +const char * +pdc_get_int_keyword(const char *keyword, const pdc_keyconn *keyconn) +{ + int i; + for (i = 0; keyconn[i].word != 0; i++) + { + if (!pdc_stricmp(keyword, keyconn[i].word)) + return keyconn[i].word; + } + return NULL; +} + +void +pdc_cleanup_optstringlist(pdc_core *pdc, char **stringlist, int ns) +{ + int j; + + for (j = 0; j < ns; j++) + { + if (stringlist[j] != NULL) + pdc_free(pdc, stringlist[j]); + } + pdc_free(pdc, stringlist); +} + +static void +pdc_delete_optvalue(pdc_core *pdc, pdc_resopt *resopt) +{ + if (resopt->val && !(resopt->flags & PDC_OPT_SAVEALL)) + { + int j; + int ja = (resopt->flags & PDC_OPT_SAVE1ELEM) ? 1 : 0; + + if (resopt->defopt->type == pdc_stringlist) + { + char **s = (char **) resopt->val; + for (j = ja; j < resopt->num; j++) + if (s[j] != NULL) + pdc_free(pdc, s[j]); + } + else if (resopt->defopt->type == pdc_polylinelist) + { + pdc_polyline *pl = (pdc_polyline *) resopt->val; + for (j = ja; j < resopt->num; j++) + if (pl[j].p != NULL) + pdc_free(pdc, pl[j].p); + } + pdc_free(pdc, resopt->val); + resopt->val = NULL; + } + if (resopt->origval && !(resopt->flags & PDC_OPT_SAVEORIG)) + { + pdc_free(pdc, resopt->origval); + resopt->origval = NULL; + } + resopt->num = 0; +} + +static int +pdc_optname_compare(const void *a, const void *b) +{ + return (strcmp(((pdc_resopt *)a)->defopt->name, + ((pdc_resopt *)b)->defopt->name)); +} + +/* destructor function for freeing temporary memory */ +static void +pdc_cleanup_optionlist_tmp(void *opaque, void *mem) +{ + if (mem) + { + pdc_core *pdc = (pdc_core *) opaque; + pdc_resopt *resopt = (pdc_resopt *) mem; + int i; + + for (i = 0; i < resopt[0].numdef; i++) + pdc_delete_optvalue(pdc, &resopt[i]); + } +} + +pdc_resopt * +pdc_parse_optionlist(pdc_core *pdc, const char *optlist, + const pdc_defopt *defopt, + const pdc_clientdata *clientdata, pdc_bool verbose) +{ + static const char *fn = "pdc_parse_optionlist"; + pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_optlist); + const char *stemp1 = NULL, *stemp2 = NULL, *stemp3 = NULL; + char **items = NULL, *keyword = NULL; + char **values = NULL, *value = NULL, **strings = NULL; + int i, j, k, nd, is, iss, it, iv; + int numdef, nitems = 0, nvalues, ncoords = 0, errcode = 0; + void *resval; + double dz, maxval; + int retval, iz; + pdc_sint32 lz = 0; + pdc_uint32 ulz = 0; + size_t len; + const pdc_defopt *dopt = NULL; + pdc_resopt *resopt = NULL; + pdc_bool ignore = pdc_false; + pdc_bool boolval = pdc_false; + pdc_bool tocheck = pdc_false; + pdc_bool issorted = pdc_true; + pdc_bool ishandle = pdc_true; + pdc_bool isutf8 = pdc_false; + + pdc_logg_cond(pdc, 1, trc_optlist, "\n\tOption list: \"%T\"\n", + optlist ? optlist : "", 0); + + /* split option list */ + if (optlist != NULL) + { + nitems = pdc_split_stringlist(pdc, optlist, PDC_OPT_LISTSEPS, + PDC_SPLIT_ISOPTLIST, &items); + isutf8 = pdc_is_utf8_bytecode(optlist); + } + if (nitems < 0) + { + keyword = (char *) optlist; + errcode = PDC_E_OPT_NOTBAL; + goto PDC_OPT_SYNTAXERROR; + } + + /* initialize result list */ + for (numdef = 0; defopt[numdef].name != NULL; numdef++) + { + /* */ ; + } + + /* allocate temporary memory for option parser result struct */ + resopt = (pdc_resopt *) pdc_calloc_tmp(pdc, numdef * sizeof(pdc_resopt), + fn, pdc, pdc_cleanup_optionlist_tmp); + for (i = 0; i < numdef; i++) + { + resopt[i].numdef = numdef; + resopt[i].defopt = &defopt[i]; + + if (defopt[i].flags & PDC_OPT_IGNOREIF1 || + defopt[i].flags & PDC_OPT_IGNOREIF2 || + defopt[i].flags & PDC_OPT_REQUIRIF1 || + defopt[i].flags & PDC_OPT_REQUIRIF2 || + defopt[i].flags & PDC_OPT_REQUIRED) + tocheck = pdc_true; + + if (i && issorted) + issorted = (strcmp(defopt[i-1].name, defopt[i].name) <= 0) ? + pdc_true : pdc_false; + } + + /* loop over all option list elements */ + for (is = 0; is < nitems; is++) + { + /* search keyword */ + boolval = pdc_undef; + keyword = items[is]; + for (it = 0; it < numdef; it++) + { + /* special handling for booleans */ + if (defopt[it].type == pdc_booleanlist) + { + if (!pdc_stricmp(keyword, defopt[it].name) || + (keyword[1] != 0 && + !pdc_stricmp(&keyword[2], defopt[it].name))) + { + iss = is + 1; + if (iss == nitems || + (pdc_stricmp(items[iss], "true") && + pdc_stricmp(items[iss], "false"))) + { + i = pdc_strincmp(defopt[it].name, "no", 2) ? 0 : 2; + if (!pdc_strincmp(&keyword[i], "no", 2)) + { + boolval = pdc_false; + break; + } + else + { + boolval = pdc_true; + break; + } + } + } + } + + if (!pdc_stricmp(keyword, defopt[it].name)) break; + } + + if (logg5) + pdc_logg(pdc, "\t\t\toption \"%s\" specified: ", keyword); + + if (it == numdef) + { + errcode = PDC_E_OPT_UNKNOWNKEY; + goto PDC_OPT_SYNTAXERROR; + } + + /* initialize */ + dopt = &defopt[it]; + ignore = pdc_false; + nvalues = 1; + values = NULL; + ishandle = pdc_true; + + /* compatibility */ + if (clientdata && clientdata->compatibility) + { + int compatibility = clientdata->compatibility; + + for (iv = PDC_1_3; iv <= PDC_X_X_LAST; iv++) + { + if (logg5 && (dopt->flags & (1L<<iv))) + pdc_logg(pdc, "(compatibility >= %s) ", + pdc_get_pdfversion(pdc, iv)); + + if ((dopt->flags & (1L<<iv)) && compatibility < iv) + { + if (logg5) + pdc_logg(pdc, "\n"); + stemp2 = pdc_get_pdfversion(pdc, compatibility); + errcode = PDC_E_OPT_VERSION; + goto PDC_OPT_SYNTAXERROR; + } + } + } + + /* not supported */ + if (dopt->flags & PDC_OPT_UNSUPP) + { + if (logg5) + pdc_logg(pdc, "(unsupported)\n"); + + keyword = (char *) dopt->name; + errcode = PDC_E_OPT_UNSUPP; + goto PDC_OPT_SYNTAXERROR; + } + + /* parse values */ + if (boolval == pdc_undef) + { + is++; + if (is == nitems) + { + errcode = PDC_E_OPT_NOVALUES; + goto PDC_OPT_SYNTAXERROR; + } + if (!ignore) + { + if (dopt->type == pdc_stringlist && + pdc_is_utf8_bytecode(items[is])) + resopt[it].flags |= PDC_OPT_ISUTF8; + + if (dopt->type != pdc_stringlist || dopt->maxnum > 1) + nvalues = pdc_split_stringlist(pdc, items[is], + (dopt->flags & PDC_OPT_SUBOPTLIST) ? + PDC_OPT_LISTSEPS : NULL, + PDC_SPLIT_ISOPTLIST, &values); + + if (dopt->flags & PDC_OPT_DUPORIGVAL) + resopt[it].origval = pdc_strdup(pdc, items[is]); + } + } + + /* ignore */ + if (ignore) continue; + + /* number of values check */ + if (nvalues < dopt->minnum) + { + stemp2 = pdc_errprintf(pdc, "%d", dopt->minnum); + errcode = PDC_E_OPT_TOOFEWVALUES; + goto PDC_OPT_SYNTAXERROR; + } + else if (nvalues > dopt->maxnum) + { + stemp2 = pdc_errprintf(pdc, "%d", dopt->maxnum); + errcode = PDC_E_OPT_TOOMANYVALUES; + goto PDC_OPT_SYNTAXERROR; + } + + /* number of values must be even */ + if (dopt->flags & PDC_OPT_EVENNUM && (nvalues % 2)) + { + errcode = PDC_E_OPT_ODDNUM; + goto PDC_OPT_SYNTAXERROR; + } + + /* number of values must be odd */ + if (dopt->flags & PDC_OPT_ODDNUM && !(nvalues % 2)) + { + errcode = PDC_E_OPT_EVENNUM; + goto PDC_OPT_SYNTAXERROR; + } + + /* option already exists */ + if (resopt[it].num) + { + pdc_delete_optvalue(pdc, &resopt[it]); + } + + /* no values */ + if (!nvalues ) continue; + + /* maximal value */ + switch (dopt->type) + { + case pdc_3ddatahandle: + maxval = clientdata->max3ddata; + break; + + case pdc_3dviewhandle: + maxval = clientdata->max3dview; + break; + + case pdc_actionhandle: + maxval = clientdata->maxaction; + break; + + case pdc_bookmarkhandle: + maxval = clientdata->maxbookmark; + break; + + case pdc_colorhandle: + maxval = clientdata->maxcolor; + break; + + case pdc_documenthandle: + maxval = clientdata->maxdocument; + break; + + case pdc_fonthandle: + maxval = clientdata->maxfont; + break; + + case pdc_gstatehandle: + maxval = clientdata->maxgstate; + break; + + case pdc_iccprofilehandle: + maxval = clientdata->maxiccprofile; + break; + + case pdc_imagehandle: + maxval = clientdata->maximage; + break; + + case pdc_layerhandle: + maxval = clientdata->maxlayer; + break; + + case pdc_pagehandle: + maxval = clientdata->maxpage; + break; + + case pdc_patternhandle: + maxval = clientdata->maxpattern; + break; + + case pdc_shadinghandle: + maxval = clientdata->maxshading; + break; + + case pdc_tablehandle: + maxval = clientdata->maxtable; + break; + + case pdc_templatehandle: + maxval = clientdata->maxtemplate; + break; + + case pdc_textflowhandle: + maxval = clientdata->maxtextflow; + break; + + case pdc_stringhandle: + maxval = clientdata->maxstring; + break; + + case pdc_polylinelist: + ncoords = 0; + + default: + maxval = dopt->maxval; + ishandle = pdc_false; + break; + } + + /* allocate value array */ + resopt[it].val = pdc_calloc(pdc, + (size_t) (nvalues * pdc_typesizes[dopt->type]), fn); + resopt[it].num = nvalues; + resopt[it].currind = it; + + if (logg5) + pdc_logg(pdc, "{"); + + /* analyze type */ + resval = resopt[it].val; + for (iv = 0; iv < nvalues; iv++) + { + errcode = 0; + if (dopt->maxnum > 1 && nvalues) + value = values[iv]; + else + value = items[is]; + if (logg5) + pdc_logg(pdc, "%s{%T}", iv ? " " : "", value, 0); + switch (dopt->type) + { + /* boolean list */ + case pdc_booleanlist: + if (boolval == pdc_true || !pdc_stricmp(value, "true")) + { + *(pdc_bool *) resval = pdc_true; + } + else if (boolval == pdc_false || !pdc_stricmp(value, "false")) + { + *(pdc_bool *) resval = pdc_false; + } + else + { + errcode = PDC_E_OPT_ILLBOOLEAN; + } + break; + + /* string list */ + case pdc_stringlist: + if (dopt->flags & PDC_OPT_NOSPACES) + { + if (pdc_split_stringlist(pdc, value, NULL, 0, &strings) > 1) + errcode = PDC_E_OPT_ILLSPACES; + pdc_cleanup_stringlist(pdc, strings); + } + if (!errcode) + { + len = strlen(value); + dz = (double) len; + if (dz < dopt->minval) + { + stemp3 = pdc_errprintf(pdc, "%d", (int) dopt->minval); + errcode = PDC_E_OPT_TOOSHORTSTR; + } + else if (dz > maxval) + { + stemp3 = pdc_errprintf(pdc, "%d", (int) maxval); + errcode = PDC_E_OPT_TOOLONGSTR; + } + + if (dopt->flags & PDC_OPT_CONVUTF8) + { + int flags = PDC_CONV_EBCDIC | PDC_CONV_WITHBOM; + + if (isutf8 || (resopt[it].flags & PDC_OPT_ISUTF8)) + flags |= PDC_CONV_ISUTF8; + + *((char **) resval) = + pdc_convert_name(pdc, value, 0, flags); + } + else + { + *((char **) resval) = pdc_strdup(pdc, value); + } + } + break; + + /* keyword list */ + case pdc_keywordlist: + if (dopt->flags & PDC_OPT_CASESENS) + iz = pdc_get_keycode(value, dopt->keylist); + else + iz = pdc_get_keycode_ci(value, dopt->keylist); + if (iz == PDC_KEY_NOTFOUND) + { + errcode = PDC_E_OPT_ILLKEYWORD; + } + else + { + *(int *) resval = iz; + } + break; + + /* character list */ + case pdc_unicharlist: + iz = pdc_string2unicode(pdc, value, dopt->flags, dopt->keylist, + pdc_false); + if (iz < 0) + { + errcode = PDC_E_OPT_ILLCHAR; + break; + } + dz = iz; + if (dz < dopt->minval) + { + stemp3 = pdc_errprintf(pdc, "%g", dopt->minval); + errcode = PDC_E_OPT_TOOSMALLVAL; + } + else if (dz > maxval) + { + stemp3 = pdc_errprintf(pdc, "%g", maxval); + errcode = PDC_E_OPT_TOOBIGVAL; + } + *(int *) resval = iz; + break; + + /* string list */ + case pdc_polylinelist: + { + int np = pdc_split_stringlist(pdc, value, NULL, 0, + &strings); + pdc_polyline *pl = (pdc_polyline *) resval; + + pl->np = np / 2; + pl->p = NULL; + + /* number of coordinates must be even */ + if (np % 2) + { + errcode = PDC_E_OPT_ODDNUM; + np = 0; + } + + /* polyline must be a box */ + else if ((dopt->flags & PDC_OPT_ISBOX) && np != 4) + { + errcode = PDC_E_OPT_ILLBOX; + np = 0; + } + + /* polyline will be closed */ + else if ((dopt->flags & PDC_OPT_CLOSEPOLY) && np <= 4) + { + errcode = PDC_E_OPT_ILLPOLYLINE; + np = 0; + } + + /* polyline not empty */ + if (np) + { + if (dopt->flags & PDC_OPT_CLOSEPOLY) + pl->np += 1; + pl->p = (pdc_vector *) pdc_malloc(pdc, + pl->np * sizeof(pdc_vector), fn); + + iz = PDC_KEY_NOTFOUND; + j = 0; + for (i = 0; i < np; i++) + { + char *sk = strings[i]; + + if (dopt->keylist) + { + /* optional keyword list */ + if (dopt->flags & PDC_OPT_CASESENS) + iz = pdc_get_keycode(sk, dopt->keylist); + else + iz = pdc_get_keycode_ci(sk, dopt->keylist); + } + if (iz == PDC_KEY_NOTFOUND) + { + /* percentage */ + if (dopt->flags & PDC_OPT_PERCENT) + { + k = (int) strlen(sk) - 1; + if (sk[k] == '%') + { + sk[k] = 0; + if (ncoords < 32) + { + resopt[it].pcmask |= (1L <<ncoords); + } + else + { + errcode = PDC_E_OPT_TOOMANYPERCVALS; + } + } + else + { + resopt[it].pcmask &= ~(1L << ncoords); + } + } + + retval = pdc_str2double(sk, &dz); + if (!retval) + { + errcode = PDC_E_OPT_ILLNUMBER; + } + else if (resopt[it].pcmask & (1L << ncoords)) + { + if (dopt->flags & PDC_OPT_PERCRANGE) + { + if (dz < 0) + errcode = PDC_E_OPT_TOOSMALLPERCVAL; + if (dz > 100) + errcode = PDC_E_OPT_TOOBIGPERCVAL; + } + dz /= 100.0; + } + } + else + { + dz = (double) iz; + } + + if (!(i % 2)) + { + pl->p[j].x = dz; + } + else + { + pl->p[j].y = dz; + j++; + } + ncoords++; + } + + if (dopt->flags & PDC_OPT_CLOSEPOLY) + pl->p[pl->np - 1] = pl->p[0]; + } + pdc_cleanup_stringlist(pdc, strings); + } + break; + + /* number list */ + case pdc_3ddatahandle: + case pdc_3dviewhandle: + case pdc_actionhandle: + case pdc_bookmarkhandle: + case pdc_colorhandle: + case pdc_documenthandle: + case pdc_fonthandle: + case pdc_gstatehandle: + case pdc_iccprofilehandle: + case pdc_imagehandle: + case pdc_layerhandle: + case pdc_pagehandle: + case pdc_patternhandle: + case pdc_shadinghandle: + case pdc_tablehandle: + case pdc_templatehandle: + case pdc_textflowhandle: + case pdc_integerlist: + case pdc_floatlist: + case pdc_doublelist: + case pdc_scalarlist: + + if (dopt->keylist && + (!(dopt->flags & PDC_OPT_KEYLIST1) || !iv)) + { + /* optional keyword and/or allowed integer list */ + if (dopt->flags & PDC_OPT_CASESENS) + iz = pdc_get_keycode(value, dopt->keylist); + else + iz = pdc_get_keycode_ci(value, dopt->keylist); + if (iz == PDC_KEY_NOTFOUND) + { + if (dopt->flags & PDC_OPT_INTLIST) + { + errcode = PDC_E_OPT_ILLINTEGER; + break; + } + } + else + { + switch (dopt->type) + { + default: + case pdc_integerlist: + *(int *) resval = iz; + break; + + case pdc_floatlist: + *(float *) resval = (float) iz; + break; + + case pdc_doublelist: + *(double *) resval = (double) iz; + break; + + case pdc_scalarlist: + *(pdc_scalar *) resval = (pdc_scalar) iz; + break; + } + break; + } + } + + /* percentage */ + if (dopt->flags & PDC_OPT_PERCENT) + { + i = (int) strlen(value) - 1; + if (value[i] == '%') + { + value[i] = 0; + if (iv < 32) + { + resopt[it].pcmask |= (1L << iv); + } + else + { + errcode = PDC_E_OPT_TOOMANYPERCVALS; + } + } + else + { + resopt[it].pcmask &= ~(1L << iv); + } + } + + case pdc_stringhandle: + + if (dopt->type == pdc_floatlist || + dopt->type == pdc_doublelist || + dopt->type == pdc_scalarlist) + { + retval = pdc_str2double(value, &dz); + } + else + { + if (dopt->minval >= 0) + { + retval = pdc_str2integer(value, PDC_INT_UNSIGNED, &ulz); + dz = ulz; + } + else + { + retval = pdc_str2integer(value, 0, &lz); + dz = lz; + } + + if (retval && ishandle && pdc->hastobepos && + dopt->type != pdc_bookmarkhandle && + dopt->type != pdc_stringhandle) + { + dz -= 1; + lz = (pdc_sint32) dz; + ulz = (pdc_uint32) dz; + } + } + if (!retval) + { + errcode = PDC_E_OPT_ILLNUMBER; + } + else + { + if (resopt[it].pcmask & (1L << iv)) + { + if (dopt->flags & PDC_OPT_PERCRANGE) + { + if (dz < 0) + errcode = PDC_E_OPT_TOOSMALLPERCVAL; + if (dz > 100) + errcode = PDC_E_OPT_TOOBIGPERCVAL; + } + dz /= 100.0; + } + + if (errcode == 0) + { + if (dz < dopt->minval) + { + if (ishandle) + { + stemp3 = pdc_get_keyword(dopt->type, + pdc_handletypes); + errcode = PDC_E_OPT_ILLHANDLE; + } + else + { + stemp3 = pdc_errprintf(pdc, "%g", dopt->minval); + errcode = PDC_E_OPT_TOOSMALLVAL; + } + } + else if (dz > maxval) + { + if (ishandle) + { + stemp3 = pdc_get_keyword(dopt->type, + pdc_handletypes); + errcode = PDC_E_OPT_ILLHANDLE; + } + else + { + stemp3 = pdc_errprintf(pdc, "%g", maxval); + errcode = PDC_E_OPT_TOOBIGVAL; + } + } + else if (dopt->flags & PDC_OPT_NOZERO && + fabs(dz) < PDC_FLOAT_PREC) + { + errcode = PDC_E_OPT_ZEROVAL; + } + else if (dopt->type == pdc_scalarlist) + { + *(pdc_scalar *) resval = dz; + } + else if (dopt->type == pdc_doublelist) + { + *(double *) resval = dz; + } + else if (dopt->type == pdc_floatlist) + { + *(float *) resval = (float) dz; + } + else + { + if (dopt->minval >= 0) + *(pdc_uint32 *) resval = ulz; + else + *(pdc_sint32 *) resval = lz; + } + } + } + break; + } + + if (errcode) + { + stemp2 = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, value); + goto PDC_OPT_SYNTAXERROR; + } + + /* increment value pointer */ + resval = (void *) ((char *)(resval) + pdc_typesizes[dopt->type]); + } + pdc_cleanup_stringlist(pdc, values); + values = NULL; + + if (logg5) + pdc_logg(pdc, "}\n"); + + /* build OR bit pattern */ + if (dopt->flags & PDC_OPT_BUILDOR && nvalues > 1) + { + int *bcode = (int *) resopt[it].val; + for (iv = 1; iv < nvalues; iv++) + { + bcode[0] |= bcode[iv]; + } + resopt[it].num = 1; + } + } + pdc_cleanup_stringlist(pdc, items); + items = NULL; + + /* required and to be ignored options */ + for (is = 0; tocheck && is < numdef; is++) + { + /* to be ignored option */ + if (resopt[is].num) + { + nd = 0; + if (defopt[is].flags & PDC_OPT_IGNOREIF1) nd = 1; + if (defopt[is].flags & PDC_OPT_IGNOREIF2) nd = 2; + for (it = is - 1; it >= is - nd && it >= 0; it--) + { + if (resopt[it].num) + { + pdc_delete_optvalue(pdc, &resopt[is]); + if (verbose) + pdc_warning(pdc, PDC_E_OPT_IGNORE, defopt[is].name, + defopt[it].name, 0, 0); + } + } + } + + /* required option */ + if (!resopt[is].num && + ((defopt[is].flags & PDC_OPT_REQUIRED) || + (defopt[is].flags & PDC_OPT_REQUIRIF1 && resopt[is-1].num) || + (defopt[is].flags & PDC_OPT_REQUIRIF2 && + (resopt[is-1].num || resopt[is-2].num)))) + { + keyword = (char *) defopt[is].name; + errcode = PDC_E_OPT_NOTFOUND; + goto PDC_OPT_SYNTAXERROR; + } + } + + /* is no sorted */ + if (!issorted) + { + qsort((void *)resopt, (size_t) numdef, sizeof(pdc_resopt), + pdc_optname_compare); + } + + /* global UTF-8 check after sort */ + if (isutf8) + resopt[0].isutf8 = pdc_true; + + /* index of last got option */ + resopt[0].lastind = -1; + + /* protocol */ + if (pdc_logg_is_enabled(pdc, 1, trc_optlist)) + { + for (is = 0; is < numdef; is++) + { + if (resopt[is].num) + pdc_logg(pdc, "\tOption \"%s\": %d value%s found\n", + resopt[is].defopt->name, resopt[is].num, + resopt[is].num == 1 ? "" : "s"); + else if (logg5) + pdc_logg(pdc, "\t\t\toption \"%s\" not specified\n", + resopt[is].defopt->name); + for (iv = 0; iv < resopt[is].num; iv++) + { + switch (resopt[is].defopt->type) + { + case pdc_booleanlist: + case pdc_keywordlist: + case pdc_integerlist: + case pdc_3ddatahandle: + case pdc_3dviewhandle: + case pdc_actionhandle: + case pdc_bookmarkhandle: + case pdc_colorhandle: + case pdc_documenthandle: + case pdc_fonthandle: + case pdc_gstatehandle: + case pdc_iccprofilehandle: + case pdc_imagehandle: + case pdc_layerhandle: + case pdc_pagehandle: + case pdc_patternhandle: + case pdc_shadinghandle: + case pdc_tablehandle: + case pdc_templatehandle: + case pdc_textflowhandle: + case pdc_stringhandle: + pdc_logg(pdc, "\tValue %d: %d\n", + iv + 1, *((int *) resopt[is].val + iv)); + break; + + case pdc_stringlist: + pdc_logg(pdc, "\tValue %d: \"%T\"\n", + iv + 1, *((char **) resopt[is].val + iv), 0); + break; + + case pdc_floatlist: + pdc_logg(pdc, "\tValue %d: %f\n", + iv + 1, *((float *) resopt[is].val + iv)); + break; + + case pdc_doublelist: + pdc_logg(pdc, "\tValue %d: %f\n", + iv + 1, *((double *) resopt[is].val + iv)); + break; + + case pdc_scalarlist: + pdc_logg(pdc, "\tValue %d: %f\n", + iv + 1, *((pdc_scalar *) resopt[is].val + iv)); + break; + + case pdc_unicharlist: + pdc_logg(pdc, "\tValue %d: %d\n", + iv + 1, *((int *) resopt[is].val + iv)); + break; + + case pdc_polylinelist: + pdc_logg(pdc, "\t\t#%d: ", iv + 1); + { + pdc_polyline *pl = (pdc_polyline *) resopt[is].val + iv; + + for (j = 0; j < pl->np; j++) + pdc_logg(pdc, "%f,%f ", pl->p[j].x, pl->p[j].y); + pdc_logg(pdc, "\n"); + } + break; + } + } + } + } + + return resopt; + + PDC_OPT_SYNTAXERROR: + stemp1 = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, keyword); + pdc_cleanup_stringlist(pdc, items); + pdc_cleanup_stringlist(pdc, values); + + pdc_set_errmsg(pdc, errcode, stemp1, stemp2, stemp3, 0); + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + + return NULL; +} + +int +pdc_get_optvalues(const char *keyword, pdc_resopt *resopt, + void *lvalues, char ***mvalues) +{ + pdc_resopt *ropt = NULL; + void *values = NULL; + int nvalues = 0; + size_t nbytes; + if (mvalues) *mvalues = NULL; + + if (resopt) + { + int i, cmp; + int lo = 0; + int hi = resopt[0].numdef; + + while (lo < hi) + { + i = (lo + hi) / 2; + cmp = strcmp(keyword, resopt[i].defopt->name); + + /* keyword found */ + if (cmp == 0) + { + ropt = &resopt[i]; + nvalues = ropt->num; + values = ropt->val; + resopt[0].lastind = i; + break; + } + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + } + + if (nvalues) + { + /* copy values */ + if (lvalues) + { + if (ropt->defopt->type == pdc_stringlist && + ropt->defopt->maxnum == 1) + { + strcpy((char *)lvalues, *((char **) values)); + } + else + { + nbytes = (size_t) (nvalues * pdc_typesizes[ropt->defopt->type]); + memcpy(lvalues, values, nbytes); + } + } + + /* copy pointer */ + if (mvalues) + { + *mvalues = (char **) values; + } + } + + return nvalues; +} + +void * +pdc_save_lastopt(pdc_resopt *resopt, int flags) +{ + int i = resopt[0].lastind; + + if (i > -1 && resopt[i].num) + { + if (flags & PDC_OPT_SAVEALL) + { + resopt[i].flags |= PDC_OPT_SAVEALL; + return resopt[i].val; + } + else if (resopt[i].defopt->type == pdc_stringlist && + (flags & PDC_OPT_SAVE1ELEM)) + { + char **s = (char **) resopt[i].val; + resopt[i].flags |= PDC_OPT_SAVE1ELEM; + return (void *) s[0]; + } + else if (flags & PDC_OPT_SAVEORIG) + { + resopt[i].flags |= PDC_OPT_SAVEORIG; + return (void *) resopt[i].origval; + } + } + + return NULL; +} + +int +pdc_get_lastopt_index(pdc_resopt *resopt) +{ + int i = resopt[0].lastind; + + if (i > -1) + return resopt[i].currind; + else + return -1; +} + +pdc_bool +pdc_is_lastopt_percent(pdc_resopt *resopt, int ind) +{ + int i = resopt[0].lastind; + + if (i > -1 && resopt[i].num < 32) + return (resopt[i].pcmask & (1L << ind)) ? pdc_true : pdc_false; + else + return pdc_false; +} + +pdc_bool +pdc_is_lastopt_utf8(pdc_resopt *resopt) +{ + int i = resopt[0].lastind; + + if (i > -1) + return resopt[0].isutf8 || + ((resopt[i].flags & PDC_OPT_ISUTF8) ? pdc_true : pdc_false); + else + return pdc_false; +} + +int +pdc_get_opt_utf8strings(pdc_core *pdc, const char *keyword, pdc_resopt *resopt, + int flags, char ***strings) +{ + int ns = pdc_get_optvalues(keyword, resopt, NULL, strings); + + if (ns) + { + if (pdc_is_lastopt_utf8(resopt)) + { + int i = resopt[0].lastind; + pdc_resopt *ropt = &resopt[i]; + char **s = (char **) ropt->val; + int j; + + for (j = 0; j < ropt->num; j++) + { + char *sb = pdc_strdup_withbom(pdc, s[j]); + + if (s[j] != NULL) + pdc_free(pdc, s[j]); + s[j] = sb; + } + } + + pdc_save_lastopt(resopt, flags); + } + + return ns; +} + +void +pdc_cleanup_optionlist(pdc_core *pdc, pdc_resopt *resopt) +{ + if (resopt != NULL) + pdc_free_tmp(pdc, resopt); +} + +const char * +pdc_get_handletype(pdc_opttype type) +{ + return pdc_get_keyword(type, pdc_handletypes); +} + diff --git a/src/pdflib/pdcore/pc_optparse.h b/src/pdflib/pdcore/pc_optparse.h new file mode 100644 index 0000000..ac9e6f2 --- /dev/null +++ b/src/pdflib/pdcore/pc_optparse.h @@ -0,0 +1,292 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_optparse.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Definitions for option parser routines + * + */ + +#ifndef PC_OPTPARSE_H +#define PC_OPTPARSE_H + +/* + * Optlist + * ------- + * An optlist is a string containing pairs of the form + * "optionname optionvalue(s)". The separator characters + * are "\f\n\r\t\v =". + * + * There are options of different types (see pdc_opttype): + * + * Boolean (pdc_booleanlist) + * Strings (pdc_stringlist) + * Keywords (pdc_keywordlist) + * Integers (pdc_integerlist) + * Floats (pdc_floatlist) + * Doubles (pdc_doublelist) + * Scalars (pdc_scalarlist) + * Unichars (pdc_unicharlist) + * Polylinelist (pdc_polylinelist) + * Handles (pdc_colorhandle ...) + * + * An option can have one or more values. Boolean options can be + * provided without any value. If an option has more than one value, + * then these values have to be set in braces. Examples: + * + * dasharray {11 22 33} + * + * Strings with white spaces have to be set in braces too. + * Examples: + * + * fullname {Ludwig Wittgenstein} + * composers {{Gustav Mahler}} + * comment {} + * + * The allowed option names and the limitations of their values + * must be defined in an array of enumeration type pdc_defopt + * (see below). Such an option definition specifies (in brackets + * the member name in the pdc_defopt struct) + * + * - the name of the option (name) + * - the type of the option (type) + * - value restrictions by bit flags (flags) + * - the minimal and maximal permitted number of values + * (minnum, maxnum) + * - the minimal and maximal permitted value, or string + * length resp. (minval, maxval) + * - the permitted keywords in a keyword list (is required) or + * the permitted integer numbers in a integer list (is optional), + * resp. (keylist) + * + * Remarks: + * + * - minnum = maxnum = 1: The program expects a single value, + * otherwise an array. If an array consists of only one value + * the braces can be omitted - but not in the case of strings + * with white spaces (see example above). + * - Boolean options have the values "true" or "false". A shorter + * equivalent notation is "name" or "noname". for "name true" + * or "name false", resp. + * - White spaces in strings can be forbidden by the flag + * PDC_OPT_NOSPACES. + * - It's only possible to specify a single number interval (minval, + * maxval) which must contain the number. The flag PDC_OPT_NOZERO + * can forbid zero additionally. + * - Keywords will always be converted to integer numbers (keycodes) + * according to the specified pdc_keyconn array. + * - It is possible to specify keywords for integers, floats and + * doubles additionally by an optional keylist entry. For integers + * it is possible to specify the allowed integer values by an optional + * keylist and by the flag PDC_OPT_INTLIST. + * - If more than one keyword is permitted, then the flag + * PDC_OPT_BUILDOR decides, whether a bit pattern must be + * built by or-ing the single keycodes or not. + * + * Program run: + * + * An optlist is parsed by the function "pdc_parse_optionlist". + * After successfully parsing this function returns a pointer to the + * allocated "pdc_resopt" structures containing the option values. + * These structures must be freed by the function "pdc_cleanup_optionlist". + * + * Values can be fetched by the function "pdc_get_optvalues". This can + * be achieved by specifying a variable pointer (lvalues) or by a pointer + * to a pointer (mvalues). In the first case the variable must be large + * enough to hold the values. In the second case the pointer is the pointer + * to the allocated array with the option values. This pointer will be + * freed in "pdc_cleanup_optionlist". To avoid this you can call the function + * "pdc_save_lastopt" after the call of "pdc_get_optvalues". Function + * "pdc_save_lastopt" returns the pointer which is protected now against + * freeing in "pdc_cleanup_optionlist". In the special case of type = + * pdc_stringlist, you can protect only the first element in the string + * list by calling "pdc_save_lastopt" with the flag PDC_OPT_SAVE1ELEM. + * Flag = PDC_OPT_SAVEALL defines the general case. The caller has the + * responsibility to free the protected pointers after use. + * + * pdc_stringlist: + * maxnum = 1: lvalues: char s[maxval+1] (defined char array) + * maxnum > 1: lvalues: char *s[maxnum] (defined char pointer array) + * mvalues: char **s (pointer to a char pointer array) + * + */ + +typedef struct pdc_keyconn_s pdc_keyconn; +typedef struct pdc_clientdata_s pdc_clientdata; +typedef struct pdc_defopt_s pdc_defopt; +typedef struct pdc_resopt_s pdc_resopt; + +/* types of option values */ +typedef enum +{ + pdc_booleanlist = 0, + pdc_stringlist, + pdc_keywordlist, + pdc_integerlist, + pdc_floatlist, + pdc_doublelist, + pdc_scalarlist, + pdc_unicharlist, + pdc_polylinelist, + + /* correspondig member of pdc_clientdata_s must be specified */ + pdc_3ddatahandle, + pdc_3dviewhandle, + pdc_actionhandle, + pdc_bookmarkhandle, + pdc_colorhandle, + pdc_documenthandle, + pdc_fonthandle, + pdc_gstatehandle, + pdc_iccprofilehandle, + pdc_imagehandle, + pdc_layerhandle, + pdc_pagehandle, + pdc_patternhandle, + pdc_shadinghandle, + pdc_tablehandle, + pdc_templatehandle, + pdc_textflowhandle, + pdc_stringhandle +} +pdc_opttype; + +/* keyword - keycode */ +struct pdc_keyconn_s +{ + char *word; + int code; +}; + +/* client data */ +struct pdc_clientdata_s +{ + int compatibility; + int max3ddata; + int max3dview; + int maxaction; + int maxbookmark; + int maxcolor; + int maxdocument; + int maxfont; + int maxgstate; + int maxiccprofile; + int maximage; + int maxlayer; + int maxpage; + int maxpattern; + int maxshading; + int maxtable; + int maxtemplate; + int maxtextflow; + int maxstring; +}; + +/* definition of an option */ +struct pdc_defopt_s +{ + const char *name; /* name of option keyword */ + pdc_opttype type; /* type of option */ + int flags; /* flags (see below) */ + int minnum; /* permitted minimal number of values */ + int maxnum; /* permitted maximal number of values */ + double minval; /* minimal permitted value / length of string */ + double maxval; /* maximal permitted value / length of string */ + const pdc_keyconn *keylist; /* list of permitted keywords - keycodes */ +}; + +#define PDC_OPT_TERMINATE \ + {NULL, pdc_booleanlist, 0L, 0, 0, 0.0, 0.0, NULL} + +#define PDC_OPT_NONE (0) /* no flag specified */ +#define PDC_OPT_NOZERO (1L<<0) /* zero value not allowed */ +#define PDC_OPT_NOSPACES (1L<<1) /* white spaces in strings not allowed */ +#define PDC_OPT_REQUIRED (1L<<2) /* option is required */ +#define PDC_OPT_BUILDOR (1L<<3) /* build an OR bit pattern by keycodes */ +#define PDC_OPT_INTLIST (1L<<4) /* keylist is list of allowed integers */ +#define PDC_OPT_IGNOREIF1 (1L<<5) /* option is ignored if previous option is + * specified */ +#define PDC_OPT_IGNOREIF2 (1L<<6) /* option is ignored if either of + * previous two options is specified */ +#define PDC_OPT_UNSUPP (1L<<8) /* option is not supported in this + * configuration */ +#define PDC_OPT_REQUIRIF1 (1L<<9) /* option is required if previous option is + * specified */ +#define PDC_OPT_REQUIRIF2 (1L<<10) /* option is required if either of + * previous two options is specified */ +#define PDC_OPT_EVENNUM (1L<<11) /* array has even number of elements */ +#define PDC_OPT_ODDNUM (1L<<12) /* array has odd number of elements */ + +/* member "compatibility" of pdc_clientdata_s must be specified (1L<<13) ... */ +#define PDC_OPT_PDC_1_3 (1L<<PDC_1_3) /* compatibility PDC_1_3 */ +#define PDC_OPT_PDC_1_4 (1L<<PDC_1_4) /* compatibility PDC_1_4 */ +#define PDC_OPT_PDC_1_5 (1L<<PDC_1_5) /* compatibility PDC_1_5 */ +#define PDC_OPT_PDC_1_6 (1L<<PDC_1_6) /* compatibility PDC_1_6 */ +#define PDC_OPT_PDC_1_7 (1L<<PDC_1_7) /* compatibility PDC_1_7 */ + +#define PDC_OPT_CASESENS (1L<<20) /* case-sensitive keywords */ +#define PDC_OPT_PERCENT (1L<<21) /* number maybe with percent sign (123%) */ +#define PDC_OPT_DUPORIGVAL (1L<<22) /* duplicate original value */ +#define PDC_OPT_SUBOPTLIST (1L<<23) /* string list is a suboptlist */ +#define PDC_OPT_CONVUTF8 (1L<<24) /* string has to be converted to UTF-8 */ +#define PDC_OPT_ISBOX (1L<<25) /* polyline is a box (four coordinates) */ +#define PDC_OPT_PERCRANGE (1L<<26) /* number only in the range 0% - 100% */ + +#define PDC_OPT_KEYLIST1 (1L<<27) /* use key list only for first element */ +#define PDC_OPT_CLOSEPOLY (1L<<28) /* close polyline, minimal vertices = 3 */ + +/* flags for single result */ +#define PDC_OPT_SAVEALL (1L<<0) /* save all pointers */ +#define PDC_OPT_SAVE1ELEM (1L<<1) /* save only first string list element */ +#define PDC_OPT_SAVEORIG (1L<<2) /* save original value string */ + +/* flag for UTF-8 value */ +#define PDC_OPT_ISUTF8 (1L<<9) /* string[list] is UTF-8 */ + +/* key word not found */ +#define PDC_KEY_NOTFOUND -1234567890 + +/* key word abbreviation not unique */ +#define PDC_KEY_NOTUNIQUE -1234567891 + +/* separator signs in option lists */ +#define PDC_OPT_LISTSEPS "\f\n\r\t\v =" + +/* pc_optparse.c */ +int pdc_get_keycode(const char *keyword, const pdc_keyconn *keyconn); +int pdc_get_keycode_ci(const char *keyword, const pdc_keyconn *keyconn); +int pdc_get_keycode_unique(const char *keyword, const pdc_keyconn *keyconn); +int pdc_get_keymask_ci(pdc_core *pdc, const char *option, + const char *keywordlist, const pdc_keyconn *keyconn); +int pdc_get_keycode_num(pdc_core *pdc, const char *option, + const char *i_keyword, int flags, const pdc_keyconn *keyconn, + int *o_num); +const char *pdc_get_keyword(int keycode, const pdc_keyconn *keyconn); +const char *pdc_get_int_keyword(const char *keyword, + const pdc_keyconn *keyconn); +pdc_resopt *pdc_parse_optionlist(pdc_core *pdc, const char *optlist, + const pdc_defopt *defopt, const pdc_clientdata *clientdata, + pdc_bool verbose); +int pdc_get_optvalues(const char *keyword, pdc_resopt *resopt, + void *lvalues, char ***mvalues); +void *pdc_save_lastopt(pdc_resopt *resopt, int flags); +int pdc_get_lastopt_index(pdc_resopt *resopt); +pdc_bool pdc_is_lastopt_percent(pdc_resopt *resopt, int ind); +pdc_bool pdc_is_lastopt_utf8(pdc_resopt *resopt); +int pdc_get_opt_utf8strings(pdc_core *pdc, const char *keyword, + pdc_resopt *resopt, int flags, char ***strings); +void pdc_cleanup_optionlist(pdc_core *pdc, pdc_resopt *resopt); +void pdc_cleanup_optstringlist(pdc_core *pdc, char **stringlist, int ns); +const char *pdc_get_handletype(pdc_opttype type); + +#endif /* PC_OPTPARSE_H */ + diff --git a/src/pdflib/pdcore/pc_output.c b/src/pdflib/pdcore/pc_output.c new file mode 100644 index 0000000..b1607c5 --- /dev/null +++ b/src/pdflib/pdcore/pc_output.c @@ -0,0 +1,1126 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_output.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib output routines + * + */ + +#include "pc_util.h" +#include "pc_file.h" +#include "pc_md5.h" + +#if (defined(WIN32) || defined(OS2)) && !defined(WINCE) +#include <fcntl.h> +#include <io.h> +#endif + +/* for time_t, timer(). +*/ +#ifndef WINCE +#include <time.h> +#else +#include <winbase.h> +#endif + +#if defined(MAC) || defined (MACOSX) + +/* + * Setting the file type requires either Carbon or InterfaceLib/Classic. + * If we have neither (i.e. a Mach-O build without Carbon) we suppress + * the code for setting the file type and creator. + */ + +#if !defined(MACOSX) || defined(PDF_TARGET_API_MAC_CARBON) +#define PDF_FILETYPE_SUPPORTED +#endif + +#ifdef PDF_FILETYPE_SUPPORTED +#include <Files.h> +#endif + +#endif /* defined(MAC) || defined (MACOSX) */ + +#ifdef HAVE_LIBZ +#include "zlib.h" +#endif + +#ifdef HAVE_LIBZ +#define PDF_DEFAULT_COMPRESSION 6 /* default zlib level */ +#else +#define PDF_DEFAULT_COMPRESSION 0 /* no compression */ +#endif + +#define STREAM_BUFSIZE 65536 /* initial output buffer size */ +#define STREAM_MAXINCR 1048576 /* max. output buffer increment */ +#define ID_CHUNKSIZE 2048 /* object ids */ + +struct pdc_output_s { + pdc_core *pdc; /* core context */ + + pdc_bool open; /* file open */ + pdc_byte *basepos; /* start of this chunk */ + pdc_byte *curpos; /* next write position */ + pdc_byte *maxpos; /* maximum position of chunk */ + int buf_incr; /* current buffer increment */ + pdc_off_t base_offset; /* base offset of this chunk */ + pdc_bool compressing; /* in compression state */ + pdc_flush_state flush; +#ifdef HAVE_LIBZ + z_stream z; /* zlib compression stream */ +#endif + + FILE *fp; /* output file stream */ +#if defined(MVS) || defined(MVS_TEST) + int blocksize; /* file record size */ +#endif + + /* client-supplied data sink procedure */ + size_t (*writeproc)(pdc_output *out, void *data, size_t size); + + int compresslevel; /* zlib compression level */ + pdc_bool compr_changed; /* compress level has been changed */ + pdc_off_t length; /* length of stream */ + + pdc_off_t *file_offset; /* the objects' file offsets */ + int file_offset_capacity; + pdc_id lastobj; /* highest object id */ + + pdc_off_t start_pos; /* stream start position */ + pdc_off_t xref_pos; /* xref table start position */ + + MD5_CTX md5; /* MD5 digest context for file ID */ + unsigned char id[2][MD5_DIGEST_LENGTH]; + void *opaque; /* this will be used to store PDF *p */ +}; + +/* --------------------- PDFlib stream handling ----------------------- */ + +void * +pdc_get_opaque(pdc_output *out) +{ + return out->opaque; +} + +#ifdef HAVE_LIBZ +/* wrapper for pdc_malloc for use in zlib */ +static voidpf +pdc_zlib_alloc(voidpf pdc, uInt items, uInt size) +{ + return (voidpf) pdc_malloc((pdc_core *) pdc, items * size, "zlib"); +} + +#endif /* HAVE_LIBZ */ + +pdc_bool +pdc_stream_not_empty(pdc_output *out) +{ + return (!out->writeproc && out->curpos != out->basepos); +} + +char * +pdc_get_stream_contents(pdc_output *out, pdc_off_t *size) +{ + pdc_core *pdc = out->pdc; + + if (out->writeproc) + pdc_error(pdc, PDC_E_IO_NOBUFFER, 0, 0, 0, 0); + + if (size) + *size = (pdc_off_t) (out->curpos - out->basepos); + + out->base_offset += (out->curpos - out->basepos); + out->curpos = out->basepos; + + return (char *) out->basepos; +} + +static size_t +pdc_writeproc_file(pdc_output *out, void *data, size_t size) +{ + return pdc__fwrite(data, 1, size, out->fp); +} + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +static pdc_bool +pdc_init_stream( + pdc_core *pdc, + pdc_output *out, + const char *filename, + FILE *fp, + size_t (*writeproc)(pdc_output *out, void *data, size_t size)) +{ + static const char fn[] = "pdc_init_stream"; + +#if defined(MAC) || defined(MACOSX) +#if !defined(TARGET_API_MAC_CARBON) || defined(__MWERKS__) + FCBPBRec fcbInfo; + Str32 name; +#endif /* TARGET_API_MAC_CARBON */ + FInfo fInfo; + FSSpec fSpec; +#endif /* defined(MAC) || defined(MACOSX) */ + + /* + * This may be left over from the previous run. We deliberately + * don't reuse the previous buffer in order to avoid potentially + * unwanted growth of the allocated buffer due to a single large + * document in a longer series of documents. + */ + if (out->basepos) + pdc_free(pdc, (void *) out->basepos); + + out->basepos = (pdc_byte *) pdc_malloc(pdc, STREAM_BUFSIZE, fn); + out->curpos = out->basepos; + out->maxpos = out->basepos + STREAM_BUFSIZE; + out->buf_incr = STREAM_BUFSIZE; + + out->base_offset = 0; + out->compressing = pdc_false; + +#ifdef HAVE_LIBZ + /* zlib sometimes reads uninitialized memory where it shouldn't... */ + memset(&out->z, 0, sizeof out->z); + + out->z.zalloc = (alloc_func) pdc_zlib_alloc; + out->z.zfree = (free_func) pdc_free; + out->z.opaque = (voidpf) pdc; + + if (deflateInit(&out->z, pdc_get_compresslevel(out)) != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "deflateInit", 0, 0, 0); + + out->compr_changed = pdc_false; +#endif + + /* Defaults */ + out->fp = (FILE *) NULL; + out->writeproc = pdc_writeproc_file; + + if (fp) + { + out->fp = fp; + } + else if (writeproc) + { + out->writeproc = writeproc; /* PDF_open_mem */ + } + else if (filename == NULL || *filename == '\0') + { + /* PDF_open_file with in-core output */ + out->writeproc = NULL; + } + else + { + /* PDF_open_file with file output */ +#if !((defined(MAC) || defined (MACOSX)) && defined(__MWERKS__)) + if (filename && !strcmp(filename, "-")) + { + out->fp = stdout; +#if !defined(__MWERKS__) && (defined(WIN32) || defined(OS2)) +#if defined WINCE + _setmode(fileno(stdout), _O_BINARY); +#else + setmode(fileno(stdout), O_BINARY); +#endif /* !WINCE */ +#endif + } + else + { +#endif /* !MAC */ + +#if defined(MVS) || defined(MVS_TEST) + out->fp = pdc_fopen_logg(out->pdc, filename, + (out->blocksize <= 1) ? WRITEMODE_V : WRITEMODE); +#else + out->fp = pdc_fopen_logg(out->pdc, filename, WRITEMODE); +#endif + + if (out->fp == NULL) + return pdc_false; + +#ifdef PDF_FILETYPE_SUPPORTED +#if defined(MAC) || defined(MACOSX) + if (!pdc->ptfrun) + { + /* set the proper type and creator for the output file */ +#if TARGET_API_MAC_CARBON && !defined(__MWERKS__) + + if (FSPathMakeFSSpec((const UInt8 *) filename, &fSpec) == noErr) + { + FSpGetFInfo(&fSpec, &fInfo); + + fInfo.fdType = 'PDF '; + fInfo.fdCreator = 'CARO'; + FSpSetFInfo(&fSpec, &fInfo); + } + +#else + + memset(&fcbInfo, 0, sizeof(FCBPBRec)); + fcbInfo.ioRefNum = (short) out->fp->handle; + fcbInfo.ioNamePtr = name; + + if (!PBGetFCBInfoSync(&fcbInfo) && + FSMakeFSSpec(fcbInfo.ioFCBVRefNum, fcbInfo.ioFCBParID, + name, &fSpec) == noErr) + { + FSpGetFInfo(&fSpec, &fInfo); + fInfo.fdType = 'PDF '; + fInfo.fdCreator = 'CARO'; + FSpSetFInfo(&fSpec, &fInfo); + } +#endif /* !defined(TARGET_API_MAC_CARBON) || defined(__MWERKS__) */ + } +#endif /* defined(MAC) || defined(MACOSX) */ +#endif /* PDF_FILETYPE_SUPPORTED */ + +#if !((defined(MAC) || defined (MACOSX)) && defined(__MWERKS__)) + } +#endif /* !MAC */ + } + + return pdc_true; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + +/* close the output file, if opened with PDF_open_file(); + * close the output stream if opened + */ + +static void +pdc_close_stream(pdc_output *out) +{ + /* this time we MUST flush the stream - + ** even if (flush == pdc_flush_none) + */ + out->flush = pdc_flush_heavy; + pdc_flush_stream(out); + +#ifdef HAVE_LIBZ + /* + * This is delicate: we must ignore the return value because of the + * following reasoning: We are called in two situations: + * - end of document + * - exception + * In the first case compression is inactive, so deflateEnd() will + * fail only in the second case. However, when an exception occurs + * the document is definitely unusable, so we avoid recursive exceptions + * or an (unallowed) exception in PDF_delete(). + */ + + (void) deflateEnd(&out->z); +#endif + + /* close the output file if writing to file, but do not close the + * in-core output stream since the caller will have to + * fetch the buffer after PDF_close(). + */ + if (out->fp) + { + pdc_fclose_logg(out->pdc, out->fp); + + /* mark fp as dead in case the error handler jumps in later */ + out->fp = NULL; + } +} + +static void +pdc_check_stream(pdc_output *out, size_t len) +{ + size_t newsize; + size_t cur; + pdc_core *pdc = out->pdc; + + if (out->curpos + len <= out->maxpos) + return; + + pdc_flush_stream(out); + + if (out->curpos + len <= out->maxpos) + return; + + do + { + out->maxpos += out->buf_incr; + + if (out->buf_incr < STREAM_MAXINCR) + out->buf_incr *= 2; + } while (out->curpos + len > out->maxpos); + + cur = (size_t) (out->curpos - out->basepos); + newsize = (size_t) (out->maxpos - out->basepos); + + out->basepos = (pdc_byte *) + pdc_realloc(pdc, (void *) out->basepos, newsize, "pdc_check_stream"); + out->maxpos = out->basepos + newsize; + out->curpos = out->basepos + cur; +} + +void +pdc_flush_stream(pdc_output *out) +{ + size_t size; + pdc_core *pdc = out->pdc; + + if (!out->writeproc || out->flush == pdc_flush_none) + return; + + size = (size_t) (out->curpos - out->basepos); + + if (size == 0) + return; + + if (out->writeproc(out, (void *) out->basepos, size) != size) { + pdc_free(pdc, out->basepos); + out->basepos = NULL; + out->writeproc = NULL; + pdc_error(pdc, PDC_E_IO_NOWRITE, 0, 0, 0, 0); + } + + out->base_offset += (out->curpos - out->basepos); + out->curpos = out->basepos; +} + +pdc_off_t +pdc_tell_out(pdc_output *out) +{ + return (out->base_offset + (out->curpos - out->basepos)); +} + +/* --------------------- compression handling ----------------------- */ + +static void +pdc_begin_compress(pdc_output *out) +{ + pdc_core *pdc = out->pdc; + + if (!pdc_get_compresslevel(out)) { + out->compressing = pdc_false; + return; + } + +#ifdef HAVE_LIBZ + if (out->compr_changed) + { + if (deflateEnd(&out->z) != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "deflateEnd", 0, 0, 0); + + if (deflateInit(&out->z, pdc_get_compresslevel(out)) != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "deflateInit", 0, 0, 0); + + out->compr_changed = pdc_false; + } + else + { + if (deflateReset(&out->z) != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "deflateReset", 0, 0, 0); + } + + out->z.avail_in = 0; +#endif /* HAVE_LIBZ */ + + out->compressing = pdc_true; +} + + +static void +pdc_end_compress(pdc_output *out) +{ + int status; + pdc_core *pdc = out->pdc; + + /* this may happen during cleanup triggered by an exception handler */ + if (!out->compressing) + return; + + if (!pdc_get_compresslevel(out)) { + out->compressing = pdc_false; + return; + } + + +#ifdef HAVE_LIBZ + /* Finish the stream */ + do { + pdc_check_stream(out, 128); + out->z.next_out = (Bytef *) out->curpos; + out->z.avail_out = (uInt) (out->maxpos - out->curpos); + + status = deflate(&(out->z), Z_FINISH); + out->curpos = out->z.next_out; + + if (status != Z_STREAM_END && status != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "Z_FINISH", 0, 0, 0); + + } while (status != Z_STREAM_END); + + out->compressing = pdc_false; +#endif /* HAVE_LIBZ */ +} + +/* ---------------------- Low-level output function ---------------------- */ +/* + * Write binary data to the output without any modification, + * and apply compression if we are currently in compression mode. + */ + + +void +pdc_write(pdc_output *out, const void *data, size_t size) +{ + int estimate = 0; + pdc_core *pdc = out->pdc; + +#ifdef HAVE_LIBZ + if (out->compressing) { + out->z.avail_in = (uInt) size; + out->z.next_in = (Bytef *) data; + out->z.avail_out = 0; + + while (out->z.avail_in > 0) { + if (out->z.avail_out == 0) { + /* estimate output buffer size */ + estimate = (int) (out->z.avail_in/4 + 16); + pdc_check_stream(out, (size_t) estimate); + out->z.next_out = (Bytef *) out->curpos; + out->z.avail_out = (uInt) (out->maxpos - out->curpos); + } + + if (deflate(&(out->z), Z_NO_FLUSH) != Z_OK) + pdc_error(pdc, PDC_E_IO_COMPRESS, "Z_NO_FLUSH", 0, 0, 0); + + out->curpos = out->z.next_out; + } + } else { +#endif /* HAVE_LIBZ */ + + pdc_check_stream(out, size); + memcpy(out->curpos, data, size); + out->curpos += size; + +#ifdef HAVE_LIBZ + } +#endif /* HAVE_LIBZ */ +} + + +/* --------------------------- Setup --------------------------- */ + +pdc_output * +pdc_boot_output(pdc_core *pdc) +{ + static const char *fn = "pdc_boot_output"; + pdc_output *out; + + out = (pdc_output*)pdc_malloc(pdc, sizeof(pdc_output), fn); + out->pdc = pdc; + + out->file_offset = NULL; + + /* curpos must be initialized here so that the check for empty + * buffer in PDF_delete() also works in the degenerate case of + * no output produced. + */ + out->basepos = out->curpos = NULL; + + out->open = pdc_false; + + return out; +} + +void +pdc_init_outctl(pdc_outctl *oc) +{ + oc->filename = 0; + oc->fp = 0; + oc->writeproc = 0; + oc->flush = pdc_flush_page; +#if defined(MVS) || defined(MVS_TEST) + oc->blocksize = 0; +#endif +} /* pdc_init_outctl */ + +/* + * Initialize the PDF output. + * Note that the caller is responsible for supplying sensible arguments. + */ +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +pdc_bool +pdc_init_output( + void *opaque, + pdc_output *out, + int compatibility, + pdc_outctl *oc) +{ + static const char *fn = "pdc_init_output"; + pdc_core *pdc = out->pdc; + int i; + + pdc_cleanup_output(out, pdc_false); + + out->opaque = opaque; + out->lastobj = 0; +#if defined(MVS) || defined(MVS_TEST) + out->blocksize = oc->blocksize; +#endif + + if (out->file_offset == NULL) { + out->file_offset_capacity = ID_CHUNKSIZE; + + out->file_offset = (pdc_off_t *) pdc_malloc(pdc, + sizeof(pdc_off_t) * out->file_offset_capacity, fn); + } + + for (i = 1; i < out->file_offset_capacity; ++i) + out->file_offset[i] = PDC_BAD_ID; + + out->compresslevel = PDF_DEFAULT_COMPRESSION; + out->compr_changed = pdc_false; + out->flush = oc->flush; + + memcpy(out->id[0], out->id[1], MD5_DIGEST_LENGTH); + + + if (!pdc_init_stream(pdc, out, oc->filename, oc->fp, oc->writeproc)) + return pdc_false; + { + /* Write the document header */ + pdc_printf(out, "%%PDF-%s\n", pdc_get_pdfversion(pdc, compatibility)); + +#define PDC_MAGIC_BINARY "\045\344\343\317\322\012" + pdc_write(out, PDC_MAGIC_BINARY, sizeof(PDC_MAGIC_BINARY) - 1); + } + + out->open = pdc_true; + + return pdc_true; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + +void +pdc_close_output(pdc_output *out) +{ + if (out->open) + { + out->open = pdc_false; + + pdc_close_stream(out); + + if (out->file_offset) + { + pdc_free(out->pdc, out->file_offset); + out->file_offset = 0; + } + + } +} + +void +pdc_cleanup_output(pdc_output *out, pdc_bool keep_buf) +{ + pdc_core *pdc = out->pdc; + + if (out->file_offset) + { + pdc_free(pdc, out->file_offset); + out->file_offset = NULL; + } + + + if (!keep_buf && out->basepos) + { + pdc_free(pdc, (void *) out->basepos); + out->basepos = NULL; + out->curpos = NULL; + } + +} + +/* --------------------------- Digest --------------------------- */ + +void +pdc_init_digest(pdc_output *out) +{ + MD5_Init(&out->md5); +} + +void +pdc_update_digest(pdc_output *out, unsigned char *input, + unsigned int len) +{ + MD5_Update(&out->md5, input, len); +} + +void +pdc_finish_digest(pdc_output *out, pdc_bool settime) +{ + if (settime) + { + time_t timer; + + time(&timer); + MD5_Update(&out->md5, (unsigned char *) &timer, sizeof timer); + } + + MD5_Final(out->id[1], &out->md5); +} + +unsigned char * +pdc_get_digest(pdc_output *out) +{ + return out->id[1]; +} + +/* --------------------------- Objects and ids --------------------------- */ + +pdc_id +pdc_begin_obj(pdc_output *out, pdc_id obj_id) +{ + if (obj_id == PDC_NEW_ID) + obj_id = pdc_alloc_id(out); + + out->file_offset[obj_id] = pdc_tell_out(out); + pdc_printf(out, "%ld 0 obj\n", obj_id); + + return obj_id; +} + +pdc_id +pdc_alloc_id(pdc_output *out) +{ + + out->lastobj++; + + if (out->lastobj > PDF_MAXINDOBJS) + pdc_error(out->pdc, PDC_E_INT_TOOMUCH_INDOBJS, + pdc_errprintf(out->pdc, "%d", PDF_MAXINDOBJS), 0, 0, 0); + + if (out->lastobj >= out->file_offset_capacity) { + out->file_offset_capacity *= 2; + out->file_offset = (pdc_off_t *) + pdc_realloc(out->pdc, out->file_offset, + sizeof(pdc_off_t) * out->file_offset_capacity, "pdc_alloc_id"); + } + + /* only needed for verifying obj table in PDF_close() */ + out->file_offset[out->lastobj] = PDC_BAD_ID; + + return out->lastobj; +} + + +/* --------------------------- Strings --------------------------- */ + +void +pdc_put_pdfstring(pdc_output *out, const char *text, int len) +{ + const unsigned char *goal, *s; + + if (!len) + len = (int) strlen(text); + + if (out->pdc->compatibility <= PDC_1_5 && len > PDF_MAXSTRINGSIZE) + pdc_error(out->pdc, PDC_E_INT_TOOLONG_TEXTSTR, + pdc_errprintf(out->pdc, "%d", PDF_MAXSTRINGSIZE), 0, 0, 0); + + + pdc_putc(out, PDF_PARENLEFT); + + goal = (const unsigned char *) text + len; + + for (s = (const unsigned char *) text; s < goal; s++) + { + switch (*s) + { + case PDF_RETURN: + pdc_putc(out, PDF_BACKSLASH); + pdc_putc(out, PDF_r); + break; + + case PDF_NEWLINE: + pdc_putc(out, PDF_BACKSLASH); + pdc_putc(out, PDF_n); + break; + + default: + if (*s == PDF_PARENLEFT || *s == PDF_PARENRIGHT || + *s == PDF_BACKSLASH) + pdc_putc(out, PDF_BACKSLASH); + pdc_putc(out, (char) *s); + } + } + + pdc_putc(out, PDF_PARENRIGHT); +} + +/* normalized file name according PDF specification */ +void +pdc_put_pdffilename(pdc_output *out, const char *text, int len) +{ + static const char *fn = "pdc_put_pdffilename"; + char *ttext; + +#if defined(WIN32) || defined(MAC) + int i, j = 0, k = 0; +#endif + + if (!len) + len = (int) strlen(text); + + ttext = (char *) pdc_malloc(out->pdc, (size_t) (len + 4), fn); + strcpy(ttext, text); + +#if defined(WIN32) + + /* absolute path name */ + if (strchr(ttext, PDF_COLON) != NULL || text[0] == PDF_BACKSLASH) + { + ttext[j] = PDF_SLASH; + j++; + } + for (i = k; i < len; i++) + { + if (text[i] == PDF_BACKSLASH) + ttext[j] = PDF_SLASH; + else if (text[i] == PDF_COLON) + continue; + else + ttext[j] = text[i]; + j++; + } + len = j; + +#elif defined(MAC) + + /* absolute path name */ + if (text[0] != PDF_COLON) + { + ttext[j] = PDF_SLASH; + j++; + } + else + { + k = 1; + } + for (i = k; i < len; i++) + { + if (text[i] == PDF_COLON) + ttext[j] = PDF_SLASH; + else + ttext[j] = text[i]; + j++; + } + len = j; + +#endif + + pdc_put_pdfstring(out, ttext, len); + + pdc_free(out->pdc, ttext); +} + +/* --------------------------- Streams --------------------------- */ + +void +pdc_begin_pdfstream(pdc_output *out) +{ + pdc_puts(out, "stream\n"); + + out->start_pos = pdc_tell_out(out); + + if (out->compresslevel) + pdc_begin_compress(out); +} + +void +pdc_end_pdfstream(pdc_output *out) +{ + if (out->compresslevel) + pdc_end_compress(out); + + out->length = pdc_tell_out(out) - out->start_pos; + + /* some PDF consumers seem to need the additional "\n" before "endstream", + ** the PDF reference allows it, and Acrobat's "repair" feature relies on it. + */ + pdc_puts(out, "\nendstream\n"); +} + +pdc_off_t +pdc_get_pdfstreamlength(pdc_output *out) +{ + return out->length; +} + +void +pdc_put_pdfstreamlength(pdc_output *out, pdc_id length_id) +{ + + pdc_begin_obj(out, length_id); /* Length object */ + pdc_printf(out, "%lld\n", out->length); + pdc_end_obj(out); +} + +void +pdc_set_compresslevel(pdc_output *out, int compresslevel) +{ + out->compresslevel = compresslevel; + out->compr_changed = pdc_true; +} + +int +pdc_get_compresslevel(pdc_output *out) +{ + return out->compresslevel; +} + + +/* --------------------------- Names --------------------------- */ + +/* characters illegal in PDF names: "()<>[]{}/%#" */ +#define PDF_ILL_IN_NAMES "\050\051\074\076\133\135\173\175\057\045\043" + +#define PDF_NEEDS_QUOTE(c) \ + ((c) < 33 || (c) > 126 || strchr(PDF_ILL_IN_NAMES, (c)) != (char *) 0) + +void +pdc_put_pdfname(pdc_output *out, const char *text, size_t len) +{ + const unsigned char *goal, *s; + static const char BinToHex[] = PDF_STRING_0123456789ABCDEF; + + if (!len) + len = strlen(text); + + goal = (const unsigned char *) text + len; + + pdc_putc(out, PDF_SLASH); + + for (s = (const unsigned char *) text; s < goal; s++) { + if (PDF_NEEDS_QUOTE(*s)) { + pdc_putc(out, PDF_HASH); + pdc_putc(out, BinToHex[*s >> 4]); /* first nibble */ + pdc_putc(out, BinToHex[*s & 0x0F]); /* second nibble */ + } else + pdc_putc(out, (char) *s); + } +} + +/* --------------------------- Document sections --------------------------- */ + +void +pdc_mark_free(pdc_output *out, pdc_id obj_id) +{ + out->file_offset[obj_id] = PDC_FREE_ID; +} + + +void +pdc_write_xref(pdc_output *out) +{ + pdc_id start = 1; + pdc_id i; + pdc_id free_id; + pdc_core * pdc = out->pdc; + + /* Don't write any object after this check! */ + + for (i = start; i <= out->lastobj; i++) { + if (out->file_offset[i] == PDC_BAD_ID) { + pdc_warning(pdc, PDC_E_INT_UNUSEDOBJ, + pdc_errprintf(pdc, "%ld", i), 0, 0, 0); + /* write a dummy object */ + pdc_begin_obj(out, i); + pdc_printf(out, "null %% unused object\n"); + pdc_end_obj(out); + } + } + + + out->xref_pos = pdc_tell_out(out); + pdc_puts(out, "xref\n"); + pdc_printf(out, "0 %ld\n", out->lastobj + 1); + + /* find the last free entry in the xref table. + */ + out->file_offset[0] = PDC_FREE_ID; + for (free_id = out->lastobj; + out->file_offset[free_id] != PDC_FREE_ID; + --free_id) + ; + + pdc_printf(out, "%010ld 65535 f \n", free_id); + free_id = 0; + +#define PDF_FLUSH_AFTER_MANY_OBJS 3000 /* ca. 60 KB */ + for (i = 1; i <= out->lastobj; i++) { + /* Avoid spike in memory usage at the end of the document */ + if (i % PDF_FLUSH_AFTER_MANY_OBJS == 0) + pdc_flush_stream(out); + + if (out->file_offset[i] == PDC_FREE_ID) + { + pdc_printf(out, "%010ld 00001 f \n", free_id); + free_id = i; + } + else + { + pdc_printf(out, "%010lld 00000 n \n", out->file_offset[i]); + } + } +} + +void +pdc_write_digest(pdc_output *out) +{ + static const char bin2hex[] = PDF_STRING_0123456789ABCDEF; + + int i; + + pdc_puts(out, "/ID[<"); + for (i = 0; i < MD5_DIGEST_LENGTH; ++i) + { + pdc_putc(out, bin2hex[out->id[0][i] >> 4]); + pdc_putc(out, bin2hex[out->id[0][i] & 0x0F]); + } + pdc_puts(out, "><"); + for (i = 0; i < MD5_DIGEST_LENGTH; ++i) + { + pdc_putc(out, bin2hex[out->id[1][i] >> 4]); + pdc_putc(out, bin2hex[out->id[1][i] & 0x0F]); + } + pdc_puts(out, ">]\n"); +} + +void +pdc_write_eof(pdc_output *out) +{ +#if defined(MVS) || defined(MVS_TEST) + int i, k; + + if (out->blocksize > 1) + { + if ((i = (pdc_tell_out(out) + 6) % out->blocksize) != 0) + { + for (k = 0; k < out->blocksize - i - 1; ++k) + pdc_putc(out, PDF_SPACE); + + pdc_putc(out, PDF_NEWLINE); + } + } +#endif /* MVS */ + pdc_puts(out, "%%EOF\n"); +} + +void +pdc_write_trailer( + pdc_output *out, + pdc_id info_id, + pdc_id root_id, + int root_gen, + long xref_size, + pdc_off_t xref_prev, + pdc_off_t xref_pos) +{ + if (xref_size == -1) + { + xref_size = out->lastobj + 1; + } + + if (xref_pos == -1) + { + xref_pos = out->xref_pos; + } + + /* we've seen PDF consumers that need the linefeed... + */ + pdc_puts(out, "trailer\n"); + + pdc_begin_dict(out); /* trailer */ + pdc_printf(out, "/Size %ld\n", xref_size); + + if (xref_prev != -1) + pdc_printf(out, "/Prev %lld\n", xref_prev); + + pdc_printf(out, "/Root %ld %d R\n", root_id, root_gen); + + if (info_id != PDC_BAD_ID) + pdc_printf(out, "/Info %ld 0 R\n", info_id); + + pdc_write_digest(out); + pdc_end_dict(out); /* trailer */ + + pdc_puts(out, "startxref\n"); + pdc_printf(out, "%lld\n", xref_pos); + pdc_write_eof(out); +} + +/* ---------------------- High-level output functions ---------------------- */ + +#define PDC_LINEBUFLEN 4048 /* len of line output buffer */ + +/* + * Write a native encoded string to the output. + */ + +static void +pdc_puts_internal(pdc_output *out, char *s, pdc_bool tocopy) +{ + char *scp = s; + (void) tocopy; + + pdc_write(out, (void *) scp, strlen(scp)); +} + +void +pdc_puts(pdc_output *out, const char *s) +{ + pdc_puts_internal(out, (char *) s, pdc_true); +} + +/* + * Write a ASCII character to the output. + */ + +void +pdc_putc(pdc_output *out, const char c) +{ + pdc_write(out, (void *) &c, (size_t) 1); +} + +/* + * Write a formatted string (native encoded) to the output. + */ + +void +pdc_printf(pdc_output *out, const char *fmt, ...) +{ + char buf[PDC_LINEBUFLEN]; + va_list ap; + + va_start(ap, fmt); + + pdc_vsprintf(out->pdc, pdc_true, buf, fmt, ap); + pdc_puts_internal(out, buf, pdc_false); + + va_end(ap); +} + diff --git a/src/pdflib/pdcore/pc_output.h b/src/pdflib/pdcore/pc_output.h new file mode 100644 index 0000000..61a5697 --- /dev/null +++ b/src/pdflib/pdcore/pc_output.h @@ -0,0 +1,203 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_output.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib output routines + * + */ + +#ifndef PC_OUTPUT_H +#define PC_OUTPUT_H + +/* --------------------------- General --------------------------- */ + +/* Acrobat viewers change absolute values < 1/65536 to zero */ +#define PDF_SMALLREAL (0.000015) + +/* Acrobat viewers have an upper limit on real and integer numbers */ +#define PDF_BIGREAL (32768.0) +#define PDF_BIGINT (2147483647.0) + +/* maximum capacity of a dictionary, in entries */ +#define PDF_MAXDICTSIZE (4095) + +/* maximum capacity of an array, in elements */ +#define PDF_MAXARRAYSIZE (8191) + +/* maximum capacity of a string, in bytes */ +#define PDF_MAXSTRINGSIZE (65535) + +/* maximum capacity of indirect objects */ +#define PDF_MAXINDOBJS (8388607) + +/* some ASCII characters and strings, deliberately defined as hex/oct codes */ + +#define PDF_NEWLINE ((char) 0x0A) /* ASCII '\n' */ +#define PDF_RETURN ((char) 0x0D) /* ASCII '\r' */ +#define PDF_SPACE ((char) 0x20) /* ASCII ' ' */ +#define PDF_HASH ((char) 0x23) /* ASCII '#' */ +#define PDF_PARENLEFT ((char) 0x28) /* ASCII '(' */ +#define PDF_PARENRIGHT ((char) 0x29) /* ASCII ')' */ +#define PDF_PLUS ((char) 0x2B) /* ASCII '+' */ +#define PDF_SLASH ((char) 0x2F) /* ASCII '/' */ +#define PDF_COLON ((char) 0x3A) /* ASCII ':' */ +#define PDF_BACKSLASH ((char) 0x5C) /* ASCII '\\' */ + +#define PDF_A ((char) 0x41) /* ASCII 'A' */ +#define PDF_n ((char) 0x6E) /* ASCII 'n' */ +#define PDF_r ((char) 0x72) /* ASCII 'r' */ + +#define PDF_STRING_0123456789ABCDEF \ + "\060\061\062\063\064\065\066\067\070\071\101\102\103\104\105\106" + +typedef struct pdc_output_s pdc_output; + +typedef enum +{ + pdc_flush_none = 0, /* end of document */ + pdc_flush_page = 1<<0, /* after page */ + pdc_flush_content = 1<<1, /* font, xobj, annots */ + + /* temporary workaround; see bugzilla #167. + */ + /* pdc_flush_heavy = 1<<4 before realloc attempt */ + pdc_flush_heavy = pdc_flush_page | pdc_flush_content +} +pdc_flush_state; + +/* output control. +*/ +typedef struct +{ + /* exactly one of the members 'filename', 'fp', and 'writeproc' + ** must be supplied, the others must be NULL: + ** + ** filename use supplied file name to create a named output file + ** filename == "" means generate output in-core + ** fp use supplied FILE * to write to file + ** writeproc use supplied procedure to write output data + */ + const char *filename; + FILE * fp; + size_t (*writeproc)(pdc_output *out, void *data, size_t size); + + pdc_flush_state flush; +#if defined(MVS) || defined(MVS_TEST) + int blocksize; /* file record size */ +#endif +} pdc_outctl; + +/* --------------------------- Setup --------------------------- */ + +pdc_output * pdc_boot_output(pdc_core *pdc); +void pdc_init_outctl(pdc_outctl *oc); +pdc_bool pdc_init_output(void *opaque, pdc_output *out, + int compatibility, pdc_outctl *oc); +void pdc_cleanup_output(pdc_output *out, pdc_bool keep_buf); +void * pdc_get_opaque(pdc_output *out); + +/* --------------------------- Digest --------------------------- */ + +void pdc_init_digest(pdc_output *out); +void pdc_update_digest(pdc_output *out, unsigned char *input, + unsigned int len); +void pdc_finish_digest(pdc_output *out, pdc_bool settime); +unsigned char * pdc_get_digest(pdc_output *out); + + +/* --------------------------- Objects and ids --------------------------- */ + +pdc_id pdc_alloc_id(pdc_output *out); +pdc_id pdc_map_id(pdc_output *out, pdc_id old_id); +void pdc_mark_free(pdc_output *out, pdc_id obj_id); + +pdc_id pdc_begin_obj(pdc_output *out, pdc_id obj_id); +#define pdc_end_obj(out) pdc_puts(out, "endobj\n") + +#define PDC_NEW_ID 0L +#define PDC_BAD_ID -1L +#define PDC_FREE_ID -2L + + +/* --------------------------- Strings --------------------------- */ +/* output a string (including parentheses) and quote all required characters */ +void pdc_put_pdfstring(pdc_output *out, const char *text, int len); +void pdc_put_pdffilename(pdc_output *out, const char *text, int len); + + +/* --------------------------- Names --------------------------- */ +/* output a PDF name (including leading slash) and quote all required chars */ +void pdc_put_pdfname(pdc_output *out, const char *text, size_t len); + + +/* --------------------------- Arrays --------------------------- */ +#define pdc_begin_array(out) pdc_puts(out, "[") +#define pdc_end_array(out) pdc_puts(out, "]\n") +#define pdc_end_array_c(out) pdc_puts(out, "]") + + +/* --------------------------- Dictionaries --------------------------- */ +#define pdc_begin_dict(out) pdc_puts(out, "<<") +#define pdc_end_dict(out) pdc_puts(out, ">>\n") +#define pdc_end_dict_c(out) pdc_puts(out, ">>") + + +/* --------------------------- Object References --------------------------- */ +#define pdc_objref(out, name, obj_id) \ + pdc_printf(out, "%s %ld 0 R\n", name, obj_id) + +#define pdc_objref_c(out, obj_id) \ + pdc_printf(out, " %ld 0 R", obj_id) + +#define pdc_objref_c2(out, obj_id, gen_no) \ + pdc_printf(out, " %ld %d R", obj_id, gen_no) + +/* --------------------------- Streams --------------------------- */ +void pdc_begin_pdfstream(pdc_output *out); +void pdc_end_pdfstream(pdc_output *out); +pdc_off_t pdc_get_pdfstreamlength(pdc_output *out); +void pdc_put_pdfstreamlength(pdc_output *out, pdc_id length_id); + +int pdc_get_compresslevel(pdc_output *out); +void pdc_set_compresslevel(pdc_output *out, int compresslevel); + + + +/* --------------------------- Document sections --------------------------- */ +void pdc_write_xref(pdc_output *out); + +void pdc_write_digest(pdc_output *out); +void pdc_write_trailer(pdc_output *out, pdc_id info_id, + pdc_id root_id, int root_gen, long xref_size, + pdc_off_t xref_prev, pdc_off_t xref_pos); +void pdc_write_eof(pdc_output *out); + + +/* --------------------------- Low-level output --------------------------- */ +void pdc_flush_stream(pdc_output *out); +pdc_off_t pdc_tell_out(pdc_output *out); +void pdc_close_output(pdc_output *out); + /* TODO2GB: size_t? */ +char * pdc_get_stream_contents(pdc_output *out, pdc_off_t *size); +int pdc_stream_not_empty(pdc_output *out); + +void pdc_write(pdc_output *out, const void *data, size_t size); +void pdc_puts(pdc_output *out, const char *s); +void pdc_putc(pdc_output *out, const char c); + + +/* ------------------------- High-level output ------------------------- */ +void pdc_printf(pdc_output *out, const char *fmt, ...); + +#endif /* PC_OUTPUT_H */ + diff --git a/src/pdflib/pdcore/pc_prefix.h b/src/pdflib/pdcore/pc_prefix.h new file mode 100644 index 0000000..bcb9135 --- /dev/null +++ b/src/pdflib/pdcore/pc_prefix.h @@ -0,0 +1,17 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_prefix.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDCORE: unique renaming of function names shared by different applications + */ + +#ifndef PC_PREFIX_H +#define PC_PREFIX_H + +#endif /* PC_PREFIX_H */ diff --git a/src/pdflib/pdcore/pc_pstok.h b/src/pdflib/pdcore/pc_pstok.h new file mode 100644 index 0000000..a3a6ca2 --- /dev/null +++ b/src/pdflib/pdcore/pc_pstok.h @@ -0,0 +1,15 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_pstok.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDCORE PostScript token scanner. + * + */ + + diff --git a/src/pdflib/pdcore/pc_resource.c b/src/pdflib/pdcore/pc_resource.c new file mode 100644 index 0000000..727df4e --- /dev/null +++ b/src/pdflib/pdcore/pc_resource.c @@ -0,0 +1,1906 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_resource.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Resource routines + * + */ + +#define PC_RESOURCE_C + +#include <errno.h> + +#include "pc_util.h" +#include "pc_file.h" +#include "pc_resource.h" +#include "pc_ctype.h" + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + + +/* -------------------------- resource handling ----------------------------- */ + +struct pdc_res_s +{ + char *name; + char *value; + pdc_res *prev; + pdc_res *next; +}; + +struct pdc_category_s +{ + char *category; + pdc_res *kids; + pdc_category *next; +}; + +struct pdc_reslist_s +{ + pdc_category *resources; /* anchor for the category resource list */ + pdc_bool filepending; /* to read resource file is pending */ + char *filename; /* name of the resource file */ +}; + +typedef enum +{ + pdc_FontOutline, + pdc_FontAFM, + pdc_FontPFM, + pdc_HostFont, + pdc_Encoding, + pdc_ICCProfile, + pdc_StandardOutputIntent, + pdc_SearchPath, + pdc_CMap, + pdc_GlyphList, + pdc_CodeList +} +pdc_rescategory; + +static const pdc_keyconn pdc_rescategories[] = +{ + {"FontOutline", pdc_FontOutline}, + {"FontAFM", pdc_FontAFM}, + {"FontPFM", pdc_FontPFM}, + {"HostFont", pdc_HostFont}, + {"Encoding", pdc_Encoding}, + {"ICCProfile", pdc_ICCProfile}, + {"StandardOutputIntent", pdc_StandardOutputIntent}, + {"SearchPath", pdc_SearchPath}, + {"CMap", pdc_CMap}, + {"GlyphList", pdc_GlyphList}, + {"CodeList", pdc_CodeList}, + {NULL, 0} +}; + +#define RESOURCEFILEENVNAME "%sRESOURCEFILE" + +#ifndef MVS +#define DEFAULTRESOURCEFILE "%s.upr" +#else +#define DEFAULTRESOURCEFILE "upr" +#endif + +#ifdef WIN32 +#define REGISTRYKEY "Software\\PDFlib\\%s\\%s" +#endif + +pdc_reslist * +pdc_new_reslist(pdc_core *pdc) +{ + static const char fn[] = "pdc_new_reslist"; + + pdc_reslist *resl = (pdc_reslist *) pdc_malloc(pdc, sizeof(pdc_reslist),fn); + + resl->resources = NULL; + resl->filepending = pdc_true; + resl->filename = NULL; + + pdc->reslist = resl; + + return resl; +} + +static pdc_category * +pdc_delete_rescategory(pdc_core *pdc, pdc_category *prevcat, pdc_category *cat, + pdc_bool empty) +{ + pdc_category *nextcat; + pdc_res *res, *lastres; + + for (res = cat->kids; res != NULL; /* */) + { + lastres = res; + res = lastres->next; + pdc_free(pdc, lastres->name); + lastres->name = NULL; + if (lastres->value) + { + pdc_free(pdc, lastres->value); + lastres->value = NULL; + } + pdc_free(pdc, lastres); + } + nextcat = cat->next; + + if (empty) + { + cat->kids = NULL; + } + else + { + pdc_free(pdc, cat->category); + cat->category = NULL; + pdc_free(pdc, cat); + cat = NULL; + + if (prevcat != NULL) + { + pdc_reslist *resl = pdc->reslist; + + if (prevcat != cat) + prevcat->next = nextcat; + else + resl->resources = nextcat; + } + } + + return nextcat; +} + +void +pdc_delete_reslist(pdc_core *pdc) +{ + pdc_reslist *resl = pdc->reslist; + + if (resl != NULL) + { + pdc_category *cat; + + for (cat = resl->resources; cat != NULL; /* */) + cat = pdc_delete_rescategory(pdc, NULL, cat, pdc_false); + + if (resl->filename) + pdc_free(pdc, resl->filename); + + pdc_free(pdc, resl); + pdc->reslist = NULL; + } +} + +static pdc_reslist * +pdc_get_reslist(pdc_core *pdc) +{ + pdc_reslist *resl = pdc->reslist; + + if (resl == NULL) + resl = pdc_new_reslist(pdc); + + return resl; +} + +void +pdc_set_resourcefile(pdc_core *pdc, const char *filename) +{ + if (filename != NULL && *filename) + { + pdc_reslist *resl = pdc_get_reslist(pdc); + + if (resl->filename) + pdc_free(pdc, resl->filename); + + resl->filename = pdc_strdup(pdc, filename); + resl->filepending = pdc_true; + } +} + +const char * +pdc_get_resourcefile(pdc_core *pdc) +{ + pdc_reslist *resl = pdc_get_reslist(pdc); + + return (resl->filename); +} + +static void +pdc_read_resourcefile(pdc_core *pdc, const char *filename) +{ + pdc_reslist *resl = pdc_get_reslist(pdc); + pdc_file *fp = NULL; + char **linelist; + char *line; + char *category = NULL; + char *uprfilename = NULL; + char tmpname[PDC_FILENAMELEN]; +#if defined(AS400) || defined(WIN32) +#define BUFSIZE 2048 + char buffer[BUFSIZE]; +#ifdef WIN32 + char regkey[128]; + HKEY hKey = NULL; + DWORD size, lType; +#endif +#endif + int il, nlines = 0, nextcat, begin; + + pdc_logg_cond(pdc, 1, trc_resource, + "\n\tSearching for resource file...\n"); + +#ifdef WIN32 + +/* don't add patchlevel's to registry searchpath */ +#define stringiz1(x) #x +#define stringiz(x) stringiz1(x) + + sprintf(regkey, REGISTRYKEY, pdc->prodname, pdc->version); + +#endif /* WIN32 */ + +#ifdef AS400 + pdc_logg_cond(pdc, 1, trc_resource, + "\tSet AS400 default resources\n"); + strcpy (buffer, "/pdflib/"); + strcat (buffer, pdc->version); + il = (int) strlen(buffer); + strcat (buffer, "/fonts"); + pdc_add_resource(pdc, "SearchPath", buffer, ""); + strcpy(&buffer[il], "/bind/data"); + pdc_add_resource(pdc, "SearchPath", buffer, ""); +#endif /* AS400 */ + +#ifdef WIN32 + /* process registry entries */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0L, + (REGSAM) KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) + { + pdc_logg_cond(pdc, 1, trc_resource, + "\tRead registry key \"%s\":\n", REGISTRYKEY); + + size = BUFSIZE - 2; + if (RegQueryValueExA(hKey, "searchpath", (LPDWORD) NULL, + &lType, (LPBYTE) buffer, &size) + == ERROR_SUCCESS && *buffer) + { + char **pathlist; + int ip, np; + + np = pdc_split_stringlist(pdc, buffer, ";", 0, &pathlist); + for (ip = 0; ip < np; ip++) + pdc_add_resource(pdc, "SearchPath", pathlist[ip], ""); + pdc_cleanup_stringlist(pdc, pathlist); + } + + RegCloseKey(hKey); + } +#endif /* WIN32 */ + + /* searching for name of upr file */ + uprfilename = (char *)filename; + if (uprfilename == NULL || *uprfilename == '\0') + { + /* upr file name via environment variable */ + sprintf(tmpname, RESOURCEFILEENVNAME, pdc->prodname); + pdc_strtoupper(tmpname); + uprfilename = pdc_getenv(tmpname); + +#ifdef WIN32 + /* registry upr file name */ + if (uprfilename == NULL || *uprfilename == '\0') + { + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0L, + (REGSAM) KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) + { + size = BUFSIZE - 2; + if (RegQueryValueExA(hKey, "resourcefile", (LPDWORD) NULL, + &lType, (LPBYTE) buffer, &size) + == ERROR_SUCCESS && *buffer) + { + uprfilename = buffer; + } + + RegCloseKey(hKey); + } + } +#endif /* WIN32 */ + + /* default upr file name */ + if (uprfilename == NULL || *uprfilename == '\0') + { + sprintf(tmpname, DEFAULTRESOURCEFILE, pdc->prodname); + uprfilename = pdc_strtolower(tmpname); + + /* user-supplied upr file */ + fp = pdc_fsearch_fopen(pdc, uprfilename, NULL, NULL, 0); + if (fp == NULL) + { + uprfilename = NULL; + } + } + } + + if (uprfilename != NULL && *uprfilename != '\0') + { + char *resfilename = resl->filename; + + pdc_logg_cond(pdc, 1, trc_resource, + "\tRead resource file \"%s\":\n", uprfilename); + + resl->filename = pdc_strdup(pdc, uprfilename); + if (resfilename) + pdc_free(pdc, resfilename); + + /* read upr file */ + if (fp == NULL) + { + fp = pdc_fsearch_fopen(pdc, resl->filename, NULL, "UPR ", + PDC_FILE_TEXT); + if (fp == NULL) + pdc_error(pdc, -1, 0, 0, 0, 0); + } + + nlines = pdc_read_textfile(pdc, fp, 0, &linelist); + pdc_fclose(fp); + + if (nlines) + { + /* Lines loop */ + begin = 1; + nextcat = 0; + for (il = 0; il < nlines; il++) + { + line = linelist[il]; + + /* Next category */ + if (line[0] == '.' && strlen(line) == 1) + { + begin = 0; + nextcat = 1; + continue; + } + + /* Skip category list */ + if (begin) continue; + + /* Category expected */ + if (nextcat) + { + /* Ressource Category */ + category = line; + nextcat = 0; + continue; + } + + /* Add resource */ + if (strlen(line)) + pdc_add_resource(pdc, category, line, NULL); + } + + pdc_cleanup_stringlist(pdc, linelist); + } + } +} + +/* + * pdc_add_resource_ext add a new resource to the resource data base + * for specified resource category. + * + * resvalue == NULL: + * resname string has the format "resname [= resvalue]" + * Then string splitting has to be performed. + * [EBCDIC-]UTF-8 must be specified by a BOM: resname = resvalue + * + * Otherwise resname and resvalue are [EBCDIC-]UTF-8 encoded. + * + */ +void +pdc_add_resource_ext(pdc_core *pdc, const char *category, const char *resname, + const char *resvalue, pdc_encoding enc, int codepage) +{ + static const char fn[] = "pdc_add_resource"; + pdc_reslist *resl = pdc_get_reslist(pdc); + pdc_rescategory rescat; + pdc_category *cat = NULL, *lastcat = NULL; + pdc_res *res = NULL, *lastres = NULL; + char *resnamutf8 = NULL; + char *resvalutf8 = NULL; + int resnamflags = PDC_CONV_EBCDIC; + int resvalflags = PDC_CONV_EBCDIC; + int k; + + if (!resvalue || !strlen(resvalue)) + pdc_logg_cond(pdc, 1, trc_resource, + "\tAdd \"%s\" to resource category \"%s\"\n", resname, category); + else + pdc_logg_cond(pdc, 1, trc_resource, + "\tAdd \"%s=%s\" to resource category \"%s\"\n", + resname, resvalue, category); + + /* We no longer raise an error but silently ignore unknown categories */ + k = pdc_get_keycode_ci(category, pdc_rescategories); + if (k == PDC_KEY_NOTFOUND) + { + pdc_warning(pdc, PDC_E_RES_BADCAT, category, 0, 0, 0); + return; + } + rescat = (pdc_rescategory) k; + + /* Read resource configuration file if it is pending */ + if (resl->filepending) + { + resl->filepending = pdc_false; + pdc_read_resourcefile(pdc, resl->filename); + } + + /* Find start of this category's resource list, if the category exists */ + lastcat = resl->resources; + for (cat = lastcat; cat != NULL; cat = cat->next) + { + if (!pdc_stricmp(cat->category, category)) + break; + lastcat = cat; + } + if (cat == NULL) + { + cat = (pdc_category *) pdc_malloc(pdc, sizeof(pdc_category), fn); + cat->category = pdc_strdup(pdc, category); + cat->kids = NULL; + cat->next = NULL; + if (lastcat != NULL) + lastcat->next = cat; + else + resl->resources = cat; + } + + /* resvalue */ + if (resvalue == NULL) + { + char **strlist = NULL; + + /* splitting of resname string */ + int ns = pdc_split_stringlist(pdc, resname, "=", 0, &strlist); + + if (ns >= 1) + pdc_str2trim(strlist[0]); + if (ns == 2) + pdc_str2trim(strlist[1]); + if (ns > 2 || + (rescat != pdc_SearchPath && (ns == 0 || !strlen(strlist[0])))) + { + pdc_cleanup_stringlist(pdc, strlist); + pdc_error(pdc, PDC_E_RES_BADRES, resname, category, 0, 0); + } + + /* resource name */ + if (ns > 0) + { + if (pdc_is_utf8_bytecode(resname)) + resnamflags |= PDC_CONV_ISUTF8; + resnamutf8 = pdc_convert_name_ext(pdc, strlist[0], 0, + enc, codepage, resnamflags); + } + + /* resource value */ + if (ns == 2) + { + resvalflags = resnamflags; + resvalutf8 = pdc_convert_name_ext(pdc, strlist[1], 0, + enc, codepage, resvalflags); + } + else + { + resvalutf8 = pdc_strdup(pdc, ""); + } + pdc_cleanup_stringlist(pdc, strlist); + } + else + { + resnamflags |= PDC_CONV_ISUTF8; + resnamutf8 = pdc_convert_name_ext(pdc, resname, 0, + enc, codepage, resnamflags); + + resvalflags |= PDC_CONV_ISUTF8; + resvalutf8 = pdc_convert_name_ext(pdc, resvalue, 0, + enc, codepage, resvalflags); + } + + switch (rescat) + { + case pdc_FontOutline: + case pdc_FontAFM: + case pdc_FontPFM: + case pdc_HostFont: + case pdc_Encoding: + case pdc_ICCProfile: + case pdc_CMap: + case pdc_GlyphList: + case pdc_CodeList: + { + if (!strlen(resnamutf8) || !strlen(resvalutf8)) + { + pdc_free(pdc, resnamutf8); + pdc_free(pdc, resvalutf8); + if (resvalue == NULL) + pdc_error(pdc, PDC_E_RES_BADRES, resname, category, 0, 0); + else + pdc_error(pdc, PDC_E_RES_BADRES2, resname, resvalue, + category, 0); + } + + /* file name check */ + resvalutf8 = pdc_check_filename(pdc, resvalutf8); + } + break; + + case pdc_SearchPath: + { + if (strlen(resvalutf8)) + { + if (resnamutf8 != NULL) + pdc_free(pdc, resnamutf8); + pdc_free(pdc, resvalutf8); + pdc_error(pdc, PDC_E_RES_BADRES, resname, category, 0, 0); + } + + if (resvalutf8 != NULL) + { + pdc_free(pdc, resvalutf8); + resvalutf8 = NULL; + } + + /* file name check */ + if (resnamutf8 != NULL && strlen(resnamutf8)) + { + resnamutf8 = pdc_check_filename(pdc, resnamutf8); + } + else + { + /* delete all entries */ + if (resnamutf8 != NULL) + pdc_free(pdc, resnamutf8); + pdc_delete_rescategory(pdc, lastcat, cat, pdc_true); + + pdc_logg_cond(pdc, 1, trc_resource, + "\tResource category \"%s\" removed\n", category); + + return; + } + } + break; + + case pdc_StandardOutputIntent: + break; + } + + /* Find resource name in resource list */ + lastres = NULL; + for (res = cat->kids; res != NULL; res = res->next) + { + if (!strcmp(res->name, resnamutf8)) + break; + lastres = res; + } + + /* New resource */ + if (res == NULL) + { + res = (pdc_res *) pdc_calloc(pdc, sizeof(pdc_res), fn); + if (lastres) + lastres->next = res; + else + cat->kids = res; + res->prev = lastres; + res->name = resnamutf8; + } + else + { + pdc_free(pdc, resnamutf8); + } + + /* New value */ + if (res->value) + pdc_free(pdc, res->value); + res->value = resvalutf8; + + if (res->value && strlen(res->value)) + pdc_logg_cond(pdc, 1, trc_resource, + "\tNew category.resource: \"%s.%s = %s\"\n", + category, res->name, res->value); + else + pdc_logg_cond(pdc, 1, trc_resource, + "\tNew category.resource: \"%s.%s\"\n", + category, res->name); +} + +void +pdc_add_resource(pdc_core *pdc, const char *category, const char *resname, + const char *resvalue) +{ + pdc_add_resource_ext(pdc, category, resname, resvalue, pdc_invalidenc, 0); +} + +const char * +pdc_find_resource(pdc_core *pdc, const char *category, const char *name) +{ + pdc_reslist *resl = pdc_get_reslist(pdc); + pdc_category *cat; + pdc_res *res; + + /* Read resource configuration file if it is pending */ + if (resl->filepending) + { + resl->filepending = pdc_false; + pdc_read_resourcefile(pdc, resl->filename); + } + + for (cat = resl->resources; cat != (pdc_category *) NULL; cat = cat->next) + { + if (!pdc_stricmp(cat->category, category)) + { + for (res = cat->kids; res != (pdc_res *)NULL; res = res->next) + { + if (!strcmp(res->name, name)) + { + if (pdc_logg_is_enabled(pdc, 1, trc_resource)) + { + const char *resval = res->name, *separ = ""; + + if (res->value && strlen(res->value)) + { + resval = res->value; + separ = " = "; + } + + pdc_logg(pdc, + "\tFound category.resource: \"%s.%s%s%s\"\n", + category, res->name, separ, resval); + } + + return res->value; + } + } + } + } + + return NULL; +} + +const char * +pdc_find_resource_nr(pdc_core *pdc, const char *category, int nr) +{ + pdc_reslist *resl = pdc_get_reslist(pdc); + pdc_category *cat; + pdc_rescategory rescat; + pdc_res *res; + int n = 0; + + /* Read resource configuration file if it is pending */ + if (resl->filepending) + { + resl->filepending = pdc_false; + pdc_read_resourcefile(pdc, resl->filename); + } + + rescat = (pdc_rescategory) pdc_get_keycode_ci(category, pdc_rescategories); + + for (cat = resl->resources; cat != (pdc_category *) NULL; cat = cat->next) + { + if (!pdc_stricmp(cat->category, category)) + { + for (res = cat->kids; res != (pdc_res *)NULL; res = res->next) + { + n++; + if (n == nr) + { + char *resname = (char *) "", *resval = res->name; + const char *separ = "", *retval; + pdc_bool tobefree = pdc_false; + + if (res->value && strlen(res->value)) + { + resname = res->name; + resval = res->value; + separ = "="; + } + + pdc_logg_cond(pdc, 1, trc_resource, + "\tFound %d. category.resource: " + "\"%s.%s%s%s\"\n", + nr, category, resname, separ, resval); + + /* conversion of host encoded file names back to UTF-8 */ + switch (rescat) + { + case pdc_StandardOutputIntent: + break; + + default: + resval = pdc_get_filename(pdc, resval); + tobefree = pdc_true; + break; + } + + retval = + pdc_errprintf(pdc, "%s%s%s", resname, separ, resval); + + if (tobefree) + pdc_free(pdc, resval); + + return retval; + } + } + } + } + + return ""; +} + + +/* ----------------------- virtual file handling ---------------------------- */ + +struct pdc_virtfile_s +{ + char *name; + const void *data; + size_t size; + pdc_bool iscopy; + int lockcount; + pdc_virtfile *next; +}; + +static pdc_virtfile * +pdc_find_pvf(pdc_core *pdc, const char *filename, pdc_virtfile **lastvfile) +{ + pdc_virtfile *vfile; + pdc_virtfile *filesystem = pdc->filesystem; + + if (lastvfile != NULL) + *lastvfile = NULL; + for (vfile = filesystem; vfile != NULL; vfile = vfile->next) + { + if (!strcmp(vfile->name, filename)) + { + pdc_logg_cond(pdc, 1, trc_filesearch, + "\n\tVirtual file \"%s\" found\n", filename); + return vfile; + } + if (lastvfile != NULL) + *lastvfile = vfile; + } + return NULL; +} + +/* definitions of pvf options */ +static const pdc_defopt pdc_create_pvf_options[] = +{ + {"copy", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + +void +pdc__create_pvf(pdc_core *pdc, const char *filename, + const void *data, size_t size, const char *optlist) +{ + static const char fn[] = "pdc__create_pvf"; + pdc_bool iscopy = pdc_false; + pdc_virtfile *vfile, *lastvfile = NULL; + pdc_resopt *results; + + if (!data) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "data", 0, 0, 0); + + if (!size) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "size", 0, 0, 0); + + /* Parse optlist */ + results = pdc_parse_optionlist(pdc, optlist, pdc_create_pvf_options, + NULL, pdc_true); + pdc_get_optvalues("copy", results, &iscopy, NULL); + pdc_cleanup_optionlist(pdc, results); + + /* Find virtual file in file system */ + vfile = pdc_find_pvf(pdc, filename, &lastvfile); + + /* Name already exists */ + if (vfile != NULL) + pdc_error(pdc, PDC_E_PVF_NAMEEXISTS, filename, 0, 0, 0); + + /* New virtual file */ + vfile = (pdc_virtfile *) pdc_calloc(pdc, sizeof(pdc_virtfile), fn); + if (lastvfile) + lastvfile->next = vfile; + else + pdc->filesystem = vfile; + + /* Fill up file struct */ + vfile->name = pdc_strdup(pdc, filename); + if (iscopy == pdc_true) + { + vfile->data = (const void *) pdc_malloc(pdc, size, fn); + memcpy((void *) vfile->data, data, size); + } + else + { + vfile->data = data; + } + vfile->size = size; + vfile->iscopy = iscopy; + vfile->lockcount = 0; + vfile->next = NULL; + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\n\tVirtual file \"%s\" created\n", filename); +} + +int +pdc__delete_pvf(pdc_core *pdc, const char *filename) +{ + pdc_virtfile *vfile, *lastvfile = NULL; + + /* Find virtual file in file system */ + vfile = pdc_find_pvf(pdc, filename, &lastvfile); + if (vfile) + { + /* File exists but locked */ + if (vfile->lockcount > 0) + { + return pdc_undef; + } + + /* Delete */ + if (vfile->iscopy == pdc_true) + { + pdc_free(pdc, (void *) vfile->data); + vfile->data = NULL; + } + pdc_free(pdc, vfile->name); + if (lastvfile) + lastvfile->next = vfile->next; + else + pdc->filesystem = vfile->next; + pdc_free(pdc, vfile); + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\tVirtual file \"%s\" deleted\n", filename); + } + + return pdc_true; +} + +void +pdc_lock_pvf(pdc_core *pdc, const char *filename) +{ + pdc_virtfile *vfile = pdc_find_pvf(pdc, filename, NULL); + if (vfile) + { + (vfile->lockcount)++; + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\tVirtual file \"%s\" locked\n", filename); + } +} + +void +pdc_unlock_pvf(pdc_core *pdc, const char *filename) +{ + pdc_virtfile *vfile = pdc_find_pvf(pdc, filename, NULL); + if (vfile) + { + (vfile->lockcount)--; + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\tVirtual file \"%s\" unlocked\n", filename); + } +} + +void +pdc_delete_filesystem(pdc_core *pdc) +{ + pdc_virtfile *vfile, *nextvfile; + pdc_virtfile *filesystem = pdc->filesystem; + + for (vfile = filesystem; vfile != NULL; /* */) + { + nextvfile = vfile->next; + if (vfile->iscopy == pdc_true && vfile->data) + pdc_free(pdc, (void *) vfile->data); + if (vfile->name) + pdc_free(pdc, vfile->name); + pdc_free(pdc, vfile); + vfile = nextvfile; + } + pdc->filesystem = NULL; +} + + +/* ------------------------ file search handling ---------------------------- */ + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +pdc_file * +pdc_fsearch_fopen(pdc_core *pdc, const char *filename, char *fullname, + const char *qualifier, int flags) +{ + pdc_reslist *resl = pdc_get_reslist(pdc); + char fullname_s[PDC_FILENAMELEN]; + const pdc_byte *data = NULL; + pdc_file *sfp = NULL; + size_t size = 0; + pdc_virtfile *vfile; + + if (fullname == NULL) + fullname = fullname_s; + strcpy(fullname, filename); + + vfile = pdc_find_pvf(pdc, filename, NULL); + if (vfile) + { + size = vfile->size; + data = (const pdc_byte *) vfile->data; + sfp = pdc_fopen(pdc, filename, qualifier, data, size, flags); + } + else + { + pdc_category *cat; + + /* Bad filename */ + if (!*filename || !strcmp(filename, ".") || !strcmp(filename, "..")) + { + pdc_set_errmsg(pdc, PDC_E_IO_ILLFILENAME, filename, 0, 0, 0); + return NULL; + } + + + /* Read resource configuration file if it is pending */ + if (resl->filepending) + { + resl->filepending = pdc_false; + pdc_read_resourcefile(pdc, resl->filename); + } + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\n\tSearching for file \"%s\":\n", filename); + + /* Searching resource category */ + for (cat = resl->resources; + cat != (pdc_category *) NULL; + cat = cat->next) + if (!pdc_stricmp(cat->category, "SearchPath")) break; + + if (!cat) + { + /* No resource category */ + sfp = pdc_fopen(pdc, filename, qualifier, NULL, 0, flags); + } + else + { + pdc_res *res = cat->kids; + pdc_res *lastres = cat->kids; + char *pathname = NULL; + FILE *fp = NULL; + int errnum = PDC_E_IO_RDOPEN_NF; + pdc_bool fatal = pdc_false; + + /* Find last SearchPath entry */ + while (res != (pdc_res *) NULL) + { + lastres = res; + res = res->next; + } + + /* First local search and then search with concatenated + * filename with search paths one after another backwards + */ + while (1) + { + /* Test opening */ + pdc_file_fullname(pathname, filename, fullname); + + if (pathname != NULL) + pdc_logg_cond(pdc, 1, trc_filesearch, + "\tin directory \"%s\": \"%s\"\n", pathname, fullname); + + fp = pdc_fopen_logg(pdc, fullname, READBMODE); + if (fp) + { + /* File found */ + pdc_fclose_logg(pdc, fp); + sfp = pdc_fopen(pdc, fullname, qualifier, NULL, 0,flags); + break; + } + errnum = pdc_get_fopen_errnum(pdc, PDC_E_IO_RDOPEN); + if (errno != 0 && errnum != PDC_E_IO_RDOPEN_NF) + { + fatal = pdc_true; + pdc_set_fopen_errmsg(pdc, PDC_E_IO_RDOPEN, + qualifier, fullname); + } + +#if defined(WIN32) + /* file name beginning with a drive letter: 'x:' + * is already full specified. + */ + if (pdc_isalpha(filename[0]) && filename[1] == ':') + break; +#endif + + if (lastres == (pdc_res *) NULL) + break; + + pathname = lastres->name; + lastres = lastres->prev; + } + + if (sfp == NULL && !fatal) + pdc_set_fopen_errmsg(pdc, PDC_E_IO_RDOPEN, + qualifier, filename); + else + filename = fullname; + } + } + + pdc_logg_cond(pdc, 1, trc_filesearch, + "\tFile \"%s\" %sfound\n", fullname, sfp == NULL ? "not " : ""); + return sfp; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + + +/* ----------------------- logging file handling ---------------------------- */ + +# ifndef DEFAULTLOGFILE +# if defined(MVS) +# define DEFAULTLOGFILE "pdflog" +# elif defined(MAC) || defined(AS400) +# define DEFAULTLOGFILE "/%s.log" +# elif defined(WIN32) +# define DEFAULTLOGFILE "\\%s.log" +# else +# define DEFAULTLOGFILE "/tmp/%s.log" +# endif +# endif + +#define LOGFILEENVNAME "%sLOGFILE" +#define LOGGINGENVNAME "%sLOGGING" + +#define PDC_CLASSLIST_SIZE 32 +#define PDC_CLASSLIST_MAX 10 + +struct pdc_loggdef_s +{ + pdc_bool enabled; /* logging enabled */ + char *filename; /* name of the logging file */ + pdc_bool fromenviron; /* logging file name defined environment */ + pdc_bool header; /* with header and separation line */ + pdc_bool flush; /* logging file will be opened and + * and closed immediately */ + FILE *fp; /* flush = false: file handle */ + pdc_strform_kind strform; /* format for logging strings */ + int maxchar; /* maximal number of characters + * of logging strings */ + int sri; /* first index in classlist for save/restore */ + char classlist[PDC_CLASSLIST_MAX][PDC_CLASSLIST_SIZE]; + /* list array of levels for logging classes */ + pdc_bool classapi; /* only api class has level = 1 + * and warning class has level = 1 */ +}; + +static pdc_loggdef * +pdc_new_logg(pdc_core *pdc) +{ + static const char fn[] = "pdc_new_logg"; + char envname[32]; + const char *envval = NULL; + + pdc_loggdef *logg = (pdc_loggdef *) + pdc_malloc(pdc, sizeof(pdc_loggdef), fn); + + logg->enabled = pdc_false; + logg->filename = NULL; + logg->fromenviron = pdc_false; + logg->header = pdc_true; + logg->flush = pdc_false; + logg->fp = NULL; + logg->strform = strform_readable; + logg->maxchar = 0; + logg->sri = 0; + memset(logg->classlist[0], 0, PDC_CLASSLIST_SIZE); + logg->classlist[0][trc_api] = 1; + logg->classlist[0][trc_warning] = 1; + logg->classapi = pdc_true; + + pdc->logg = logg; + + /* logging file name defined by environment variable */ + sprintf(envname, LOGFILEENVNAME, pdc->prodname); + pdc_strtoupper(envname); + envval = pdc_getenv(envname); + if (envval != NULL) + { + logg->filename = pdc_strdup(pdc, envval); + logg->fromenviron = pdc_true; + } + + return logg; +} + +void +pdc_delete_logg(pdc_core *pdc) +{ + if (pdc->logg != NULL) + { + pdc_loggdef *logg = pdc->logg; + + logg->enabled = pdc_false; + + /* close file */ + if (logg->fp != NULL && logg->fp != stdout && logg->fp != stderr) + { + fclose(logg->fp); + logg->fp = NULL; + } + + if (logg->filename != NULL) + { + pdc_free(pdc, logg->filename); + logg->filename = NULL; + } + + pdc_free(pdc, logg); + pdc->logg = NULL; + } +} + +static pdc_loggdef * +pdc_get_logg(pdc_core *pdc) +{ + pdc_loggdef *logg = pdc->logg; + + if (logg == NULL) + logg = pdc_new_logg(pdc); + + return logg; +} + +static const pdc_keyconn pdc_strform_keylist[] = +{ + {"readable", strform_readable}, + {"readable0", strform_readable0}, + {"octal", strform_octal}, + {"hex", strform_hexa}, + {"java", strform_java}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_protoclass_keylist[] = +{ + {"api", trc_api}, + {"encoding", trc_encoding}, + {"digsig", trc_digsig}, + {"filesearch", trc_filesearch}, + {"font", trc_font}, + {"image", trc_image}, + {"memory", trc_memory}, + {"optlist", trc_optlist}, + {"other", trc_other}, + {"pcos", trc_pcos}, + {"pdi", trc_pdi}, + {"resource", trc_resource}, + {"shadow", trc_shadow}, + {"table", trc_table}, + {"text", trc_text}, + {"textflow", trc_textflow}, + {"user", trc_user}, + {"warning", trc_warning}, + {"wordfinder", trc_wordfinder}, + {"xmp", trc_xmp}, + {"zones", trc_zones}, + {NULL, 0} +}; + +#define PDC_FILENAMELEN 1024 + +static const pdc_defopt pdc_logg_options[] = +{ + {"header", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"enable", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"disable", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"flush", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"remove", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"filename", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_FILENAMELEN, NULL}, + + {"restore", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"save", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"stringformat", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdc_strform_keylist}, + + {"stringlimit", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"classes", pdc_stringlist, PDC_OPT_EVENNUM |PDC_OPT_SUBOPTLIST, + 1, 2 * PDC_CLASSLIST_SIZE, 1.0, 64, NULL}, + + PDC_OPT_TERMINATE +}; + +static const char *separstr = + "[ --------------------------------------------------------- ]\n"; + +void +pdc_set_logg_options(pdc_core *pdc, const char *optlist) +{ + pdc_loggdef *logg = pdc_get_logg(pdc); + pdc_resopt *resopts = NULL; + char **strlist, *keyword; + char filename[PDC_FILENAMELEN+1]; + pdc_bool sare = pdc_false; + pdc_bool enable = pdc_true; + pdc_bool remfile = pdc_false; + pdc_char level; + int inum, i, pclass = 0, sumlevel = 0; + + filename[0] = 0; + if (optlist && strlen(optlist)) + { + resopts = pdc_parse_optionlist(pdc, optlist, pdc_logg_options, + NULL, pdc_true); + + if (pdc_get_optvalues("save", resopts, &sare, NULL) && sare) + { + i = logg->sri + 1; + if (i >= PDC_CLASSLIST_MAX) + pdc_error(pdc, PDC_E_INT_TOOMUCH_SARE, 0, 0, 0, 0); + memcpy(logg->classlist[i], logg->classlist[logg->sri], + PDC_CLASSLIST_SIZE); + logg->sri = i; + } + + if (pdc_get_optvalues("restore", resopts, &sare, NULL) && sare) + { + i = logg->sri - 1; + if (i < 0) + pdc_error(pdc, PDC_E_INT_TOOMUCH_SARE, 0, 0, 0, 0); + logg->sri = i; + } + + if (pdc_get_optvalues("disable", resopts, &inum, NULL)) + enable = inum ? pdc_false : pdc_true; + + pdc_get_optvalues("header", resopts, &logg->header, NULL); + + pdc_get_optvalues("flush", resopts, &logg->flush, NULL); + + pdc_get_optvalues("remove", resopts, &remfile, NULL); + + if (!logg->fromenviron) + pdc_get_optvalues("filename", resopts, filename, NULL); + + if (pdc_get_optvalues("stringformat", resopts, &inum, NULL)) + logg->strform = (pdc_strform_kind) inum; + + pdc_get_optvalues("stringlimit", resopts, &logg->maxchar, NULL); + + inum = pdc_get_optvalues("classes", resopts, NULL, &strlist); + if (inum) + { + for (i = 0; i < inum; i++, i++) + { + if (!pdc_stricmp(strlist[i], "other")) + { + i++; + if (pdc_str2integer(strlist[i], + PDC_INT_CHAR | PDC_INT_UNSIGNED, + &level)) + { + memset(logg->classlist[logg->sri], (int)level, + PDC_CLASSLIST_SIZE); + } + break; + } + } + for (i = 0; i < inum; i++) + { + keyword = strlist[i]; + pclass = pdc_get_keycode_ci(keyword, pdf_protoclass_keylist); + if (pclass == PDC_KEY_NOTFOUND) + pdc_error(pdc, PDC_E_OPT_ILLKEYWORD, + "classes", keyword, 0, 0); + i++; + if (!pdc_str2integer(strlist[i], + PDC_INT_CHAR | PDC_INT_UNSIGNED, + &level)) + pdc_error(pdc, PDC_E_OPT_ILLINTEGER, + keyword, strlist[i], 0, 0); + + logg->classlist[logg->sri][pclass] = level; + } + + for (i = 0; i < PDC_CLASSLIST_SIZE; i++) + sumlevel += (int) logg->classlist[logg->sri][i]; + logg->classapi = + (sumlevel == 2 && + logg->classlist[logg->sri][trc_api] && + logg->classlist[logg->sri][trc_warning]) ? + pdc_true : pdc_false; + } + + pdc_cleanup_optionlist(pdc, resopts); + } + + /* disable */ + if (logg->enabled && logg->header && !enable) + { + pdc_logg(pdc, "\n"); + pdc_logg(pdc, separstr); + } + + /* no new logging file name specified */ + if (!strlen(filename)) + { + if (logg->filename == NULL) + { + char tmpname[PDC_FILENAMELEN]; + + sprintf(tmpname, DEFAULTLOGFILE, pdc->prodname); + pdc_strtolower(tmpname); + strcpy(filename, tmpname); + } + else + { + strcpy(filename, logg->filename); + } + } + + /* new logging file */ + if (logg->filename == NULL || strcmp(logg->filename, filename)) + { + pdc_time ltime; + + /* close file */ + if (logg->fp != stdout && logg->fp != stderr && logg->filename) + { + pdc_localtime(<ime); + pdc_logg(pdc, "[%04d-%02d-%02d %02d:%02d:%02d]\n", + ltime.year + 1900, ltime.month + 1, ltime.mday, + ltime.hour, ltime.minute, ltime.second); + if (logg->fp != NULL) + fclose(logg->fp); + } + logg->enabled = pdc_false; + + /* remove file */ + if (remfile && strcmp(filename, "stdout") && strcmp(filename, "stderr")) + remove(filename); + + /* file name */ + if (logg->filename != NULL) + pdc_free(pdc, logg->filename); + logg->filename = pdc_strdup(pdc, filename); + + /* open file */ + if (!logg->flush) + { + if (!strcmp(logg->filename, "stdout")) + logg->fp = stdout; + else if (!strcmp(logg->filename, "stderr")) + logg->fp = stderr; + else + logg->fp = fopen(logg->filename, APPENDMODE); + if (logg->fp == NULL) + { + pdc_error(pdc, PDC_E_IO_WROPEN, "log ", logg->filename, + 0, 0); + } + } + else + { + logg->fp = NULL; + } + + + /* header line */ + logg->enabled = enable; + if (logg->enabled && logg->header && pdc->prodname != NULL) + { + char binding[64]; + + pdc_localtime(<ime); + binding[0] = 0; + if (pdc->binding) + { + strcat(binding, pdc->binding); + strcat(binding, " binding "); + } + pdc_logg(pdc, separstr); + pdc_logg(pdc, "[ %s %s %son %s (%s) ", + pdc->prodname, pdc->version, binding, + PDF_PLATFORM, PDC_ISBIGENDIAN ? "be" : "le"); + pdc_logg(pdc, "%04d-%02d-%02d %02d:%02d:%02d ]\n", + ltime.year + 1900, ltime.month + 1, ltime.mday, + ltime.hour, ltime.minute, ltime.second); + + if (logg->classapi) + pdc_logg(pdc, "[ Use %%s/\\[[^]]*\\]//g and %%s/)$/);" + "/ in vi to compile it ]\n"); + pdc_logg(pdc, separstr); + } + } + else + { + logg->enabled = enable; + } +} + +const char * +pdc_print_loggstring(pdc_core *pdc, const char *str, int len) +{ + if (pdc->logg != NULL && pdc->logg->enabled) + { + + str = pdc_strprint(pdc, str, len, pdc->logg->maxchar, + pdc->logg->strform); + + + return str; + } + else + return ""; +} + +/* logging function without any class level check and decorations + */ +static void +pdc_logg_output(pdc_core *pdc, const char *fmt, va_list ap) +{ + pdc_loggdef *logg = pdc->logg; + + if (logg->flush) + { + FILE *fp = NULL; + + if (!strcmp(logg->filename, "stdout")) + fp = stdout; + else if (!strcmp(logg->filename, "stderr")) + fp = stderr; + else + fp = fopen(logg->filename, APPENDMODE); + + if (fp == NULL) + { + logg->enabled = pdc_false; + pdc_error(pdc, PDC_E_IO_WROPEN, "log ", logg->filename, + 0, 0); + } + + pdc_vfprintf(pdc, pdc_false, fp, fmt, ap); + + if (fp != stdout && fp != stderr) + fclose(fp); + } + else + { + pdc_vfprintf(pdc, pdc_false, logg->fp, fmt, ap); + fflush(logg->fp); + } +} + + +/* standard logging protocol functions for api function calls + */ +pdc_bool +pdc_enter_api_logg(pdc_core *pdc, const char *funame, pdc_bool enter_api, + const char *fmt, va_list args) +{ + pdc_bool retval = pdc_true; + + if (enter_api) + retval = pdc_enter_api(pdc, funame); + + if (retval) + { + /* logging option list defined by environment variable */ + if (pdc->loggenv == pdc_false) + { + char envname[32]; + const char *envval = NULL; + + pdc->loggenv = pdc_true; + sprintf(envname, LOGGINGENVNAME, pdc->prodname); + pdc_strtoupper(envname); + envval = pdc_getenv(envname); + if (envval != NULL) + { + pdc_set_logg_options(pdc, envval); + } +#if defined(WIN32) + else + { + char buffer[BUFSIZE]; + char regkey[128]; + HKEY hKey = NULL; + DWORD size, lType; + + sprintf(regkey, REGISTRYKEY, pdc->prodname, pdc->version); + + /* process registry entries */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0L, + (REGSAM) KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) + { + size = BUFSIZE - 2; + pdc_strtolower(envname); + if (RegQueryValueExA(hKey, envname, (LPDWORD) NULL, + &lType, (LPBYTE) buffer, &size) + == ERROR_SUCCESS && *buffer) + { + pdc_set_logg_options(pdc, buffer); + } + + RegCloseKey(hKey); + } + } + #endif + } + + if (pdc->logg != NULL && + pdc->logg->enabled && + pdc->logg->classlist[pdc->logg->sri][trc_api]) + { + /* time stamp */ + if (pdc->logg->classlist[pdc->logg->sri][trc_api] > 1) + { + pdc_time ltime; + + if (funame[0] == '\n') + { + pdc_logg(pdc, "\n"); + funame++; + } + + pdc_localtime(<ime); + pdc_logg(pdc, "[%02d:%02d:%02d] ", + ltime.hour, ltime.minute, ltime.second); + } + + /* function name */ + pdc_logg(pdc, "%s", funame); + + /* function arg list */ + pdc_logg_output(pdc, fmt, args); + } + } + + return retval; +} + +void +pdc_logg_exit_api(pdc_core *pdc, pdc_bool cleanup, const char *fmt, ...) +{ + if (fmt != NULL && pdc != NULL && + pdc->logg != NULL && + pdc->logg->enabled && + pdc->logg->classlist[pdc->logg->sri][trc_api]) + { + va_list ap; + + va_start(ap, fmt); + pdc_logg_output(pdc, fmt, ap); + va_end(ap); + } + + if (cleanup) + pdc_tmlist_cleanup(pdc); +} + +/* + * General logging functions + */ + +/* + * pdc_logg_enable() enables/disables logging + */ +void +pdc_logg_enable(pdc_core *pdc, pdc_bool enable) +{ + if (pdc != NULL && pdc->logg != NULL) + pdc->logg->enabled = enable; +} + +/* + * pdc_logg_is_enabled() returns pdc_true + * if logging is enabled for logging class 'pclass' and level 'level'. + * Otherwise pdc_false will be returned. + */ +pdc_bool +pdc_logg_is_enabled(pdc_core *pdc, int level, int pclass) +{ + return pdc->logg != NULL && + pdc->logg->enabled && + level <= pdc->logg->classlist[pdc->logg->sri][pclass]; +} + + +/* + * pdc_logg() writes formatted text in the current logging file + * without checking whether logging is enabled. + * This function should only be used in connection with + * pdc_logg_is_enabled(): + */ +void +pdc_logg(pdc_core *pdc, const char *fmt, ...) +{ + if (pdc != NULL && pdc->logg != NULL && pdc->logg->enabled) + { + va_list ap; + + va_start(ap, fmt); + pdc_logg_output(pdc, fmt, ap); + va_end(ap); + } +} + +/* + * pdc_logg_cond() writes formatted text in the current logging file + * if logging is enabled for logging class 'pclass' and level 'level'. + */ +void +pdc_logg_cond(pdc_core *pdc, int level, int pclass, const char *fmt, ...) +{ + if (pdc != NULL && pdc->logg != NULL && + pdc->logg->enabled && + level <= pdc->logg->classlist[pdc->logg->sri][pclass]) + { + va_list ap; + + va_start(ap, fmt); + pdc_logg_output(pdc, fmt, ap); + va_end(ap); + } +} + + +/* + * pdc_logg_getlevel() returns the current level for a logging class + */ +int +pdc_logg_getlevel(pdc_core *pdc, int pclass) +{ + if (pdc->logg != NULL && pdc->logg->enabled) + return (int) pdc->logg->classlist[pdc->logg->sri][pclass]; + else + return 0; +} + +/* + * pdc_logg_bitarr() writes the literal representation of a bit array + (including a descriptive message) in 1 line in the current logging file. + variable nbit must be <=32. + */ +void +pdc_logg_bitarr(pdc_core *pdc, const char *msg, const char *bitarr, int nbit) +{ + int i; + + pdc_logg(pdc,"%s = ", msg); + + nbit = MIN(nbit, 32); + for (i = 0; i <= nbit; i++) + { + if (!(i%8)) + { + pdc_logg(pdc, "|"); + } + if (i == nbit) + { + if (nbit == 8) + pdc_logg(pdc, " (%02X)", bitarr[0]); + else if (nbit == 16) + pdc_logg(pdc, " (%04X)", *((pdc_uint16 *) &bitarr[0])); + else if (nbit == 32) + pdc_logg(pdc, " (%08X)", *((pdc_uint32 *) &bitarr[0])); + pdc_logg(pdc, "\n"); + } + else + { + pdc_logg(pdc, "%s", pdc_getbit(bitarr, i) ? "1" : "0"); + } + } +} + + +/* + * pdc_logg_hexdump() writes the hexadecimal output of the specified buffer + (including a descriptive message) in the current logging file. + */ +void +pdc_logg_hexdump(pdc_core *pdc, const char *msg, const char *prefix, + const char *text, int tlen) +{ + int i, k; + pdc_byte ct; + + if (tlen == 1) + { + ct = (pdc_byte) text[0]; + pdc_logg(pdc, "%s%s: %02X '%c'\n", prefix, msg, ct, + pdc_logg_isprint((int) ct) ? ct : '.'); + } + else + { + pdc_logg(pdc,"%s%s:\n", prefix, msg); + + for (i = 0; i < tlen; i += 16) + { + pdc_logg(pdc,"%s", prefix); + for (k = 0; k < 16; ++k) + { + if (i + k < tlen) + { + ct = (pdc_byte) text[i + k]; + pdc_logg(pdc,"%02X ", ct); + } + else + pdc_logg(pdc," "); + } + + pdc_logg(pdc," "); + for (k = 0; k < 16; ++k) + { + if (i + k < tlen) + { + ct = (pdc_byte) text[i + k]; + pdc_logg(pdc,"%c", pdc_logg_isprint((int)ct) ? ct : '.'); + } + else + pdc_logg(pdc," "); + } + + pdc_logg(pdc,"\n"); + } + } +} + +/* + * pdc_warning() is the former function of PDFlib exception handling. + * Now, pdc_warning() calls the function pdc_set_warnmsg(), which writes + * only a warning message generated from a xx_generr.h file into the logfile, + * if warning = 1. + */ +void +pdc_warning(pdc_core *pdc, int errnum, const char *parm1, const char *parm2, + const char *parm3, const char *parm4) +{ + if (!pdc->smokerun) + pdc_set_warnmsg(pdc, errnum, parm1, parm2, parm3, parm4); +} + +/* + * utility function for logging a Unicode character + * + */ +void +pdc_logg_unichar(pdc_core *pdc, int unichar, pdc_bool kfill, pdc_bool newline) +{ + if (unichar > 0xFFFF) + { + pdc_logg(pdc, "U+%05X", unichar); + } + else + { + pdc_logg(pdc, "U+%04X", unichar); + + if ((unichar >= PDC_UNICODE_SPACE && unichar <= PDC_UNICODE_DELETE) || + (unichar >= PDC_UNICODE_NBSP && unichar <= PDC_UNICODE_MAXLATIN1)) + { + char c = (char) unichar; + + + pdc_logg(pdc, " [%c]", c); + } + else if (kfill) + { + pdc_logg(pdc, " "); + } + } + + if (newline) + pdc_logg(pdc, "\n"); +} + +/* + * utility function for logging a Unicode string + * + */ +static const pdc_keyconn pdc_ascii_escape_keylist[] = +{ + {"a", 0x07}, + {"b", 0x08}, + {"e", 0x1B}, + {"f", 0x0C}, + {"n", 0x0A}, + {"r", 0x0D}, + {"t", 0x09}, + {"v", 0x0B}, + {NULL, 0} +}; + +void +pdc_logg_unitext(pdc_core *pdc, pdc_ushort *ustext, int len, pdc_bool newline) +{ + int i; + pdc_ushort usv; + const char *s; + char c; + + pdc_logg(pdc, "\""); + for (i = 0; i < len; i++) + { + usv = ustext[i]; + if (usv > PDC_UNICODE_MAXLATIN1) + { + pdc_logg(pdc, "\\u%04X", usv); + } + else + { + if (usv < PDC_UNICODE_SPACE) + { + s = pdc_get_keyword((int) usv, pdc_ascii_escape_keylist); + if (s != NULL) + { + pdc_logg(pdc, "\\%s", s); + continue; + } + } + + if ((usv >= PDC_UNICODE_SPACE && usv <= PDC_UNICODE_DELETE) || + (usv >= PDC_UNICODE_NBSP && usv <= PDC_UNICODE_MAXLATIN1)) + { + c = (char) usv; + + + pdc_logg(pdc, "%c", c); + } + else + { + pdc_logg(pdc, "\\x%02X", usv); + } + } + } + + pdc_logg(pdc, "\""); + if (newline) + pdc_logg(pdc, "\n"); +} + + diff --git a/src/pdflib/pdcore/pc_resource.h b/src/pdflib/pdcore/pc_resource.h new file mode 100644 index 0000000..f83498c --- /dev/null +++ b/src/pdflib/pdcore/pc_resource.h @@ -0,0 +1,124 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_resource.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Resource routines + * + */ + +#ifndef PC_RESOURCE_H +#define PC_RESOURCE_H + +/* pdcore logg classes (maximal PDC_CLASSLIST_SIZE) */ +typedef enum +{ + trc_other = 0, /* other classes */ + trc_api, /* API function call logging */ + trc_encoding, /* encoding, cmap end textformat logging */ + trc_digsig, /* digital signatures */ + trc_filesearch, /* file search logging */ + trc_font, /* font logging */ + trc_image, /* image and template logging */ + trc_memory, /* memory logging */ + trc_optlist, /* optlist logging */ + trc_pcos, /* pcos logging */ + trc_pdi, /* pdi logging */ + trc_resource, /* resource logging */ + trc_shadow, /* shadow logging */ + trc_text, /* text logging */ + trc_textflow, /* textflow logging */ + trc_table, /* table logging */ + trc_user, /* user logging */ + trc_warning, /* logging of disabled warnings */ + trc_wordfinder, /* word finder logging */ + trc_xmp, /* xmp logging */ + trc_zones /* zones logging */ +} +pdc_logg_class; + +/* string code kinds */ +typedef enum +{ + strform_readable, + strform_readable0, + strform_octal, + strform_hexa, + strform_java +} +pdc_strform_kind; + + +typedef struct pdc_res_s pdc_res; +typedef struct pdc_category_s pdc_category; +typedef struct pdc_reslist_s pdc_reslist; +typedef struct pdc_virtfile_s pdc_virtfile; +typedef struct pdc_loggdef_s pdc_loggdef; + + +/* -------------------------- resource handling ----------------------------- */ + +pdc_reslist *pdc_new_reslist(pdc_core *pdc); +void pdc_delete_reslist(pdc_core *pdc); +void pdc_set_resourcefile(pdc_core *pdc, const char *filename); +void pdc_add_resource_ext(pdc_core *pdc, const char *category, + const char *resname, const char *resvalue, pdc_encoding enc, + int codepage); +void pdc_add_resource(pdc_core *pdc, const char *category, + const char *resname, const char *resvalue); +const char *pdc_find_resource(pdc_core *pdc, const char *category, + const char *name); +const char *pdc_find_resource_nr(pdc_core *pdc, const char *category, int nr); +const char *pdc_get_resourcefile(pdc_core *pdc); + + + +/* ----------------------- virtual file handling ---------------------------- */ + +void pdc__create_pvf(pdc_core *pdc, const char *filename, + const void *data, size_t size, const char *optlist); +int pdc__delete_pvf(pdc_core *pdc, const char *filename); +void pdc_lock_pvf(pdc_core *pdc, const char *filename); +void pdc_unlock_pvf(pdc_core *pdc, const char *filename); +void pdc_delete_filesystem(pdc_core *pdc); + + +/* ----------------------- logging file handling ---------------------------- */ + +void pdc_delete_logg(pdc_core *pdc); +void pdc_set_logg_options(pdc_core *pdc, const char *optlist); +const char *pdc_print_loggstring(pdc_core *pdc, const char *str, int len); +pdc_bool pdc_enter_api_logg(pdc_core *pdc, const char *funame, + pdc_bool enter_api, const char *fmt, va_list args); +void pdc_logg_exit_api(pdc_core *pdc, pdc_bool cleanup, + const char *fmt, ...); +void pdc_logg_enable(pdc_core *pdc, pdc_bool enable); +pdc_bool pdc_logg_is_enabled(pdc_core *pdc, int level, int pclass); +void pdc_logg(pdc_core *pdc, const char *fmt, ...); +void pdc_logg_cond(pdc_core *pdc, int level, int pclass, + const char *fmt, ...); +void pdc_logg_bitarr(pdc_core *pdc, const char *msg, const char *bitarr, + int nbit); +void pdc_logg_hexdump(pdc_core *pdc, const char *msg, const char *prefix, + const char *text, int tlen); +void pdc_warning(pdc_core *pdc, int errnum, const char *parm1, + const char *parm2, const char *parm3, const char *parm4); + +void pdc_logg_unichar(pdc_core *pdc, int unichar, pdc_bool kfill, + pdc_bool newline); +void pdc_logg_unitext(pdc_core *pdc, pdc_ushort *ustext, int len, + pdc_bool newline); + +int pdc_logg_getlevel(pdc_core *pdc, int pclass); + +#endif /* PC_RESOURCE_H */ + diff --git a/src/pdflib/pdcore/pc_scan.c b/src/pdflib/pdcore/pc_scan.c new file mode 100644 index 0000000..94e713a --- /dev/null +++ b/src/pdflib/pdcore/pc_scan.c @@ -0,0 +1,19 @@ +/*---------------------------------------------------------------------------* + | PDC -- PDF content stream parser | + +---------------------------------------------------------------------------+ + | Copyright (c) 2002 PDFlib GmbH. All rights reserved. | + *---------------------------------------------------------------------------* + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_scan.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ */ + + +#include "pc_util.h" +#include "pc_strconst.h" +#include "pc_ctype.h" +#include "pc_scan.h" + +#include "pc_string.h" + + diff --git a/src/pdflib/pdcore/pc_scan.h b/src/pdflib/pdcore/pc_scan.h new file mode 100644 index 0000000..1b31e54 --- /dev/null +++ b/src/pdflib/pdcore/pc_scan.h @@ -0,0 +1,15 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_scan.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ */ + +#ifndef PC_SCAN_H_INCLUDED +#define PC_SCAN_H_INCLUDED + + +#endif /* PC_SCAN_H_INCLUDED */ diff --git a/src/pdflib/pdcore/pc_scantok.h b/src/pdflib/pdcore/pc_scantok.h new file mode 100644 index 0000000..84420c9 --- /dev/null +++ b/src/pdflib/pdcore/pc_scantok.h @@ -0,0 +1,14 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | Proprietary source code -- do not redistribute! | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_scantok.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDCORE generic token scanner standard tokens. + * + */ + diff --git a/src/pdflib/pdcore/pc_scope.c b/src/pdflib/pdcore/pc_scope.c new file mode 100644 index 0000000..73daac2 --- /dev/null +++ b/src/pdflib/pdcore/pc_scope.c @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_scope.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Scoping routines and macros + * + */ + +#include "pc_util.h" +#include "pc_scope.h" +#include "pc_file.h" +#include "pc_ctype.h" + + +static void pdc_check_scope_core(void) {} + diff --git a/src/pdflib/pdcore/pc_scope.h b/src/pdflib/pdcore/pc_scope.h new file mode 100644 index 0000000..8c8a8f6 --- /dev/null +++ b/src/pdflib/pdcore/pc_scope.h @@ -0,0 +1,23 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_scope.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Scoping routines and macros + * + */ + +#ifndef PC_SCOPE_H +#define PC_SCOPE_H + + +#endif /* PC_SCOPE_H */ diff --git a/src/pdflib/pdcore/pc_strconst.h b/src/pdflib/pdcore/pc_strconst.h new file mode 100644 index 0000000..2e96842 --- /dev/null +++ b/src/pdflib/pdcore/pc_strconst.h @@ -0,0 +1,5 @@ +#ifndef PC_STRCONST_H_INCLUDED +#define PC_STRCONST_H_INCLUDED + +#endif /* PC_STRCONST_H_INCLUDED */ + diff --git a/src/pdflib/pdcore/pc_string.c b/src/pdflib/pdcore/pc_string.c new file mode 100644 index 0000000..f792ac1 --- /dev/null +++ b/src/pdflib/pdcore/pc_string.c @@ -0,0 +1,514 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_string.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * The core string classes. + * + */ + +#include <string.h> + +#include "pc_util.h" +#include "pc_string.h" +#include "pc_ctype.h" + +#undef SBUF_RESERVE +#define SBUF_RESERVE PDC_STR_INLINE_CAP + + +/* TODO: + + - think over the pdcore temporary memory model. + + - s->buf should be reference-counted (delayed copy). +*/ + +void pdc_init_strings(pdc_core *pdc) +{ + pdc->bstr_pool = pdc_mp_new(pdc, sizeof (pdc_bstr)); + pdc->ustr_pool = pdc_mp_new(pdc, sizeof (pdc_ustr)); +} /* pdc_init_strings */ + +void pdc_cleanup_strings(pdc_core *pdc) +{ + pdc_mp_delete(pdc->bstr_pool); + pdc_mp_delete(pdc->ustr_pool); +} /* pdc_init_strings */ + + +/************************************************************************/ +/* */ +/* string object construction and deletion. */ +/* */ +/************************************************************************/ + +void +pdc_bs_boot(pdc_core *pdc, pdc_bstr *s) +{ + s->pdc = pdc; + s->buf = (pdc_byte *) 0; + s->len = 0; + s->cap = PDC_STR_INLINE_CAP; +} /* pdc_bs_boot */ + +void +pdc_us_boot(pdc_core *pdc, pdc_ustr *s) +{ + s->pdc = pdc; + s->buf = (pdc_ucval *) 0; + s->len = 0; + s->cap = PDC_STR_INLINE_CAP; +} /* pdc_us_boot */ + + +void +pdc_bs_shutdown(pdc_bstr *s) +{ + if (s->buf != (pdc_byte *) 0) + pdc_free(s->pdc, s->buf); + + pdc_bs_boot(s->pdc, s); +} /* pdc_bs_shutdown */ + +void +pdc_us_shutdown(pdc_ustr *s) +{ + if (s->buf != (pdc_ucval *) 0) + pdc_free(s->pdc, s->buf); + + pdc_us_boot(s->pdc, s); +} /* pdc_us_shutdown */ + + +#undef USE_POOL +#define USE_POOL + +pdc_bstr * +pdc_bs_new(pdc_core *pdc) +{ +#ifndef USE_POOL + static const char fn[] = "pdc_bs_new"; + + pdc_bstr *result = (pdc_bstr *) pdc_malloc(pdc, sizeof (pdc_bstr), fn); +#else + pdc_bstr *result = (pdc_bstr *) pdc_mp_alloc(pdc->bstr_pool); +#endif + + pdc_bs_boot(pdc, result); + return result; +} /* pdc_bs_new */ + +pdc_ustr * +pdc_us_new(pdc_core *pdc, const pdc_ucval *src, size_t len) +{ +#ifndef USE_POOL + static const char fn[] = "pdc_us_new"; + + pdc_ustr *result = (pdc_ustr *) pdc_malloc(pdc, sizeof (pdc_ustr), fn); +#else + pdc_ustr *result = (pdc_ustr *) pdc_mp_alloc(pdc->ustr_pool); +#endif + + pdc_us_boot(pdc, result); + pdc_us_write(result, src, len); + return result; +} /* pdc_us_new */ + + +pdc_bstr * +pdc_bs_dup(const pdc_bstr *src) +{ + const pdc_byte * buf = src->buf ? src->buf : src->buf0; + pdc_bstr * result = pdc_bs_new(src->pdc); + + pdc_bs_write(result, buf, src->len); + return result; +} /* pdc_bs_dup */ + +pdc_ustr * +pdc_us_dup(const pdc_ustr *src) +{ + const pdc_ucval *buf = src->buf ? src->buf : src->buf0; + + return pdc_us_new(src->pdc, buf, src->len); +} /* pdc_us_dup */ + + +void +pdc_bs_delete(pdc_bstr *s) +{ + pdc_bs_shutdown(s); +#ifndef USE_POOL + pdc_free(s->pdc, s); +#else + pdc_mp_free(s->pdc->bstr_pool, s); +#endif +} /* pdc_bs_delete */ + +void +pdc_us_delete(pdc_ustr *s) +{ + pdc_us_shutdown(s); +#ifndef USE_POOL + pdc_free(s->pdc, s); +#else + pdc_mp_free(s->pdc->ustr_pool, s); +#endif +} /* pdc_bs_delete */ + + +/************************************************************************/ +/* */ +/* "getters". */ +/* */ +/************************************************************************/ + +size_t +pdc_bs_length(const pdc_bstr *s) +{ + return s->len; +} /* pdc_bs_length */ + +size_t +pdc_us_length(const pdc_ustr *s) +{ + return s->len; +} /* pdc_us_length */ + + +pdc_byte +pdc_bs_get(const pdc_bstr *s, int idx) +{ + static const char fn[] = "pdc_bs_get"; + + const pdc_byte *buf = s->buf ? s->buf : s->buf0; + + if (idx < 0 || s->len <= (size_t) idx) + pdc_error(s->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0); + + return buf[idx]; +} /* pdc_bs_get */ + +pdc_ucval +pdc_us_get(const pdc_ustr *s, int idx) +{ + static const char fn[] = "pdc_us_get"; + + const pdc_ucval *buf = s->buf ? s->buf : s->buf0; + + if (idx < 0 || s->len <= (size_t) idx) + pdc_error(s->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0); + + return buf[idx]; +} /* pdc_us_get */ + + +const pdc_byte * +pdc_bs_get_cptr(const pdc_bstr *s) +{ + static const pdc_byte empty = 0; + + /* TODO: avoid the ugly "un-const" cast. */ + pdc_byte *buf = (pdc_byte *) (s->buf ? s->buf : s->buf0); + + if (!s->len) + return ∅ + + buf[s->len] = 0; + return buf; +} + +const pdc_byte * +pdc_us_get_cptr(const pdc_ustr *s) +{ + static const pdc_byte empty = 0; + + const pdc_ucval *buf = s->buf ? s->buf : s->buf0; + + if (!s->len) + return ∅ + + return (const pdc_byte *) buf; +} + + +/************************************************************************/ +/* */ +/* "modifiers". */ +/* */ +/************************************************************************/ + +void +pdc_bs_copy(pdc_bstr *dst, const pdc_bstr *src) +{ + const pdc_byte *buf = src->buf ? src->buf : src->buf0; + + dst->len = 0; + + if (src->len) + pdc_bs_write(dst, buf, src->len); +} /* pdc_bs_copy */ + +void +pdc_us_copy(pdc_ustr *dst, const pdc_ustr *src) +{ + const pdc_ucval *buf = src->buf ? src->buf : src->buf0; + + dst->len = 0; + + if (src->len) + pdc_us_write(dst, buf, src->len); +} /* pdc_us_copy */ + + +void +pdc_bs_substr(pdc_bstr *dst, const pdc_bstr *src, size_t pos, size_t len) +{ + static const char fn[] = "pdc_bs_substr"; + + const pdc_byte *buf = src->buf ? src->buf : src->buf0; + + if ((pos < 0) || (len < 0) || (pos > src->len) || ((pos + len) > src->len)) + pdc_error(src->pdc, PDC_E_INT_ILLARG, fn, 0, 0, 0); + + dst->len = 0; + pdc_bs_write(dst, buf + pos, len); +} /* pdc_bs_substr */ + +void +pdc_us_substr(pdc_ustr *dst, const pdc_ustr *src, size_t pos, size_t len) +{ + static const char fn[] = "pdc_us_substr"; + + const pdc_ucval *buf = src->buf ? src->buf : src->buf0; + + if ((pos < 0) || (len < 0) || (pos > src->len) || ((pos + len) > src->len)) + pdc_error(src->pdc, PDC_E_INT_ILLARG, fn, 0, 0, 0); + + dst->len = 0; + pdc_us_write(dst, buf + pos, len); +} /* pdc_us_substr */ + + +void +pdc_bs_concat(pdc_bstr *dst, const pdc_bstr *src) +{ + const pdc_byte *buf = src->buf ? src->buf : src->buf0; + + if (src->len) + pdc_bs_write(dst, buf, src->len); +} /* pdc_bs_concat */ + +void +pdc_us_concat(pdc_ustr *dst, const pdc_ustr *src) +{ + const pdc_ucval *buf = src->buf ? src->buf : src->buf0; + + if (src->len) + pdc_us_write(dst, buf, src->len); +} /* pdc_us_concat */ + + +void +pdc_bs_set(pdc_bstr *s, int idx, pdc_byte val) +{ + static const char fn[] = "pdc_bs_set"; + + pdc_byte *buf = s->buf ? s->buf : s->buf0; + + if (idx < 0 || s->len <= (size_t) idx) + pdc_error(s->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0); + + buf[idx] = val; +} /* pdc_bs_set */ + +void +pdc_us_set(pdc_ustr *s, int idx, pdc_ucval val) +{ + static const char fn[] = "pdc_us_set"; + + pdc_ucval *buf = s->buf ? s->buf : s->buf0; + + if (idx < 0 || s->len <= (size_t) idx) + pdc_error(s->pdc, PDC_E_INT_ARRIDX, + pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0); + + buf[idx] = val; +} /* pdc_us_set */ + + +void +pdc_bs_tolower(pdc_bstr *s) +{ + pdc_byte * buf = s->buf ? s->buf : s->buf0; + int i; + + for (i = 0; i < (int) s->len; ++i) + buf[i] = pdc_tolower(buf[i]); +} /* pdc_bs_tolower */ + +void +pdc_bs_toupper(pdc_bstr *s) +{ + pdc_byte * buf = s->buf ? s->buf : s->buf0; + int i; + + for (i = 0; i < (int) s->len; ++i) + buf[i] = pdc_toupper(buf[i]); +} /* pdc_bs_toupper */ + + +/************************************************************************/ +/* */ +/* stream-like functions. */ +/* */ +/************************************************************************/ + +void +pdc_bs_write(pdc_bstr *dst, const pdc_byte *src, size_t len) +{ + static const char fn[] = "pdc_bs_write"; + + pdc_byte *buf = dst->buf ? dst->buf : dst->buf0; + + if (!src || !len) + return; + + if (dst->cap < dst->len + len + 1) + { + dst->cap = dst->len + len + 1 + SBUF_RESERVE; + + if (!dst->buf) + { + dst->buf = (pdc_byte *) pdc_malloc(dst->pdc, dst->cap, fn); + memcpy(dst->buf, dst->buf0, dst->len); + } + else + { + dst->buf = (pdc_byte *) pdc_realloc(dst->pdc, + dst->buf, dst->cap, fn); + } + + buf = dst->buf; + } + + memcpy(buf + dst->len, src, len); + dst->len += len; +} /* pdc_bs_write */ + + +void +pdc_bs_puts(pdc_bstr *dst, const pdc_byte *src) +{ + if (!src) + return; + + pdc_bs_write(dst, src, strlen(src)); +} /* pdc_bs_puts */ + + +void +pdc_us_write(pdc_ustr *dst, const pdc_ucval *src, size_t len) +{ + static const char fn[] = "pdc_us_write"; + + pdc_ucval *buf = dst->buf ? dst->buf : dst->buf0; + + if (!src || len == 0) + return; + + if (dst->cap < dst->len + len) + { + dst->cap = dst->len + len + SBUF_RESERVE; + + if (!dst->buf) + { + dst->buf = (pdc_ucval *) + pdc_malloc(dst->pdc, dst->cap * sizeof (pdc_ucval), fn); + + memcpy(dst->buf, dst->buf0, dst->len * sizeof (pdc_ucval)); + } + else + { + dst->buf = (pdc_ucval *) pdc_realloc(dst->pdc, + dst->buf, dst->cap * sizeof (pdc_ucval), fn); + } + + buf = dst->buf; + } + + memcpy(buf + dst->len, src, len * sizeof (pdc_ucval)); + dst->len += len; +} /* pdc_us_write */ + + +void +pdc_bs_rewrite(pdc_bstr *s) +{ + s->len = 0; +} /* pdc_bs_rewrite */ + +void +pdc_us_rewrite(pdc_ustr *s) +{ + s->len = 0; +} /* pdc_us_rewrite */ + + +void +pdc_bs_putc(pdc_bstr *s, pdc_byte val) +{ + pdc_bs_write(s, &val, 1); +} /* pdc_bs_putc */ + +void +pdc_us_putc(pdc_ustr *s, pdc_ucval val) +{ + pdc_us_write(s, &val, 1); +} /* pdc_us_putc */ + + +/************************************************************************/ +/* */ +/* other utilities. */ +/* */ +/************************************************************************/ + +int +pdc_bs_compare(const pdc_bstr *s1, const pdc_bstr *s2) +{ + const char *buf1 = (const char *) (s1->buf ? s1->buf : s1->buf0); + const char *buf2 = (const char *) (s2->buf ? s2->buf : s2->buf0); + int result; + + if (s1->len < s2->len) + { + if ((result = strncmp(buf1, buf2, s1->len)) != 0) + return result; + + return -1; + } + + if (s2->len < s1->len) + { + if ((result = strncmp(buf1, buf2, s2->len)) != 0) + return result; + + return +1; + } + + return strncmp(buf1, buf2, s1->len); +} /* pdc_bs_compare */ diff --git a/src/pdflib/pdcore/pc_string.h b/src/pdflib/pdcore/pc_string.h new file mode 100644 index 0000000..631635f --- /dev/null +++ b/src/pdflib/pdcore/pc_string.h @@ -0,0 +1,267 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_string.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * The core string classes. + * + */ + +#ifndef PC_STRING_H +#define PC_STRING_H + +#include "pc_core.h" + +/* there are two pdcore string classes. the structures "behind" +** these classes are opaque. conceptually, pdc_bstr objects are +** sequences of 'pdc_byte' (unsigned 8-bit entities), whereas +** pdc_ustr objects are sequences of 'pdc_ucval' ("unicode value"; +** unsigned 32-bit entities). +*/ +#ifndef PDC_STRINGS_DEFINED +#define PDC_STRINGS_DEFINED +typedef struct pdc_bstr_s pdc_bstr; /* byte strings */ +typedef struct pdc_ustr_s pdc_ustr; /* unicode strings */ +#endif + + +/* TODO: naming conventions for "per module" init/cleanup */ +void pdc_init_strings(pdc_core *pdc); +void pdc_cleanup_strings(pdc_core *pdc); + + +/************************************************************************/ +/* */ +/* string object construction and deletion. */ +/* */ +/************************************************************************/ + +/* convert raw memory into an (empty) string object. +*/ +void pdc_bs_boot(pdc_core *pdc, pdc_bstr *s); +void pdc_us_boot(pdc_core *pdc, pdc_ustr *s); + +/* release all resources allocated by a string object (if any). +*/ +void pdc_bs_shutdown(pdc_bstr *s); +void pdc_us_shutdown(pdc_ustr *s); + +/* allocate a new (empty) pdc_bstr object. +*/ +pdc_bstr *pdc_bs_new(pdc_core *pdc); + +/* allocate a new pdc_ustr object and initialize its contents with the +** 'n' values from 'src'. if 'src' is null or 'n' is zero, +** an empty string object is constructed. +*/ +pdc_ustr *pdc_us_new(pdc_core *pdc, const pdc_ucval *src, size_t n); + +/* TODO: more constructors for various "source" types, eg. +** +pdc_ustr *pdc_us_new_utf16(pdc_core *pdc, const pdc_ushort *src, size_t n); +pdc_ustr *pdc_us_new_utf8(pdc_core *pdc, const pdc_byte *src, size_t n); +*/ + +/* return a copy of string 'src' ("copy constructor"). +*/ +pdc_bstr *pdc_bs_dup(const pdc_bstr *src); +pdc_ustr *pdc_us_dup(const pdc_ustr *src); + +/* delete a string object explicitly ("destructor"). +*/ +void pdc_bs_delete(pdc_bstr *s); +void pdc_us_delete(pdc_ustr *s); + +/************************************************************************/ +/* */ +/* "getters". */ +/* */ +/************************************************************************/ + +/* get the length of a string object in bytes or unicode values, resp. +*/ +size_t pdc_bs_length(const pdc_bstr *s); +size_t pdc_us_length(const pdc_ustr *s); + +/* string component access (range checked). +*/ +pdc_byte pdc_bs_get(const pdc_bstr *s, int idx); +pdc_ucval pdc_us_get(const pdc_ustr *s, int idx); + +/* TODO: try to get rid of that. */ +const pdc_byte *pdc_bs_get_cptr(const pdc_bstr *s); +const pdc_byte *pdc_us_get_cptr(const pdc_ustr *s); + +/************************************************************************/ +/* */ +/* "modifiers". */ +/* */ +/************************************************************************/ + +/* copy 'src' to 'dst' ("assignment operator"). +*/ +void pdc_bs_copy(pdc_bstr *dst, const pdc_bstr *src); +void pdc_us_copy(pdc_ustr *dst, const pdc_ustr *src); + +/* copy part of 'src' to 'dst'. +*/ +void pdc_bs_substr(pdc_bstr *dst, const pdc_bstr *src, + size_t pos, size_t len); +void pdc_us_substr(pdc_ustr *dst, const pdc_ustr *src, + size_t pos, size_t len); + +/* insert 'src' into 'dst' at 'pos'. +*/ +void pdc_bs_insert(pdc_bstr *dst, const pdc_bstr *src, size_t pos); +void pdc_us_insert(pdc_ustr *dst, const pdc_ustr *src, size_t pos); + +/* append 'src' to 'dst'. +*/ +void pdc_bs_concat(pdc_bstr *dst, const pdc_bstr *src); +void pdc_us_concat(pdc_ustr *dst, const pdc_ustr *src); + +/* string component access (range checked). +*/ +void pdc_bs_set(pdc_bstr *s, int idx, pdc_byte val); +void pdc_us_set(pdc_ustr *s, int idx, pdc_ucval val); + +/* case conversion. +*/ +void pdc_bs_tolower(pdc_bstr *s); +void pdc_bs_toupper(pdc_bstr *s); + +/************************************************************************/ +/* */ +/* stream-like functions. */ +/* */ +/************************************************************************/ + +/* append 'n' values from 'src' to 'dst'. if 'n' is zero, +** or 'src' is null, 'dst' remains unchanged. +*/ +void pdc_bs_write(pdc_bstr *dst, const pdc_byte *src, size_t n); + +/* append the null terminated string 'src' to 'dst'. +*/ +void pdc_bs_puts(pdc_bstr *dst, const pdc_byte *src); + +/* append 'n' values from 'src' to 'dst'. if 'src' is null or 'n' +** is zero, 'dst' remains unchanged. +*/ +void pdc_us_write(pdc_ustr *dst, const pdc_ucval *src, size_t n); + +void pdc_us_write_utf16(pdc_ustr *dst, const pdc_ushort *src, size_t n); + +/* TODO: more writer functions for various "source" types, eg. +** +void pdc_us_write_utf8(pdc_ustr *dst, const pdc_byte *src, size_t n); +*/ + +/* reset 's' to an empty stream object. +*/ +void pdc_bs_rewrite(pdc_bstr *s); +void pdc_us_rewrite(pdc_ustr *s); + +/* append a single byte (or unicode value, resp.) to a string object. +*/ +void pdc_bs_putc(pdc_bstr *s, pdc_byte val); +void pdc_us_putc(pdc_ustr *s, pdc_ucval val); + +/* TODO: stream-like read access. again, the read functions for pdc_ustr +** objects will be available in several flavors in order to support +** conversion to various "external" formats. +** +void pdc_bs_reset(pdc_bstr *s); +void pdc_us_reset(pdc_ustr *s); +void pdc_bs_seek(pdc_bstr *s, size_t pos); +void pdc_us_seek(pdc_ustr *s, size_t pos); +size_t pdc_bs_tell(const pdc_bstr *s); +size_t pdc_us_tell(const pdc_ustr *s); +size_t pdc_bs_read(pdc_bstr *src, pdc_byte *dst, size_t n); +size_t pdc_us_read(pdc_ustr *src, pdc_ucval *dst, size_t n); +size_t pdc_us_read_utf16(pdc_ustr *src, pdc_ushort *dst, size_t n); +size_t pdc_us_read_utf8(pdc_ustr *src, pdc_byte *dst, size_t n); +*/ + +/************************************************************************/ +/* */ +/* other utilities. */ +/* */ +/************************************************************************/ + +int pdc_bs_compare(const pdc_bstr *s1, const pdc_bstr *s2); + +/************************************************************************/ +/* */ +/* PRIVATE SECTION */ +/* */ +/* the declarations below are strictly private to the implementation */ +/* module, and must not be used by any client modules! */ +/* */ +/************************************************************************/ + +#define PDC_STR_INLINE_CAP 16 + +struct pdc_bstr_s +{ + pdc_core * pdc; + + pdc_byte buf0[PDC_STR_INLINE_CAP]; + pdc_byte * buf; + size_t len; + size_t cap; +}; + +struct pdc_ustr_s +{ + pdc_core * pdc; + + pdc_ucval buf0[PDC_STR_INLINE_CAP]; + pdc_ucval * buf; + size_t len; + size_t cap; +}; + +#if 0 +/* string representation. +*/ +typedef struct +{ + pdc_byte * buf; /* contents */ + size_t cap; /* capacity (unit: pdc_byte) */ + size_t len; /* length (unit: pdc_byte) */ + int ref; /* reference count */ +} pdc_bs_rep; + +typedef struct +{ + pdc_ucval * buf; /* contents */ + size_t cap; /* capacity (unit: pdc_ucval) */ + size_t len; /* length (unit: pdc_ucval) */ + int ref; /* reference count */ +} pdc_us_rep; + + +struct pdc_bstr_s +{ + pdc_core * pdc; + pdc_bs_rep *rep; +}; + +struct pdc_ustr_s +{ + pdc_core * pdc; + pdc_us_rep *rep; +}; +#endif + +#endif /* PC_STRING_H */ diff --git a/src/pdflib/pdcore/pc_unicode.c b/src/pdflib/pdcore/pc_unicode.c new file mode 100644 index 0000000..7b32022 --- /dev/null +++ b/src/pdflib/pdcore/pc_unicode.c @@ -0,0 +1,1886 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_unicode.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib Unicode converting routines + * + */ + +#define PC_UNICODE_C + +#include "pc_util.h" + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif /* WIN32 */ + +/* + * The following source is based on Unicode's original source + * code ConvertUTF.c. It has been adapted to PDFlib programming + * conventions. + * + * The original file had the following notice: + * + * Copyright 2001 Unicode, Inc. + * + * Limitations on Rights to Redistribute This Code + * + * Author: Mark E. Davis, 1994. + * Rev History: Rick McGowan, fixes & updates May 2001. + * + * + * Functions for conversions between UTF32, UTF-16, and UTF-8. + * These funtions forming a complete set of conversions between + * the three formats. UTF-7 is not included here. + * + * Each of these routines takes pointers to input buffers and output + * buffers. The input buffers are const. + * + * Each routine converts the text between *sourceStart and sourceEnd, + * putting the result into the buffer between *targetStart and + * targetEnd. Note: the end pointers are *after* the last item: e.g. + * *(sourceEnd - 1) is the last item. + * + * The return result indicates whether the conversion was successful, + * and if not, whether the problem was in the source or target buffers. + * (Only the first encountered problem is indicated.) + * + * After the conversion, *sourceStart and *targetStart are both + * updated to point to the end of last text successfully converted in + * the respective buffers. + * + * Input parameters: + * sourceStart - pointer to a pointer to the source buffer. + * The contents of this are modified on return so that + * it points at the next thing to be converted. + * targetStart - similarly, pointer to pointer to the target buffer. + * sourceEnd, targetEnd - respectively pointers to the ends of the + * two buffers, for overflow checking only. + * + * These conversion functions take a pdc_convers_flags argument. When this + * flag is set to strict, both irregular sequences and isolated surrogates + * will cause an error. When the flag is set to lenient, both irregular + * sequences and isolated surrogates are converted. + * + * Whether the flag is strict or lenient, all illegal sequences will cause + * an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, + * or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + * must check for illegal sequences. + * + * When the flag is set to lenient, characters over 0x10FFFF are converted + * to the replacement character; otherwise (when the flag is set to strict) + * they constitute an error. + * + * Output parameters: + * The value "sourceIllegal" is returned from some routines if the input + * sequence is malformed. When "sourceIllegal" is returned, the source + * value will point to the illegal value that caused the problem. E.g., + * in UTF-8 when a sequence is malformed, it points to the start of the + * malformed sequence. + * + * Author: Mark E. Davis, 1994. + * Rev History: Rick McGowan, fixes & updates May 2001. + * + */ + +/* + * The following 4 definitions are compiler-specific. + * The C standard does not guarantee that wchar_t has at least + * 16 bits, so wchar_t is no less portable than unsigned short! + * All should be unsigned values to avoid sign extension during + * bit mask & shift operations. + */ + +/* Unicode original: +typedef unsigned long UTF32; at least 32 bits +typedef unsigned short UTF16; at least 16 bits +*/ + +typedef unsigned int UTF32; /* 32 bits */ +typedef unsigned short UTF16; /* 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ + +/* Some fundamental constants */ +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF32toUTF16 ( + UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, const UTF16* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + if ((flags == strictConversion) && + (ch >= UNI_SUR_HIGH_START && + ch <= UNI_SUR_LOW_END)) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = (UTF16) ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + result = targetExhausted; + break; + } + ch -= halfBase; + *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF16toUTF32 ( + UTF16** sourceStart, UTF16* sourceEnd, + UTF32** targetStart, const UTF32* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + ch = *source++; + if (ch >= UNI_SUR_HIGH_START && + ch <= UNI_SUR_HIGH_END && + source < sourceEnd) { + ch2 = *source; + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { + /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else if ((flags == strictConversion) && + (ch >= UNI_SUR_LOW_START && + ch <= UNI_SUR_LOW_END)) { + /* an unpaired low surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + if (target >= targetEnd) { + result = targetExhausted; + break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "pdc_convertUTF16toUTF32 illegal seq 0x%04x,%04x\n", + ch, ch2); + fflush(stderr); +} +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +#if 0 +static const char +pdc_get_trailingBytesForUTF8(int i) { + return (trailingBytesForUTF8[i]); +} +#endif + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { + 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL +}; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... six byte sequence.) + */ +static const UTF8 firstByteMark[7] = { + 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC +}; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "pdc_islegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF16toUTF8 ( + UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, const UTF8* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && + ch <= UNI_SUR_HIGH_END && + source < sourceEnd) { + UTF32 ch2 = *source; + if (ch2 >= UNI_SUR_LOW_START && + ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { + /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else if ((flags == strictConversion) && + (ch >= UNI_SUR_LOW_START && + ch <= UNI_SUR_LOW_END)) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x200000) { bytesToWrite = 4; + } else { bytesToWrite = 2; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from pdc_convertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns pdc_false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static pdc_bool +pdc_islegalUTF8(UTF8 *source, int length) { + UTF8 a; + UTF8 *srcptr = source+length; + switch (length) { + default: return pdc_false; + /* Everything else falls through when "pdc_true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return pdc_false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return pdc_false; + case 2: if ((a = (*--srcptr)) > 0xBF) return pdc_false; + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return pdc_false; break; + case 0xF0: if (a < 0x90) return pdc_false; break; + case 0xF4: if (a > 0x8F) return pdc_false; break; + default: if (a < 0x80) return pdc_false; + } + case 1: if (*source >= 0x80 && *source < 0xC2) return pdc_false; + if (*source > 0xF4) return pdc_false; + } + return pdc_true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +#if 0 +static pdc_bool pdc_islegalUTF8sequence(UTF8 *source, UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return pdc_false; + } + return pdc_islegalUTF8(source, length); +} +#endif + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF8toUTF16 ( + UTF8** sourceStart, UTF8* sourceEnd, + UTF16** targetStart, const UTF16* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0L; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; + break; + } + /* Do this check whether lenient or strict */ + if (! pdc_islegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + result = targetExhausted; + break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + if ((flags == strictConversion) && + (ch >= UNI_SUR_HIGH_START && + ch <= UNI_SUR_LOW_END)) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = (UTF16) ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= extraBytesToRead; /* return to the start */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + result = targetExhausted; + break; + } + ch -= halfBase; + *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF32toUTF8 ( + UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, const UTF8* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0x000000BF; + const UTF32 byteMark = 0x00000080; + ch = *source++; + /* surrogates of any stripe are not legal UTF32 characters */ + if (flags == strictConversion ) { + if ((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_LOW_END)) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x200000) { bytesToWrite = 4; + } else { bytesToWrite = 2; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8) ((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +static pdc_convers_result +pdc_convertUTF8toUTF32 ( + UTF8** sourceStart, UTF8* sourceEnd, + UTF32** targetStart, const UTF32* targetEnd, + const pdc_convers_flags flags) { + pdc_convers_result result = conversionOK; + UTF8* source = *sourceStart; + UTF32* target = *targetStart; + + (void) flags; + + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! pdc_islegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + result = targetExhausted; + break; + } + if (ch <= UNI_MAX_UTF32) { + *target++ = ch; + } else if (ch > UNI_MAX_UTF32) { + *target++ = UNI_REPLACEMENT_CHAR; + } else { + if (target + 1 >= targetEnd) { + result = targetExhausted; + break; + } + ch -= halfBase; + *target++ = (ch >> halfShift) + UNI_SUR_HIGH_START; + *target++ = (ch & halfMask) + UNI_SUR_LOW_START; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ + +static const pdc_keyconn pdc_utfformat_keylist[] = +{ + {"8", pdc_utf8}, + {"16", pdc_utf16}, + {"32", pdc_utf32}, + {NULL, 0} +}; + + +/* + * pdc_convert_string converts a arbitrary encoded string (maybe UTF) to + * another encoded string. + * + * The new converted string is allocated and terminated by the required + * number of zeros. + * + * The caller is responsible for freeing the resulting string buffer. + * + * + * LBP: low byte picking + * + * Input-Parameter: + * + * inutf: input string format (see pc_unicode.h): + * + * pdc_auto: If codepage != 0: + * see above. + * Otherwise: + * If a BOM is recognized: + * pdc_utf8 or pdc_utf16xx resp. + * Otherwise if input encoding <inev> is specified + * and flag PDC_CONV_FORCEUTF16 not set: + * pdc_bytes + * Otherwise: + * pdc_utf16 + * + * pdc_auto2: If input encoding is not specified: + * pdc_utf16 + * Otherwise after successfull LBP: + * pdc_auto + * Otherwise: + * pdc_utf16 + * + * pdc_bytes: 8-bit string. Encoding is <inev> if specified. + * + * pdc_bytes2: After successfull LBP: + * pdc_bytes + * Otherwise: + * pdc_utf16 + * + * pdc_utf8: UTF-8 formatted string. + * + * pdc_ebcdicutf8: EBCDIC-UTF-8 formatted string. + * + * pdc_utf16: If a UTF16 BOM is recognized: + * pdc_utf16be or pdc_utf16le + * Otherwise UTF-16 machine byte ordered string. + * + * pdc_utf16be UTF-16 big endian formatted string. + * + * pdc_utf16le UTF-16 little endian formatted string. + * + * codepage: OEM multi byte code-page number. If > 0 and + * <inutf> = pdc_auto, text will be converted to UTF-16. + * + * inev: Encoding vector for input pdc_bytes string. + * + * glyphtab: Mapping table for character reference names + * + * tabsize: Size of mapping table + * + * replchar: Treatment of non resolvable character references: + * >= 0: replacement character + * == text_error: error message + * == text_nocheck: will be ignored + * (see also pdc_charref2unicodelist()) + * + * instring: Input string. + * + * inlen: Length of input string in byte. + * + * oututf: Target format for output string. + * pdc_auto, pdc_auto2 and pdc_bytes2 are not supported. + * + * outev: Encoding vector for output pdc_bytes string. + * + * flags: PDC_CONV_FORCEUTF16: + * In the case of <inutf> = pdc_auto[2] and <inev> != NULL + * <inutf> = pdc_utf16 will be forced. + * + * PDC_CONV_TRY7BYTES: + * UTF-8 output strings will have no BOM if each byte + * is smaller than x80. + * *oututf: pdc_byte. + * + * PDC_CONV_TRYBYTES: + * UTF-UTF-16xx output strings will be converted by LBP + * if each character is smaller than x0100. + * *oututf: pdc_byte. + * + * PDC_CONV_WITHBOM: + * UTF-8 or UTF-UTF-16xx output strings will be armed + * with an appropriate BOM. + * + * PDC_CONV_NOBOM: + * In UTF-8 or UTF-UTF-16xx output strings any BOM sequence + * will be removed. PDC_CONV_WITHBOM is dominant. + * + * PDC_CONV_AUTOBOM: + * BOM sequence will be set automatically if input string + * has a BOM. + * + * PDC_CONV_ANALYZE: + * Only analyzing BOMs of input string and dissolving auto + * textformats. + * + * PDC_CONV_TMPALLOC + * Temporary memory functions (pdc_malloc_tmp) are used + * rather than pdc_malloc etc. + * + * PDC_CONV_HTMLCHAR + * If input encoding vector is specified HTML character + * entities will be substituted. + * + * PDC_CONV_NEWALLOC + * Input string must be allocated at first to guarantee + * pointer alignment. + * + * PDC_CONV_INFLATE + * Invalid UTF-8 to UTF-16xx conversion will not cause + * an exception but rather an inflated byte string will + * be output. + * + * PDC_CONV_ESCSEQU + * Unicode sequences framed by escape character U+001B + * (found in PDF text strings) will be skipped. + * + * PDC_CONV_BSSEQU + * Code sequences beginning with backslash '\' + * will be substituted. + * + * PDC_CONV_ENCERROR + * If an 8-bit code cannot be converted to Unicode by <inev> + * or a Unicode cannot be converted to an 8-bit code by <outev> + * an error message will be created. + * + * PDC_CONV_KEEPLBCHAR + * In the case of PDC_CONV_ENCERROR relevant characters for + * line breaking do not lead to an error message. + * + * PDC_CONV_LOGGING + * Enables logging. + * + * verbose: Error messages are put out. Otherwise they are saved only. + * + * Output-Parameter: + * + * oututf: Reached format for output string. + * + * outstring: Pointer of allocated output string + * + * outlen: Length of output string. + * + */ + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +int +pdc_convert_string(pdc_core *pdc, + pdc_text_format inutf, int codepage, + pdc_encodingvector *inev, + pdc_byte *instring, int inlen, + pdc_text_format *oututf_p, pdc_encodingvector *outev, + pdc_byte **outstring, int *outlen, int flags, + pdc_bool verbose) +{ + return pdc_convert_textstring(pdc, inutf, codepage, inev, + NULL, 0, -1, instring, inlen, oututf_p, outev, + outstring, outlen, flags, verbose); +} + +int +pdc_convert_textstring(pdc_core *pdc, + pdc_text_format inutf, int codepage, + pdc_encodingvector *inev, + const pdc_glyph_tab *glyphtab, int tabsize, int replchar, + pdc_byte *instring, int inlen, + pdc_text_format *oututf_p, pdc_encodingvector *outev, + pdc_byte **outstring, int *outlen, int flags, + pdc_bool verbose) +{ + static const char *fn = "pdc_convert_textstring"; + pdc_bool logg = flags & PDC_CONV_LOGGING; + const char *stemp1 = NULL, *stemp2 = NULL; + pdc_text_format oututf = *oututf_p; + pdc_text_format oututf_s; + pdc_ushort *usinstr = (pdc_ushort *) instring; + pdc_ushort uv = 0; + pdc_byte *instr = NULL; + pdc_bool inalloc = pdc_false; + pdc_bool hasbom = pdc_false; + pdc_bool toswap = pdc_false; + int errcode = 0; + int i, j, n, len = 0; + + (void) glyphtab; + (void) tabsize; + (void) replchar; + + if (logg) + pdc_logg(pdc, "\t\tinput textformat for string conversion: %s\n", + pdc_get_keyword(inutf, pdc_textformat_keylist)); + + /* prophylactic */ + if (!inlen) + { + instring = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, 4, fn, NULL, NULL) : + pdc_calloc(pdc, 4, fn)); + + inalloc = pdc_true; + } + else if ((flags & PDC_CONV_NEWALLOC) || + (flags & PDC_CONV_TMPALLOC) || + (flags & PDC_CONV_BSSEQU)) + { + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (inlen + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (inlen + 2), fn)); + memcpy(instr, instring, (size_t) inlen); + + inalloc = pdc_true; + instring = instr; + instr = NULL; + usinstr = (pdc_ushort *) instring; + } + + switch(inutf) + { + /* analyzing 2 byte textformat */ + case pdc_auto2: + case pdc_bytes2: + if ((inutf == pdc_auto2 && + (inev == NULL || (flags & PDC_CONV_FORCEUTF16))) || + (flags & PDC_CONV_ANALYZE)) + { + inutf = pdc_utf16; + } + else + { + if (logg) + pdc_logg(pdc, "\t\ttry to pick low bytes\n"); + + len = inlen / 2; + if (2 * len != inlen) + { + errcode = PDC_E_CONV_ILLUTF16; + goto PDC_CONV_ERROR; + } + for (i = 0; i < len; i++) + if (usinstr[i] > PDC_UNICODE_MAXLATIN1) + break; + + /* low byte picking */ + if (i == len) + { + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + for (i = 0; i < len; i++) + instr[i] = (pdc_byte) usinstr[i]; + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + inalloc = pdc_true; + instring = instr; + instr = NULL; + inlen = len; + + if (inutf == pdc_bytes2) + inutf = pdc_bytes; + else + inutf = pdc_auto; + } + else + { + inutf = pdc_utf16; + } + } + break; + + /* OEM multi byte text strings */ + case pdc_auto: + case pdc_bytes: + if (codepage > 0) + { +#if defined(WIN32) + if (!(flags & PDC_CONV_ANALYZE)) + { + if (logg) + pdc_logg(pdc, + "\t\tconverting according Windows codepage %d\n", + codepage); + + len = MultiByteToWideChar((UINT) codepage, (DWORD) 0, + (LPCSTR) instring, inlen, NULL, 0); + if (len == 0) + { + DWORD lasterror = GetLastError(); + + stemp1 = pdc_errprintf(pdc, "cp%d", codepage); + if (lasterror == ERROR_INVALID_PARAMETER) + { + errcode = PDC_E_CONV_UNSUPP_MBTEXTFORM; + } + else + { + errcode = PDC_E_CONV_ILL_MBTEXTSTRING; + } + goto PDC_CONV_ERROR; + } + + len *= 2; + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, + NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + MultiByteToWideChar((UINT) codepage, (DWORD) 0, (LPCSTR) + instring, inlen, + (LPWSTR) instr, len); + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + inalloc = pdc_true; + instring = instr; + instr = NULL; + inlen = len; + + inutf = pdc_utf16; + } + else + { + inutf = pdc_bytes; + } +#else /* WIN32 */ + errcode = PDC_E_CONV_UNSUPP_MBTEXTFORM; + goto PDC_CONV_ERROR; +#endif /* !WIN32 */ + } + break; + + default: + break; + } + + /* analyzing UTF-16 textformat */ + if (inutf == pdc_utf16) + { + if (pdc_is_utf16be_unicode(instring)) + inutf = pdc_utf16be; + else if (pdc_is_utf16le_unicode(instring)) + inutf = pdc_utf16le; + } + + /* analyzing auto textformat */ + else if (inutf == pdc_auto) + { + if (pdc_is_utf8_bytecode(instring)) + inutf = PDC_UTF8; + else if (pdc_is_utf16be_unicode(instring)) + inutf = pdc_utf16be; + else if (pdc_is_utf16le_unicode(instring)) + inutf = pdc_utf16le; + else if (inev && !(flags & PDC_CONV_FORCEUTF16)) + inutf = pdc_bytes; + else + inutf = pdc_utf16; + } + + if (logg) + pdc_logg(pdc, "\t\tdetermined textformat: %s\n", + pdc_get_keyword(inutf, pdc_textformat_keylist)); + + /* only analyzing */ + if (flags & PDC_CONV_ANALYZE) + goto PDC_CONV_EXIT; + + /* conversion to UTF-16 by swapping */ + if ((inutf == pdc_utf16be || inutf == pdc_utf16le) && + (inutf != oututf || flags & PDC_CONV_TRYBYTES || + flags & PDC_CONV_HTMLCHAR)) + { + if (inlen && + ((inutf == pdc_utf16be && !PDC_ISBIGENDIAN) || + (inutf == pdc_utf16le && PDC_ISBIGENDIAN))) + { + if (inalloc) + pdc_swap_bytes((char *) instring, inlen, NULL); + else + { + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (inlen + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (inlen + 2), fn)); + pdc_swap_bytes((char *) instring, inlen, (char *) instr); + + inalloc = pdc_true; + instring = instr; + instr = NULL; + } + } + inutf = pdc_utf16; + } + + /* illegal UTF-16 */ + if (inutf >= pdc_utf16 && inlen % 2) + { + errcode = PDC_E_CONV_ILLUTF16; + goto PDC_CONV_ERROR; + } + + + /* conversion to UTF-16 by inflation or encoding vector */ + if (inutf == pdc_bytes && + (oututf != pdc_bytes || flags & PDC_CONV_HTMLCHAR || inev != outev)) + { + if (logg) + { + if (flags & PDC_CONV_HTMLCHAR) + pdc_logg(pdc, "\t\tbyte character entity substitution\n"); + } + + len = 2 * inlen; + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + usinstr = (pdc_ushort *) instr; + + j = 0; + for (i = 0; i < inlen; i++) + { + uv = (pdc_ushort) instring[i]; + if (inev) + { + uv = inev->codes[uv]; + if (!uv && (flags & PDC_CONV_ENCERROR) && + (!(flags & PDC_CONV_KEEPLBCHAR) || + !pdc_is_linebreaking_relchar(uv))) + { + errcode = PDC_E_ENC_NOTDEF_CODE; + stemp1 = pdc_errprintf(pdc, "x%02X", instring[i]); + stemp2 = inev->apiname; + goto PDC_CONV_ERROR; + } + } + + + usinstr[j] = uv; + j++; + } + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + inalloc = pdc_true; + instring = instr; + instr = NULL; + inlen = 2 * j; + inutf = pdc_utf16; + } + + + + /* UTF conversion */ + oututf_s = oututf; + if ((oututf_s == pdc_bytes && inutf == pdc_utf8) || + oututf_s == pdc_utf16be || oututf_s == pdc_utf16le) + oututf_s = pdc_utf16; + if (inutf != oututf_s && oututf_s != pdc_bytes) + { + len = 4 * (inlen + 1); + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) len, fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) len, fn)); + + if (inlen) + { + pdc_convers_result result = conversionOK; + pdc_byte *instringa, *instra, *instringe, *instre; + UTF8 *isa8, *ise8; + UTF16 *isa16, *ise16; + UTF32 *isa32, *ise32; + + if (logg) + pdc_logg(pdc, "\t\tUTF conversion\n"); + + instringa = instring; + instringe = instring + inlen; + instra = instr; + instre = instr + len; + + if (inutf == pdc_utf8) + { + isa8 = (UTF8 *) instringa; + ise8 = (UTF8 *) instringe; + if (oututf_s == pdc_utf16) + { + isa16 = (UTF16 *) instra; + ise16 = (UTF16 *) instre; + result = pdc_convertUTF8toUTF16(&isa8, ise8, + &isa16, ise16, + strictConversion); + instra = (pdc_byte *) isa16; + instre = (pdc_byte *) ise16; + } + else + { + isa32 = (UTF32 *) instra; + ise32 = (UTF32 *) instre; + result = pdc_convertUTF8toUTF32(&isa8, ise8, + &isa32, ise32, + strictConversion); + instra = (pdc_byte *) isa32; + instre = (pdc_byte *) ise32; + } + } + else if (inutf == pdc_utf16) + { + isa16 = (UTF16 *) instringa; + ise16 = (UTF16 *) instringe; + if (oututf_s == pdc_utf8) + { + isa8 = (UTF8 *) instra; + ise8 = (UTF8 *) instre; + result = pdc_convertUTF16toUTF8(&isa16, ise16, &isa8, ise8, + strictConversion); + instra = (pdc_byte *) isa8; + instre = (pdc_byte *) ise8; + } + else + { + isa32 = (UTF32 *) instra; + ise32 = (UTF32 *) instre; + result = pdc_convertUTF16toUTF32(&isa16, ise16, + &isa32, ise32, + strictConversion); + instra = (pdc_byte *) isa32; + instre = (pdc_byte *) ise32; + } + } + else if (inutf == pdc_utf32) + { + isa32 = (UTF32 *) instringa; + ise32 = (UTF32 *) instringe; + if (oututf_s == pdc_utf8) + { + isa8 = (UTF8 *) instra; + ise8 = (UTF8 *) instre; + result = pdc_convertUTF32toUTF8(&isa32, ise32, + &isa8, ise8, + strictConversion); + instra = (pdc_byte *) isa8; + instre = (pdc_byte *) ise8; + } + else + { + isa16 = (UTF16 *) instra; + ise16 = (UTF16 *) instre; + result = pdc_convertUTF32toUTF16(&isa32, ise32, + &isa16, ise16, + strictConversion); + instra = (pdc_byte *) isa16; + instre = (pdc_byte *) ise16; + } + } + + switch (result) + { + case targetExhausted: + errcode = PDC_E_CONV_MEMOVERFLOW; + break; + + case sourceExhausted: + case sourceIllegal: + if (inutf == pdc_utf8 && (flags & PDC_CONV_INFLATE)) + { + pdc_inflate_ascii((char *) instring, inlen, (char *) instr, + pdc_utf16); + instra = instr + 2 * inlen; + } + else + { + errcode = PDC_E_CONV_ILLUTF; + stemp1 = pdc_get_keyword((int)inutf, pdc_utfformat_keylist); + } + break; + + default: + break; + } + + if (errcode) + { + if (logg) + pdc_logg(pdc, "\t\tUTF conversion error %d\n", result); + + goto PDC_CONV_ERROR; + } + + inlen = instra - instr; + } + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + len = (oututf == pdc_utf32) ? inlen + 4 : inlen + 2; + if (inlen + 4 != len) + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_realloc_tmp(pdc, instr, (size_t) len, fn) : + pdc_realloc(pdc, instr, (size_t) len, fn)); + instr[inlen] = 0; + instr[inlen + 1] = 0; + if (oututf == pdc_utf32) + { + instr[inlen + 2] = 0; + instr[inlen + 3] = 0; + } + + inalloc = pdc_true; + instring = instr; + instr = NULL; + inutf = oututf_s; + } + + if (inutf == pdc_bytes) + { + if (!inalloc) + { + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (inlen + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (inlen + 2), fn)); + memcpy(instr, instring, (size_t) inlen); + + inalloc = pdc_true; + instring = instr; + instr = NULL; + } + } + + /* trying to reduce UTF-16 string to bytes string */ + if (inutf == pdc_utf16 && + (oututf == pdc_bytes || flags & PDC_CONV_TRYBYTES)) + { + if (logg) + pdc_logg(pdc, "\t\ttry to reduce UTF-16 to bytes\n"); + + if (pdc_is_utf16be_unicode(instring) || + pdc_is_utf16le_unicode(instring)) + n = 1; + else + n = 0; + + len = (inlen - n) / 2; + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + usinstr = (pdc_ushort *) instring; + + for (i = 0; i < len; i++) + { + uv = usinstr[i + n]; + if (outev && uv) + { + j = pdc_get_encoding_bytecode(pdc, outev, uv); + if (j < 0 && (flags & PDC_CONV_ENCERROR) && oututf == pdc_bytes) + { + errcode = PDC_E_ENC_NOTDEF_UNICODE; + stemp1 = pdc_errprintf(pdc, "%04X", uv); + stemp2 = outev->apiname; + goto PDC_CONV_ERROR; + } + uv = (pdc_ushort) j; + } + if (uv > PDC_UNICODE_MAXLATIN1) + break; + + instr[i] = (pdc_byte) uv; + } + + if (i == len) + { + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + inalloc = pdc_true; + instring = instr; + instr = NULL; + inlen = len; + inutf = pdc_bytes; + } + else + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instr); + else + pdc_free(pdc, instr); + instr = NULL; + } + } + + /* UTF-8 format */ + if (inutf == pdc_utf8) + { + hasbom = pdc_is_utf8_unicode(instring); + + if (flags & PDC_CONV_TRY7BYTES) + { + if (logg) + pdc_logg(pdc, "\t\ttry to reduce UTF-8 to 7-bit\n"); + + for (i = hasbom ? 3 : 0; i < inlen; i++) + if (instring[i] > PDC_UNICODE_MAXASCII) + break; + if (i == inlen) + { + flags &= ~PDC_CONV_WITHBOM; + flags |= PDC_CONV_NOBOM; + inutf = pdc_bytes; + } + } + else if (hasbom && (flags & PDC_CONV_AUTOBOM)) + { + flags &= ~PDC_CONV_NOBOM; + flags |= PDC_CONV_WITHBOM; + } + else if ((flags & PDC_CONV_WITHBOM) && (flags & PDC_CONV_NOBOM)) + { + flags &= ~PDC_CONV_NOBOM; + } + + if (!inalloc || flags & PDC_CONV_WITHBOM || flags & PDC_CONV_NOBOM) + { + i = (flags & PDC_CONV_WITHBOM && !hasbom) ? 3 : 0; + j = (flags & PDC_CONV_NOBOM && hasbom) ? 3 : 0; + + len = inlen + i - j; + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + memcpy(&instr[i], &instring[j], (size_t) (inlen - j)); + instr[len] = 0; + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + instring = instr; + instr = NULL; + inlen = len; + + hasbom = (flags & PDC_CONV_WITHBOM); + } + + if (hasbom) + { + instring[0] = PDF_BOM2; + instring[1] = PDF_BOM3; + instring[2] = PDF_BOM4; + } + + } + + /* UTF-16 formats */ + if (inutf == pdc_utf16 || inutf == pdc_utf16be || inutf == pdc_utf16le) + { + hasbom = pdc_is_utf16be_unicode(instring) || + pdc_is_utf16le_unicode(instring); + + if (hasbom && (flags & PDC_CONV_AUTOBOM)) + { + flags &= ~PDC_CONV_NOBOM; + flags |= PDC_CONV_WITHBOM; + } + else if ((flags & PDC_CONV_WITHBOM) && (flags & PDC_CONV_NOBOM)) + { + flags &= ~PDC_CONV_NOBOM; + } + + if (!inalloc || oututf == pdc_utf16be || oututf == pdc_utf16le || + flags & PDC_CONV_WITHBOM || flags & PDC_CONV_NOBOM) + { + i = (flags & PDC_CONV_WITHBOM && !hasbom) ? 2 : 0; + j = (flags & PDC_CONV_NOBOM && hasbom) ? 2 : 0; + + len = inlen + i - j; + instr = (pdc_byte *) ((flags & PDC_CONV_TMPALLOC) ? + pdc_calloc_tmp(pdc, (size_t) (len + 2), fn, NULL, NULL) : + pdc_calloc(pdc, (size_t) (len + 2), fn)); + memcpy(&instr[i], &instring[j], (size_t) (inlen - j)); + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + instring = instr; + instr = NULL; + inlen = len; + + hasbom = (flags & PDC_CONV_WITHBOM); + } + + i = hasbom ? 2 : 0; + if (inutf == pdc_utf16) + { + if (oututf == pdc_utf16be) + { + inutf = pdc_utf16be; + toswap = !PDC_ISBIGENDIAN; + } + if (oututf == pdc_utf16le) + { + inutf = pdc_utf16le; + toswap = PDC_ISBIGENDIAN; + } + if (toswap) + pdc_swap_bytes((char *) &instring[i], inlen - i, NULL); + } + + if (hasbom) + { + if (inutf == pdc_utf16be || + (inutf == pdc_utf16 && PDC_ISBIGENDIAN)) + { + instring[0] = PDF_BOM0; + instring[1] = PDF_BOM1; + } + if (inutf == pdc_utf16le || + (inutf == pdc_utf16 && !PDC_ISBIGENDIAN)) + { + instring[0] = PDF_BOM1; + instring[1] = PDF_BOM0; + } + } + } + + if (logg) + pdc_logg(pdc, "\t\ttextformat of converted string: %s\n", + pdc_get_keyword(inutf, pdc_textformat_keylist)); + + PDC_CONV_EXIT: + *oututf_p = inutf; + if (outlen) + *outlen = inlen; + *outstring = instring; + return 0; + + PDC_CONV_ERROR: + if (outlen) + *outlen = 0; + *outstring = NULL; + + if (errcode > 0) + pdc_set_errmsg(pdc, errcode, stemp1, stemp2, 0, 0); + + if (instr != NULL) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instr); + else + pdc_free(pdc, instr); + } + + if (inalloc) + { + if (flags & PDC_CONV_TMPALLOC) + pdc_free_tmp(pdc, instring); + else + pdc_free(pdc, instring); + } + + if (verbose) + PDC_RETHROW(pdc); + + return errcode; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + + +/* + * pdc_convert_name_ext converts a string of name data type to UTF-8 + * + * flags & PDC_CONV_EBCDIC: converts to EBCDIC-UTF-8 + * + * len == 0: If the string has a [EBCDIC-]UTF-8 BOM or + * flags & PDC_CONV_ISUTF8 is set the string will be duplicated. + * Otherwise the string has encoding enc and codepage + * codepage. + * If enc < pdc_winansi the string is "host" encoded. + * + * len > 0: The string is a UTF-16 string of len bytes. + * + */ +char * +pdc_convert_name_ext(pdc_core *pdc, const char *name, int len, + pdc_encoding enc, int codepage, int flags) +{ + pdc_encodingvector *ev = NULL; + pdc_text_format nameformat = pdc_utf16; + pdc_text_format outnameformat = pdc_utf8; + pdc_byte *convname; + char *outname = NULL; + int outlen; + + if (name == NULL) + return NULL; + + if (len == 0) + { + pdc_bool hasbom = pdc_is_utf8_bytecode(name); + pdc_bool withbom = (flags & PDC_CONV_WITHBOM) ? pdc_true : pdc_false; + + /* already [EBCDIC-]UTF-8 encoded */ + if ((flags & PDC_CONV_ISUTF8) || hasbom) + { + if ((hasbom && withbom) || (!hasbom && !withbom)) + outname = pdc_strdup(pdc, name); + else if (hasbom && !withbom) + outname = pdc_strdup(pdc, &name[3]); + else if (!hasbom && withbom) + outname = pdc_strdup_withbom(pdc, name); + if (outname != NULL) + { + return outname; + } + } + + /* 8-bit encoded string */ + nameformat = pdc_bytes; + if (enc < pdc_winansi) + ev = pdc_get_encoding_vector(pdc, pdc_find_encoding(pdc, "host")); + else + ev = pdc_get_encoding_vector(pdc, enc); + + len = (int) strlen(name); + } + + if (flags & PDC_CONV_EBCDIC) + outnameformat = PDC_UTF8; + + flags |= PDC_CONV_TRY7BYTES; + if (pdc->charref) + flags |= PDC_CONV_HTMLCHAR; + if (pdc->escapesequ) + flags |= PDC_CONV_BSSEQU; + + /* convert to UTF-8 */ + pdc_convert_string(pdc, nameformat, codepage, ev, (pdc_byte *) name, len, + &outnameformat, NULL, &convname, &outlen, flags, + pdc_true); + + return (char *) convname; +} + +char * +pdc_convert_name(pdc_core *pdc, const char *name, int len, int flags) +{ + return pdc_convert_name_ext(pdc, name, len, pdc_invalidenc, 0, flags); +} + +char * +pdc_utf8_to_hostbytes(pdc_core *pdc, pdc_bool honorlang, char *name) +{ + static const char fn[] = "pdc_utf8_to_hostbytes"; + pdc_encoding outenc = pdc_invalidenc; + pdc_encodingvector *outev = NULL; + pdc_text_format informat = PDC_UTF8; + pdc_text_format outformat = pdc_utf16; + pdc_byte *outname = NULL; + int len = (int) strlen(name); + + { + (void) fn; + (void) honorlang; + outenc = pdc_find_encoding(pdc, "host"); + } + + outev = pdc_get_encoding_vector(pdc, outenc); + + pdc_convert_string(pdc, informat, 0, NULL, (pdc_byte *) name, len, + &outformat, outev, &outname, &len, + PDC_CONV_TRYBYTES | PDC_CONV_NOBOM, pdc_true); + if (outformat == pdc_utf16) + { + pdc_free(pdc, outname); + outname = NULL; + } + + return (char *) outname; +} + +char * +pdc_hostbytes_to_utf8(pdc_core *pdc, pdc_bool honorlang, char *name) +{ + static const char fn[] = "pdc_hostbytes_to_utf8"; + pdc_encoding inenc = pdc_invalidenc; + pdc_encodingvector *inev = NULL; + pdc_text_format informat = pdc_bytes; + pdc_text_format outformat = PDC_UTF8; + pdc_byte *outname = NULL; + int len = (int) strlen(name); + + { + (void) fn; + (void) honorlang; + inenc = pdc_find_encoding(pdc, "host"); + } + + inev = pdc_get_encoding_vector(pdc, inenc); + + pdc_convert_string(pdc, informat, 0, inev, (pdc_byte *) name, len, + &outformat, NULL, &outname, &len, + PDC_CONV_NOBOM, pdc_true); + + return (char *) outname; +} + +/* --------------------- basic UTF conversion functions --------------------- */ + +char * +pdc_utf16_to_utf8(pdc_core *pdc, const char *utf16string, int len, int flags, + int *size) +{ + pdc_text_format outtextformat = pdc_utf8; + pdc_byte *utf8string = NULL; + int outlen; + + if (!utf16string) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "utf16string", 0, 0, 0); + + if (flags & PDC_CONV_EBCDIC) + outtextformat = PDC_UTF8; + + flags |= PDC_CONV_AUTOBOM; + pdc_convert_string(pdc, pdc_utf16, 0, NULL, + (pdc_byte *) utf16string, len, + &outtextformat, NULL, &utf8string, &outlen, + flags, pdc_true); + + if (size) *size = outlen; + + return (char *) utf8string; +} + +char * +pdc_utf8_to_utf16(pdc_core *pdc, const char *utf8string, const char *format, + int flags, int *size) +{ + pdc_text_format textformat = pdc_utf8; + pdc_text_format outtextformat = pdc_utf16; + pdc_byte *utf16string = NULL; + int len; + + if (!utf8string) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "utf8string", 0, 0, 0); + len = (int) strlen(utf8string); + + if (format && *format) + { + int k = pdc_get_keycode_ci(format, pdc_textformat_keylist); + if (k == PDC_KEY_NOTFOUND || + ((pdc_text_format) k != pdc_utf16 && + (pdc_text_format) k != pdc_utf16be && + (pdc_text_format) k != pdc_utf16le)) + pdc_error(pdc, PDC_E_ILLARG_STRING, "format", format, 0, 0); + outtextformat = (pdc_text_format) k; + } + + if (flags & PDC_CONV_EBCDIC) + textformat = PDC_UTF8; + + if (outtextformat == pdc_utf16) + flags |= PDC_CONV_AUTOBOM; + else + flags |= PDC_CONV_WITHBOM; + pdc_convert_string(pdc, textformat, 0, NULL, + (pdc_byte *) utf8string, len, + &outtextformat, NULL, &utf16string, size, + flags, pdc_true); + + return (char *) utf16string; +} + +char * +pdc_utf16_to_utf32(pdc_core *pdc, const char *utf16string, int len, int *size) +{ + pdc_text_format outtextformat = pdc_utf32; + pdc_byte *utf32string = NULL; + + if (!utf16string) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "utf16string", 0, 0, 0); + + pdc_convert_string(pdc, pdc_utf16, 0, NULL, + (pdc_byte *) utf16string, len, + &outtextformat, NULL, &utf32string, size, + 0, pdc_true); + + return (char *) utf32string; +} + +char * +pdc_utf32_to_utf8(pdc_core *pdc, const char *utf32string, int len, int flags, + int *size) +{ + pdc_text_format outtextformat = pdc_utf8; + pdc_byte *utf8string = NULL; + int outlen; + + if (!utf32string) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "utf32string", 0, 0, 0); + + if (flags & PDC_CONV_EBCDIC) + outtextformat = PDC_UTF8; + + flags |= PDC_CONV_AUTOBOM; + pdc_convert_string(pdc, pdc_utf32, 0, NULL, + (pdc_byte *) utf32string, len, + &outtextformat, NULL, &utf8string, &outlen, + flags, pdc_true); + + if (size) *size = outlen; + + return (char *) utf8string; +} + +char * +pdc_utf32_to_utf16(pdc_core *pdc, const char *utf32string, int len, + const char *format, int flags, int *size) +{ + pdc_text_format textformat = pdc_utf32; + pdc_text_format outtextformat = pdc_utf16; + pdc_byte *utf16string = NULL; + + if (!utf32string) + pdc_error(pdc, PDC_E_ILLARG_EMPTY, "utf32string", 0, 0, 0); + + if (format && *format) + { + int k = pdc_get_keycode_ci(format, pdc_textformat_keylist); + if (k == PDC_KEY_NOTFOUND || + ((pdc_text_format) k != pdc_utf16 && + (pdc_text_format) k != pdc_utf16be && + (pdc_text_format) k != pdc_utf16le)) + pdc_error(pdc, PDC_E_ILLARG_STRING, "format", format, 0, 0); + outtextformat = (pdc_text_format) k; + } + + if (outtextformat == pdc_utf16) + flags |= PDC_CONV_AUTOBOM; + else + flags |= PDC_CONV_WITHBOM; + pdc_convert_string(pdc, textformat, 0, NULL, + (pdc_byte *) utf32string, len, + &outtextformat, NULL, &utf16string, size, + flags, pdc_true); + + return (char *) utf16string; +} + +int +pdc_char16_to_char32(pdc_core *pdc, const pdc_ushort *ustext, int *ic, int len, + pdc_bool verbose) +{ + pdc_ushort uvh = ustext[*ic]; + + if (uvh < PDC_UNICODE_MINHIGHSUR || uvh > PDC_UNICODE_MAXLOWSUR) + { + return (int) uvh; + } + else + { + UTF16 *isa16 = (UTF16 *) &ustext[*ic]; + pdc_ushort uvl = 0; + int icn = *ic + 1; + + if (icn < len) + { + uvl = ustext[icn]; + if (uvh <= PDC_UNICODE_MAXHIGHSUR) + { + if (uvl >= PDC_UNICODE_MINLOWSUR && + uvl <= PDC_UNICODE_MAXLOWSUR) + { + int usv; + UTF16 *ise16 = isa16 + 2; + UTF32 *isa32 = (UTF32 *) &usv; + UTF32 *ise32 = isa32 + 1; + + pdc_convers_result result = pdc_convertUTF16toUTF32( + &isa16, ise16, &isa32, ise32, strictConversion); + if (result == conversionOK) + { + *ic = icn; + return usv; + } + } + } + } + + pdc_set_errmsg(pdc, PDC_E_CONV_ILLUTF16SUR, + pdc_errprintf(pdc, "%04X", uvh), + pdc_errprintf(pdc, "%04X", uvl), 0, 0); + + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + } + + return -1; +} + +int +pdc_char32_to_char16(pdc_core *pdc, int usv, pdc_ushort *uvlist, + pdc_bool verbose) +{ + if (usv < PDC_NUM_BMPVAL) + { + uvlist[0] = (pdc_ushort) usv; + return 1; + } + else + { + UTF32 *isa32 = (UTF32 *) &usv; + UTF32 *ise32 = isa32 + 1; + UTF16 *isa16 = (UTF16 *) uvlist; + UTF16 *ise16 = isa16 + 2; + + pdc_convers_result result = pdc_convertUTF32toUTF16( + &isa32, ise32, &isa16, ise16, strictConversion); + if (result == conversionOK) + { + return 2; + } + + pdc_set_errmsg(pdc, PDC_E_CONV_ILLUTF32, + pdc_errprintf(pdc, "%05X", usv), 0, 0, 0); + + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + } + + return 0; +} diff --git a/src/pdflib/pdcore/pc_unicode.h b/src/pdflib/pdcore/pc_unicode.h new file mode 100644 index 0000000..c5c1354 --- /dev/null +++ b/src/pdflib/pdcore/pc_unicode.h @@ -0,0 +1,283 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_unicode.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Unicode glyph name conversion routines + * + */ + +#ifndef PC_UNICODE_H +#define PC_UNICODE_H + +#define PDC_NUM_BMPVAL 0x10000 +#define PDC_NUM_UNIVAL 0x110000 +#define PDC_MAX_UNIVAL 0x10FFFF + +#define PDC_UNICODE_HT 0x0009 +#define PDC_UNICODE_LF 0x000A +#define PDC_UNICODE_VT 0x000B +#define PDC_UNICODE_FF 0x000C +#define PDC_UNICODE_CR 0x000D +#define PDC_UNICODE_ETB 0x0017 +#define PDC_UNICODE_ESC 0x001B +#define PDC_UNICODE_SPACE 0x0020 +#define PDC_UNICODE_QUOTMARK 0x0022 +#define PDC_UNICODE_AMPERSAND 0x0026 +#define PDC_UNICODE_APOSTROPHE 0x0027 +#define PDC_UNICODE_HYPHEN 0x002D +#define PDC_UNICODE_PERIOD 0x002E +#define PDC_UNICODE_SEMICOLON 0x003B +#define PDC_UNICODE_LESS_THAN 0x003C +#define PDC_UNICODE_GREATER_THAN 0x003E +#define PDC_UNICODE_BACKSLASH 0x005C +#define PDC_UNICODE_LEFT_CURLY 0x007B +#define PDC_UNICODE_RIGHT_CURLY 0x007D +#define PDC_UNICODE_DELETE 0x007F +#define PDC_UNICODE_NEL 0x0085 +#define PDC_UNICODE_NBSP 0x00A0 +#define PDC_UNICODE_SHY 0x00AD +#define PDC_UNICODE_MACRON 0x00AF +#define PDC_UNICODE_MICRO 0x00B5 +#define PDC_UNICODE_MIDDLEDOT 0x00B7 +#define PDC_UNICODE_MODMACRON 0x02C9 +#define PDC_UNICODE_CAPDELTA 0x0394 +#define PDC_UNICODE_CAPOMEGA 0x03A9 +#define PDC_UNICODE_SMALLMU 0x03BC +#define PDC_UNICODE_LS 0x2028 +#define PDC_UNICODE_PS 0x2029 +#define PDC_UNICODE_NNBSP 0x202F +#define PDC_UNICODE_FRACSLASH 0x2044 +#define PDC_UNICODE_MMSPACE 0x205F +#define PDC_UNICODE_EURO 0x20AC +#define PDC_UNICODE_OHMSIGN 0x2126 +#define PDC_UNICODE_INCREMENT 0x2206 +#define PDC_UNICODE_DIVSLASH 0x2215 +#define PDC_UNICODE_BULLETOP 0x2219 +#define PDC_UNICODE_IDEOSPACE 0x3000 + +/* maximal value of Latin-1 characters */ +#define PDC_UNICODE_MAXASCII 0x007F +#define PDC_UNICODE_MAXLATIN1 0x00FF + +/* maximal resp. single value of Japanese HW characters */ +#define PDC_UNICODE_MAXHW 0x007E +#define PDC_UNICODE_SINGHW 0x00A5 + +/* Unicode borders of fullwidth forms of ASCII characters */ +#define PDC_UNICODE_MINFWASCII 0xFF00 +#define PDC_UNICODE_MAXFWASCII 0xFF5E +#define PDC_UNICODE_DIFFWASCII 0xFEE0 + /* PDC_UNICODE_MINFASCII - PDC_UNICODE_SPACE */ + +/* Unicode borders of fullwidth forms of Symbol characters */ +#define PDC_UNICODE_MINFWSYMBOL 0xFFE0 +#define PDC_UNICODE_MAXFWSYMBOL 0xFFE6 + +/* Unicode borders of Private Use Area (PUA) */ +#define PDC_UNICODE_MINPUA 0xE000 +#define PDC_UNICODE_MAXPUA 0xF8FF + +/* Begin of PDFlib PUA */ +#define PDC_UNICODE_PDFPUA 0xF200 + +/* Unicode borders of Unicode Corporate Use Subarea as used by Adobe Systems */ +#define PDC_UNICODE_MINCUS 0xF600 +#define PDC_UNICODE_MAXCUS 0xF8FF + +/* Unicode Surrogate ranges */ +#define PDC_UNICODE_MINHIGHSUR 0xD800 +#define PDC_UNICODE_MAXHIGHSUR 0xDBFF +#define PDC_UNICODE_MINLOWSUR 0xDC00 +#define PDC_UNICODE_MAXLOWSUR 0xDFFF + +/* Unicode borders of higher Unicode spaces */ +#define PDC_UNICODE_MINSPACE 0x2000 +#define PDC_UNICODE_MAXSPACE 0x200B + +/* Unicode borders of CJK compatibility forms and small form variants */ +#define PDC_UNICODE_MINCJKFORMS 0xFE30 +#define PDC_UNICODE_MIDCJKFORMS 0xFE48 +#define PDC_UNICODE_MAXCJKFORMS 0xFE6F + +/* replacement character */ +#define PDC_UNICODE_REPLCHAR 0xFFFD + +/* special character for CRLF */ +#define PDF_UNICODE_CRLF 0xFDD0 + +/* not a character */ +#define PDC_UNICODE_NOTCHAR 0xFFFF + +/* Latin and Armenian ligatures */ +#define PDC_UNICODE_CAPLIGATIJ 0x0132 +#define PDC_UNICODE_SMALLLIGATIJ 0x0133 +#define PDC_UNICODE_MINLIGAT 0xFB00 +#define PDC_UNICODE_MAXLIGAT 0xFB17 + + +/* The Unicode byte order mark (BOM) byte parts */ +#define PDC_UNICODE_BOM 0xFEFF +#define PDF_BOM0 0xFE +#define PDF_BOM1 0xFF +#define PDF_BOM2 0xEF +#define PDF_BOM3 0xBB +#define PDF_BOM4 0xBF + +/* + * check whether the string is plain C or UTF16 unicode + * by looking for the BOM in big-endian or little-endian format resp. + * s must not be NULL. + */ +#define pdc_is_utf16be_unicode(s) \ + (((pdc_byte *)(s))[0] == PDF_BOM0 && \ + ((pdc_byte *)(s))[1] == PDF_BOM1) + +#define pdc_is_utf16le_unicode(s) \ + (((pdc_byte *)(s))[0] == PDF_BOM1 && \ + ((pdc_byte *)(s))[1] == PDF_BOM0) + +/* + * check whether the string is plain C or UTF8 unicode + * by looking for the BOM + * s must not be NULL. + */ +#define pdc_is_utf8_unicode(s) \ + (((pdc_byte *)(s))[0] == PDF_BOM2 && \ + ((pdc_byte *)(s))[1] == PDF_BOM3 && \ + ((pdc_byte *)(s))[2] == PDF_BOM4) + + +#define PDC_UTF8_STRING "\xEF\xBB\xBF" +#define pdc_is_utf8_bytecode(s) \ + (((pdc_byte *)(s))[0] == PDF_BOM2 && \ + ((pdc_byte *)(s))[1] == PDF_BOM3 && \ + ((pdc_byte *)(s))[2] == PDF_BOM4) +#define pdc_copy_utf8_bom(s) \ + ((pdc_byte *)(s))[0] = PDF_BOM2, \ + ((pdc_byte *)(s))[1] = PDF_BOM3, \ + ((pdc_byte *)(s))[2] = PDF_BOM4; +#define PDC_UTF8 pdc_utf8 +#define PDC_UTF8_STRG "utf8" +#define PDC_UTF8_FLAG pdc_false + + +#define PDC_HTML_CTRLCHAR '&' +#define PDC_HTML_DELIMITCHAR ';' + +typedef enum +{ + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} +pdc_convers_result; + +typedef enum +{ + strictConversion = 0, + lenientConversion +} +pdc_convers_flags; + +/* flags for pdc_convert_string(), pdc_strdup_ext(), + * pdc_utfxx6_to_utfxx(), pdc_convert_name_ext() + */ +#define PDC_CONV_FORCEUTF16 (1<<0) +#define PDC_CONV_TRY7BYTES (1<<1) +#define PDC_CONV_TRYBYTES (1<<2) +#define PDC_CONV_WITHBOM (1<<3) +#define PDC_CONV_NOBOM (1<<4) +#define PDC_CONV_AUTOBOM (1<<5) +#define PDC_CONV_ANALYZE (1<<6) +#define PDC_CONV_TMPALLOC (1<<7) +#define PDC_CONV_HTMLCHAR (1<<8) +#define PDC_CONV_NEWALLOC (1<<9) +#define PDC_CONV_INFLATE (1<<10) +#define PDC_CONV_ESCSEQU (1<<11) +#define PDC_CONV_BSSEQU (1<<12) +#define PDC_CONV_EBCDIC (1<<13) +#define PDC_CONV_ENCERROR (1<<14) +#define PDC_CONV_KEEPLBCHAR (1<<15) +#define PDC_CONV_LOGGING (1<<16) +#define PDC_CONV_ISUTF8 (1<<17) + +/* DON'T change the order */ +typedef enum +{ + pdc_auto = 1, + pdc_auto2 = 2, + pdc_bytes = 3, + pdc_bytes2 = 4, + pdc_utf8 = 5, /* UTF-8 */ + + pdc_utf16 = 7, /* UTF-16 */ + pdc_utf16be = 8, /* UTF-16 big endian */ + pdc_utf16le = 9, /* UTF-16 little endian */ + pdc_utf32 = 10 /* UTF-32 */ +} +pdc_text_format; + +/* copy for pdflib in p_keyconn.h */ +#if defined(PC_UNICODE_C) +static const pdc_keyconn pdc_textformat_keylist[] = +{ + {"auto", pdc_auto}, + {"auto2", pdc_auto2}, + {"bytes", pdc_bytes}, + {"bytes2", pdc_bytes2}, + {"utf8", pdc_utf8}, + {"utf16", pdc_utf16}, + {"utf16be", pdc_utf16be}, + {"utf16le", pdc_utf16le}, + {NULL, 0} +}; +#endif /* PC_UNICODE_C */ + +int pdc_convert_string(pdc_core *pdc, + pdc_text_format inutf, int codepage, pdc_encodingvector *inev, + pdc_byte *instring, int inlen, pdc_text_format *oututf_p, + pdc_encodingvector *outev, pdc_byte **outstring, int *outlen, int flags, + pdc_bool verbose); + +int pdc_convert_textstring(pdc_core *pdc, + pdc_text_format inutf, int codepage, pdc_encodingvector *inev, + const pdc_glyph_tab *glyphtab, int tabsize, int replchar, + pdc_byte *instring, int inlen, + pdc_text_format *oututf_p, pdc_encodingvector *outev, + pdc_byte **outstring, int *outlen, int flags, + pdc_bool verbose); + +char *pdc_convert_name(pdc_core *pdc, const char *name, int len, int flags); +char *pdc_convert_name_ext(pdc_core *pdc, const char *name, int len, + pdc_encoding enc, int codepage, int flags); + +char *pdc_utf8_to_hostbytes(pdc_core *pdc, pdc_bool honorlang, char *name); +char *pdc_hostbytes_to_utf8(pdc_core *pdc, pdc_bool honorlang, char *name); + +char *pdc_utf16_to_utf8(pdc_core *pdc, const char *utf16string, int len, + int flags, int *size); +char *pdc_utf8_to_utf16(pdc_core *pdc, const char *utf8string, + const char *format, int flags, int *size); +char *pdc_utf16_to_utf32(pdc_core *pdc, const char *utf16string, int len, + int *size); +char *pdc_utf32_to_utf8(pdc_core *pdc, const char *utf32string, int len, + int flags, int *size); +char *pdc_utf32_to_utf16(pdc_core *pdc, const char *utf32string, int len, + const char *format, int flags, int *size); +int pdc_char16_to_char32(pdc_core *pdc, const pdc_ushort *ustext, int *ic, + int len, pdc_bool verbose); +int pdc_char32_to_char16(pdc_core *pdc, int usv, pdc_ushort *uvlist, + pdc_bool verbose); + +#endif /* PC_UNICODE_H */ diff --git a/src/pdflib/pdcore/pc_util.c b/src/pdflib/pdcore/pc_util.c new file mode 100644 index 0000000..320ee52 --- /dev/null +++ b/src/pdflib/pdcore/pc_util.c @@ -0,0 +1,2726 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_util.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * PDFlib various utility routines + * + */ + +#include <errno.h> + +#include "pc_util.h" +#include "pc_file.h" +#include "pc_ctype.h" + +#ifdef AS400 +#include <qp0z1170.h> /* for getenv() emulation */ +#endif + +#ifdef __sun +#include <ieeefp.h> /* for finite */ +#endif + +#if defined (isfinite) +#define PDC_ISFINITE isfinite +#else /* isfinite */ + +#ifdef _WIN32 +#include <windows.h> +#include <float.h> +#define PDC_ISFINITE _finite +#else /* _WIN32 */ + +#ifdef OS_ZOS_SASC +#define PDC_ISFINITE isfinite +#else /* OS_ZOS_SASC */ + +#define PDC_ISFINITE finite +#endif +#endif +#endif + + +/* ------------------- Floating-point number check ----------------------- */ + + + +/* + * pdc_check_number checks whether a floating-point number + * is valid and within the specified range. If not, an exception + * will be thrown. + */ +void +pdc_check_number_limits(pdc_core *pdc, const char *paramname, double dz, + double dmin, double dmax) +{ + if (!PDC_ISFINITE(dz)) + { + pdc_error(pdc, PDC_E_ILLARG_FLOAT_NAN, paramname, 0, 0, 0); + } + else if (dz < dmin) + { + pdc_error(pdc, PDC_E_ILLARG_FLOAT_TOOSMALL, paramname, + pdc_errprintf(pdc, "%f", dz), + pdc_errprintf(pdc, "%f", dmin), 0); + } + else if (dz > dmax) + { + pdc_error(pdc, PDC_E_ILLARG_FLOAT_TOOLARGE, paramname, + pdc_errprintf(pdc, "%f", dz), + pdc_errprintf(pdc, "%f", dmax), 0); + } +} + +void +pdc_check_number(pdc_core *pdc, const char *paramname, double dz) +{ + pdc_check_number_limits(pdc, paramname, dz, PDC_FLOAT_MIN, PDC_FLOAT_MAX); +} + +void +pdc_check_number_zero(pdc_core *pdc, const char *paramname, double dz) +{ + pdc_check_number_limits(pdc, paramname, dz, PDC_FLOAT_MIN, PDC_FLOAT_MAX); + + if (PDC_FLOAT_ISNULL(dz)) + { + pdc_error(pdc, PDC_E_ILLARG_FLOAT_ZERO, paramname, + pdc_errprintf(pdc, "%f", dz), 0, 0); + } +} + + +/* ---------------- "unsupported feature" error message ------------------ */ + +void +pdc_set_unsupp_error(pdc_core *pdc, int err_config, int err_lite, + pdc_bool warning) +{ + (void) err_config; + (void) err_lite; + +/* this feature is sufficient for non public version */ + if (warning) + pdc_warning(pdc, err_lite, 0, 0, 0, 0); + else + pdc_error(pdc, err_lite, 0, 0, 0, 0); +} + + +/* -------------------------- Time functions ------------------------------ */ + +#ifndef WINCE +#ifndef __USE_POSIX +#define __USE_POSIX +#endif +#include <time.h> +#else +#include <winbase.h> +#endif + +/* our private localtime() function. this one circumvents platform +** quirks we found on WINCE and Solaris, and perhaps some more in +** the future. +*/ +void +pdc_localtime(pdc_time *t) +{ +#ifdef WINCE + + SYSTEMTIME st; + + GetLocalTime (&st); + + t->second = st.wSecond; + t->minute = st.wMinute; + t->hour = st.wHour; + t->mday = st.wDay; + t->wday = st.wDayOfWeek; + t->month = st.wMonth; + t->year = st.wYear; + +#else + + time_t timer; + struct tm ltime; + + time(&timer); + +#if defined(PDC_NEEDS_R_FUNCTIONS) + + /* the localtime() function isn't thread safe on this platform. + ** a thread safe variant must be used instead. + */ + (void) localtime_r(&timer, <ime); + +#else + + ltime = *localtime(&timer); + +#endif /* !PDC_NEEDS_R_FUNCTIONS */ + + t->second = ltime.tm_sec; + t->minute = ltime.tm_min; + t->hour = ltime.tm_hour; + t->mday = ltime.tm_mday; + t->wday = ltime.tm_wday; + t->month = ltime.tm_mon; + t->year = ltime.tm_year; + +#endif /* !WINCE */ +} + +static void +pdc_localtime_r(const time_t *timer, struct tm *res) +{ +#if defined(PDC_NEEDS_R_FUNCTIONS) + (void) localtime_r(timer, res); +#else + *res = *localtime(timer); +#endif +} + +static void +pdc_gmtime_r(const time_t *timer, struct tm *res) +{ +#if defined(PDC_NEEDS_R_FUNCTIONS) + (void) gmtime_r(timer, res); +#else + *res = *gmtime(timer); +#endif +} + +void +pdc_get_timestr(char *str, pdc_bool ktoascii) +{ +#ifndef WINCE + time_t timer, gtimer; + struct tm ltime; + double diffminutes; + int utcoffset; +#else + SYSTEMTIME st; +#endif + + (void) ktoascii; + +#ifndef WINCE + time(&timer); + +#if !defined(I370) + pdc_gmtime_r(&timer, <ime); + gtimer = mktime(<ime); + pdc_localtime_r(&timer, <ime); + ltime.tm_isdst = 0; + diffminutes = difftime(mktime(<ime), gtimer) / 60; + if (diffminutes >= 0) + utcoffset = (int)(diffminutes + 0.5); + else + utcoffset = (int)(diffminutes - 0.5); +#else + utcoffset = 0; +#endif + + /* Get local time again, previous data is damaged by mktime(). */ + pdc_localtime_r(&timer, <ime); + + if (utcoffset > 0) + sprintf(str, "D:%04d%02d%02d%02d%02d%02d+%02d'%02d'", + ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday, + ltime.tm_hour, ltime.tm_min, ltime.tm_sec, + utcoffset / 60, utcoffset % 60); + else if (utcoffset < 0) + sprintf(str, "D:%04d%02d%02d%02d%02d%02d-%02d'%02d'", + ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday, + ltime.tm_hour, ltime.tm_min, ltime.tm_sec, + abs(utcoffset) / 60, abs(utcoffset) % 60); + else + sprintf(str, "D:%04d%02d%02d%02d%02d%02dZ", + ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday, + ltime.tm_hour, ltime.tm_min, ltime.tm_sec); + +#else + GetLocalTime (&st); + sprintf(str, "D:%04d%02d%02d%02d%02d%02d", + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); +#endif /* !WINCE */ + + +} + + +/* -------------------------- Environment ------------------------------ */ + +char * +pdc_getenv(const char *name) +{ +#ifdef HAVE_ENVVARS + return getenv(name); +#else + (void) name; + + return (char *) 0; +#endif +} + + +/* ------------------------ Language Code ------------------------------ */ + +/* ISO 639 Windows and Mac Language codes */ +static const char lang_codes_ISO639[] = + "ab aa af sq am ar hy as ay az ba eu bn dz bh bi br bg my be km ca zh co" + "hr cs da nl en eo et fo fa fj fi fr fy gl gd gv ka de el kl gn gu ha he" + "hi hu is id ia ie iu ik ga it ja jv kn ks kk rw ky rn ko ku lo la lv li" + "ln lt mk mg ms ml mt mi mr mo mn na ne no oc or om ps pl pt pa qu rm ro" + "ru sm sg sa sr sh st tn sn sd si ss sk sl so es su sw sv tl tg ta tt te" + "th bo ti to ts tr tk tw ug uk ur uz vi vo cy wo xh yi yo zu" + "pt-br en-gb en-us de-de de-ch"; + +pdc_bool +pdc_check_lang_code(pdc_core *pdc, const char* lang_code) +{ + pdc_bool valid = pdc_false; + int i; + char* country_code; + char* language; + + if ((lang_code != NULL) && *lang_code) + { + /* do not check for IANA or private languages */ + if (!(valid = ((lang_code[0] == 'i') || (lang_code[0] == 'x')))) + { + language = pdc_strdup(pdc, lang_code); + for (i = 0; i < (int)strlen(language); i++) + { + if (pdc_isupper(language[i])) + { + language[i] = (char) pdc_tolower((int)language[i]); + } + } + + + country_code = (char *)strstr(lang_codes_ISO639, language); + valid = (country_code != NULL); + + if (!valid && (strlen(language) > 2)) + { + country_code = strchr(language, '-'); + if (country_code != NULL) + { + country_code[0] = '\0'; + + country_code = (char *)strstr(lang_codes_ISO639, language); + valid = (country_code != NULL); + + if (!valid) + { + pdc_warning(pdc, PDC_E_ILLARG_LANG_CODE, + lang_code, 0, 0, 0); + } + } + } + + pdc_free(pdc, language); + } + } + + return valid; +} + + +/* -------------------------- Bit arryas ------------------------------ */ + +void +pdc_setbit(char *bitarr, int bit) +{ + bitarr[bit/8] |= (char) (1<<(bit%8)); +} + +pdc_bool +pdc_getbit(const char *bitarr, int bit) +{ + return (pdc_bool) (bitarr[bit/8] & (1<<(bit%8))); +} + +void +pdc_setbit_text(char *bitarr, const pdc_byte *text, int len, + int nbits, int size) +{ + int i, bit; + pdc_ushort *ustext = (pdc_ushort *) text; + + for (i = 0; i < len; i += size) + { + if (size == sizeof(pdc_byte)) + bit = (int) text[i]; + else + bit = ustext[i/size]; + if (bit < nbits) pdc_setbit(bitarr, bit); + } +} + + +/* ---------- Get functions of integer binary data types --------------- */ + +pdc_short +pdc_get_le_short(const pdc_byte *data) +{ + return (pdc_short) ((pdc_short) (data[1] << 8) | data[0]); +} + +pdc_ushort +pdc_get_le_ushort(const pdc_byte *data) +{ + return (pdc_ushort) ((data[1] << 8) | data[0]); +} + +pdc_uint32 +pdc_get_le_ulong3(const pdc_byte *data) +{ + return (pdc_uint32) (((((data[2]) << 8) | data[1]) << 8) | data[0]); +} + +pdc_sint32 +pdc_get_le_long(const pdc_byte *data) +{ + return ((pdc_sint32) + (((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]); +} + +pdc_uint32 +pdc_get_le_ulong(const pdc_byte *data) +{ + return (pdc_uint32) + ((((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]); +} + +pdc_short +pdc_get_be_short(const pdc_byte *data) +{ + return (pdc_short) ((pdc_short) (data[0] << 8) | data[1]); +} + +pdc_ushort +pdc_get_be_ushort(const pdc_byte *data) +{ + return (pdc_ushort) ((data[0] << 8) | data[1]); +} + +pdc_uint32 +pdc_get_be_ulong3(const pdc_byte *data) +{ + return (pdc_uint32) (((((data[0]) << 8) | data[1]) << 8) | data[2]); +} + +pdc_sint32 +pdc_get_be_long(const pdc_byte *data) +{ + return ((pdc_sint32) + (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]); +} + +pdc_uint32 +pdc_get_be_ulong(const pdc_byte *data) +{ + return (pdc_uint32) + ((((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]); +} + + +/* ----------------- String handling for Unicode too ------------------- */ + +/* strlen() for unicode strings, which are terminated by two zero bytes. + * wstrlen() returns the number of bytes in the Unicode string, + * not including the two terminating null bytes. + */ +static size_t +wstrlen(const char *s) +{ + size_t len = 0; + + while(s[len] != 0 || s[len+1] != 0) + { + len += 2; + } + + return len; +} + +/* + * This function returns the length in bytes for C and Unicode strings. + * Note that unlike strlen() it returns the length _including_ the + * terminator, which may be one or two null bytes. + */ +size_t +pdc_strlen(const char *text) +{ + if (pdc_is_utf16be_unicode(text) || pdc_is_utf16le_unicode(text)) + return wstrlen(text); + else + return strlen(text); +} + + +/* Allocate a local buffer and copy the string including + * the terminating sentinel. If the string starts with the Unicode BOM + * it is considered a Unicode string, and must be terminated by + * two null bytes. Otherwise it is considered a plain C string and + * must be terminated by a single null byte. + * The caller is responsible for freeing the buffer. + * + * The special functions pdc_strdup and pdc_strdup_tmp + * should be replaced by the more sophisticated function pdc_strdup_ext. + * There: flags (see pc_unicode.h): + * + * PDC_CONV_TMPALLOC, PDC_CONV_EBCDIC + * + */ +char * +pdc_strdup_ext(pdc_core *pdc, const char *text, int flags, const char *fn) +{ + char *buf = NULL; + + if (text != NULL) + { + size_t len = pdc_strlen(text) + 1; + + if (flags & PDC_CONV_TMPALLOC) + buf = (char *) pdc_malloc_tmp(pdc, len + 1, fn, NULL, NULL); + else + buf = (char *) pdc_malloc(pdc, len + 1, fn); + memcpy(buf, text, len); + buf[len] = 0; + + } + + return buf; +} + +char * +pdc_strdup(pdc_core *pdc, const char *text) +{ + char *buf = NULL; + static const char fn[] = "pdc_strdup"; + + if (text != NULL) + { + size_t len = pdc_strlen(text) + 1; + + buf = (char *) pdc_malloc(pdc, len + 1, fn); + memcpy(buf, text, len); + buf[len] = 0; + } + + return buf; +} + +char * +pdc_strdup2(pdc_core *pdc, const char *text, size_t len) +{ + char *buf = NULL; + static const char fn[] = "pdc_strdup2"; + + if (text != NULL) + { + buf = (char *) pdc_malloc(pdc, len + 1, fn); + memcpy(buf, text, len); + buf[len] = 0; + } + + return buf; +} + +char * +pdc_strdup_tmp(pdc_core *pdc, const char *text) +{ + char *buf = NULL; + static const char fn[] = "pdc_strdup_tmp"; + + if (text != NULL) + { + size_t len = pdc_strlen(text) + 1; + + buf = (char *) pdc_malloc_tmp(pdc, len + 1, fn, NULL, NULL); + memcpy(buf, text, len); + buf[len] = 0; + } + + return buf; +} + +/* Allocate a local buffer and copy a locale UTF-8 string + * provided with an UTF-8 BOM. + * The caller is responsible for freeing the buffer. + */ +char * +pdc_strdup_withbom(pdc_core *pdc, const char *text) +{ + char *buf = NULL; + static const char fn[] = "pdc_strdup_withbom"; + + if (text != NULL) + { + size_t len; + + if (pdc_is_utf8_bytecode(text)) + { + buf = pdc_strdup(pdc, text); + } + else + { + len = strlen(text); + buf = (char *) pdc_malloc(pdc, len + 4, fn); + + pdc_copy_utf8_bom(buf); + strcpy(&buf[3], text); + } + } + + return buf; +} + +char * +pdc_strdup_convert(pdc_core *pdc, pdc_encoding encto, pdc_encoding encfrom, + const char *text, int flags, const char *fn) +{ + pdc_encodingvector *evfrom, *evto; + char *buf; + size_t len; + int i; + + evto = pdc_get_encoding_vector(pdc, encto); + evfrom = pdc_get_encoding_vector(pdc, encfrom); + buf = pdc_strdup_ext(pdc, text, flags, fn); + len = strlen(buf); + + for (i = 0; i < (int) len; i++) + buf[i] = (char) pdc_transform_bytecode(pdc, evto, evfrom, + (pdc_byte) text[i]); + + return buf; +} + +pdc_bool +pdc_logg_isprint(int c) +{ + if (c < 0x20 || (c >= 0x7F && c < 0xA0)) + return pdc_false; + return pdc_true; +} + + +/* + * Put out an arbitrary string. + * + * strform = readable: Direct byte output with replacing not + * printable bytes by their octal codes. + * = readable0: Like readable, but byte 0 will be displayed as space. + * = octal: All bytes will be put out as octal. + * = hexa: All bytes will be put out as hexadecimal value. + * = java: Like readable, but Unicode strings and not printable + * bytes will be put out in Java notation \uxxxx, + * + * Output string is temporarily allocated. + * + */ +char * +pdc_strprint(pdc_core *pdc, const char *str, int leni, int maxchar, + pdc_strform_kind strform) +{ + static const char fn[] = "pdc_strprint"; + + if (str != NULL) + { + pdc_bool isunicode = pdc_false; + int len = leni; + + if (!leni) + len = (int) strlen(str); + + if (len) + { + pdc_strform_kind sf; + char *ts, *tmpstr; + pdc_byte c = ' ', cp = '.'; + pdc_ushort *ush = (pdc_ushort *) str; + int i, im; + + tmpstr = (char *) pdc_calloc_tmp(pdc, (size_t) (4 * (len + 4)), fn, + NULL, NULL); + ts = tmpstr; + + if (strform == strform_java) + { + if (leni && !(leni % 2)) + isunicode = pdc_true; + else + strform = strform_readable; + } + + if (maxchar <= 0) + maxchar = len; + im = (maxchar < len) ? maxchar : len; + if (isunicode) + im = im/2; + for (i = 0; i < im; i++) + { + if (isunicode) + { + if (ush[i] > PDC_UNICODE_MAXLATIN1) + { + sf = strform_java; + } + else + { + c = (pdc_byte) ush[i]; + sf = strform_readable; + } + } + else + { + c = (pdc_byte) str[i]; + sf = strform; + } + + switch (sf) + { + case strform_hexa: + ts += sprintf(ts, "\\x%02X", c); + break; + + case strform_octal: + ts += sprintf(ts, "\\%03o", c); + break; + + case strform_java: + ts += sprintf(ts, "\\u%04X", ush[i]); + break; + + default: + if (c == 0x0 && sf == strform_readable0) + c = 0x20; + + if (!pdc_logg_isprint((int) c)) + { + if (isunicode) + ts += sprintf(ts, "\\u%04X", c); + else + ts += sprintf(ts, "\\%03o", c); + } + else + { + if (c == '"') + { + *ts = '\\'; + ts++; + } + *ts = (char) c; + ts++; + } + } + } + + if (maxchar < len) + { + switch (strform) + { + case strform_hexa: + ts += sprintf(ts, "\\x%02X\\x%02X\\x%02X", cp, cp, cp); + break; + + case strform_octal: + ts += sprintf(ts, "\\%03o\\%03o\\%03o", cp, cp, cp); + break; + + case strform_java: + ts += sprintf(ts, "\\u%04X\\u%04X\\u%04X", cp, cp, cp); + break; + + default: + ts += sprintf(ts, "%c%c%c", cp, cp, cp); + break; + } + } + + return tmpstr; + } + } + + return (char *) pdc_calloc_tmp(pdc, 1, fn, NULL, NULL); +} + +const char * +pdc_utf8strprint(pdc_core *pdc, const char *str) +{ + int i = pdc_is_utf8_bytecode(str) ? 3 : 0; + return pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, &str[i]); +} + +/* + * Split a given text string into single strings which are separated by + * arbitrary characters. This characters must be specified in a string. + * If this string is NULL, " \f\n\r\t\v" (standard white spaces) is assumed. + * + * There is the convention that text inside braces {} will be taken verbatim. + * Inside brace expressions braces must exist only in pairs. Braces are + * masked by backslash. + * + * The caller is responsible for freeing the resultated string list + * by calling the function pdc_cleanup_stringlist. + * + * Not for unicode strings. + * + * Return value: Number of strings. + * If braces aren't balanced the number is negative. + * + */ +int +pdc_split_stringlist(pdc_core *pdc, const char *text, const char *i_separstr, + int flags, char ***stringlist) +{ + static const char fn[] = "pdc_split_stringlist"; + const char *separstr = " \f\n\r\t\v"; + const char *oldtext; + char **strlist = NULL, *newtext; + pdc_bool isoptlist = (flags & PDC_SPLIT_ISOPTLIST); + int it, len, jt = 0, jtb = 0, maxk = 0, count = 0, inside = 0; + int ns, nbs = 0, nbss; + + if (stringlist) + *stringlist = NULL; + if (i_separstr) + separstr = i_separstr; + + if (text == NULL) + return 0; + + /* check for empty string */ + ns = (int) strspn(text, separstr); + oldtext = &text[ns]; + len = (int) strlen(oldtext); + if (!len) return 0; + + /* check for UTF-8-BOM */ + if (pdc_is_utf8_bytecode(oldtext)) + { + oldtext = &text[ns + 3]; + len -= 3; + ns = (int) strspn(oldtext, separstr); + oldtext = &oldtext[ns]; + len -= ns; + if (!len) return 0; + } + + /* new string */ + newtext = (char *) pdc_malloc(pdc, (size_t) (len + 1), fn); + for (it = 0; it <= len; it++) + { + /* check for separators */ + if (it == len) + ns = 1; + else if (inside <= 0) + ns = (int) strspn(&oldtext[it], separstr); + else + ns = 0; + + /* close text part */ + if (ns) + { + newtext[jt] = 0; + if (count == maxk) + { + maxk += 16; + strlist = (strlist == NULL) ? + (char **) pdc_malloc(pdc, maxk * sizeof(char *), fn): + (char **) pdc_realloc(pdc, strlist, maxk * + sizeof(char *), fn); + } + strlist[count] = &newtext[jtb]; + count++; + + /* Exit */ + it += ns; + if (it >= len ) break; + + /* new text part */ + jt++; + jtb = jt; + } + + /* option list */ + if (isoptlist) + { + /* save backslash counter */ + nbss = nbs; + + /* backslash */ + if (oldtext[it] == '\\') + { + nbs++; + if (!(nbs % 2) && inside <= 1) + continue; + } + else + { + nbs = 0; + } + + /* open and close brace */ + if (oldtext[it] == '{') + { + if (!(nbss % 2)) + { + inside++; + if (inside == 1) + continue; + } + else if (inside <= 1) + { + jt--; + } + } + else if (oldtext[it] == '}') + { + if (!(nbss % 2)) + { + inside--; + if (inside == 0) + continue; + } + else if (inside <= 1) + { + jt--; + } + } + } + + /* save character */ + newtext[jt] = oldtext[it]; + jt++; + } + + if (stringlist) + *stringlist = strlist; + + return inside ? -count : count; +} + +void +pdc_cleanup_stringlist(pdc_core *pdc, char **stringlist) +{ + if(stringlist != NULL) + { + if(stringlist[0] != NULL) + pdc_free(pdc, stringlist[0]); + + pdc_free(pdc, stringlist); + } +} + + +/* + * Substitute a list of variables in a string by its values recursively. + * A variable begins with the character 'vchar' and ends at a character + * in 'delimiters' or at the end of string resp.. + * + * The character 'vchar' must be masked by 'vchar'. + * + * If at least one of a variable was substituted, a new allocated null + * terminated string is returned. Otherwise the original pointer. + * + * The caller is responsible for freeing the new string. + * + * string null terminated string with variables + * vchar begin character for a variable + * delimiters string with characters delimiting a variable name + * varslist list of variable names + * valslist list of variable values + * nvars number of variables + * errind[2] contains index and length of an unkown variable in string + * + */ + +static char * +substitute_variables(pdc_core *pdc, char *string, int ibeg, int *level, + const char **varslist, const char **valslist, int nvars, char vchar, + const char *separstr, int *errind) +{ + static const char fn[] = "substitue_variables"; + int i, j, l; + + j = ibeg; + for (i = ibeg; string[i] != 0; i++) + { + if (string[i] == vchar) + { + if (string[i + 1] == vchar) + i++; + else + break; + } + + string[j] = string[i]; + j++; + } + + if (string[i] != 0) + { + char *s = &string[i + 1]; + size_t n = strcspn(s, separstr); + + for (l = 0; l < nvars; l++) + { + if (n == strlen(varslist[l]) && !strncmp(s, varslist[l], n)) + { + char *newstring; + int k = (int) (i + n + 1); + size_t nv = strlen(valslist[l]); + size_t nr = strlen(&string[k]); + size_t nb = (size_t) j + nv + nr + 1; + + newstring = (char *) pdc_malloc(pdc, nb, fn); + strncpy(newstring, string, (size_t) j); + strncpy(&newstring[j], valslist[l], nv); + strcpy(&newstring[j + nv], &string[k]); + + pdc_free(pdc, string); + (*level)++; + + string = substitute_variables(pdc, newstring, j, level, + varslist, valslist, nvars, vchar, separstr, + errind); + break; + } + } + if (l == nvars) + { + errind[0] = i; + errind[1] = (int) (n + 1); + } + } + else + { + string[j] = 0; + } + return string; +} + +char * +pdc_substitute_variables(pdc_core *pdc, const char *string, char vchar, + const char *delimiters, const char **varslist, + const char **valslist, int nvars, int *errind) +{ + static const char fn[] = "pdc_substitue_variables"; + char *subststr, *newstring, separstr[64]; + int level = 0; + + newstring = pdc_strdup_ext(pdc, string, 0, fn); + + separstr[0] = vchar; + separstr[1] = 0; + strcat(separstr, delimiters); + + errind[0] = -1; + errind[1] = 0; + subststr = substitute_variables(pdc, newstring, 0, &level, + varslist, valslist, nvars, vchar, separstr, errind); + + return subststr; +} + +/* + * Compares its arguments and returns an integer less than, + * equal to, or greater than zero, depending on whether s1 + * is lexicographically less than, equal to, or greater than s2. + * Null pointer values for s1 and s2 are treated the same as pointers + * to empty strings. + * + * Presupposition: basic character set + * + * Return value: < 0 s1 < s2; + * = 0 s1 == s2; + * > 0 s1 > s2; + * + */ +int +pdc_strcmp(const char *s1, const char *s2) +{ + if (s1 == s2) return (0); + if (s1 == NULL) return (-1); + if (s2 == NULL) return (1); + + return strcmp(s1, s2); +} + +int +pdc_stricmp(const char *s1, const char *s2) +{ + if (s1 == s2) return (0); + if (s1 == NULL) return (-1); + if (s2 == NULL) return (1); + + for (; *s1; ++s1, ++s2) + { + if (pdc_tolower(*s1) != pdc_tolower(*s2)) + break; + } + + return (pdc_tolower(*s1) - pdc_tolower(*s2)); +} + + +/* + * Compares its arguments and returns an integer less than, + * equal to, or greater than zero, depending on whether s1 + * is lexicographically less than, equal to, or greater than s2. + * But only up to n characters compared (n less than or equal + * to zero yields equality).Null pointer values for s1 and s2 + * are treated the same as pointers to empty strings. + * + * Presupposition: basic character set + * + * Return value: < 0 s1 < s2; + * = 0 s1 == s2; + * > 0 s1 > s2; + * + */ +int +pdc_strincmp(const char *s1, const char *s2, int n) +{ + int i; + + if (s1 == s2) return (0); + if (s1 == NULL) return (-1); + if (s2 == NULL) return (1); + + for (i = 0; i < n && *s1 && *s2; ++i, ++s1, ++s2) + { + if (pdc_tolower(*s1) != pdc_tolower(*s2)) + break; + } + + return (i == n) ? 0 : (pdc_tolower(*s1) - pdc_tolower(*s2)); +} + +/* + * pdc_strtrim removes trailing white space characters from an input string. + * pdc_str2trim removes leading and trailing white space characters from an + * input string.. + */ +char * +pdc_strtrim(char *str) +{ + int i, n; + + n = (int) strlen(str); + for (i = n - 1; i >= 0; i--) + if (!pdc_isspace(str[i])) break; + str[i + 1] = '\0'; + + return str; +} + +char * +pdc_str2trim(char *str) +{ + int i, n; + + n = (int) strlen(str); + for (i = n - 1; i >= 0; i--) + if (!pdc_isspace(str[i])) break; + str[i + 1] = '\0'; + + for (i = 0; ; i++) + if (!pdc_isspace(str[i])) break; + if (i > 0) + memmove(str, &str[i], strlen(&str[i]) + 1); + + return str; +} + +char * +pdc_strtoupper(char *str) +{ + int i, n; + + n = (int) strlen(str); + for (i = 0; i < n; i++) + str[i] = (char) pdc_toupper(str[i]); + + return str; +} + +char * +pdc_strtolower(char *str) +{ + int i, n; + + n = (int) strlen(str); + for (i = 0; i < n; i++) + str[i] = (char) pdc_tolower(str[i]); + + return str; +} + +int +pdc_tolower_ascii(int c) +{ + c = (int) pdc_tolower(c); + + return c; +} + +int +pdc_toupper_ascii(int c) +{ + c = (int) pdc_toupper((int) c); + + return c; +} + +void +pdc_swap_bytes(char *instring, int inlen, char *outstring) +{ + char c; + int i,j; + + if (instring == NULL) + return; + + if (outstring == NULL) + outstring = instring; + + inlen = 2 * inlen / 2; + for (i = 0; i < inlen; i++) + { + j = i; + i++; + c = instring[j]; + outstring[j] = instring[i]; + outstring[i] = c; + } +} + +void +pdc_swap_unicodes(char *instring) +{ + if (instring && + ((pdc_is_utf16be_unicode(instring) && !PDC_ISBIGENDIAN) || + (pdc_is_utf16le_unicode(instring) && PDC_ISBIGENDIAN))) + pdc_swap_bytes(&instring[2], (int) (wstrlen(instring) - 2), NULL); +} + +void +pdc_inflate_ascii(const char *instring, int inlen, char *outstring, + pdc_text_format textformat) +{ + int i, j; + pdc_bool is_bigendian = (textformat == pdc_utf16be) || + (textformat == pdc_utf16 && PDC_ISBIGENDIAN); + + j = 0; + for (i = 0; i < inlen; i++) + { + if (is_bigendian) + { + outstring[j] = 0; + j++; + outstring[j] = instring[i]; + } + else + { + outstring[j] = instring[i]; + j++; + outstring[j] = 0; + } + j++; + } +} + +/* + * pdc_stresc -- + * Remove from a string containing escaped non-printable cha- + * racters. The string must follows the C-standard escape + * mechanism: an escaped character is preceeded by an escape + * character which is a backslash '\' character and followed + * by one or more characters to define the non-printable + * character to be inserted here. The supported escapes are + * + * \a bell (ASCII/EBCDIC-BEL) + * \b backspace (ASCII/EBCDIC-BS) + * \e escape charater (ASCII/EBCDIC-ESC) + * \f formfeed (ASCII/EBCDIC-FF) + * \n linefeed (ASCII/EBCDIC-LF) + * \r return (ASCII/EBCDIC-CR) + * \t tab character (ASCII/EBCDIC-TAB) + * \v vertical tab (ASCII/EBCDIC-VT) + * \\ the slash itself + * \xnn two hex digits n to define a + * character numerically as ASCII/EBCDIC value. + * \nnn three octal digits n to define a + * character numerically as ASCII/EBCDIC value. + * + * For example: \x0A, \x0a or \012 has the same effect in ASCII + * as \n (i.e linefeed). + * Note, if the last character in a string is the backslash + * then the backslash is illegal. + * The special characters a,b,e,f, and so on are recognized in + * lower case only. + * + * textformat: + * pdc_bytes: Latin1 or EBCDIC bytes on EBCDIC platforms + * pdc_utf8: Latin1 + * pdc_ebcdicutf8: EBCDIC - only on EBCDIC platforms + * pdc_utf16: 2 bytes Latin1 + * + * If a illegal escaped sequence was detected an exception will + * be thrown (verbose == pdc_true) or the sequence will be taken + * as it (verbose == pdc_false). + * +*/ + +static const pdc_keyconn pdc_ascii_escape_keylist[] = +{ + {"\\", 0x5C}, + {"a", 0x07}, + {"b", 0x08}, + {"e", 0x1B}, + {"f", 0x0C}, + {"n", 0x0A}, + {"r", 0x0D}, + {"t", 0x09}, + {"v", 0x0B}, + {"x", 0x78}, + {NULL, 0} +}; + +pdc_ushort +pdc_get_string_value(pdc_byte *str, int i, int charlen) +{ + pdc_ushort retval = 0; + + if (charlen == 1) + { + retval = (pdc_ushort) str[i]; + } + else + { + pdc_ushort *ustr = (pdc_ushort *) str; + + retval = ustr[i]; + } + + return retval; +} + +int +pdc_subst_backslash(pdc_core *pdc, pdc_byte *str, int len, + pdc_encodingvector *ev, pdc_text_format textformat, + pdc_bool verbose) +{ + pdc_ushort *ustr = (pdc_ushort *) str; + int charlen = (textformat == pdc_utf16) ? 2 : 1; + pdc_byte bschar = '\\'; + pdc_ushort uv; + int i, j, k, code; + + if (ev != NULL) + { + code = pdc_get_encoding_bytecode(pdc, ev, PDC_UNICODE_BACKSLASH); + if (code != -1) + bschar = (pdc_byte) code; + } + + + j = 0; + len /= charlen; + for (i = 0; i < len; i++) + { + uv = pdc_get_string_value(str, i, charlen); + if (uv > PDC_UNICODE_MAXLATIN1) + { + ustr[j] = uv; + j++; + continue; + } + + /* backslash found */ + if (uv == bschar) + { + pdc_byte escseq[4], stemp[6]; + pdc_bool kerror = pdc_false; + + i++; + if (i < len) + { + uv = pdc_get_string_value(str, i, charlen); + if (uv > PDC_UNICODE_MAXLATIN1) + goto PDC_OVERFLOW_EXIT; + + escseq[0] = (pdc_byte) uv; + escseq[1] = 0; + + code = pdc_get_keycode((char *) escseq, + pdc_ascii_escape_keylist); + if (code != PDC_KEY_NOTFOUND) + { + /* hex number */ + if (code == 0x78) + { + for (k = 0; k < 2; k++) + { + i++; + if (i < len) + { + uv = pdc_get_string_value(str, i, charlen); + if (uv > PDC_UNICODE_MAXLATIN1) + goto PDC_OVERFLOW_EXIT; + } + else + { + uv = 0; + } + escseq[k] = (pdc_byte) uv; + } + escseq[k] = 0; + if (i >= len || + !pdc_str2integer((char *) escseq, PDC_INT_UNICODE, + &uv)) + { + strcpy((char *) stemp, "\\x"); + strcat((char *) stemp, (char *) escseq); + kerror = pdc_true; + } + } + else + { + pdc_char c = (pdc_char) code; + uv = (pdc_ushort) (pdc_byte) c; + } + } + else + { + /* octal number */ + for (k = 0; k < 3; k++) + { + if (k) i++; + if (i < len) + { + uv = pdc_get_string_value(str, i, charlen); + if (uv > PDC_UNICODE_MAXLATIN1) + goto PDC_OVERFLOW_EXIT; + } + else + { + uv = 0; + } + escseq[k] = (pdc_byte) uv; + } + escseq[k] = 0; + if (i >= len || + !pdc_str2integer((char *) escseq, + PDC_INT_SHORT | + PDC_INT_UNSIGNED | + PDC_INT_OCTAL, + &uv) || + (charlen == 1 && uv > 0xFF)) + { + strcpy((char *) stemp, "\\"); + strcat((char *) stemp, (char *) escseq); + kerror = pdc_true; + } + } + } + else + { + strcpy((char *) stemp, "\\"); + kerror = pdc_true; + } + + /* error message */ + if (kerror) + { + pdc_set_errmsg(pdc, PDC_E_STR_ILL_ESCSEQ, (char *) stemp, + 0, 0, 0); + + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + + return 0; + } + } + + if (charlen == 1) + str[j] = (pdc_byte) uv; + else + ustr[j] = uv; + + j++; + } + + if (charlen == 1) + str[j] = 0; + else + ustr[j] = 0; + + return charlen * j; + + PDC_OVERFLOW_EXIT: + + pdc_set_errmsg(pdc, PDC_E_STR_ILL_UNIESCSEQ, + pdc_errprintf(pdc, "%04X", uv), 0, 0, 0); + + if (verbose) + pdc_error(pdc, -1, 0, 0, 0, 0); + + return 0; +} + + +/* ----------------------- number converting ----------------------- */ + +/* + * pdc_str2double converts a null terminated and trimmed string + * to a double precision number + */ +pdc_bool +pdc_str2double(const char *string, double *o_dz) +{ + const char *s = string; + double dz = 0; + int is = 1, isd = 0; + + *o_dz = 0; + + /* sign */ + if (*s == '-') + { + is = -1; + s++; + } + else if (*s == '+') + s++; + + if (!*s) + return pdc_false; + + /* places before decimal point */ + isd = pdc_isdigit(*s); + if (isd) + { + do + { + dz = 10 * dz + *s - '0'; + s++; + } + while (pdc_isdigit(*s)); + } + + /* decimal point */ + if (*s == '.' || *s == ',') + { + const char *sa; + double adz = 0; + + s++; + isd = pdc_isdigit(*s); + if (!isd) + return pdc_false; + + /* places after decimal point */ + sa = s; + do + { + adz = 10 * adz + *s - '0'; + s++; + } + while (pdc_isdigit(*s)); + dz += adz / pow(10.0, (double)(s - sa)); + } + + /* power sign */ + if (*s == 'e' || *s == 'E') + { + s++; + if (!isd) + return pdc_false; + + /* sign */ + if (!*s) + { + dz *= 10; + } + else + { + int isp = 1; + double pdz = 0, pdl = log10(dz); + + if (*s == '-') + { + isp = -1; + s++; + } + else if (*s == '+') + s++; + + if (!pdc_isdigit(*s)) + return pdc_false; + do + { + pdz = 10 * pdz + *s - '0'; + s++; + } + while (pdc_isdigit(*s)); + + + if (*s || fabs(pdl + pdz) > 300.0) + return pdc_false; + + dz *= pow(10.0, isp * pdz); + } + } + else if(*s) + { + return pdc_false; + } + + *o_dz = is * dz; + return pdc_true; +} + +/* + * pdc_str2integer converts a null terminated and trimmed string + * to an hexadecimal or decimal integer number of arbitrary size + */ +pdc_bool +pdc_str2integer(const char *string, int flags, void *o_iz) +{ + const char *s = string; + double dz = 0; + pdc_char cz = 0; + pdc_short sz = 0; + pdc_sint32 lz = 0; + pdc_byte ucz = 0; + pdc_ushort usz = 0; + pdc_uint32 ulz = 0; + int is = 1, lzd; + + if (flags & PDC_INT_CHAR) + memcpy(o_iz, &cz, sizeof(pdc_char)); + else if (flags & PDC_INT_SHORT) + memcpy(o_iz, &sz, sizeof(pdc_short)); + else + memcpy(o_iz, &lz, sizeof(pdc_sint32)); + + /* sign */ + if (*s == '-') + { + if (flags & PDC_INT_UNSIGNED) + return pdc_false; + is = -1; + s++; + } + else if (*s == '+') + s++; + + if (!*s) + return pdc_false; + + /* hexadecimal test */ + if (!(flags & PDC_INT_DEC)) + { + const char *ss = s; + + if (*s == '<') + s += 1; + else if (*s == 'x' || *s == 'X') + s += 1; + else if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) + s += 2; + if (s > ss) + { + if (!*s) + return pdc_false; + flags |= PDC_INT_HEXADEC; + } + } + + /* hexadecimal */ + if (flags & PDC_INT_HEXADEC) + { + while (pdc_isxdigit(*s)) + { + if (pdc_isalpha(*s)) + lzd = (pdc_isupper(*s) ? 'A' : 'a') - 10; + else + lzd = '0'; + dz = 16 * dz + *s - lzd; + s++; + } + if (*string == '<') + { + if (*s == '>') + s += 1; + else + return pdc_false; + } + } + + /* octal */ + if (flags & PDC_INT_OCTAL) + { + while (pdc_isdigit(*s) && *s < '8') + { + dz = 8 * dz + *s - '0'; + s++; + } + } + + /* decimal */ + else + { + while (pdc_isdigit(*s)) + { + dz = 10 * dz + *s - '0'; + s++; + } + } + if (*s) + return pdc_false; + + dz *= is; + if (flags & PDC_INT_CHAR) + { + if (flags & PDC_INT_UNSIGNED) + { + if (dz > PDC_UCHAR_MAX) + return pdc_false; + ucz = (pdc_byte) dz; + memcpy(o_iz, &ucz, sizeof(pdc_byte)); + } + else + { + if (dz < PDC_SCHAR_MIN || dz > PDC_SCHAR_MAX) + return pdc_false; + cz = (pdc_char) dz; + memcpy(o_iz, &cz, sizeof(pdc_char)); + } + } + else if (flags & PDC_INT_SHORT) + { + if (flags & PDC_INT_UNSIGNED) + { + if (dz > PDC_USHRT_MAX) + return pdc_false; + usz = (pdc_ushort) dz; + memcpy(o_iz, &usz, sizeof(pdc_ushort)); + } + else + { + if (dz < PDC_SHRT_MIN || dz > PDC_SHRT_MAX) + return pdc_false; + sz = (pdc_short) dz; + memcpy(o_iz, &sz, sizeof(pdc_short)); + } + } + else + { + if (flags & PDC_INT_UNSIGNED) + { + if (dz > PDC_UINT_MAX) + return pdc_false; + ulz = (pdc_uint32) dz; + memcpy(o_iz, &ulz, sizeof(pdc_uint32)); + } + else + { + if (dz < PDC_INT_MIN || dz > PDC_INT_MAX) + return pdc_false; + lz = (pdc_sint32) dz; + memcpy(o_iz, &lz, sizeof(pdc_sint32)); + } + } + + return pdc_true; +} + +static const char digits[] = "0123456789ABCDEF"; + +static char * +pdc_ltoa(char *buf, long n, int width, char pad, int base) +{ + char aux[100]; + int k, i = sizeof aux; + char * dest = buf; + pdc_bool sign; + + if (n == 0) + { + if (width == 0) + width = 1; + + for (k = 0; k < width; ++k) + *(dest++) = '0'; + + return dest; + } + + if (n < 0 && base == 10) + { + --width; + sign = pdc_true; + aux[--i] = digits[- (n % base)]; + n = n / -base; + } + else + { + sign = pdc_false; + aux[--i] = digits[n % base]; + n = n / base; + } + + while (0 < n) + { + aux[--i] = digits[n % base]; + n = n / base; + } + + width -= (int) (sizeof aux) - i; + for (k = 0; k < width; ++k) + *(dest++) = pad; + + if (sign) + *(dest++) = '-'; + + memcpy(dest, &aux[i], sizeof aux - i); + return dest + sizeof aux - i; +} /* pdc_ltoa */ + + +static char * +pdc_off_t2a(char *buf, pdc_off_t n, int width, char pad, int base) +{ + char aux[100]; + int k, i = sizeof aux; + char * dest = buf; + pdc_bool sign; + + if (n < 0 && base == 10) + { + --width; + sign = pdc_true; + aux[--i] = digits[- (n % base)]; + n = n / -base; + } + else + { + sign = pdc_false; + aux[--i] = digits[n % base]; + n = n / base; + } + + while (0 < n) + { + aux[--i] = digits[n % base]; + n = n / base; + } + + width -= (int) (sizeof aux) - i; + for (k = 0; k < width; ++k) + *(dest++) = pad; + + if (sign) + *(dest++) = '-'; + + memcpy(dest, &aux[i], sizeof aux - i); + return dest + sizeof aux - i; +} /* pdc_off_t2a */ + + +/* + * pdc_ftoa converts a floating point number to string + * + * Because of historical reason "%f" = "%.12g". + * + * The function calls sprintf() and replaces + * decimal comma by decimal point. + * + * If the number is infinite or not a number + * "nan" will be set. + * + */ + +static char * +pdc_ftoa(pdc_core *pdc, const char *format, char *buf, double x) +{ + char *dest = buf; + char *cd; + int n; + + (void) pdc; + + /* check whether the number is valid */ + if (!PDC_ISFINITE(x)) + { + strcpy(dest, "nan"); + return dest + 3; + } + + /* standard C convert */ + if (!strcmp(format, "%f")) + n = sprintf(dest, "%.12g", x); + else + n = sprintf(dest, format, x); + + /* normalized to decimal point */ + cd = strchr(dest, ','); + if (cd != NULL) + *cd = '.'; + + return dest + n; +} /* pdc_ftoa */ + +/* + * pdc_ftoa_pdfconf converts a floating point number to string + * PDF conforming + * + */ + +static char * +pdc_ftoa_pdfconf(pdc_core *pdc, char *buf, double x) +{ + static const long pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; + char * dest = buf; + double integ, fract, powd; + int ifd; + long f; + + /* check whether the number is valid */ + if (!PDC_ISFINITE(x)) + pdc_error(pdc, PDC_E_INT_ILLFLOAT, 0, 0, 0, 0); + + /* small number will be mapped to 0 */ + if (x < PDF_SMALLREAL && x > -PDF_SMALLREAL) + { + *dest = '0'; + return dest + 1; + } + + /* negative number */ + if (x < 0) + { + x = -x; + *(dest++) = '-'; + } + + /* large number is invalid or will be mapped to integer */ + if (x >= PDF_BIGREAL) + { + if (x > PDF_BIGINT) + pdc_error(pdc, PDC_E_INT_FLOATTOOLARGE, + pdc_errprintf(pdc, "%f", x), 0, 0, 0); + + return pdc_ltoa(dest, (long) (x + 0.5), 0, ' ', 10); + } + + ifd = pdc->floatdigits; + powd = pow10[ifd]; + + fract = modf(x, &integ); + f = (long) (fract * powd + 0.5); + + if (f == powd) + { + integ += 1.0; + f = 0; + } + + if (integ == 0 && f == 0) /* avoid "-0" */ + dest = buf; + + dest = pdc_ltoa(dest, (long) integ, 0, ' ', 10); + + if (f != 0) + { + char * aux; + long rem; + + *(dest++) = '.'; + + do /* avoid trailing zeros */ + { + rem = f % 10; + f = f / 10; + --ifd; + } while (rem == 0); + + aux = dest + ifd + 1; + dest[ifd--] = digits[rem]; + + for (; 0 <= ifd; --ifd) + { + dest[ifd] = digits[f % 10]; + f = f / 10; + } + + return aux; + } + + return dest; +} /* pdc_ftoa_pdfconf */ + +static int +pdc_vxprintf( + pdc_core *pdc, + pdc_bool pdfconf, + char *cp, + FILE *fp, + const char *format, + va_list args) +{ + static const char fn[] = "pdc_vxprintf"; + const char *format_p; + char aux[1024]; + char *buf = cp ? cp : aux; + char *dest = buf; + + for (/* */ ; /* */ ; /* */) + { + int width = 0; + int prec = 0; + char pad = ' '; + pdc_bool left_justify = pdc_false; + + /* as long as there is no '%', just print. + */ + while (*format != 0 && *format != '%') + *(dest++) = *(format++); + + if (*format == 0) + { + if (fp != (FILE *) 0) + { + if (dest > buf) + pdc_fwrite_ascii(pdc, buf, (size_t) (dest - buf), fp); + } + else + *dest = 0; + + return (int) (dest - buf); + } + format_p = format; + + /* get the "flags", if any. + */ + if (*(++format) == '-') + { + left_justify = pdc_true; + ++format; + } + + if (*format == '0') + { + if (!left_justify) + pad = '0'; + + ++format; + } + + /* get the "width", if present. + */ + if (*format == '*') + { + width = va_arg(args, int); /* TODO: sign? */ + ++format; + } + else + { + while (pdc_isdigit(*format)) + width = 10 * width + *(format++) - '0'; + } + + /* get the "precision", if present. + */ + if (*format == '.') + { + ++format; + + if (*format == '*') + { + prec = va_arg(args, int); /* TODO: sign? */ + ++format; + } + else + { + while (pdc_isdigit(*format)) + prec = 10 * prec + *(format++) - '0'; + } + } + + switch (*format) + { + case 'x': + case 'X': + dest = pdc_off_t2a( + dest, (pdc_off_t) va_arg(args, unsigned int), + width, pad, 16); + break; + + case 'c': + *(dest++) = (char) va_arg(args, int); + break; + + case 'd': + dest = pdc_off_t2a(dest, (pdc_off_t) va_arg(args, int), + width, pad, 10); + break; + + case 'g': + case 'f': + if (pdfconf) + { + dest = pdc_ftoa_pdfconf(pdc, dest, va_arg(args, double)); + } + else + { + char ff[32]; + size_t n = (size_t) (format - format_p + 1); + + strncpy(ff, format_p, n); + ff[n] = 0; + dest = pdc_ftoa(pdc, ff, dest, va_arg(args, double)); + } + break; + + case 'l': + { + pdc_off_t n; + + if (format[1] == 'l') + { + n = va_arg(args, pdc_off_t); + ++format; + } + else + { + n = va_arg(args, long); + } + + switch (*(++format)) + { + case 'x': + case 'X': + dest = pdc_off_t2a(dest, n, width, pad, 16); + break; + + case 'd': + dest = pdc_off_t2a(dest, n, width, pad, 10); + break; + + default: + pdc_error(pdc, PDC_E_INT_BADFORMAT, + pdc_errprintf(pdc, "l%c", + pdc_isprint((int) *format) ? *format : '?'), + pdc_errprintf(pdc, "0x%02X", *format), + 0, 0); + } + + break; + } + + case 'p': + { + void *ptr = va_arg(args, void *); + dest += sprintf(dest, "%p", ptr); + break; + } + + case 'a': + case 's': + case 'T': + { + char *str = va_arg(args, char *); + const char *cstr = str; + pdc_bool tobefree = pdc_false; + size_t len; + + if (str == 0) + cstr = "(NULL)"; + len = strlen(cstr); + + if (*format == 'T') + { + int l = va_arg(args, int); + + if (str != 0) + { + cstr = pdc_print_loggstring(pdc, str, l); + len = strlen(cstr); + } + } + + if (*format == 'a' && str != 0) + { + cstr = pdc_strdup_ext(pdc, str, PDC_CONV_EBCDIC, fn); + tobefree = pdc_true; + } + + if (!left_justify && len < (size_t) width) + { + memset(dest, pad, width - len); + dest += width - len; + } + + if (len != 0) + { + if (fp != (FILE *) 0) + { + if (dest > buf) + { + pdc_fwrite_ascii(pdc, buf, + (size_t) (dest - buf), fp); + dest = buf; + } + + pdc_fwrite_ascii(pdc, cstr, len, fp); + } + else + { + memcpy(dest, cstr, len); + dest += len; + } + + if (tobefree) + pdc_free(pdc, (char *) cstr); + } + + if (left_justify && len < (size_t) width) + { + memset(dest, pad, width - len); + dest += width - len; + } + + break; + } + + case '%': + *(dest++) = '%'; + break; + + default: + pdc_error(pdc, PDC_E_INT_BADFORMAT, + pdc_errprintf(pdc, "%c", pdc_isprint((int) *format) ? + *format : '?'), + pdc_errprintf(pdc, "0x%02X", *format), + 0, 0); + } /* switch */ + + ++format; + } /* loop */ +} /* pdc_vxprintf */ + + +/* ----------------------- formatted output ----------------------- */ + +/* + * formatted output to file + */ +int +pdc_vfprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp, + const char *format, va_list args) +{ + return pdc_vxprintf(pdc, pdfconf, NULL, fp, format, args); +} /* pdc_vfprintf */ + +int +pdc_fprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp, + const char *format, ...) +{ + int result; + va_list ap; + + va_start(ap, format); + result = pdc_vxprintf(pdc, pdfconf, NULL, fp, format, ap); + va_end(ap); + + return result; +} /* pdc_fprintf */ + + +/* + * formatted output to character string + */ +int +pdc_vsprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf, + const char *format, va_list args) +{ + return pdc_vxprintf(pdc, pdfconf, buf, NULL, format, args); +} /* pdc_vsprintf */ + +int +pdc_sprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf, + const char *format, ...) +{ + int result; + va_list ap; + + va_start(ap, format); + result = pdc_vxprintf(pdc, pdfconf, buf, NULL, format, ap); + va_end(ap); + + return result; +} /* pdc_sprintf */ + +/* + * we cannot use own converter because of missing format + * specifications like %lu + */ +int +pdc_vsnprintf(char *buf, size_t size, const char *format, va_list args) +{ + int result; + +#if defined (PDC_NO_VSNPRINTF) + (void) size; + result = vsprintf(buf, format, args); +#else +#if defined(WIN32) + result = _vsnprintf(buf, size, format, args); +#else + result = vsnprintf(buf, size, format, args); +#endif +#endif + + return result; +} /* pdc_vsnprintf */ + + +/* --------------------- name tree handling ----------------------- */ + +struct pdc_branch_s +{ + char *name; /* name - must be allocated pointer */ + void *data; /* private data - must be allocated pointer */ + int nalloc; /* number of allocated kid structs */ + int nkids; /* number of kids */ + pdc_branch **kids; /* kids */ + pdc_branch *parent; /* parent branch */ +}; + +pdc_branch * +pdc_init_tree(pdc_core *pdc) +{ + return pdc_create_treebranch(pdc, NULL, "__tree__root__", + NULL, 0, 0, NULL, NULL); +} + +pdc_branch * +pdc_create_treebranch(pdc_core *pdc, pdc_branch *root, const char *pathname, + void *data, int flags, int size, + pdc_branch_error *errcode, const char **name_p) +{ + static const char fn[] = "pdc_create_branch"; + char *name = NULL; + pdc_branch *branch = NULL; + pdc_branch *kid = NULL; + pdc_branch *parent = NULL; + char **namelist; + int i, j, k, nnames, nkids; + + if (errcode) *errcode = tree_ok; + if (name_p) *name_p = ""; + + if (root) + { + /* search for parent branch */ + parent = root; + nnames = pdc_split_stringlist(pdc, pathname, PDC_NAME_SEPARSTRG, 0, + &namelist); + for (i = 0; i < nnames; i++) + { + /* parent branch must not be a leaf branch */ + if (!parent->nalloc) + { + if (errcode) *errcode = tree_isleaf; + pdc_cleanup_stringlist(pdc, namelist); + return NULL; + } + if (i == nnames - 1) + break; + + name = namelist[i]; + if (name_p) + *name_p = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, name); + + nkids = parent->nkids; + for (j = 0; j < nkids; j++) + { + kid = parent->kids[j]; + k = pdc_is_utf8_bytecode(kid->name) ? 3 : 0; + if (!strcmp(&kid->name[k], name)) + { + parent = kid; + break; + } + } + if (j == nkids) + { + if (errcode) *errcode = tree_notfound; + pdc_cleanup_stringlist(pdc, namelist); + return NULL; + } + } + + if (pdc_is_utf8_bytecode(pathname)) + name = pdc_strdup_withbom(pdc, namelist[nnames - 1]); + else + name = pdc_strdup(pdc, namelist[nnames - 1]); + pdc_cleanup_stringlist(pdc, namelist); + + /* kids must have different names */ + for (j = 0; j < parent->nkids; j++) + { + kid = parent->kids[j]; + if (!strcmp(kid->name, name)) + { + if (errcode) *errcode = tree_nameexists; + if (name_p) *name_p = + pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, name); + pdc_free(pdc, name); + return NULL; + } + } + } + else + { + parent = NULL; + name = pdc_strdup(pdc, pathname); + } + + branch = (pdc_branch *) pdc_malloc(pdc, sizeof(pdc_branch), fn); + branch->name = name; + branch->data = data; + if (flags & PDC_TREE_ISLEAF) + { + branch->nalloc = 0; + branch->nkids = 0; + branch->kids = NULL; + } + else + { + branch->nalloc = PDC_KIDS_CHUNKSIZE; + branch->nkids = 0; + branch->kids = (pdc_branch **) pdc_malloc(pdc, + branch->nalloc * sizeof(pdc_branch *), fn); + } + branch->parent = parent; + + /* insert kid */ + if (parent) + { + if (parent->nkids == parent->nalloc) + { + parent->nalloc *= 2; + parent->kids = (pdc_branch **) pdc_realloc(pdc, parent->kids, + parent->nalloc * sizeof(pdc_branch *), fn); + } + parent->kids[parent->nkids] = branch; + (parent->nkids)++; + + if ((flags & PDC_TREE_INHERIT) && parent->data) + memcpy(branch->data, parent->data, (size_t) size); + } + + return branch; +} + +void +pdc_deactivate_name_treebranch(pdc_core *pdc, pdc_branch *branch) +{ + static const char fn[] = "pdc_deactivate_name_treebranch"; + size_t len = strlen(branch->name); + + branch->name = (char *) pdc_realloc(pdc, branch->name, len + 2, fn); + branch->name[len] = PDC_NAME_SEPARSIGN; + branch->name[len+1] = 0; +} + +char * +pdc_get_name_treebranch(pdc_branch *branch) +{ + return branch->name; +} + +pdc_branch * +pdc_get_parent_treebranch(pdc_branch *branch) +{ + return branch->parent; +} + +void * +pdc_get_data_treebranch(pdc_branch *branch) +{ + return branch->data; +} + +pdc_branch ** +pdc_get_kids_treebranch(pdc_branch *branch, int *nkids) +{ + *nkids = branch->nkids; + return branch->kids; +} + +void +pdc_cleanup_treebranch(pdc_core *pdc, pdc_branch *branch) +{ + int i; + + if (branch->name) + pdc_free(pdc, branch->name); + + if (branch->data) + pdc_free(pdc, branch->data); + + if (branch->kids) + { + for(i = 0; i < branch->nkids; i++) + pdc_cleanup_treebranch(pdc, branch->kids[i]); + pdc_free(pdc, branch->kids); + } + + pdc_free(pdc, branch); +} + +/***************************** memory pools *****************************/ + +/* the data structures and functions in this section are more than +** confusing. the funny "mp_item" structure below makes them more +** readable, believe it or not. +*/ +typedef struct mp_item_s mp_item; + +struct mp_item_s +{ + mp_item * next; +}; + +struct pdc_mempool_s +{ + pdc_core * pdc; + + char ** pool_tab; + mp_item * free_list; + + size_t pool_incr; /* pool growth chunk size (items) */ + + size_t ptab_cap; /* total # of slots in pool_tab */ + size_t ptab_size; /* used # of slots in pool_tab */ + size_t ptab_incr; /* pool_tab growth chunk size (slots) */ + + size_t item_size; /* size of a single item (bytes) */ +}; + +#undef COMMENT +#ifdef COMMENT + + pool_incr = 5 + ptab_incr = 4 + ptab_cap = 4 (1 * ptab_incr) + + + +------+ + | free | + +------+ +----------------------------------+ + | free | +--> | | | | free | free | + +------+ | +----------------------------------+ + | | ---+ + +------+ +----------------------------------+ + | | ------> | | | | | | + +------+ +----------------------------------+ + + pool_tab + +#endif /* COMMENT */ + + +pdc_mempool * +pdc_mp_new(pdc_core *pdc, size_t item_size) +{ + static const char fn[] = "pdc_mp_new"; + + int m; + pdc_mempool *mp = (pdc_mempool *) + pdc_malloc(pdc, sizeof (pdc_mempool), fn); + + /* round up 'item_size' to a multiple of 'sizeof (mp_item)' + ** to ensure proper alignment. + */ + if ((m = (int) (item_size % sizeof (mp_item))) != 0) + item_size += sizeof (mp_item) - m; + + mp->pdc = pdc; + + mp->pool_tab = (char **) 0; + mp->free_list = (mp_item *) 0; + mp->pool_incr = 1000; + + mp->ptab_cap = 0; + mp->ptab_size = 0; + mp->ptab_incr = 100; + + mp->item_size = item_size; + + return mp; +} /* pdc_mp_new */ + + +void +pdc_mp_delete(pdc_mempool *mp) +{ + /* TODO: exception if there are still alloc'd items in the pool? */ + /* or, the other way round, call destructors? */ + + pdc_core * pdc = mp->pdc; + int i; + + for (i = 0; i < (int) mp->ptab_size; ++i) + pdc_free(pdc, mp->pool_tab[i]); + + if (mp->pool_tab) + pdc_free(pdc, mp->pool_tab); + + pdc_free(pdc, mp); +} /* pdc_mp_delete */ + + +void * +pdc_mp_alloc(pdc_mempool *mp) +{ + static const char fn[] = "pdc_mp_alloc"; + + pdc_core * pdc = mp->pdc; + mp_item * result; + + if (!mp->free_list) + { + char * new_chunk; + int i; + + if (mp->ptab_size == mp->ptab_cap) + { + mp->ptab_cap += mp->ptab_incr; + + mp->pool_tab = (char **) pdc_realloc(pdc, + mp->pool_tab, mp->ptab_cap * sizeof (char **), fn); + } + + new_chunk = mp->pool_tab[mp->ptab_size] = (char *) + pdc_malloc(pdc, mp->pool_incr * mp->item_size, fn); + + ++mp->ptab_size; + mp->free_list = (mp_item *) new_chunk; + mp->free_list->next = (mp_item *) 0; + + for (i = 1; i < (int) mp->pool_incr; ++i) + { + mp_item *scan = (mp_item *) (new_chunk + i * mp->item_size); + + scan->next = mp->free_list; + mp->free_list = scan; + } + } + + result = mp->free_list; + mp->free_list = result->next; + + return (void *) result; +} /* pdc_mp_alloc */ + + +void +pdc_mp_free(pdc_mempool *mp, void *item) +{ + mp_item *mpi = (mp_item *) item; + + mpi->next = mp->free_list; + mp->free_list = mpi; +} /* pdc_mp_free */ + + +/***************************** miscellaneous ****************************/ + +/* search a sorted (strcmp order) array "names" of size "size" +** for string "name". return the index if found, otherwise -1. +*/ +int +pdc_name2idx(const char **names, int size, const char *name) +{ + int lo = 0, hi = size; + + while (lo != hi) + { + int idx = (lo + hi) / 2; + int cmp = strcmp(name, names[idx]); + + if (cmp == 0) + return idx; + + if (cmp < 0) + hi = idx; + else + lo = idx + 1; + } + + return -1; +} /* pdc_name2idx */ + + +/* linear search; see man page LSEARCH(3). +*/ +void * +pdc_lfind( + const void *key, + const void *base, + size_t * nmemb, + size_t size, + int (*compar)(const void *, const void *)) +{ + size_t i; + + for (i = 0; i < *nmemb; ++i) + { + const char *cp = (const char *) base + i * size; + + if (compar(key, (void *) cp) == 0) + return (void *) cp; + } + + return (void *) 0; +} /* pdc_lfind */ + + +/********************* pseudo random numbers *********************/ + +int +pdc_rand(pdc_core *pdc) +{ + pdc->last_rand = pdc->last_rand * 1103515245 + 12345; + + return (pdc_uint)(pdc->last_rand / 65536) % 32768; +} /* pdc_rand */ + +void +pdc_srand(pdc_core *pdc, pdc_uint seed) +{ + pdc->last_rand = seed; +} /* pdc_srand */ diff --git a/src/pdflib/pdcore/pc_util.h b/src/pdflib/pdcore/pc_util.h new file mode 100644 index 0000000..af84606 --- /dev/null +++ b/src/pdflib/pdcore/pc_util.h @@ -0,0 +1,268 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_util.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * Declaration of various utility routines + * + */ + +#ifndef PC_UTIL_H +#define PC_UTIL_H + +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdarg.h> + +#include "pc_config.h" +#include "pc_core.h" +#include "pc_ebcdic.h" +#include "pc_optparse.h" +#include "pc_encoding.h" +#include "pc_output.h" +#include "pc_unicode.h" +#include "pc_resource.h" + +/* ---------------------------- forward typedefs --------------------------- */ + +#ifndef PDC_STRINGS_DEFINED +#define PDC_STRINGS_DEFINED +typedef struct pdc_bstr_s pdc_bstr; /* byte strings */ +typedef struct pdc_ustr_s pdc_ustr; /* unicode strings */ +#endif + +#ifndef PDC_MEMPOOL_DEFINED +#define PDC_MEMPOOL_DEFINED +typedef struct pdc_mempool_s pdc_mempool; +#endif + +/* ------------------------ the core public structure ---------------------- */ + +struct pdc_core_s +{ + pdc_core_priv *pr; /* pdcore private structure */ + + pdc_reslist *reslist; /* resource list */ + pdc_virtfile *filesystem; /* virtual file system */ + pdc_loggdef *logg; /* logging definition */ + pdc_bool loggenv; /* logging environ. variable checked */ + pdc_encoding_stack *encstack; /* encoding stack */ + pdc_priv_glyphtab *pglyphtab; /* private glyph table */ + pdc_mempool *bstr_pool; /* pdc_bstr pool */ + pdc_mempool *ustr_pool; /* pdc_ustr pool */ + pdc_ulong last_rand; /* for pdc_rand()/pdc_srand() */ + + const char *prodname; /* product name */ + const char *version; /* version string */ + char *binding; /* name of the language binding */ + pdc_bool unicaplang; /* Unicode capable language */ + pdc_bool objorient; /* binding object orientated */ + pdc_bool hastobepos; /* handles have to be positiv */ + pdc_bool ptfrun; /* while PTF is running */ + pdc_bool smokerun; /* while smoketest is running */ + pdc_bool charref; /* HTML character references will + * be resolved */ + pdc_bool escapesequ; /* escape sequences will be resolved */ + pdc_bool honorlang; /* honor LANG codeset for file names */ + int compatibility; /* PDF version number * 10 */ + int floatdigits; /* floating point output precision */ + int uniqueno; /* unique number for numbering */ + +}; + +#define PDC_BOOLSTR(a) (a != 0 ? "true" : "false") + +#define PDC_ABS(x) (((x) < 0) ? -(x) : (x)) + +/* TODO: replace with PDC_MIN, PDC_MAX +*/ +#ifndef MIN +#define MIN(a, b) (((a) < (b) ? (a) : (b))) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b) ? (a) : (b))) +#endif + +/* reasonable values for number limits */ +#define PDC_FLOAT_MAX ((double) 1e+18) +#define PDC_FLOAT_MIN ((double) -1e+18) +#define PDC_FLOAT_PREC ((double) 1e-6) + +#define PDC_ROUND(x) (((x) < 0) ? ceil((x) - 0.5) : floor((x) + 0.5)) + +#define PDC_FLOAT_ISNULL(x) \ + (((((x) < 0) ? -1 * (x) : (x)) < PDC_FLOAT_PREC) ? pdc_true : pdc_false) + +/* flags for pdc_split_stringlist */ +#define PDC_SPLIT_ISOPTLIST (1L<<0) + +#define PDC_INT_UNSIGNED (1L<<0) +#define PDC_INT_CHAR (1L<<1) +#define PDC_INT_SHORT (1L<<2) +#define PDC_INT_HEXADEC (1L<<4) +#define PDC_INT_DEC (1L<<5) +#define PDC_INT_OCTAL (1L<<6) +#define PDC_INT_CASESENS (1L<<7) + +#define PDC_INT_CODE (PDC_INT_UNSIGNED | PDC_INT_CHAR | PDC_INT_HEXADEC) +#define PDC_INT_UNICODE (PDC_INT_UNSIGNED | PDC_INT_SHORT | PDC_INT_HEXADEC) + +#define PDC_GET_SHORT pdc_get_le_short +#define PDC_GET_USHORT pdc_get_le_ushort +#define PDC_GET_WORD pdc_get_le_ushort +#define PDC_GET_DWORD pdc_get_le_ulong +#define PDC_GET_DWORD3 pdc_get_le_ulong3 +#define PDC_GET_LONG pdc_get_le_long +#define PDC_GET_ULONG pdc_get_le_ulong + +#define PDC_TREE_INHERIT (1L<<0) +#define PDC_TREE_ISLEAF (1L<<1) + +#define PDC_NAME_SEPARSIGN '.' +#define PDC_NAME_SEPARSTRG "." + +#define PDC_KIDS_CHUNKSIZE 5 + +/* tree error codes */ +typedef enum +{ + tree_ok = 0, + tree_notfound, + tree_nameexists, + tree_isleaf +} +pdc_branch_error; + +typedef struct pdc_branch_s pdc_branch; + +#define PDC_TIME_SBUF_SIZE 50 + +void pdc_set_unsupp_error(pdc_core *pdc, int err_config, int err_lite, + pdc_bool warning); +void pdc_check_number(pdc_core *pdc, const char *paramname, double dz); +void pdc_check_number_limits(pdc_core *pdc, const char *paramname, double dz, + double dmin, double dmax); +void pdc_check_number_zero(pdc_core *pdc, const char *paramname, double dz); + +typedef struct +{ + int second; + int minute; + int hour; + int mday; + int wday; + int month; + int year; +} pdc_time; + +void pdc_localtime(pdc_time *t); +void pdc_get_timestr(char *str, pdc_bool ktoascii); + +pdc_bool pdc_check_lang_code(pdc_core *pdc, const char* lang_code); + +void pdc_setbit(char *bitarr, int bit); +pdc_bool pdc_getbit(const char *bitarr, int bit); +void pdc_setbit_text(char *bitarr, const unsigned char *text, + int len, int nbits, int size); + +pdc_short pdc_get_le_short(const pdc_byte *data); +pdc_ushort pdc_get_le_ushort(const pdc_byte *data); +pdc_sint32 pdc_get_le_long(const pdc_byte *data); +pdc_uint32 pdc_get_le_ulong3(const pdc_byte *data); +pdc_uint32 pdc_get_le_ulong(const pdc_byte *data); +pdc_short pdc_get_be_short(const pdc_byte *data); +pdc_ushort pdc_get_be_ushort(const pdc_byte *data); +pdc_sint32 pdc_get_be_long(const pdc_byte *data); +pdc_uint32 pdc_get_be_ulong3(const pdc_byte *data); +pdc_uint32 pdc_get_be_ulong(const pdc_byte *data); + +size_t pdc_strlen(const char *text); +char *pdc_getenv(const char *name); +char *pdc_strdup_ext(pdc_core *pdc, const char *text, int flags, + const char *fn); +char *pdc_strdup(pdc_core *pdc, const char *text); +char *pdc_strdup2(pdc_core *pdc, const char *text, size_t len); +char *pdc_strdup_tmp(pdc_core *pdc, const char *text); +pdc_bool pdc_logg_isprint(int c); +char *pdc_strprint(pdc_core *pdc, const char *str, int leni, + int maxchar, pdc_strform_kind strform); +char *pdc_strdup_convert(pdc_core *pdc, pdc_encoding encto, + pdc_encoding encfrom, const char *text, int flags, + const char *fn); +const char *pdc_utf8strprint(pdc_core *pdc, const char *str); +int pdc_split_stringlist(pdc_core *pdc, const char *text, + const char *i_separstr, int flags, char ***stringlist); +char * pdc_substitute_variables(pdc_core *pdc, const char *string, char vchar, + const char *delimiters, const char **varslist, + const char **valslist, int nvars, int *errind); +void pdc_cleanup_stringlist(pdc_core *pdc, char **stringlist); +int pdc_strcmp(const char *s1, const char *s2); +int pdc_stricmp(const char *s1, const char *s2); +int pdc_strincmp(const char *s1, const char *s2, int n); +char *pdc_strtrim(char *m_str); +char *pdc_str2trim(char *m_str); +char *pdc_strtoupper(char *str); +char *pdc_strtolower(char *str); +int pdc_tolower_ascii(int c); +int pdc_toupper_ascii(int c); +void pdc_swap_bytes(char *instring, int inlen, char *outstring); +void pdc_swap_unicodes(char *instring); +char *pdc_strdup_withbom(pdc_core *pdc, const char *text); +void pdc_inflate_ascii(const char *instring, int inlen, char *outstring, + pdc_text_format textformat); + +pdc_ushort pdc_get_string_value(pdc_byte *str, int i, int charlen); + +int pdc_subst_backslash(pdc_core *pdc, pdc_byte *str, int len, + pdc_encodingvector *ev, pdc_text_format textformat, pdc_bool verbose); + +pdc_bool pdc_str2double(const char *string, double *o_dz); +pdc_bool pdc_str2integer(const char *string, int flags, void *o_iz); + +int pdc_vfprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp, + const char *format, va_list args); +int pdc_fprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp, + const char *format, ...); +int pdc_vsprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf, + const char *format, va_list args); +int pdc_sprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf, + const char *format, ...); +int pdc_vsnprintf(char *buf, size_t size, + const char *format, va_list args); + +pdc_branch *pdc_init_tree(pdc_core *pdc); +pdc_branch *pdc_create_treebranch(pdc_core *pdc, pdc_branch *root, + const char *pathname, void *data, int flags, int size, + pdc_branch_error *errcode, const char **name_p); +char *pdc_get_name_treebranch(pdc_branch *branch); +pdc_branch *pdc_get_parent_treebranch(pdc_branch *branch); +pdc_branch **pdc_get_kids_treebranch(pdc_branch *branch, int *nkids); +void *pdc_get_data_treebranch(pdc_branch *branch); +void pdc_cleanup_treebranch(pdc_core *pdc, pdc_branch *branch); +void pdc_deactivate_name_treebranch(pdc_core *pdc, pdc_branch *branch); + +pdc_mempool * pdc_mp_new(pdc_core *pdc, size_t item_size); +void pdc_mp_delete(pdc_mempool *mp); +void * pdc_mp_alloc(pdc_mempool *mp); +void pdc_mp_free(pdc_mempool *mp, void *item); + +int pdc_name2idx(const char **names, int size, const char *name); +void * pdc_lfind(const void *key, const void *base, size_t *nmemb, + size_t size, int (*compar)(const void *, const void *)); + +int pdc_rand(pdc_core *pdc); +void pdc_srand(pdc_core *pdc, pdc_uint seed); + +#endif /* PC_UTIL_H */ diff --git a/src/pdflib/pdcore/pc_xmp.c b/src/pdflib/pdcore/pc_xmp.c new file mode 100644 index 0000000..f939c0b --- /dev/null +++ b/src/pdflib/pdcore/pc_xmp.c @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_xmp.c,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * The core XMP support. + * + */ + +#include "pc_util.h" +#include "pc_strconst.h" +#include "pc_md5.h" + + + + + + + + + + diff --git a/src/pdflib/pdcore/pc_xmp.h b/src/pdflib/pdcore/pc_xmp.h new file mode 100644 index 0000000..4ad0f12 --- /dev/null +++ b/src/pdflib/pdcore/pc_xmp.h @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pc_xmp.h,v 1.1 2008/10/17 06:10:43 scuri Exp $ + * + * The public core XMP support. + * + */ + +#ifndef PC_XMP_H +#define PC_XMP_H + + +#endif /* PC_XMP_H */ + + + + diff --git a/src/pdflib/pdflib/p_3d.c b/src/pdflib/pdflib/p_3d.c new file mode 100644 index 0000000..033c834 --- /dev/null +++ b/src/pdflib/pdflib/p_3d.c @@ -0,0 +1,22 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + *---------------------------------------------------------------------------*/ + +/* $Id: p_3d.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib 3D functions routines + * + */ + +#define P_3D_C + +#include "p_intern.h" +#include "p_color.h" + diff --git a/src/pdflib/pdflib/p_actions.c b/src/pdflib/pdflib/p_actions.c new file mode 100644 index 0000000..f3c42fc --- /dev/null +++ b/src/pdflib/pdflib/p_actions.c @@ -0,0 +1,1155 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_actions.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib actions handling routines + * + */ + +#define P_ACTIONS_C + +#include "p_intern.h" +#include "p_layer.h" + +typedef enum +{ + pdf_allact = -1, + pdf_goto = (1<<0), + pdf_gotor = (1<<1), + pdf_launch = (1<<2), + pdf_uri = (1<<3), + pdf_hide = (1<<4), + pdf_named = (1<<5), + pdf_submitform = (1<<6), + pdf_resetform = (1<<7), + pdf_importdata = (1<<8), + pdf_javascript = (1<<9), + pdf_setocgstate = (1<<10), + pdf_trans = (1<<11), + pdf_goto3dview = (1<<12) +} +pdf_actiontype; + +static const pdc_keyconn pdf_action_pdfkeylist[] = +{ + {"GoTo", pdf_goto}, + {"GoToR", pdf_gotor}, + {"Launch", pdf_launch}, + {"URI", pdf_uri}, + {"Hide", pdf_hide}, + {"Named", pdf_named}, + {"SubmitForm", pdf_submitform}, + {"ResetForm", pdf_resetform}, + {"ImportData", pdf_importdata}, + {"JavaScript", pdf_javascript}, + {"SetOCGState", pdf_setocgstate}, + {"Trans", pdf_trans}, + {"GoTo3DView", pdf_goto3dview}, + {NULL, 0} +}; + + +typedef enum +{ + /* values are identical with PDF values */ + pdf_exp_fdf = (1<<1), + pdf_exp_html = (1<<2), + pdf_exp_getrequest = (1<<3), + pdf_exp_coordinates = (1<<4), + pdf_exp_xfdf = (1<<5), + pdf_exp_updates = (1<<6), + pdf_exp_annotfields = (1<<7), + pdf_exp_pdf = (1<<8), + pdf_exp_onlyuser = (1<<10), + pdf_exp_exclurl = (1<<11) +} +pdf_exportmethod; + +/* allowed combinations of exportmethod keywords */ +static pdf_exportmethod pdf_allfdf = (pdf_exportmethod) + (pdf_exp_fdf | + pdf_exp_updates | + pdf_exp_exclurl | + pdf_exp_annotfields | + pdf_exp_onlyuser); + +static pdf_exportmethod pdf_allhtml = (pdf_exportmethod) + (pdf_exp_html | + pdf_exp_getrequest | + pdf_exp_coordinates); + +static pdf_exportmethod pdf_allxfdf = pdf_exp_xfdf; + +static pdf_exportmethod pdf_allpdf = (pdf_exportmethod) + (pdf_exp_pdf | + pdf_exp_getrequest); + +static const pdc_keyconn pdf_exportmethod_keylist[] = +{ + {"fdf", pdf_exp_fdf}, + {"html", pdf_exp_html}, + {"xfdf", pdf_exp_xfdf}, + {"pdf", pdf_exp_pdf}, + {"getrequest", pdf_exp_getrequest}, + {"coordinates", pdf_exp_coordinates}, + {"updates", pdf_exp_updates}, + {"annotfields", pdf_exp_annotfields}, + {"onlyuser", pdf_exp_onlyuser}, + {"exclurl", pdf_exp_exclurl}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_filename_keylist[] = +{ + {"filename", (pdf_actiontype) (pdf_gotor | pdf_launch | pdf_importdata)}, + {"url", (pdf_actiontype) (pdf_uri | pdf_submitform)}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_operation_pdfkeylist[] = +{ + {"open", 1}, + {"print", 2}, + {NULL, 0} +}; + + +static const pdc_keyconn pdf_3dview_keylist[] = +{ + {NULL, 0} +}; + + + +#define PDF_LAYER_FLAG PDC_OPT_UNSUPP + +#define PDF_JAVASCRIPT_FLAG PDC_OPT_UNSUPP +#define PDF_3DVIEW_FLAG PDC_OPT_UNSUPP + +static const pdc_defopt pdf_create_action_options[] = +{ + /* deprecated */ + {"actionwarning", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"filename", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_FILENAMELEN, NULL}, + + {"url", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"parameters", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"operation", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_operation_pdfkeylist}, + + {"defaultdir", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"menuname", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"script", pdc_stringlist, PDF_JAVASCRIPT_FLAG, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"scriptname", pdc_stringlist, PDF_JAVASCRIPT_FLAG, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"namelist", pdc_stringlist, PDC_OPT_NONE, 1, PDF_MAXARRAYSIZE, + 0.0, PDC_USHRT_MAX, NULL}, + + {"exportmethod", pdc_keywordlist, PDC_OPT_BUILDOR, 1, 10, + 0.0, 0.0, pdf_exportmethod_keylist}, + + {"newwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"ismap", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"hide", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"exclude", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"submitemptyfields", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1, + 0.0, 0.0, NULL}, + + {"canonicaldate", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"layerstate", pdc_stringlist, PDF_LAYER_FLAG | PDC_OPT_EVENNUM, 1, 100, + 1.0, 8.0, NULL}, + + {"preserveradio", pdc_booleanlist, PDF_LAYER_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"3dview", pdc_3dviewhandle, PDF_3DVIEW_FLAG, 1, 1, + 0.0, 0.0, pdf_3dview_keylist}, + + {"target", pdc_stringlist, PDF_3DVIEW_FLAG, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"transition", pdc_keywordlist, PDC_OPT_PDC_1_5, 1, 1, + 0.0, 0.0, pdf_transition_keylist}, + + {"duration", pdc_scalarlist, PDC_OPT_PDC_1_5, 1, 1, + 0.0, PDC_FLOAT_MAX, NULL}, + + PDF_ERRORPOLICY_OPTION + + PDC_OPT_TERMINATE +}; + +typedef struct pdf_action_s +{ + pdc_id obj_id; + pdf_actiontype atype; + pdf_dest *dest; + pdc_encoding hypertextencoding; + char *filename; + char *parameters; + char *operation; + char *defaultdir; + char *menuname; + char *script; + char *scriptname; + char **namelist; + int nsnames; + pdc_bool newwindow; + pdc_bool ismap; + pdc_bool hide; + pdc_bool exclude; + pdc_bool submitemptyfields; + pdc_bool canonicaldate; + pdf_exportmethod exportmethod; + int transition; + double duration; +} +pdf_action; + +static void +pdf_reclaim_action(void *item) +{ + pdf_action *action = (pdf_action *) item; + + action->obj_id = PDC_BAD_ID; + action->atype = (pdf_actiontype) 0; + action->dest = NULL; + action->hypertextencoding = pdc_invalidenc; + action->filename = NULL; + action->parameters = NULL; + action->operation = NULL; + action->defaultdir = NULL; + action->menuname = NULL; + action->script = NULL; + action->scriptname = NULL; + action->namelist = NULL; + action->nsnames = 0; + action->newwindow = pdc_undef; + action->ismap = pdc_false; + action->hide = pdc_true; + action->exclude = pdc_false; + action->submitemptyfields = pdc_false; + action->canonicaldate = pdc_false; + action->exportmethod = pdf_exp_fdf; + action->transition = (int) trans_replace; + action->duration = 1; +} + +static void +pdf_release_action(void *context, void *item) +{ + PDF *p = (PDF *) context; + pdf_action *action = (pdf_action *) item; + + pdf_cleanup_destination(p, action->dest); + + if (action->filename) + { + pdc_free(p->pdc, action->filename); + action->filename = NULL; + } + + if (action->parameters) + { + pdc_free(p->pdc, action->parameters); + action->parameters = NULL; + } + + if (action->defaultdir) + { + pdc_free(p->pdc, action->defaultdir); + action->defaultdir = NULL; + } + + if (action->menuname) + { + pdc_free(p->pdc, action->menuname); + action->menuname = NULL; + } + + if (action->script) + { + pdc_free(p->pdc, action->script); + action->script = NULL; + } + + if (action->namelist) + { + pdc_cleanup_optstringlist(p->pdc, action->namelist, action->nsnames); + action->namelist = NULL; + } + +} + +static pdc_ced pdf_action_ced = +{ + sizeof(pdf_action), pdf_reclaim_action, pdf_release_action, NULL +}; + +static pdc_vtr_parms pdf_action_parms = +{ + 0, 10, 10 +}; + +static pdf_action * +pdf_new_action(PDF *p) +{ + pdf_action *result; + + if (p->actions == NULL) + p->actions = pdc_vtr_new(p->pdc, &pdf_action_ced, p, &pdf_action_parms); + + result = pdc_vtr_incr(p->actions, pdf_action); + result->hypertextencoding = p->hypertextencoding; + return result; +} + +void +pdf_delete_actions(PDF *p) +{ + if (p->actions != NULL) + { + pdc_vtr_delete(p->actions); + p->actions = NULL; + } +} + +int +pdf_get_max_action(PDF *p) +{ + return (p->actions == NULL) ? -1 : pdc_vtr_size(p->actions) - 1; +} + +static pdc_id pdf_write_action(PDF *p, pdf_action *action, pdc_id next_id); + + +static int +pdf_opt_effectless(PDF *p, const char *keyword, pdf_actiontype curratype, + pdf_actiontype intendatypes) +{ + if ((pdf_actiontype) !(intendatypes & curratype)) + { + const char *type = pdc_get_keyword(curratype, pdf_action_pdfkeylist); + pdc_warning(p->pdc, PDF_E_ACT_OPTIGNORE_FORTYPE, keyword,type, 0, 0); + return 1; + } + return 0; +} + +int +pdf__create_action(PDF *p, const char *type, const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdc_clientdata data; + pdf_action *action; + pdf_actiontype atype; + pdf_dest *dest = NULL; + pdc_bool verbose = pdc_true; + pdc_bool hasdest = pdc_false; + pdc_encoding htenc; + int htcp; + const char *keyword; + char **strlist; + int i, k, ns; + + if (type == NULL || *type == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0); + + k = pdc_get_keycode_ci(type, pdf_action_pdfkeylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0); + atype = (pdf_actiontype) k; + + + if (atype == pdf_javascript) + pdc_error(p->pdc, PDF_E_UNSUPP_JAVASCRIPT, 0, 0, 0, 0); + + /* compatibility */ + if (p->compatibility < PDC_1_6 && atype == pdf_goto3dview) + { + pdc_error(p->pdc, PDC_E_PAR_VERSION, type, + pdc_get_pdfversion(p->pdc, PDC_1_6), 0, 0); + } + if (p->compatibility < PDC_1_5 && + (atype == pdf_setocgstate || atype == pdf_trans)) + { + pdc_error(p->pdc, PDC_E_PAR_VERSION, type, + pdc_get_pdfversion(p->pdc, PDC_1_5), 0, 0); + } + + /* new action */ + action = pdf_new_action(p); + action->atype = atype; + + /* Parsing option list */ + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_create_action_options, + &data, pdc_true); + + keyword = "actionwarning"; + pdc_get_optvalues(keyword, resopts, &verbose, NULL); + verbose = pdf_get_errorpolicy(p, resopts, verbose); + + htenc = pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true); + + keyword = "destination"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist)) + { + if (!pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) (pdf_goto | pdf_gotor))) + { + action->dest = pdf_parse_destination_optlist(p, strlist[0], + (atype == pdf_goto) ? 0 : 1, + (atype == pdf_goto) ? pdf_locallink : pdf_remotelink); + hasdest = pdc_true; + } + } + else + { + keyword = "destname"; + if (atype == pdf_goto || atype == pdf_gotor) + dest = pdf_get_option_destname(p, resopts, htenc, htcp); + else if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) (pdf_goto | pdf_gotor)); + if (dest) + { + action->dest = dest; + hasdest = pdc_true; + } + } + + /* filename or url */ + for (i = 0; ; i++) + { + keyword = pdf_filename_keylist[i].word; + if (keyword) + { + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist)) + { + if (!pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) pdf_filename_keylist[i].code)) + { + action->filename = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + } + } + else + break; + } + + keyword = "parameters"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL) && + !pdf_opt_effectless(p, keyword, atype, pdf_launch)) + action->parameters = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "operation"; + if (pdc_get_optvalues(keyword, resopts, &k, NULL) && + !pdf_opt_effectless(p, keyword, atype, pdf_launch)) + action->operation = + (char *) pdc_get_keyword(k, pdf_operation_pdfkeylist); + + keyword = "defaultdir"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL) && + !pdf_opt_effectless(p, keyword, atype, pdf_launch)) + action->defaultdir = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "menuname"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL) && + !pdf_opt_effectless(p, keyword, atype, pdf_named)) + { + action->menuname = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + keyword = "namelist"; + ns = pdc_get_optvalues(keyword, resopts, NULL, NULL); + if (ns && !pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) (pdf_hide | pdf_submitform | pdf_resetform))) + { + action->namelist = (char **) pdc_save_lastopt(resopts, PDC_OPT_SAVEALL); + action->nsnames = ns; + } + + + keyword = "exportmethod"; + if (pdc_get_optvalues(keyword, resopts, &k, NULL)) + { + action->exportmethod = (pdf_exportmethod) k; + if (!pdf_opt_effectless(p, keyword, atype, pdf_submitform)) + { + if ((action->exportmethod & pdf_exp_fdf && + (action->exportmethod | pdf_allfdf) != pdf_allfdf) || + (action->exportmethod & pdf_exp_html && + (action->exportmethod | pdf_allhtml) != pdf_allhtml) || + (action->exportmethod & pdf_exp_xfdf && + (action->exportmethod | pdf_allxfdf) != pdf_allxfdf) || + (action->exportmethod & pdf_exp_pdf && + (action->exportmethod | pdf_allpdf) != pdf_allpdf)) + { + pdc_error(p->pdc, PDC_E_OPT_ILLCOMB, keyword, 0, 0, 0); + } + if (action->exportmethod & pdf_exp_fdf) + action->exportmethod = (pdf_exportmethod) + (action->exportmethod & ~pdf_exp_fdf); + } + } + + keyword = "newwindow"; + if (pdc_get_optvalues(keyword, resopts, &action->newwindow, NULL)) + pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) (pdf_gotor | pdf_launch)); + + keyword = "ismap"; + if (pdc_get_optvalues(keyword, resopts, &action->ismap, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_uri); + + keyword = "hide"; + if (pdc_get_optvalues(keyword, resopts, &action->hide, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_hide); + + keyword = "exclude"; + if (pdc_get_optvalues(keyword, resopts, &action->exclude, NULL)) + pdf_opt_effectless(p, keyword, atype, + (pdf_actiontype) (pdf_submitform | pdf_resetform)); + + keyword = "submitemptyfields"; + if (pdc_get_optvalues(keyword, resopts, &action->submitemptyfields, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_submitform); + + keyword = "canonicaldate"; + if (pdc_get_optvalues(keyword, resopts, &action->canonicaldate, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_submitform); + + keyword = "transition"; + if (pdc_get_optvalues(keyword, resopts, &action->transition, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_trans); + + keyword = "duration"; + if (pdc_get_optvalues(keyword, resopts, &action->duration, NULL)) + pdf_opt_effectless(p, keyword, atype, pdf_trans); + + + + /* required options */ + keyword = NULL; + if (!hasdest && + (atype == pdf_goto || atype == pdf_gotor)) + keyword = "destination"; + if (!action->filename && + (atype == pdf_gotor || atype == pdf_launch || atype == pdf_importdata)) + keyword = "filename"; + if (!action->menuname && atype == pdf_named) + keyword = "menuname"; + if (!action->namelist && atype == pdf_hide) + keyword = "namelist"; + if (!action->filename && + (atype == pdf_uri || atype == pdf_submitform)) + keyword = "url"; + if (keyword) + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, keyword, 0, 0, 0); + + + return pdf_get_max_action(p); +} + + +static pdc_id +pdf_write_action(PDF *p, pdf_action *action, pdc_id next_id) +{ + pdc_id ret_id = PDC_BAD_ID; + int i, flags = 0; + + + ret_id = pdc_begin_obj(p->out, PDC_NEW_ID); /* Action object */ + pdc_begin_dict(p->out); /* Action dict */ + + pdc_puts(p->out, "/Type/Action\n"); + pdc_printf(p->out, "/S/%s\n", + pdc_get_keyword(action->atype, pdf_action_pdfkeylist)); + + /* next action */ + if (next_id != PDC_BAD_ID) + pdc_objref(p->out, "/Next", next_id); + else + action->obj_id = ret_id; + + /* destination */ + switch (action->atype) + { + case pdf_goto: + case pdf_gotor: + + pdc_puts(p->out, "/D"); + pdf_write_destination(p, action->dest); + + default: + break; + } + + /* file specification */ + switch (action->atype) + { + case pdf_gotor: + case pdf_launch: + if (action->newwindow != pdc_undef) + pdc_printf(p->out, "/NewWindow %s\n", + PDC_BOOLSTR(action->newwindow)); + case pdf_importdata: + + if (action->parameters || action->operation || action->defaultdir) + { + /* Windows-specific launch parameters */ + pdc_puts(p->out, "/Win"); + pdc_begin_dict(p->out); /* Win dict */ + pdc_printf(p->out, "/F"); + pdf_put_hypertext(p, action->filename); + pdc_puts(p->out, "\n"); + if (action->parameters) + { + pdc_printf(p->out, "/P"); + pdf_put_hypertext(p, action->parameters); + pdc_puts(p->out, "\n"); + pdc_free(p->pdc, action->parameters); + action->parameters = NULL; + } + if (action->operation) + { + pdc_printf(p->out, "/O"); + pdf_put_hypertext(p, action->operation); + pdc_puts(p->out, "\n"); + action->operation = NULL; + } + if (action->defaultdir) + { + pdc_printf(p->out, "/D"); + pdf_put_hypertext(p, action->defaultdir); + pdc_puts(p->out, "\n"); + pdc_free(p->pdc, action->defaultdir); + action->defaultdir = NULL; + } + pdc_end_dict(p->out); /* Win dict */ + } + else + { + pdc_puts(p->out, "/F"); + pdc_begin_dict(p->out); /* F dict */ + pdc_puts(p->out, "/Type/Filespec\n"); + pdc_printf(p->out, "/F"); + pdf_put_pdffilename(p, action->filename); + pdc_puts(p->out, "\n"); + pdc_end_dict(p->out); /* F dict */ + } + + default: + break; + } + + /* URI */ + switch (action->atype) + { + case pdf_uri: + pdc_puts(p->out, "/URI"); + pdf_put_hypertext(p, action->filename); + pdc_puts(p->out, "\n"); + + /* IsMap */ + if (action->ismap == pdc_true) + pdc_puts(p->out, "/IsMap true\n"); + + default: + break; + } + + /* Named */ + switch (action->atype) + { + case pdf_named: + pdc_printf(p->out, "/N"); + pdf_put_pdfname(p, action->menuname); + pdc_puts(p->out, "\n"); + + default: + break; + } + + /* name list */ + switch (action->atype) + { + case pdf_hide: + if (action->hide == pdc_false) + pdc_puts(p->out, "/H false\n"); + case pdf_submitform: + case pdf_resetform: + + if (action->nsnames) + { + pdc_printf(p->out, "/%s", + (action->atype == pdf_hide) ? "T" : "Fields"); + pdc_begin_array(p->out); + for (i = 0; i < action->nsnames; i++) + { + pdf_put_hypertext(p, action->namelist[i]); + if (i < action->nsnames - 1) + pdc_puts(p->out, "\n"); + else + pdc_end_array(p->out); + } + } + + default: + break; + } + + /* URL */ + switch (action->atype) + { + case pdf_submitform: + pdc_puts(p->out, "/F"); + pdc_begin_dict(p->out); /* F dict */ + pdc_puts(p->out, "/FS/URL\n"); + pdc_printf(p->out, "/F"); + pdf_put_hypertext(p, action->filename); + pdc_puts(p->out, "\n"); + pdc_end_dict(p->out); /* F dict */ + + default: + break; + } + + /* Trans */ + switch (action->atype) + { + case pdf_trans: + pdc_puts(p->out, "/Trans"); + pdc_begin_dict(p->out); /* Trans dict */ + pdc_puts(p->out, "/Type/Trans\n"); + if (action->transition != trans_replace) + pdc_printf(p->out, "/S/%s", + pdc_get_keyword(action->transition, pdf_transition_pdfkeylist)); + if (action->duration > 0) + pdc_printf(p->out, "/D %f\n", action->duration); + pdc_end_dict(p->out); /* Trans dict */ + + default: + break; + } + + /* Flags */ + switch (action->atype) + { + case pdf_submitform: + flags = (int) action->exportmethod; + if (action->submitemptyfields) + flags |= (1<<1); + if (action->canonicaldate) + flags |= (1<<9); + case pdf_resetform: + + if (action->exclude) + flags |= (1<<0); + if (flags) + pdc_printf(p->out, "/Flags %d\n", flags); + + default: + break; + } + + + + pdc_end_dict(p->out); /* Action dict */ + pdc_end_obj(p->out); /* Action object */ + + return ret_id; +} + + + +/* ---- Annotations events ---- */ + +static const pdc_keyconn pdf_annotevent_keylist[] = +{ + {"activate", 0}, + {"enter", 1}, + {"exit", 2}, + {"down", 3}, + {"up", 4}, + {"focus", 5}, + {"blur", 6}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_annotevent_pdfkeylist[] = +{ + {"A", 0}, + {"E", 1}, + {"X", 2}, + {"D", 3}, + {"U", 4}, + {"Fo", 5}, + {"Bl", 6}, + {NULL, 0} +}; + +static int pdf_annotevent_beginjava = 99; + +static const pdc_defopt pdf_annotevent_options[] = +{ + {"activate", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"enter", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"exit", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"down", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"up", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"focus", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"blur", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + + +/* ---- Bookmark events ---- */ + +static const pdc_keyconn pdf_bookmarkevent_keylist[] = +{ + {"activate", 0}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_bookmarkevent_pdfkeylist[] = +{ + {"A", 0}, + {NULL, 0} +}; + +static int pdf_bookmarkevent_beginjava = 99; + +static const pdc_defopt pdf_bookmarkevent_options[] = +{ + {"activate", pdc_actionhandle, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + + +/* ---- Document events ---- */ + +static const pdc_keyconn pdf_documentevent_keylist[] = +{ + {"open", 0}, + {"didprint", 1}, + {"didsave", 2}, + {"willclose", 3}, + {"willprint", 4}, + {"willsave", 5}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_documentevent_pdfkeylist[] = +{ + {"OpenAction", 0}, + {"DP", 1}, + {"DS", 2}, + {"WC", 3}, + {"WP", 4}, + {"WS", 5}, + {NULL, 0} +}; + +static int pdf_documentevent_beginjava = 1; + +static const pdc_defopt pdf_documentevent_options[] = +{ + {"open", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"didprint", pdc_actionhandle, PDC_OPT_PDC_1_4, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"didsave", pdc_actionhandle, PDC_OPT_PDC_1_4, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"willclose", pdc_actionhandle, PDC_OPT_PDC_1_4, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"willprint", pdc_actionhandle, PDC_OPT_PDC_1_4, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"willsave", pdc_actionhandle, PDC_OPT_PDC_1_4, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + + +/* ---- Page events ---- */ + +static const pdc_keyconn pdf_pageevent_keylist[] = +{ + {"", 0}, + {"open", 1}, + {"close", 2}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_pageevent_pdfkeylist[] = +{ + {"", 0}, + {"O", 1}, + {"C", 2}, + {NULL, 0} +}; + +static int pdf_pageevent_beginjava = 99; + +static const pdc_defopt pdf_pageevent_options[] = +{ + {"open", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + {"close", pdc_actionhandle, PDC_OPT_NONE, 1, PDC_USHRT_MAX, + 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + + +pdc_bool +pdf_parse_and_write_actionlist(PDF *p, pdf_event_object eventobj, + pdc_id *act_idlist, const char *optlist) +{ + const pdc_defopt *defopttable = NULL; + const pdc_keyconn *keyconntable = NULL; + pdc_resopt *resopts = NULL; + pdc_clientdata data; + pdc_id ret_id = PDC_BAD_ID; + pdf_action *action = NULL; + pdc_bool calcevent = pdc_false; + const char *keyword, *type; + char **strlist; + int *actlist; + int i, code, nsact, beginjava = 0; + + switch(eventobj) + { + + case event_annotation: + defopttable = pdf_annotevent_options; + keyconntable = pdf_annotevent_keylist; + beginjava = pdf_annotevent_beginjava; + break; + + case event_bookmark: + defopttable = pdf_bookmarkevent_options; + keyconntable = pdf_bookmarkevent_keylist; + beginjava = pdf_bookmarkevent_beginjava; + break; + + case event_document: + defopttable = pdf_documentevent_options; + keyconntable = pdf_documentevent_keylist; + beginjava = pdf_documentevent_beginjava; + break; + + case event_page: + defopttable = pdf_pageevent_options; + keyconntable = pdf_pageevent_keylist; + beginjava = pdf_pageevent_beginjava; + break; + + default: + break; + } + + /* parsing option list */ + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, defopttable, + &data, pdc_true); + + /* write actions and saving action ids */ + for (code = 0; ; code++) + { + keyword = pdc_get_keyword(code, keyconntable); + if (keyword) + { + nsact = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + actlist = (int *) strlist; + + /* Not activate event */ + if (code && nsact) + { + /* additional action type check */ + for (i = 0; i < nsact; i++) + { + action = (pdf_action *) &pdc_vtr_at(p->actions, actlist[i], + pdf_action); + if (code >= beginjava && action->atype != pdf_javascript) + { + type = pdc_get_keyword(action->atype, + pdf_action_pdfkeylist); + pdc_error(p->pdc, PDF_E_ACT_BADACTTYPE, + type, keyword, 0, 0); + } + } + + /* saving calculation event */ + if (!strcmp(keyword, "calculate")) + calcevent = pdc_true; + } + + /* write action objects */ + if (act_idlist != NULL) + { + if (nsact == 1) + { + action = (pdf_action *) &pdc_vtr_at(p->actions, actlist[0], + pdf_action); + if (action->obj_id == PDC_BAD_ID) + ret_id = pdf_write_action(p, action, PDC_BAD_ID); + else + ret_id = action->obj_id; + } + else if (nsact > 1) + { + for (i = nsact-1; i >= 0; i--) + { + action = (pdf_action *) &pdc_vtr_at(p->actions, + actlist[i], pdf_action); + ret_id = pdf_write_action(p, action, ret_id); + } + } + else + ret_id = PDC_BAD_ID; + act_idlist[code] = ret_id; + } + } + else + break; + } + + return calcevent; +} + +pdc_bool +pdf_write_action_entries(PDF *p, pdf_event_object eventobj, pdc_id *act_idlist) +{ + const pdc_keyconn *keyconntable = NULL; + const char *keyword; + pdc_id act_id = PDC_BAD_ID; + pdc_bool adict = pdc_false; + pdc_bool aadict = pdc_false; + int code; + + + switch(eventobj) + { + + case event_annotation: + keyconntable = pdf_annotevent_pdfkeylist; + break; + + case event_bookmark: + keyconntable = pdf_bookmarkevent_pdfkeylist; + break; + + case event_document: + keyconntable = pdf_documentevent_pdfkeylist; + break; + + case event_page: + keyconntable = pdf_pageevent_pdfkeylist; + break; + + default: + break; + } + + for (code = 0; ; code++) + { + keyword = pdc_get_keyword(code, keyconntable); + if (keyword) + { + act_id = act_idlist[code]; + if (act_id != PDC_BAD_ID) + { + if (code && !aadict) + { + pdc_puts(p->out, "/AA"); + pdc_begin_dict(p->out); /* AA dict */ + aadict = pdc_true; + } + else if (!code) + adict = pdc_true; + pdc_printf(p->out, "/%s", keyword); + pdc_objref_c(p->out, act_id); + } + } + else + break; + } + if (aadict) + pdc_end_dict(p->out); /* AA dict */ + else if (adict) + pdc_puts(p->out, "\n"); + + return adict; +} diff --git a/src/pdflib/pdflib/p_afm.c b/src/pdflib/pdflib/p_afm.c new file mode 100644 index 0000000..8de04a5 --- /dev/null +++ b/src/pdflib/pdflib/p_afm.c @@ -0,0 +1,756 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_afm.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib AFM parsing routines + * + */ + +#include "p_intern.h" +#include "p_font.h" + +#define AFM_GLYPH_SUPPL 3 + +#define AFM_LINEBUF 4096 + +#define AFM_SEPARATORS "\f\n\r\t\v ,:;" + +/* The values of each of these enumerated items correspond to an entry in the + * table of strings defined below. Therefore, if you add a new string as + * new keyword into the keyStrings table, you must also add a corresponding + * pdf_afmkey AND it MUST be in the same position! + * + * IMPORTANT: since the sorting algorithm is a binary search, the strings of + * keywords must be placed in lexicographical order, below. [Therefore, the + * enumerated items are not necessarily in lexicographical order, depending + * on the name chosen. BUT, they must be placed in the same position as the + * corresponding key string.] The NOPE shall remain in the last position, + * since it does not correspond to any key string. + */ + +#ifndef PDFLIB_EBCDIC +typedef enum +{ + ASCENDER, + CHARBBOX, + CODE, + COMPCHAR, + CODEHEX, + CAPHEIGHT, + CHARWIDTH, + CHARACTERSET, + CHARACTERS, + COMMENT, + DESCENDER, + ENCODINGSCHEME, + ENDCHARMETRICS, + ENDCOMPOSITES, + ENDDIRECTION, + ENDFONTMETRICS, + ENDKERNDATA, + ENDKERNPAIRS, + ENDKERNPAIRS0, + ENDKERNPAIRS1, + ENDMASTERFONTMETRICS, + ENDTRACKKERN, + ESCCHAR, + FAMILYNAME, + FONTBBOX, + FONTNAME, + FULLNAME, + ISBASEFONT, + ISCIDFONT, + ISFIXEDPITCH, + ISFIXEDV, + ITALICANGLE, + KERNPAIR, + KERNPAIRHAMT, + KERNPAIRXAMT, + KERNPAIRYAMT, + LIGATURE, + MAPPINGSCHEME, + METRICSSETS, + CHARNAME, + NOTICE, + COMPCHARPIECE, + STARTCHARMETRICS, + STARTCOMPFONTMETRICS, + STARTCOMPOSITES, + STARTDIRECTION, + STARTFONTMETRICS, + STARTKERNDATA, + STARTKERNPAIRS, + STARTKERNPAIRS0, + STARTKERNPAIRS1, + STARTMASTERFONTMETRICS, + STARTTRACKKERN, + STDHW, + STDVW, + TRACKKERN, + UNDERLINEPOSITION, + UNDERLINETHICKNESS, + VVECTOR, + VERSION, + XYWIDTH, + XY0WIDTH, + X0WIDTH, + Y0WIDTH, + XY1WIDTH, + X1WIDTH, + Y1WIDTH, + XWIDTH, + YWIDTH, + WEIGHT, + XHEIGHT, + NOPE +} +pdf_afmkey; + +/* keywords for the system: + * This a table of all of the current strings that are vaild AFM keys. + * Each entry can be referenced by the appropriate pdf_afmkey value (an + * enumerated data type defined above). If you add a new keyword here, + * a corresponding pdf_afmkey MUST be added to the enumerated data type + * defined above, AND it MUST be added in the same position as the + * string is in this table. + * + * IMPORTANT: since the sorting algorithm is a binary search, the keywords + * must be placed in lexicographical order. And, NULL should remain at the + * end. + */ + +static const char *keyStrings[] = +{ + "Ascender", + "B", + "C", + "CC", + "CH", + "CapHeight", + "CharWidth", + "CharacterSet", + "Characters", + "Comment", + "Descender", + "EncodingScheme", + "EndCharMetrics", + "EndComposites", + "EndDirection", + "EndFontMetrics", + "EndKernData", + "EndKernPairs", + "EndKernPairs0", + "EndKernPairs1", + "EndMasterFontMetrics", + "EndTrackKern", + "EscChar", + "FamilyName", + "FontBBox", + "FontName", + "FullName", + "IsBaseFont", + "IsCIDFont", + "IsFixedPitch", + "IsFixedV", + "ItalicAngle", + "KP", + "KPH", + "KPX", + "KPY", + "L", + "MappingScheme", + "MetricsSets", + "N", + "Notice", + "PCC", + "StartCharMetrics", + "StartCompFontMetrics", + "StartComposites", + "StartDirection", + "StartFontMetrics", + "StartKernData", + "StartKernPairs", + "StartKernPairs0", + "StartKernPairs1", + "StartMasterFontMetrics", + "StartTrackKern", + "StdHW", + "StdVW", + "TrackKern", + "UnderlinePosition", + "UnderlineThickness", + "VVector", + "Version", + "W", + "W0", + "W0X", + "W0Y", + "W1", + "W1X", + "W1Y", + "WX", + "WY", + "Weight", + "XHeight" +}; + +#else /* !PDFLIB_EBCDIC */ +#endif /* PDFLIB_EBCDIC */ + +static pdc_bool +pdf_parse_afm( + PDF *p, + pdc_file *fp, + pdf_font *font, + const char *fontname, + const char *filename) +{ + static const char fn[] = "pdf_parse_afm"; + fnt_font_metric *ftm = &font->ft.m; + const char *afmtype = NULL; + char **wordlist, *keyword, *arg1; + char line[AFM_LINEBUF]; + int i, cmp, lo, hi, nwords, nglyphs = 0, nline = 0; + int tablen = ((sizeof keyStrings) / (sizeof (char *))); + pdc_sint32 iz; + double dz; + pdc_scalar charwidth = -1; + pdf_afmkey keynumber; + fnt_glyphwidth *glw; + pdc_bool toskip = pdc_false; + pdc_bool is_zadbfont = !strcmp(fontname, "ZapfDingbats"); + + /* all new glyph names of AGL 2.0 are missing */ + font->missingglyphs = 0xFFFFFFFF; + + /* read loop. because of Mac files we use pdc_fgetline */ + while (pdc_fgetline(line, AFM_LINEBUF, fp) != NULL) + { + /* split line */ + nline++; + nwords = pdc_split_stringlist(p->pdc, line, AFM_SEPARATORS, 0, + &wordlist); + if (!nwords) continue; + keyword = wordlist[0]; + + /* find keynumber */ + lo = 0; + hi = tablen; + keynumber = NOPE; + while (lo < hi) + { + i = (lo + hi) / 2; + cmp = strcmp(keyword, keyStrings[i]); + + if (cmp == 0) + { + keynumber = (pdf_afmkey) i; + break; + } + + if (cmp < 0) + hi = i; + else + lo = i + 1; + } + + /* unkown key */ + if (keynumber == NOPE) + { + pdc_warning(p->pdc, PDF_E_T1_AFMBADKEY, keyword, filename, 0,0); + goto PDF_PARSECONTD; + } + if (keynumber == ENDDIRECTION) + toskip = pdc_false; + + if (nwords == 1 || toskip == pdc_true) + goto PDF_PARSECONTD; + + /* key switch */ + arg1 = wordlist[1]; + switch (keynumber) + { + case STARTDIRECTION: + if (pdc_str2integer(arg1, 0, &iz) != pdc_true) + goto PDF_SYNTAXERROR; + if (iz) + toskip = pdc_true; + break; + + case STARTCOMPFONTMETRICS: + afmtype = "ACFM"; + goto PDF_SYNTAXERROR; + + case STARTMASTERFONTMETRICS: + afmtype = "AMFM"; + goto PDF_SYNTAXERROR; + + case ISCIDFONT: + afmtype = "CID font"; + if (!strcmp(arg1, "true")) + goto PDF_SYNTAXERROR; + break; + + case FONTNAME: + font->ft.name = pdc_strdup(p->pdc, arg1); + ftm->name = pdc_strdup(p->pdc, arg1); + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPostScript font name: \"%s\"\n", ftm->name); + break; + + /* Recognize Multiple Master fonts by last part of name */ + case FAMILYNAME: + if (!strcmp(wordlist[nwords-1], "MM")) + ftm->type = fnt_MMType1; + else + ftm->type = fnt_Type1; + break; + + /* Default: FontSpecific */ + case ENCODINGSCHEME: + if (!pdc_stricmp(arg1, "StandardEncoding") || + !pdc_stricmp(arg1, "AdobeStandardEncoding")) + font->ft.issymbfont = pdc_false; + break; + + case STDHW: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->StdHW = (int) dz; + break; + + case STDVW: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->StdVW = (int) dz; + break; + + case WEIGHT: + font->ft.weight = fnt_check_weight(fnt_weightname2weight(arg1)); + break; + + case ISFIXEDPITCH: + if (!pdc_stricmp(arg1, "false")) + ftm->isFixedPitch = pdc_false; + else + ftm->isFixedPitch = pdc_true; + break; + + /* New AFM 4.1 keyword "CharWidth" implies fixed pitch */ + case CHARWIDTH: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + charwidth = dz; + ftm->isFixedPitch = pdc_true; + break; + + case ITALICANGLE: + { + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->italicAngle = dz; + } + break; + + case UNDERLINEPOSITION: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->underlinePosition = (int) dz; + break; + + case UNDERLINETHICKNESS: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->underlineThickness = (int) dz; + break; + + case FONTBBOX: + { + if (nwords != 5) + goto PDF_SYNTAXERROR; + for (i = 1; i < nwords; i++) + { + if (pdc_str2double(wordlist[i], &dz) != pdc_true) + goto PDF_SYNTAXERROR; + if (i == 1) + ftm->llx = dz; + else if (i == 2) + ftm->lly = dz; + else if (i == 3) + ftm->urx = dz; + else if (i == 4) + ftm->ury = dz; + } + } + break; + + case CAPHEIGHT: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->capHeight = (int) dz; + break; + + case XHEIGHT: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->xHeight = (int) dz; + break; + + case DESCENDER: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->descender = (int) dz; + break; + + case ASCENDER: + if (pdc_str2double(arg1, &dz) != pdc_true) + goto PDF_SYNTAXERROR; + ftm->ascender = (int) dz; + break; + + /* Character widths */ + + case STARTCHARMETRICS: + if (pdc_str2integer(arg1, PDC_INT_UNSIGNED, (pdc_sint32 *) &nglyphs) + != pdc_true || nglyphs <= 0) + goto PDF_SYNTAXERROR; + ftm->glw = (fnt_glyphwidth *) pdc_calloc(p->pdc, + (size_t) nglyphs * sizeof(fnt_glyphwidth), fn); + break; + + /* Character code */ + case CODE: + case CODEHEX: + if (!nglyphs || !ftm->glw) + goto PDF_SYNTAXERROR; + if (font->ft.numglyphs >= nglyphs) + { + nglyphs++; + ftm->glw = (fnt_glyphwidth *) pdc_realloc(p->pdc, ftm->glw, + (size_t) nglyphs * sizeof(fnt_glyphwidth), fn); + } + glw = &ftm->glw[font->ft.numglyphs]; + if (keynumber == CODE) + { + if (pdc_str2integer(arg1, 0, &iz) != pdc_true) + goto PDF_SYNTAXERROR; + } + else + { + if (pdc_str2integer(arg1, PDC_INT_HEXADEC, &iz) != pdc_true) + goto PDF_SYNTAXERROR; + } + glw->code = (pdc_short) iz; + glw->unicode = 0; + glw->width = (pdc_ushort) + (font->opt.monospace ? font->opt.monospace : charwidth); + font->ft.numglyphs++; + + /* Character width and name */ + for (i = 2; i < nwords; i++) + { + if (!strcmp(wordlist[i], "WX") || + !strcmp(wordlist[i], "W0X") || + !strcmp(wordlist[i], "W")) + { + i++; + if (i == nwords) + goto PDF_SYNTAXERROR; + if (pdc_str2double(wordlist[i], &dz) != pdc_true) + goto PDF_SYNTAXERROR; + glw->width = (pdc_ushort) + (font->opt.monospace ? font->opt.monospace : dz); + } + + if (!strcmp(wordlist[i], "N")) + { + i++; + if (i == nwords) + goto PDF_SYNTAXERROR; + + /* Unicode value by means of AGL, + * internal and private table + */ + glw->unicode = is_zadbfont ? + (pdc_ushort) pdc_zadb2unicode(wordlist[i]): + pdc_insert_glyphname(p->pdc, wordlist[i]); + pdc_delete_missingglyph_bit(glw->unicode, + &font->missingglyphs); + + } + } + break; + + + default: + break; + } + + PDF_PARSECONTD: + pdc_cleanup_stringlist(p->pdc, wordlist); + wordlist = NULL; + + if (keynumber == ENDFONTMETRICS) + break; + } + + /* necessary font struct members */ + if (font->ft.name == NULL || ftm->glw == NULL) + goto PDF_SYNTAXERROR; + + pdc_fclose(fp); + + ftm->numglwidths = font->ft.numglyphs; + return pdc_true; + + PDF_SYNTAXERROR: + pdc_fclose(fp); + pdc_cleanup_stringlist(p->pdc, wordlist); + + if (afmtype) + pdc_set_errmsg(p->pdc, PDF_E_T1_UNSUPP_FORMAT, afmtype, 0, 0, 0); + else + pdc_set_errmsg(p->pdc, PDC_E_IO_ILLSYNTAX, "AFM ", filename, + pdc_errprintf(p->pdc, "%d", nline), 0); + return pdc_false; +} + +pdc_bool +pdf_process_metrics_data( + PDF *p, + pdf_font *font, + const char *fontname) +{ + static const char fn[] = "pdf_process_metrics_data"; + fnt_font_metric *ftm = &font->ft.m; + int width = 0; + pdc_ushort uv; + pdc_encoding enc = font->ft.enc; + pdc_encodingvector *ev = NULL; + int nalloc, foundglyphs = 0, i, j = 0, k; + + (void) j; + + /* Unallowed encoding */ + if (enc == pdc_cid || enc < pdc_builtin) + { + + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + + return pdc_false; + } + + /* Determine the default character width (width of space character) */ + if (font->opt.monospace) + { + ftm->defwidth = font->opt.monospace; + } + else + { + width = fnt_get_glyphwidth((int) PDF_DEFAULT_CHAR, &font->ft); + if (width != FNT_MISSING_WIDTH) + ftm->defwidth = width; + else + ftm->defwidth = FNT_DEFAULT_WIDTH; + } + + /* builtin font */ + if (font->ft.issymbfont == pdc_true && enc != pdc_builtin && + !strcmp(font->encapiname, "auto")) + { + enc = pdc_builtin; + font->ft.enc = enc; + } + + /* optimizing PDF output */ + if (enc == pdc_ebcdic || + enc == pdc_ebcdic_37 || + enc == pdc_ebcdic_winansi) + font->towinansi = pdc_winansi; + + /* glyph name list for incore fonts */ + nalloc = font->ft.numglyphs + AFM_GLYPH_SUPPL; + + /* + * Generate character width according to the chosen encoding + */ + + { + font->ft.numcodes = 256; + font->ft.code2gid = (pdc_ushort *) pdc_calloc(p->pdc, + font->ft.numcodes * sizeof (pdc_ushort), fn); + + ftm->numwidths = font->ft.numcodes; + ftm->widths = (int *)pdc_calloc(p->pdc, + font->ft.numcodes * sizeof(int), fn); + + /* Given 8-bit encoding */ + if (enc >= 0) + { + ev = pdc_get_encoding_vector(p->pdc, enc); + for (k = 0; k < font->ft.numcodes; k++) + { + uv = ev->codes[k]; + ftm->widths[k] = ftm->defwidth; + if (uv) + { + uv = pdc_get_alter_glyphname(uv, font->missingglyphs, NULL); + if (uv) + { + for (i = 0; i < ftm->numglwidths; i++) + { + if (ftm->glw[i].unicode == uv) + { + j = i + 1; + ftm->widths[k] = ftm->glw[i].width; + font->ft.code2gid[k] = j; + foundglyphs++; + } + } + } + } + } + + if (ftm->ciw != NULL) + { + pdc_free(p->pdc, ftm->ciw); + ftm->ciw = NULL; + } + + pdc_logg_cond(p->pdc, 2, trc_font, + "\t\t%d glyphs could be mapped to Unicode\n", foundglyphs); + + /* No characters found */ + if (!foundglyphs) + { + if (font->ft.issymbfont == pdc_false) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + return pdc_false; + } + else + { + /* We enforce builtin encoding */ + pdc_warning(p->pdc, PDF_E_FONT_FORCEENC, + pdf_get_encoding_name(p, pdc_builtin, font), + 0, 0, 0); + enc = pdc_builtin; + font->ft.enc = enc; + font->towinansi = pdc_invalidenc; + } + } + else if (foundglyphs < PDF_MIN_GLYPHS) + { + pdc_warning(p->pdc, PDF_E_FONT_INAPPROPENC, + pdc_errprintf(p->pdc, "%d", foundglyphs), 0, 0, 0); + } + } + + /* built-in encoding */ + if (enc == pdc_builtin) + { + if (ftm->glw == NULL) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + return pdc_false; + } + + /* encoding for builtin */ + ev = pdf_create_font_encoding(p, enc, font, fontname, pdc_true); + font->symenc = font->ft.enc; + + /***************************/ + font->ft.enc = pdc_builtin; + /***************************/ + + for (i = 0; i < font->ft.numcodes; i++) + { + ftm->widths[i] = ftm->defwidth; + } + + for (i = 0; i < font->ft.numglyphs; i++) + { + pdc_short code = ftm->glw[i].code; + + if (code >= 0 && code < font->ft.numcodes) + { + j = i + 1; + ftm->widths[code] = ftm->glw[i].width; + font->ft.code2gid[code] = j; + if (ev != NULL) + { + ev->codes[code] = ftm->glw[i].unicode; + } + } + } + } + } + + + if (ftm->glw != NULL) + { + pdc_free(p->pdc, ftm->glw); + ftm->glw = NULL; + } + + return pdc_true; +} + +pdc_bool +pdf_get_metrics_afm( + PDF *p, + pdf_font *font, + const char *fontname, + pdc_encoding enc, + const char *filename, + pdc_bool requested) +{ + static const char fn[] = "pdf_get_metrics_afm"; + char fullname[PDC_FILENAMELEN]; + pdc_file *afmfile; + + /* open AFM file */ + afmfile = pdc_fsearch_fopen(p->pdc, filename, fullname, "AFM ", + PDC_FILE_TEXT); + if (afmfile == NULL) + return pdc_check_fopen_errmsg(p->pdc, requested); + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tLoading AFM metric fontfile \"%s\":\n", fullname); + + /* parse AFM file */ + if (pdf_parse_afm(p, afmfile, font, fontname, fullname) == pdc_false) + return pdc_false; + + /* members not fount */ + if (font->ft.m.type == fnt_unknownType) + font->ft.m.type = fnt_Type1; + if (font->ft.name == NULL) + { + font->ft.name = pdc_strdup(p->pdc, fontname); + font->ft.m.name = pdc_strdup(p->pdc, fontname); + } + + /* save full filename */ + font->metricfilename = pdc_strdup_ext(p->pdc, fullname, 0, fn); + + /* process metric data */ + font->ft.enc = enc; + if (pdf_process_metrics_data(p, font, fontname) == pdc_false) + return pdc_false; + + if (!pdf_make_fontflag(p, font)) + return pdc_false; + + return pdc_true; +} diff --git a/src/pdflib/pdflib/p_annots.c b/src/pdflib/pdflib/p_annots.c new file mode 100644 index 0000000..b38da91 --- /dev/null +++ b/src/pdflib/pdflib/p_annots.c @@ -0,0 +1,2078 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_annots.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib routines for annnotations + * + */ + +#define P_ANNOTS_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_image.h" + + + + +/* annotation types */ +typedef enum +{ + ann_text = (1<<0), + ann_link = (1<<1), + ann_freetext = (1<<2), + ann_line = (1<<3), + ann_square = (1<<4), + ann_circle = (1<<5), + ann_highlight = (1<<6), + ann_underline = (1<<7), + ann_squiggly = (1<<8), + ann_strikeout = (1<<9), + ann_stamp = (1<<10), + ann_ink = (1<<11), + ann_polygon = (1<<12), + ann_polyline = (1<<13), + ann_popup = (1<<14), + ann_fileattachment = (1<<15), + ann_3d = (1<<16) +} +pdf_annottype; + +static const pdc_keyconn pdf_annottype_pdfkeylist[] = +{ + {"Text", ann_text}, + {"Link", ann_link}, + {"FreeText", ann_freetext}, + {"Line", ann_line}, + {"Square", ann_square}, + {"Circle", ann_circle}, + {"Highlight", ann_highlight}, + {"Underline", ann_underline}, + {"Squiggly", ann_squiggly}, + {"StrikeOut", ann_strikeout}, + {"Stamp", ann_stamp}, + {"Polygon", ann_polygon}, + {"PolyLine", ann_polyline}, + {"Ink", ann_ink}, + {"Popup", ann_popup}, + {"FileAttachment", ann_fileattachment}, + {"3D", ann_3d}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_polyline_pdfkeylist[] = +{ + {"QuadPoints", ann_link}, + {"QuadPoints", ann_highlight}, + {"QuadPoints", ann_underline}, + {"QuadPoints", ann_squiggly}, + {"QuadPoints", ann_strikeout}, + {"InkList", ann_ink}, + {"Vertices", ann_polygon}, + {"Vertices", ann_polyline}, + {NULL, 0} +}; + +/* flags for annotation dictionary entries */ +typedef enum +{ + anndict_a = (1<<0), + anndict_bs = (1<<1), + anndict_c = (1<<2), + anndict_contents = (1<<3), + anndict_f = (1<<4), + anndict_fs = (1<<5), + anndict_h = (1<<6), + anndict_ic = (1<<7), + anndict_inklist = (1<<8), + anndict_l = (1<<9), + anndict_le = (1<<10), + anndict_name = (1<<11), + anndict_nm = (1<<12), + anndict_open = (1<<13), + anndict_parent = (1<<14), + anndict_popup = (1<<15), + anndict_q = (1<<16), + anndict_quadpoints = (1<<17), + anndict_rect = (1<<18), + anndict_subtype = (1<<19), + anndict_t = (1<<20), + anndict_vertices = (1<<21), + anndict_3dd = (1<<22), + anndict_3da = (1<<23), + anndict_3dv = (1<<24) +} +pdf_anndictentries; + +static const pdc_keyconn pdf_perm_entries_pdfkeylist[] = +{ + {"Contents", anndict_contents}, + {"Name", anndict_name}, + {"NM", anndict_nm}, + {"Open", anndict_open}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_forb_entries_pdfkeylist[] = +{ + {"A", anndict_a}, + {"BS", anndict_bs}, + {"C", anndict_c}, + {"F", anndict_f}, + {"FS", anndict_fs}, + {"H", anndict_h}, + {"IC", anndict_ic}, + {"InkList", anndict_inklist}, + {"L", anndict_l}, + {"LE", anndict_le}, + {"Parent", anndict_parent}, + {"Popup", anndict_popup}, + {"Q", anndict_q}, + {"QuadPoints", anndict_quadpoints}, + {"Rect", anndict_rect}, + {"Subtype", anndict_subtype}, + {"T", anndict_t}, + {"Vertices", anndict_vertices}, + {"3DD", anndict_3dd}, + {"3DV", anndict_3dv}, + {"3DA", anndict_3da}, + {NULL, 0} +}; + +/* line ending styles */ +typedef enum +{ + line_none, + line_square, + line_circle, + line_diamond, + line_openarrow, + line_closedarrow +} +pdf_endingstyles; + +static const pdc_keyconn pdf_endingstyles_pdfkeylist[] = +{ + {"None", line_none}, + {"Square", line_square}, + {"Circle", line_circle}, + {"Diamond", line_diamond}, + {"OpenArrow", line_openarrow}, + {"ClosedArrow", line_closedarrow}, + {NULL, 0} +}; + +/* text icon names */ +typedef enum +{ + icon_text_comment, + icon_text_help, + icon_text_key, + icon_text_insert, + icon_text_newparagraph, + icon_text_note, + icon_text_paragraph +} +pdf_text_iconnames; + +static const pdc_keyconn pdf_text_iconnames_pdfkeylist[] = +{ + {"Comment", icon_text_comment}, + {"Help", icon_text_help}, + {"Key", icon_text_key}, + {"Insert", icon_text_insert}, + {"NewParagraph", icon_text_newparagraph}, + {"Note", icon_text_note}, + {"Paragraph", icon_text_paragraph}, + {NULL, 0} +}; + +/* stamp icon names */ +typedef enum +{ + icon_stamp_approved, + icon_stamp_asls, + icon_stamp_confidential, + icon_stamp_departmental, + icon_stamp_draft, + icon_stamp_experimental, + icon_stamp_expired, + icon_stamp_final, + icon_stamp_forcomment, + icon_stamp_forpublicrelease, + icon_stamp_notapproved, + icon_stamp_notforpublicrelease, + icon_stamp_sold, + icon_stamp_topsecret +} +pdf_stamp_iconnames; + +static const pdc_keyconn pdf_stamp_iconnames_pdfkeylist[] = +{ + {"Approved", icon_stamp_approved}, + {"AsIs", icon_stamp_asls}, + {"Confidential", icon_stamp_confidential}, + {"Departmental", icon_stamp_departmental}, + {"Draft", icon_stamp_draft}, + {"Experimental", icon_stamp_experimental}, + {"Expired", icon_stamp_expired}, + {"Final", icon_stamp_final}, + {"ForComment", icon_stamp_forcomment}, + {"ForPublicRelease", icon_stamp_forpublicrelease}, + {"NotApproved", icon_stamp_notapproved}, + {"NotForPublicRelease", icon_stamp_notforpublicrelease}, + {"Sold", icon_stamp_sold}, + {"TopSecret", icon_stamp_topsecret}, + {NULL, 0} +}; + +/* file attachment icon names */ +typedef enum +{ + icon_attach_graph, + icon_attach_paperclip, + icon_attach_pushpin, + icon_attach_tag +} +pdf_attach_iconnames; + +static const pdc_keyconn pdf_attach_iconnames_pdfkeylist[] = +{ + {"Graph", icon_attach_graph}, + {"Paperclip", icon_attach_paperclip}, + {"PushPin", icon_attach_pushpin}, + {"Tag", icon_attach_tag}, + {NULL, 0} +}; + + +static const pdc_keyconn pdf_3dview_keylist[] = +{ + {NULL, 0} +}; + + + +#define PDF_LAYER_FLAG PDC_OPT_UNSUPP + +#define PDF_3DANNOT_FLAG PDC_OPT_UNSUPP +static const pdc_defopt pdf_create_annot_options[] = +{ + /* deprecated */ + {"annotwarning", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"usercoordinates", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"custom", pdc_stringlist, PDC_OPT_NONE, 1, 64, + 0.0, PDC_INT_MAX, NULL}, + + {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"parentname", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"popup", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"title", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"subject", pdc_stringlist, PDC_OPT_PDC_1_5, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"annotcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"borderstyle", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_borderstyle_keylist}, + + {"dasharray", pdc_scalarlist, PDC_OPT_NONE, 1, 2, + PDC_FLOAT_PREC, PDC_FLOAT_MAX, NULL}, + + {"linewidth", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"opacity", pdc_scalarlist, PDC_OPT_PDC_1_4 | PDC_OPT_PERCENT, 1, 1, + 0.0, 1.0, NULL}, + + {"highlight", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_highlight_keylist}, + + {"display", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_display_keylist}, + + {"zoom", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"rotate", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"readonly", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"locked", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1, + 0.0, 0.0, NULL}, + + {"open", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1, + 0.0, 0.0, NULL}, + + {"createdate", pdc_booleanlist, PDC_OPT_PDC_1_5, 1, 1, + 0.0, 0.0, NULL}, + + {"fillcolor", pdc_stringlist, PDC_OPT_NONE, 2, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"alignment", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_quadding_keylist}, + + {"font", pdc_fonthandle, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"fontsize", pdc_scalarlist, PDC_OPT_SUBOPTLIST | PDC_OPT_KEYLIST1, 1, 2, + 0.0, PDC_FLOAT_MAX, pdf_fontsize_keylist}, + + {"orientate", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_orientate_keylist}, + + {"contents", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"filename", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 1.0, PDC_FILENAMELEN, NULL}, + + {"mimetype", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"iconname", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"endingstyles", pdc_keywordlist, PDC_OPT_NONE, 2, 2, + 0.0, 0.0, pdf_endingstyles_pdfkeylist}, + + {"interiorcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"cloudy", pdc_scalarlist, PDC_OPT_PDC_1_5, 1, 1, + 0.0, 2.0, NULL}, + + {"line", pdc_scalarlist, PDC_OPT_NONE, 4, 4, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"polylinelist", pdc_polylinelist, PDC_OPT_NONE, 1, PDF_MAXARRAYSIZE, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"usematchbox", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"layer", pdc_layerhandle, PDF_LAYER_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"3dactivate", pdc_stringlist, PDF_3DANNOT_FLAG, 1, 1, + 0.0, PDC_USHRT_MAX, NULL}, + + {"3dbox", pdc_scalarlist, PDF_3DANNOT_FLAG, 4, 4, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"3ddata", pdc_3ddatahandle, PDF_3DANNOT_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"3dinteractive", pdc_booleanlist, PDF_3DANNOT_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"3dshared", pdc_booleanlist, PDF_3DANNOT_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"3dinitialview", pdc_3dviewhandle, PDF_3DANNOT_FLAG, 1, 1, + 0.0, 0.0, pdf_3dview_keylist}, + + PDC_OPT_TERMINATE +}; + +/* Annotation member */ +typedef struct pdf_annot_s +{ + pdc_bool iscopy; + pdc_id obj_id; + pdf_annottype atype; + int mask; + pdc_rectangle rect; + pdc_bool usercoordinates; + pdc_encoding hypertextencoding; + int hypertextcodepage; + pdf_coloropt annotcolor; + pdf_coloropt interiorcolor; + pdf_coloropt fillcolor; + int linewidth; + pdc_scalar opacity; + pdf_borderstyle borderstyle; + pdc_scalar dasharray[2]; + pdf_highlight highlight; + pdf_display display; + pdc_bool zoom; + pdc_bool rotate; + pdc_bool kreadonly; + pdc_bool locked; + pdc_bool open; + pdc_bool createdate; + int font; + pdc_scalar fontsize; + int orientate; + pdf_quadding alignment; + pdf_endingstyles endingstyles[2]; + pdc_scalar cloudy; + pdf_dest *dest; + char *name; + char *parentname; + char *popup; + char *title; + char *subject; + char *contents; + char *filename; + char *mimetype; + const char *iconname; + pdc_off_t filesize; + pdc_scalar *line; + pdc_polyline *polylinelist; + int nplines; + char **custom; + int ncustoms; + char *action; + + +} +pdf_annot; + +static void +pdf_reclaim_annot(void *item) +{ + pdf_annot *ann = (pdf_annot *) item; + + ann->iscopy = pdc_false; + ann->obj_id = PDC_BAD_ID; + ann->atype = (pdf_annottype)0; + ann->mask = 0; + ann->usercoordinates = pdc_false; + ann->hypertextencoding = pdc_invalidenc; + ann->hypertextcodepage = 0; + ann->annotcolor.type = (int) color_none; + ann->interiorcolor.type = (int) color_none; + ann->fillcolor.type = (int) color_none; + ann->linewidth = 1; + ann->opacity = 1; + ann->borderstyle = border_solid; + ann->dasharray[0] = 3; + ann->dasharray[1] = 3; + ann->highlight = high_invert; + ann->display = disp_visible; + ann->zoom = pdc_true; + ann->rotate = pdc_true; + ann->kreadonly = pdc_false; + ann->locked = pdc_false; + ann->open = pdc_false; + ann->createdate = pdc_false; + ann->font = -1; + ann->fontsize = 0; + ann->orientate = 0; + ann->alignment = quadd_left; + ann->cloudy = -1; + ann->endingstyles[0] = line_none; + ann->endingstyles[1] = line_none; + ann->dest = NULL; + ann->name = NULL; + ann->parentname = NULL; + ann->popup = NULL; + ann->title = NULL; + ann->subject = NULL; + ann->contents = NULL; + ann->filename = NULL; + ann->mimetype = NULL; + ann->iconname = NULL; + ann->filesize = 0; + ann->line = NULL; + ann->polylinelist = NULL; + ann->nplines = 0; + ann->custom = NULL; + ann->ncustoms = 0; + ann->action = NULL; + + + + +} + +static void +pdf_release_annot(void *context, void *item) +{ + PDF *p = (PDF *) context; + pdf_annot *ann = (pdf_annot *) item; + + /* is not a copy */ + if (!ann->iscopy) + { + pdf_cleanup_destination(p, ann->dest); + ann->dest = NULL; + + if (ann->name) + { + pdc_free(p->pdc, ann->name); + ann->name = NULL; + } + if (ann->parentname) + { + pdc_free(p->pdc, ann->parentname); + ann->parentname = NULL; + } + if (ann->popup) + { + pdc_free(p->pdc, ann->popup); + ann->popup = NULL; + } + if (ann->title) + { + pdc_free(p->pdc, ann->title); + ann->title = NULL; + } + if (ann->subject) + { + pdc_free(p->pdc, ann->subject); + ann->subject = NULL; + } + if (ann->contents) + { + pdc_free(p->pdc, ann->contents); + ann->contents = NULL; + } + if (ann->filename) + { + pdc_free(p->pdc, ann->filename); + ann->filename = NULL; + } + if (ann->mimetype) + { + pdc_free(p->pdc, ann->mimetype); + ann->mimetype = NULL; + } + if (ann->line) + { + pdc_free(p->pdc, ann->line); + ann->line = NULL; + } + if (ann->custom) + { + pdc_cleanup_optstringlist(p->pdc, ann->custom, ann->ncustoms); + ann->custom = NULL; + ann->ncustoms = 0; + } + if (ann->action) + { + pdc_free(p->pdc, ann->action); + ann->action = NULL; + } + } + + ann->polylinelist = (pdc_polyline *)pdc_delete_polylinelist( + p->pdc, ann->polylinelist, ann->nplines); +} + +static pdc_ced pdf_annot_ced = +{ + sizeof(pdf_annot), pdf_reclaim_annot, pdf_release_annot, NULL +}; + +static pdc_vtr_parms pdf_annot_parms = +{ + 0, 10, 10 +}; + +static pdf_annot * +pdf_new_annot(PDF *p) +{ + pdc_vtr *annots = pdf_get_annots_list(p); + pdf_annot *result; + + if (annots == NULL) + { + annots = pdc_vtr_new(p->pdc, &pdf_annot_ced, p, &pdf_annot_parms); + pdf_set_annots_list(p, annots); + } + + result = pdc_vtr_incr(annots, pdf_annot); + result->usercoordinates = p->usercoordinates; + result->hypertextencoding = p->hypertextencoding; + result->hypertextcodepage = p->hypertextcodepage; + pdf_init_coloropt(p, &result->fillcolor); + + + return result; +} + +static void +pdf_delete_last_annot(PDF *p) +{ + pdc_vtr *annots = pdf_get_annots_list(p); + + if (annots != NULL) + { + if (pdc_vtr_size(annots) > 1) + { + pdc_vtr_pop(annots); + } + else + { + pdc_vtr_delete(annots); + pdf_set_annots_list(p, NULL); + } + } +} + +static void +pdf_init_rectangle(PDF *p, pdf_annot *ann, + pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury, + pdc_vector *polyline) +{ + static const char fn[] = "pdf_init_rectangle"; + pdc_matrix *ctm = &p->curr_ppt->gstate[p->curr_ppt->sl].ctm; + int i; + + pdc_check_number(p->pdc, "llx", llx); + pdc_check_number(p->pdc, "lly", lly); + pdc_check_number(p->pdc, "urx", urx); + pdc_check_number(p->pdc, "ury", ury); + + pdc_delete_polylinelist(p->pdc, ann->polylinelist, ann->nplines); + ann->nplines = 1; + ann->polylinelist = (pdc_polyline *) pdc_malloc(p->pdc, + ann->nplines * sizeof(pdc_polyline), fn); + ann->polylinelist[0].np = 5; + ann->polylinelist[0].p = (pdc_vector *) pdc_malloc(p->pdc, + ann->polylinelist[0].np * sizeof(pdc_vector), fn); + + if (polyline == NULL) + { + if (!ann->usercoordinates) + ctm = NULL; + pdc_rect_init(&ann->rect, llx, lly, urx, ury); + pdc_rect2polyline(ctm, &ann->rect, ann->polylinelist[0].p); + } + else + { + for (i = 0; i < 5; i++) + pdc_transform_vector(ctm, &polyline[i], + &ann->polylinelist[0].p[i]); + } + + if (ctm != NULL) + pdc_polyline2rect(ann->polylinelist[0].p, 4, &ann->rect); +} + +/* because of Acrobat muddle */ +static void +pdf_permute_coordinates(pdf_annot *ann, pdf_annottype atype) +{ + if (ann->nplines == 1 && + (atype == ann_highlight || + atype == ann_underline || + atype == ann_squiggly || + atype == ann_strikeout)) + { + pdc_vector pl[5]; + int i; + + for (i = 0; i < ann->polylinelist[0].np; i++) + pl[i] = ann->polylinelist[0].p[i]; + + ann->polylinelist[0].p[0] = pl[3]; + ann->polylinelist[0].p[1] = pl[2]; + ann->polylinelist[0].p[2] = pl[0]; + ann->polylinelist[0].p[3] = pl[1]; + ann->polylinelist[0].p[4] = pl[3]; + } +} + +static const pdc_keyconn pdf_keytype_keylist[] = +{ + {"boolean", pdc_booleanlist}, + {"name", pdc_keywordlist}, + {"string", pdc_stringlist}, + {NULL, 0} +}; + +static const pdc_defopt pdf_custom_list_options[] = +{ + {"key", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1, + 1.0, PDF_MAX_NAMESTRING, NULL}, + + {"type", pdc_keywordlist, PDC_OPT_REQUIRED, 1, 1, + 0.0, 0.0, pdf_keytype_keylist}, + + {"value", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1, + 1.0, PDC_USHRT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +static void +pdf_parse_and_write_annot_customlist(PDF *p, pdf_annot *ann, pdc_bool output) +{ + int i; + + /* custom entries */ + for (i = 0; i < ann->ncustoms; i++) + { + pdc_resopt *resopts = NULL; + const char *stemp; + const char *keyword; + char **strlist = NULL; + char *string; + int inum; + + resopts = pdc_parse_optionlist(p->pdc, ann->custom[i], + pdf_custom_list_options, NULL, pdc_true); + + keyword = "key"; + pdc_get_optvalues(keyword, resopts, NULL, &strlist); + string = strlist[0]; + + inum = pdc_get_keycode(string, pdf_forb_entries_pdfkeylist); + if (inum != PDC_KEY_NOTFOUND) + { + stemp = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, string); + pdc_error(p->pdc, PDF_E_ANN_ILLCUSTOMKEY, stemp, 0, 0, 0); + } + inum = pdc_get_keycode(string, pdf_perm_entries_pdfkeylist); + if (inum != PDC_KEY_NOTFOUND) + ann->mask |= inum; + + if (output) + pdc_printf(p->out, "/%s", string); + + keyword = "type"; + pdc_get_optvalues(keyword, resopts, &inum, NULL); + + keyword = "value"; + pdc_get_optvalues(keyword, resopts, NULL, &strlist); + string = strlist[0]; + + switch (inum) + { + case pdc_booleanlist: + if (pdc_stricmp(string, "true") && pdc_stricmp(string, "false")) + { + stemp = + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, string); + + pdc_error(p->pdc, PDC_E_OPT_ILLBOOLEAN, keyword, stemp, 0, 0); + } + if (output) + pdc_printf(p->out, " %s", + PDC_BOOLSTR(pdc_stricmp(string, "false"))); + break; + + case pdc_keywordlist: + if (output) + pdc_printf(p->out, "/%s", string); + break; + + case pdc_stringlist: + pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, &string, NULL); + if (output) + pdf_put_hypertext(p, string); + break; + } + if (output) + pdc_puts(p->out, "\n"); + } +} + + + +static void +pdf_opt_alrdef(PDF *p, const char *keyword, pdf_annot *ann, int flag) +{ + if (ann->mask & flag) + pdc_error(p->pdc, PDF_E_ANN_OPTALRDEF, keyword, 0, 0, 0); +} + +static int +pdf_opt_effectless(PDF *p, const char *keyword, pdf_annottype curratype, + pdf_annottype intendatypes) +{ + if ((pdf_annottype) !(intendatypes & curratype)) + { + const char *type = pdc_get_keyword(curratype, pdf_annottype_pdfkeylist); + pdc_warning(p->pdc, PDF_E_ANN_OPTEFFLESS_FORTYPE, keyword, type, + 0, 0); + return 1; + } + return 0; +} + +void +pdf__create_annotation(PDF *p, + pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury, + const char *type, const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdc_clientdata cdata; + pdf_annottype atype; + pdf_annot *ann; + pdf_dest *dest = NULL; + const char *keyword, *keyword_s = NULL; + char **strlist = NULL; + pdc_scalar *line; + int i, j, k, ns, nss[2]; + pdf_ppt *ppt = p->curr_ppt; + pdc_matrix *ctm = &ppt->gstate[ppt->sl].ctm; + + pdc_check_number(p->pdc, "llx", llx); + pdc_check_number(p->pdc, "lly", lly); + pdc_check_number(p->pdc, "urx", urx); + pdc_check_number(p->pdc, "ury", ury); + + if (type == NULL || *type == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0); + + k = pdc_get_keycode_ci(type, pdf_annottype_pdfkeylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0); + atype = (pdf_annottype) k; + + + /* compatibility */ + if (p->compatibility < PDC_1_5 && + (atype == ann_polygon || atype == ann_polyline)) + { + pdc_error(p->pdc, PDC_E_PAR_VERSION, type, + pdc_get_pdfversion(p->pdc, PDC_1_5), 0, 0); + } + + /* Parsing option list */ + pdf_set_clientdata(p, &cdata); + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_create_annot_options, + &cdata, pdc_true); + + /* Initializing */ + ann = pdf_new_annot(p); + ann->atype = atype; + + keyword = "usercoordinates"; + pdc_get_optvalues(keyword, resopts, &ann->usercoordinates, NULL); + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + + ann->hypertextencoding = + pdf_get_hypertextencoding_opt(p, resopts, &ann->hypertextcodepage, + pdc_true); + + keyword = "custom"; + ns = pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, NULL, &ann->custom); + if (ns) + { + pdc_save_lastopt(resopts, PDC_OPT_SAVEALL); + ann->ncustoms = ns; + pdf_parse_and_write_annot_customlist(p, ann, pdc_false); + } + + keyword = "name"; + ns = pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, &ann->name, NULL); + if (ns) + { + pdf_opt_alrdef(p, keyword, ann, anndict_nm); + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + keyword = "parentname"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + ann->parentname = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "popup"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + ann->popup = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "title"; + if (pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, &ann->title, NULL)) + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "subject"; + if (pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, &ann->subject, NULL)) + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "annotcolor"; + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns) + { + pdf_parse_coloropt(p, keyword, strlist, ns, (int) color_rgb, + &ann->annotcolor); + } + + keyword = "borderstyle"; + if (pdc_get_optvalues(keyword, resopts, &ns, NULL)) + ann->borderstyle = (pdf_borderstyle) ns; + + keyword = "dasharray"; + ns = pdc_get_optvalues(keyword, resopts, ann->dasharray, NULL); + if (ns) + { + if (ns == 1) + ann->dasharray[1] = ann->dasharray[0]; + if (ann->borderstyle != border_dashed) + pdc_warning(p->pdc, PDC_E_OPT_IGNORED, keyword, 0, 0, 0); + } + + keyword = "linewidth"; + pdc_get_optvalues(keyword, resopts, &ann->linewidth, NULL); + + keyword = "opacity"; + pdc_get_optvalues(keyword, resopts, &ann->opacity, NULL); + + + keyword = "highlight"; + if (pdc_get_optvalues(keyword, resopts, &ns, NULL)) + { + pdf_opt_effectless(p, keyword, atype, ann_link); + ann->highlight = (pdf_highlight) ns; + } + + keyword = "display"; + if (pdc_get_optvalues(keyword, resopts, &ann->display, NULL)) + ann->display = (pdf_display) ns; + + keyword = "zoom"; + pdc_get_optvalues(keyword, resopts, &ann->zoom, NULL); + + keyword = "rotate"; + pdc_get_optvalues(keyword, resopts, &ann->rotate, NULL); + + keyword = "readonly"; + pdc_get_optvalues(keyword, resopts, &ann->kreadonly, NULL); + + keyword = "locked"; + pdc_get_optvalues(keyword, resopts, &ann->locked, NULL); + + keyword = "open"; + if (pdc_get_optvalues(keyword, resopts, &ann->open, NULL)) + { + pdf_opt_alrdef(p, keyword, ann, anndict_open); + pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_text | ann_popup)); + } + + keyword = "createdate"; + pdc_get_optvalues(keyword, resopts, &ann->createdate, NULL); + + keyword = "fillcolor"; + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns && !pdf_opt_effectless(p, keyword, atype, ann_freetext)) + { + pdf_parse_coloropt(p, keyword, strlist, ns, (int) color_cmyk, + &ann->fillcolor); + } + + keyword = "alignment"; + if (pdc_get_optvalues(keyword, resopts, &ns, NULL)) + ann->alignment = (pdf_quadding) ns; + + keyword = "font"; + if (pdc_get_optvalues(keyword, resopts, &ann->font, NULL)) + pdf_opt_effectless(p, keyword, atype, ann_freetext); + + keyword = "fontsize"; + if (pdf_get_fontsize_option(p, ann->font, resopts, &ann->fontsize)) + { + pdf_opt_effectless(p, keyword, atype, ann_freetext); + if (ann->usercoordinates == pdc_true) + ann->fontsize = pdc_transform_scalar(ctm, ann->fontsize); + } + + keyword = "orientate"; + if (pdc_get_optvalues(keyword, resopts, &ann->orientate, NULL)) + pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_freetext | ann_stamp)); + + keyword = "contents"; + if (atype == ann_freetext) + { + pdc_encoding enc = pdc_invalidenc; + int codepage = 0; + + if (ann->font > -1) + { + enc = p->fonts[ann->font].ft.enc; + codepage = p->fonts[ann->font].codepage; + } + pdf_get_opt_textlist(p, keyword, resopts, enc, codepage, + pdc_false, NULL, &ann->contents, NULL); + } + else + { + pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding, + ann->hypertextcodepage, pdc_true, NULL, &ann->contents, NULL); + } + if (ann->contents) + { + pdf_opt_alrdef(p, keyword, ann, anndict_contents); + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + keyword = "destination"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist) && + !pdf_opt_effectless(p, keyword, atype, ann_link)) + { + ann->dest = pdf_parse_destination_optlist(p, strlist[0], 0, + pdf_locallink); + keyword_s = keyword; + } + else + { + keyword = "destname"; + if (atype == ann_link) + dest = pdf_get_option_destname(p, resopts, ann->hypertextencoding, + ann->hypertextcodepage); + else if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + pdf_opt_effectless(p, keyword, atype, ann_link); + if (dest) + { + ann->dest = dest; + keyword_s = keyword; + } + } + + keyword = "filename"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL) && + !pdf_opt_effectless(p, keyword, atype, ann_fileattachment)) + { + ann->filename = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + ann->filesize = pdf_check_file(p, ann->filename, pdc_true); + } + + keyword = "mimetype"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL) && + !pdf_opt_effectless(p, keyword, atype, ann_fileattachment)) + ann->mimetype = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + keyword = "iconname"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist) && + !pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_text | ann_stamp | ann_fileattachment))) + { + const pdc_keyconn *kc = pdf_text_iconnames_pdfkeylist; + + pdf_opt_alrdef(p, keyword, ann, anndict_name); + + if (atype == ann_stamp) + kc = pdf_stamp_iconnames_pdfkeylist; + else if (atype == ann_fileattachment) + kc = pdf_attach_iconnames_pdfkeylist; + + ann->iconname = pdc_get_int_keyword(strlist[0], kc); + if (ann->iconname == NULL) + pdc_error(p->pdc, PDC_E_OPT_ILLKEYWORD, keyword, strlist[0], + 0, 0); + } + + keyword = "endingstyles"; + if (pdc_get_optvalues(keyword, resopts, nss, NULL)) + { + ann->endingstyles[0] = (pdf_endingstyles) nss[0]; + ann->endingstyles[1] = (pdf_endingstyles) nss[1]; + pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_line | ann_polyline)); + } + + keyword = "interiorcolor"; + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns && !pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_line | ann_polyline | + ann_square | ann_circle))) + { + pdf_parse_coloropt(p, keyword, strlist, ns, (int) color_rgb, + &ann->interiorcolor); + } + + keyword = "cloudy"; + if (pdc_get_optvalues(keyword, resopts, &ann->cloudy, NULL)) + pdf_opt_effectless(p, keyword, atype, ann_polygon); + + keyword = "line"; + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns && !pdf_opt_effectless(p, keyword, atype, ann_line)) + { + line = (pdc_scalar *) strlist; + if (ann->usercoordinates == pdc_true) + { + pdc_transform_point(ctm, line[0], line[1], &line[0], &line[1]); + pdc_transform_point(ctm, line[2], line[3], &line[2], &line[3]); + } + ann->line = (pdc_scalar *) pdc_save_lastopt(resopts, PDC_OPT_SAVEALL); + } + + keyword = "polylinelist"; + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns) + { + if (!pdf_opt_effectless(p, keyword, atype, + (pdf_annottype) (ann_ink | ann_polygon | ann_polyline | + ann_highlight | ann_underline | + ann_squiggly | ann_strikeout))) + { + pdc_polyline *pl = (pdc_polyline *) strlist; + + for (j = 0; j < ns; j++) + { + if (pl[j].np < 2 || + (atype != ann_ink && atype != ann_polygon && + atype != ann_polyline && pl[j].np != 4)) + { + pdc_error(p->pdc, PDF_E_ANN_BADNUMCOORD, keyword, 0, 0, 0); + } + for (i = 0; i < pl[j].np; i++) + { + if (ann->usercoordinates == pdc_true) + pdc_transform_vector(ctm, &pl[j].p[i], NULL); + } + } + pdc_delete_polylinelist(p->pdc, ann->polylinelist, ann->nplines); + ann->polylinelist = pl; + ann->nplines = ns; + pdc_save_lastopt(resopts, PDC_OPT_SAVEALL); + } + } + else + pdf_permute_coordinates(ann, atype); + + keyword = "action"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist)) + { + if (ann->dest) + { + pdf_cleanup_destination(p, ann->dest); + ann->dest = NULL; + pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword_s, keyword, 0, 0); + } + + /* parsing of action list */ + pdf_parse_and_write_actionlist(p, event_annotation, NULL, + (const char *) strlist[0]); + ann->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + + + /* required options */ + keyword = NULL; + if (ann->contents == NULL && atype != ann_link && atype != ann_popup) + keyword = "contents"; + if (ann->fontsize == 0 && atype == ann_freetext) + keyword = "fontsize"; + if (ann->font == -1 && atype == ann_freetext) + keyword = "font"; + if (ann->filename == NULL && atype == ann_fileattachment) + keyword = "filename"; + if (ann->line == NULL && atype == ann_line) + keyword = "line"; + if (ann->polylinelist == NULL && + (atype == ann_ink || atype == ann_polygon || atype == ann_polyline)) + keyword = "polylinelist"; + + if (keyword) + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, keyword, 0, 0, 0); + + + if (atype == ann_freetext) + { + pdf_font *font_s = &p->fonts[ann->font]; + const char *fontname = + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, font_s->ft.name); + + if (!strcmp(pdf_get_pdf_fontname(font_s), fontname)) + pdc_error(p->pdc, PDF_E_ANN_NOSTDFONT, fontname, 0, 0, 0); + } + + /* + * matchbox available + */ + keyword = "usematchbox"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist)) + { + pdf_annot *ann_first = ann; + const char *mboxname; + int ir, nrect, irect; + + mboxname = pdf_get_usematchbox(p, keyword, strlist[0], &irect, &nrect); + if (mboxname != NULL) + { + if (irect > nrect) + { + pdf_delete_last_annot(p); + } + else + { + pdf_mbox *mbox; + pdc_vector pl[5]; + + /* rectangle loop */ + for (ir = irect; ir <= nrect; ir++) + { + if (ir > irect) + { + /* create copy */ + ann = pdf_new_annot(p); + ann->atype = atype; + memcpy(ann, ann_first, sizeof(pdf_annot)); + ann->obj_id = PDC_BAD_ID; + ann->iscopy = pdc_true; + ann->nplines = 0; + ann->polylinelist = NULL; + } + + /* rectangle #ir */ + mbox = pdf_get_mbox(p, NULL, mboxname, ir, NULL); + pdf_get_mbox_rectangle(p, mbox, pl); + pdf_init_rectangle(p, ann, 0, 0, 0, 0, pl); + pdf_permute_coordinates(ann, atype); + ann->usercoordinates = pdc_true; + } + } + } + } + +} + +pdc_id +pdf_write_annots_root(PDF *p, pdc_vtr *annots, pdf_widget *widgetlist) +{ + pdc_id result = PDC_BAD_ID; + + /* Annotations array */ + if (annots != NULL || widgetlist) + { + result = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_array(p->out); + + if (annots != NULL) + { + pdf_annot *ann; + int i, na = pdc_vtr_size(annots); + + for (i = 0; i < na; i++) + { + ann = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot); + if (ann->obj_id == PDC_BAD_ID) + ann->obj_id = pdc_alloc_id(p->out); + pdc_objref_c(p->out, ann->obj_id); + } + } + + (void) widgetlist; + + pdc_end_array(p->out); + pdc_end_obj(p->out); + } + + return result; +} + +#define BUFSIZE 256 + +static void +pdf_write_defappstring(PDF *p, pdf_annot *ann) +{ + char buf[BUFSIZE], *bufc; + pdf_coloropt *fs; + int ct; + + if (ann->font == -1) + return; + + bufc = buf; + + /* font and fontsize */ + bufc += pdc_sprintf(p->pdc, pdc_true, bufc, "/%s %f Tf", + pdf_get_pdf_fontname(&p->fonts[ann->font]), + ann->fontsize); + + /* fill and stroke color */ + fs = &ann->fillcolor; + ct = fs->type; + switch (ct) + { + case color_gray: + bufc += pdc_sprintf(p->pdc, pdc_true, bufc, " %f g", + fs->value[0]); + break; + + case color_rgb: + bufc += pdc_sprintf(p->pdc, pdc_true, bufc, " %f %f %f rg", + fs->value[0], fs->value[1], fs->value[2]); + break; + + case color_cmyk: + bufc += pdc_sprintf(p->pdc, pdc_true, bufc, " %f %f %f %f k", + fs->value[0], fs->value[1], + fs->value[2], fs->value[3]); + break; + } + + pdc_puts(p->out, "/DA"); + pdf_put_hypertext(p, buf); + pdc_puts(p->out, "\n"); +} + +void +pdf_write_page_annots(PDF *p, pdc_vtr *annots) +{ + pdf_annot *ann, *annpar; + pdc_id act_idlist[PDF_MAX_EVENTS]; + int i, j, k, na, flags; + + na = pdc_vtr_size(annots); + + for (k = 0; k < na; k++) + { + ann = (pdf_annot *) &pdc_vtr_at(annots, k, pdf_annot); + + + /* write action objects */ + if (ann->action) + pdf_parse_and_write_actionlist(p, event_annotation, act_idlist, + (const char *) ann->action); + + + pdc_begin_obj(p->out, ann->obj_id); /* Annotation object */ + pdc_begin_dict(p->out); /* Annotation dict */ + + pdc_puts(p->out, "/Type/Annot\n"); + pdc_printf(p->out, "/Subtype/%s\n", + pdc_get_keyword(ann->atype, pdf_annottype_pdfkeylist)); + + + + + /* Contents */ + if (ann->contents) + { + pdc_puts(p->out, "/Contents"); + if (ann->atype == ann_freetext) + pdf_put_fieldtext(p, ann->contents, ann->font); + else + pdf_put_hypertext(p, ann->contents); + pdc_puts(p->out, "\n"); + } + + /* Current Page */ + pdc_objref(p->out, "/P", pdf_get_page_id(p, 0)); + + /* Rectangle */ + pdc_printf(p->out, "/Rect[%f %f %f %f]\n", + ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); + + /* Name */ + if (ann->name) + { + pdc_puts(p->out, "/NM"); + pdf_put_hypertext(p, ann->name); + pdc_puts(p->out, "\n"); + } + + /* Flags */ + flags = 0; + if (ann->display != disp_noprint) + { + flags = (1<<2); + flags |= ann->display; + } + if (!ann->zoom) + flags |= (1<<3); + if (!ann->rotate) + flags |= (1<<4); + if (ann->kreadonly) + flags |= (1<<6); + if (ann->locked) + flags |= (1<<7); + if (flags) + pdc_printf(p->out, "/F %d\n", flags); + + /* Border style dictionary */ + if (ann->linewidth != 1 || ann->borderstyle != border_solid) + { + pdc_puts(p->out, "/BS"); + pdc_begin_dict(p->out); /* BS dict */ + + pdc_printf(p->out, "/W %d", ann->linewidth); + pdc_printf(p->out, "/S/%s", + pdc_get_keyword(ann->borderstyle, pdf_borderstyle_pdfkeylist)); + if (ann->borderstyle == border_dashed) + pdc_printf(p->out, "/D[%f %f]", + ann->dasharray[0], ann->dasharray[1]); + + pdc_end_dict(p->out); /* BS dict */ + + /* Write the Border key in old-style PDF 1.1 format + * because of a bug in PDF 1.4 and earlier + */ + pdc_printf(p->out, "/Border[0 0 %f", (double) ann->linewidth); + + if (ann->borderstyle == border_dashed) + pdc_printf(p->out, "[%f %f]", + ann->dasharray[0], ann->dasharray[1]); + pdc_puts(p->out, "]\n"); + } + + /* Annotation color */ + if (ann->annotcolor.type != (int) color_none) + { + pdc_printf(p->out, "/C[%f %f %f]\n", ann->annotcolor.value[0], + ann->annotcolor.value[1], ann->annotcolor.value[2]); + } + + /* Title */ + if (ann->title && *ann->title) + { + pdc_puts(p->out, "/T"); + pdf_put_hypertext(p, ann->title); + pdc_puts(p->out, "\n"); + } + + /* Subject */ + if (ann->subject && *ann->subject) + { + pdc_puts(p->out, "/Subj"); + pdf_put_hypertext(p, ann->subject); + pdc_puts(p->out, "\n"); + } + + /* Popup */ + if (ann->popup && *ann->popup) + { + for (i = 0; i < na; i++) + { + annpar = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot); + if (annpar->name != NULL && + !strcmp(ann->popup, annpar->name)) + { + pdc_objref(p->out, "/Popup", annpar->obj_id); + break; + } + } + } + + /* Icon Name */ + if (ann->iconname && *ann->iconname) + pdc_printf(p->out, "/Name/%s\n", ann->iconname); + + /* CreationDate */ + if (ann->createdate) + { + char time_str[PDC_TIME_SBUF_SIZE]; + + pdc_get_timestr(time_str, pdc_false); + pdc_puts(p->out, "/CreationDate "); + pdf_put_hypertext(p, time_str); + pdc_puts(p->out, "\n"); + } + + /* Opacity */ + if (ann->opacity != 1) + pdc_printf(p->out, "/CA %f\n", ann->opacity); + + /* write Action entries */ + if (ann->action) + pdf_write_action_entries(p, event_annotation, act_idlist); + + /* custom entries */ + pdf_parse_and_write_annot_customlist(p, ann, pdc_true); + + switch (ann->atype) + { + /* Open */ + case ann_text: + case ann_popup: + if (ann->open) + pdc_puts(p->out, "/Open true\n"); + break; + + /* Alignment, Default appearance string */ + case ann_freetext: + if (ann->alignment != quadd_left) + pdc_printf(p->out, "/Q %d\n", ann->alignment); + pdf_write_defappstring(p, ann); + break; + + /* Line */ + case ann_line: + pdc_printf(p->out, "/L[%f %f %f %f]\n", + ann->line[0], ann->line[1], ann->line[2], ann->line[3]); + break; + + /* InkList, QuadPoints and Vertices */ + case ann_link: + if (!ann->usercoordinates || p->compatibility < PDC_1_6) + break; + case ann_highlight: + case ann_underline: + case ann_squiggly: + case ann_strikeout: + ann->polylinelist[0].np = 4; /* because of Acrobat error */ + case ann_ink: + case ann_polygon: + case ann_polyline: + pdc_printf(p->out, "/%s", + pdc_get_keyword(ann->atype, pdf_polyline_pdfkeylist)); + pdc_begin_array(p->out); + for (i = 0; i < ann->nplines; i++) + { + if (ann->atype == ann_ink) + pdc_begin_array(p->out); + for (j = 0; j < ann->polylinelist[i].np; j++) + pdc_printf(p->out, "%f %f ", ann->polylinelist[i].p[j].x, + ann->polylinelist[i].p[j].y); + if (ann->atype == ann_ink) + pdc_end_array_c(p->out); + } + pdc_end_array(p->out); + break; + + default: + break; + } + + switch (ann->atype) + { + /* Destination, Highlight */ + case ann_link: + if (ann->dest) + { + pdc_puts(p->out, "/Dest"); + pdf_write_destination(p, ann->dest); + } + if (ann->highlight != high_invert) + pdc_printf(p->out, "/H/%s\n", + pdc_get_keyword(ann->highlight, pdf_highlight_pdfkeylist)); + break; + + /* Line ending styles */ + case ann_line: + case ann_polyline: + if (ann->endingstyles[0] != line_none || + ann->endingstyles[1] != line_none) + pdc_printf(p->out, "/LE[/%s /%s]\n", + pdc_get_keyword(ann->endingstyles[0], + pdf_endingstyles_pdfkeylist), + pdc_get_keyword(ann->endingstyles[1], + pdf_endingstyles_pdfkeylist)); + break; + + /* border effect dictionary */ + case ann_polygon: + if (ann->cloudy > -1) + { + pdc_puts(p->out, "/BE"); + pdc_begin_dict(p->out); /* BE dict */ + pdc_puts(p->out, "/S/C"); + if (ann->cloudy > 0) + pdc_printf(p->out, "/I %f", ann->cloudy); + pdc_end_dict(p->out); /* BE dict */ + } + + /* rotate */ + case ann_stamp: + case ann_freetext: + if (ann->orientate) + pdc_printf(p->out, "/Rotate %d", ann->orientate); + break; + + default: + break; + } + + switch (ann->atype) + { + /* Interior color */ + case ann_line: + case ann_polyline: + case ann_square: + case ann_circle: + if (ann->interiorcolor.type != (int) color_none) + { + pdc_printf(p->out, "/IC[%f %f %f]\n", + ann->interiorcolor.value[0], + ann->interiorcolor.value[1], + ann->interiorcolor.value[2]); + } + break; + + /* Parent Annotation */ + case ann_popup: + if (ann->parentname && *ann->parentname) + { + for (i = 0; i < na; i++) + { + annpar = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot); + if (annpar->name != NULL && + !strcmp(ann->parentname, annpar->name)) + { + pdc_objref(p->out, "/Parent", annpar->obj_id); + break; + } + } + } + break; + + /* File specification */ + case ann_fileattachment: + { + pdc_puts(p->out, "/FS"); + pdc_begin_dict(p->out); /* FS dict */ + pdc_puts(p->out, "/Type/Filespec\n"); + pdc_puts(p->out, "/F"); + pdf_put_pdffilename(p, ann->filename); + pdc_puts(p->out, "\n"); + + /* alloc id for the actual embedded file stream */ + ann->obj_id = pdc_alloc_id(p->out); + pdc_puts(p->out, "/EF"); + pdc_begin_dict(p->out); + pdc_objref(p->out, "/F", ann->obj_id); + pdc_end_dict(p->out); + pdc_end_dict(p->out); /* FS dict */ + } + break; + + + default: + break; + } + + + pdc_end_dict(p->out); /* Annotation dict */ + pdc_end_obj(p->out); /* Annotation object */ + } + + /* Write the actual embedded files with preallocated ids */ + for (k = 0; k < na; k++) + { + ann = (pdf_annot *) &pdc_vtr_at(annots, k, pdf_annot); + if (ann->atype == ann_fileattachment) + pdf_embed_file(p, ann->obj_id, ann->filename, ann->mimetype, + ann->filesize); + } +} + +/*****************************************************************************/ +/** deprecated historical annotation functions **/ +/*****************************************************************************/ + +void +pdf_create_link( + PDF *p, + const char *type, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *annopts, + const char *utext, + int len) +{ + char optlist[2048]; + char *name; + int acthdl; + + if (!pdc_stricmp(type, "URI")) + strcpy(optlist, "url {"); + else if (!pdc_stricmp(type, "GoTo")) + strcpy(optlist, "destname {"); + else if (!pdc_stricmp(type, "GoToR")) + strcpy(optlist, "destination {page 1} filename {"); + + name = pdf_convert_name(p, utext, len, PDC_CONV_WITHBOM); + strcat(optlist, name); + pdc_free(p->pdc, name); + + strcat(optlist, "}"); + + acthdl = pdf__create_action(p, type, optlist); + if (acthdl > -1) + { + if (p->pdc->hastobepos) acthdl++; + pdc_sprintf(p->pdc, pdc_false, optlist, + "action {activate %d} usercoordinates ", acthdl); + strcat(optlist, annopts); + pdf__create_annotation(p, llx, lly, urx, ury, "Link", optlist); + } +} + +void +pdf_init_annot_params(PDF *p) +{ + /* annotation border style defaults */ + p->border_style = border_solid; + p->border_width = 1; + p->border_red = 0; + p->border_green = 0; + p->border_blue = 0; + p->border_dash1 = 3; + p->border_dash2 = 3; + + /* auxiliary function parameters */ + p->launchlink_parameters = NULL; + p->launchlink_operation = NULL; + p->launchlink_defaultdir = NULL; +} + +void +pdf_cleanup_annot_params(PDF *p) +{ + if (p->launchlink_parameters) + { + pdc_free(p->pdc, p->launchlink_parameters); + p->launchlink_parameters = NULL; + } + + if (p->launchlink_operation) + { + pdc_free(p->pdc, p->launchlink_operation); + p->launchlink_operation = NULL; + } + + if (p->launchlink_defaultdir) + { + pdc_free(p->pdc, p->launchlink_defaultdir); + p->launchlink_defaultdir = NULL; + } +} + +static void +pdf_insert_annot_params(PDF *p, pdf_annot *ann) +{ + ann->borderstyle = p->border_style; + ann->linewidth = (int) p->border_width; + ann->annotcolor.type = (int) color_rgb; + ann->annotcolor.value[0] = p->border_red; + ann->annotcolor.value[1] = p->border_green; + ann->annotcolor.value[2] = p->border_blue; + ann->annotcolor.value[3] = 0; + ann->dasharray[0] = p->border_dash1; + ann->dasharray[1] = p->border_dash2; +} + +void +pdf__attach_file( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *filename, + int len_filename, + const char *description, + int len_descr, + const char *author, + int len_auth, + const char *mimetype, + const char *icon) +{ + pdc_file *attfile; + pdf_annot *ann; + pdf_attach_iconnames icontype = icon_attach_pushpin; + + filename = pdf_convert_filename(p, filename, len_filename, "filename", + PDC_CONV_WITHBOM); + + if (icon != NULL && *icon) + { + int k = pdc_get_keycode_ci(icon, pdf_attach_iconnames_pdfkeylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0); + icontype = (pdf_attach_iconnames) k; + } + + attfile = pdc_fsearch_fopen(p->pdc, filename, NULL, "attachment ", 0); + if (attfile == NULL) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + + pdc_lock_pvf(p->pdc, filename); + pdc_fclose(attfile); + + /* fill up annotation struct */ + ann = pdf_new_annot(p); + ann->atype = ann_fileattachment; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + ann->filename = pdc_strdup(p->pdc, filename); + ann->filesize = pdf_check_file(p, ann->filename, pdc_true); + ann->contents = pdf_convert_hypertext_depr(p, description, len_descr); + ann->title = pdf_convert_hypertext_depr(p, author, len_auth); + if (mimetype != NULL && mimetype) + ann->mimetype = pdc_strdup(p->pdc, mimetype); + if (icontype != icon_attach_pushpin) + ann->iconname = + pdc_get_keyword(icontype, pdf_attach_iconnames_pdfkeylist); + ann->zoom = pdc_false; + ann->rotate = pdc_false; +} + +void +pdf__add_note( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *contents, + int len_cont, + const char *title, + int len_title, + const char *icon, + int kopen) +{ + pdf_annot *ann; + pdf_text_iconnames icontype = icon_text_note; + + if (icon != NULL && *icon) + { + int k = pdc_get_keycode_ci(icon, pdf_text_iconnames_pdfkeylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0); + icontype = (pdf_text_iconnames) k; + } + + /* fill up annotation struct */ + ann = pdf_new_annot(p); + ann->atype = ann_text; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + ann->contents = pdf_convert_hypertext_depr(p, contents, len_cont); + ann->title = pdf_convert_hypertext_depr(p, title, len_title); + if (icontype != icon_text_note) + ann->iconname = pdc_get_keyword(icontype,pdf_text_iconnames_pdfkeylist); + ann->open = kopen; + ann->display = disp_noprint; +} + +void +pdf__add_pdflink( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *filename, + int page, + const char *optlist) +{ + char actoptlist[2048], *sopt; + pdf_annot *ann; + int acthdl; + + if (filename == NULL || *filename == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0); + + /* creating a GoToR action */ + actoptlist[0] = 0; + sopt = actoptlist; + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "filename {%s} ", filename); + if (optlist == NULL) optlist = ""; + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "destination {%s page %d} ", + optlist, page); + acthdl = pdf__create_action(p, "GoToR", actoptlist); + + /* fill up annotation struct */ + if (acthdl > -1) + { + ann = pdf_new_annot(p); + ann->atype = ann_link; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + if (p->pdc->hastobepos) acthdl++; + pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl); + ann->action = pdc_strdup(p->pdc, actoptlist); + ann->display = disp_noprint; + } +} + +void +pdf__add_launchlink( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *filename) +{ + char actoptlist[2048], *sopt; + pdf_annot *ann; + int acthdl; + + if (filename == NULL || *filename == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0); + + /* creating a Launch action */ + actoptlist[0] = 0; + sopt = actoptlist; + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "filename {%s} ", filename); + if (p->launchlink_parameters) + { + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "parameters {%s} ", + p->launchlink_parameters); + pdc_free(p->pdc, p->launchlink_parameters); + p->launchlink_parameters = NULL; + } + if (p->launchlink_operation) + { + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "operation {%s} ", + p->launchlink_operation); + pdc_free(p->pdc, p->launchlink_operation); + p->launchlink_operation = NULL; + } + if (p->launchlink_defaultdir) + { + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "defaultdir {%s} ", + p->launchlink_defaultdir); + pdc_free(p->pdc, p->launchlink_defaultdir); + p->launchlink_defaultdir = NULL; + } + acthdl = pdf__create_action(p, "Launch", actoptlist); + + /* fill up annotation struct */ + if (acthdl > -1) + { + ann = pdf_new_annot(p); + ann->atype = ann_link; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + if (p->pdc->hastobepos) acthdl++; + pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl); + ann->action = pdc_strdup(p->pdc, actoptlist); + ann->display = disp_noprint; + } +} + +void +pdf__add_locallink( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + int page, + const char *optlist) +{ + pdf_annot *ann; + + /* fill up annotation struct */ + ann = pdf_new_annot(p); + ann->atype = ann_link; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + ann->dest = pdf_parse_destination_optlist(p, optlist, page, pdf_locallink); + ann->display = disp_noprint; +} + +void +pdf__add_weblink( + PDF *p, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury, + const char *url) +{ + char actoptlist[2048]; + pdf_annot *ann; + int acthdl; + + if (url == NULL || *url == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "url", 0, 0, 0); + + /* creating a URI action */ + pdc_sprintf(p->pdc, pdc_false, actoptlist, "url {%s} ", url); + acthdl = pdf__create_action(p, "URI", actoptlist); + + /* fill up annotation struct */ + if (acthdl > -1) + { + ann = pdf_new_annot(p); + ann->atype = ann_link; + pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL); + pdf_insert_annot_params(p, ann); + if (p->pdc->hastobepos) acthdl++; + pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl); + ann->action = pdc_strdup(p->pdc, actoptlist); + ann->display = disp_noprint; + } +} + +void +pdf__set_border_style(PDF *p, const char *style, pdc_scalar width) +{ + int k; + + p->border_style = border_solid; + if (style) + { + k = pdc_get_keycode_ci(style, pdf_borderstyle_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "style", style, 0, 0); + p->border_style = (pdf_borderstyle) k; + } + + pdc_check_number_limits(p->pdc, "width", width, 0.0, PDC_FLOAT_MAX); + + p->border_width = width; +} + +void +pdf__set_border_color(PDF *p, pdc_scalar red, pdc_scalar green, pdc_scalar blue) +{ + pdc_check_number_limits(p->pdc, "red", red, 0.0, 1.0); + pdc_check_number_limits(p->pdc, "green", green, 0.0, 1.0); + pdc_check_number_limits(p->pdc, "blue", blue, 0.0, 1.0); + + p->border_red = red; + p->border_green = green; + p->border_blue = blue; +} + +void +pdf__set_border_dash(PDF *p, pdc_scalar b, pdc_scalar w) +{ + pdc_check_number_limits(p->pdc, "b", b, 0.0, PDC_FLOAT_MAX); + pdc_check_number_limits(p->pdc, "w", w, 0.0, PDC_FLOAT_MAX); + + p->border_dash1 = b; + p->border_dash2 = w; +} + + + diff --git a/src/pdflib/pdflib/p_block.c b/src/pdflib/pdflib/p_block.c new file mode 100644 index 0000000..24a55a8 --- /dev/null +++ b/src/pdflib/pdflib/p_block.c @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2007 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_block.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Block processing routines (require the PDI library) + * + */ + +#define P_BLOCK_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_image.h" +#include "p_defopt.h" + diff --git a/src/pdflib/pdflib/p_bmp.c b/src/pdflib/pdflib/p_bmp.c new file mode 100644 index 0000000..ac6a974 --- /dev/null +++ b/src/pdflib/pdflib/p_bmp.c @@ -0,0 +1,795 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_bmp.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * BMP processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#ifndef PDF_BMP_SUPPORTED + +pdc_bool +pdf_is_BMP_file(PDF *p, pdc_file *fp) +{ + (void) p; + (void) fp; + + return pdc_false; +} + +int +pdf_process_BMP_data( + PDF *p, + int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "BMP", 0, 0, 0); + + return -1; +} + +#else /* !PDF_BMP_SUPPORTED */ + +/* for documentation only */ +#if 0 + +/* BMP file header structure */ +typedef struct +{ + pdc_ushort bfType; /* Magic number for file */ + pdc_uint32 bfSize; /* Size of file */ + pdc_ushort bfReserved1; /* Reserved */ + pdc_ushort bfReserved2; /* ... */ + pdc_uint32 bfOffBits; /* Offset to bitmap data */ +} +BITMAPFILEHEADER; + +/* BMP file info structure */ +typedef struct +{ + pdc_uint32 biSize; /* Size of info header */ + pdc_sint32 biWidth; /* Width of image */ + pdc_sint32 biHeight; /* Height of image */ + pdc_ushort biPlanes; /* Number of color planes */ + pdc_ushort biBitCount; /* Number of bits per pixel */ + pdc_uint32 biCompression; /* Type of compression to use */ + pdc_uint32 biSizeImage; /* Size of image data */ + pdc_sint32 biXPelsPerMeter; /* X pixels per meter */ + pdc_sint32 biYPelsPerMeter; /* Y pixels per meter */ + pdc_uint32 biClrUsed; /* Number of colors used */ + pdc_uint32 biClrImportant; /* Number of important colors */ +} +BITMAPINFOHEADER; + +#endif + +#define PDF_GET_BYTE(pos) *pos, pos += sizeof(pdc_byte) +#define PDF_GET_SHORT(pos) pdc_get_le_short(pos), pos += sizeof(pdc_short) +#define PDF_GET_USHORT(pos) pdc_get_le_ushort(pos), pos += sizeof(pdc_ushort) +#define PDF_GET_LONG(pos) pdc_get_le_long(pos), pos += sizeof(pdc_sint32) +#define PDF_GET_ULONG(pos) pdc_get_le_ulong(pos), pos += sizeof(pdc_uint32) + +#define PDF_BMP_STRING "\102\115" /* "BM" */ + +#define PDF_BMP_RGB 0 /* No compression - straight BGR data */ +#define PDF_BMP_RLE8 1 /* 8-bit run-length compression */ +#define PDF_BMP_RLE4 2 /* 4-bit run-length compression */ +#define PDF_BMP_BITFIELDS 3 /* RGB bitmap with RGB masks */ + +#define PDF_BMP_FILE_HEADSIZE 14 /* File header size */ +#define PDF_BMP_INFO_HEAD2SIZE 12 /* Info header size BMP Version 2 */ +#define PDF_BMP_INFO_HEAD3SIZE 40 /* Info header size BMP Version 3 */ +#define PDF_BMP_INFO_HEAD4SIZE 108 /* Info header size BMP Version 4 */ + +static void +pdf_data_source_BMP_init(PDF *p, PDF_data_source *src) +{ + static const char *fn = "pdf_data_source_BMP_init"; + pdf_image *image = (pdf_image *) src->private_data; + + src->buffer_length = image->info.bmp.rowbytes_buf; + src->buffer_start = (pdc_byte *) + pdc_calloc(p->pdc, image->info.bmp.rowbytes_pad, fn); + src->bytes_available = image->info.bmp.rowbytes_pdf; + src->next_byte = src->buffer_start; +} + +static pdc_bool +pdf_data_source_BMP_fill(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + int i, j; + + (void) p; + + if (image->info.bmp.bpp == 16) + { + if (image->info.bmp.pos < image->info.bmp.end) + { + pdc_ushort pixel, ppixel; + int ilast = image->info.bmp.rowbytes_buf - 3; + + i = 0; + for (j = 0; j < (int) image->info.bmp.rowbytes; j += 2) + { + pixel = PDF_GET_USHORT(image->info.bmp.pos); + + if (i <= ilast) + { + ppixel = (pixel & image->info.bmp.redmask); + ppixel = (ppixel >> image->info.bmp.redmove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.redmax); + i++; + + ppixel = (pixel & image->info.bmp.greenmask); + ppixel = (ppixel >> image->info.bmp.greenmove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.greenmax); + i++; + + ppixel = (pixel & image->info.bmp.bluemask); + ppixel = (ppixel >> image->info.bmp.bluemove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.bluemax); + i++; + } + } + } + else + { + src->bytes_available = 0; + } + } + + else if (image->info.bmp.bpp == 32 || + image->info.bmp.compression == PDF_BMP_RGB) + { + size_t avail; + + /* Read 1 padded row from file */ + avail = pdc_fread(src->buffer_start, 1, image->info.bmp.rowbytes_pad, + image->fp); + if (avail > 0) + { + /* Fill up remaining bytes */ + if (avail < image->info.bmp.rowbytes_pad) + { + for (i = (int) avail; i < (int) src->buffer_length; i++) + src->buffer_start[i] = 0; + } + + if (image->colorspace == DeviceRGB) + { + /* Swap red and blue */ + if (image->info.bmp.bpp == 32) + { + pdc_uint32 pixel, ppixel; + pdc_byte *pos = src->buffer_start; + + i = 0; + for (j = 0; j < (int) image->info.bmp.rowbytes_buf; j += 4) + { + pixel = PDF_GET_ULONG(pos); + + ppixel = (pixel & image->info.bmp.redmask); + ppixel = (ppixel >> image->info.bmp.redmove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.redmax); + i++; + + ppixel = (pixel & image->info.bmp.greenmask); + ppixel = (ppixel >> image->info.bmp.greenmove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.greenmax); + i++; + + ppixel = (pixel & image->info.bmp.bluemask); + ppixel = (ppixel >> image->info.bmp.bluemove); + src->buffer_start[i] = (pdc_byte) ((ppixel * 255) / + image->info.bmp.bluemax); + i++; + } + } + else + { + for (j = 0; j < (int) image->info.bmp.rowbytes_buf; j += 3) + { + pdc_byte c = src->buffer_start[j]; + src->buffer_start[j] = src->buffer_start[j + 2]; + src->buffer_start[j + 2] = c; + } + } + } + } + else + { + src->bytes_available = 0; + } + } + + /* Compression methods RLE8 and RLE4 */ + else + { + int col = 0; + int fnibble = 1; + pdc_byte c, cc, ccc, cn[2], ccn; + + if (image->info.bmp.pos < image->info.bmp.end) + { + if (image->info.bmp.skiprows) + { + for (; col < (int) image->info.bmp.rowbytes; col++) + src->buffer_start[col] = 0; + image->info.bmp.skiprows--; + } + else + { + while (1) + { + c = *image->info.bmp.pos; + image->info.bmp.pos++; + if (image->info.bmp.pos >= image->info.bmp.end) + goto PDF_BMP_CORRUPT; + cc = *image->info.bmp.pos; + + if (c != 0) + { + /* Repeat c time pixel value */ + if (image->info.bmp.compression == PDF_BMP_RLE8) + { + for (i = 0; i < (int) c; i++) + { + if (col >= (int) image->info.bmp.rowbytes) + goto PDF_BMP_CORRUPT; + src->buffer_start[col] = cc; + col++; + } + } + else + { + cn[0] = (pdc_byte) ((cc & 0xF0) >> 4); + cn[1] = (pdc_byte) (cc & 0x0F); + for (i = 0; i < (int) c; i++) + { + if (col >= (int) image->info.bmp.rowbytes) + goto PDF_BMP_CORRUPT; + ccn = cn[i%2]; + if (fnibble) + { + fnibble = 0; + src->buffer_start[col] = + (pdc_byte) (ccn << 4); + } + else + { + fnibble = 1; + src->buffer_start[col] |= ccn; + col++; + } + } + } + } + else if (cc > 2) + { + /* cc different pixel values */ + if (image->info.bmp.compression == PDF_BMP_RLE8) + { + for (i = 0; i < (int) cc; i++) + { + image->info.bmp.pos++; + if (image->info.bmp.pos >= image->info.bmp.end) + goto PDF_BMP_CORRUPT; + if (col >= (int) image->info.bmp.rowbytes) + goto PDF_BMP_CORRUPT; + src->buffer_start[col] = *image->info.bmp.pos; + col++; + } + } + else + { + for (i = 0; i < (int) cc; i++) + { + if (!(i%2)) + { + image->info.bmp.pos++; + if (image->info.bmp.pos >= + image->info.bmp.end) + goto PDF_BMP_CORRUPT; + ccc = *image->info.bmp.pos; + cn[0] = (pdc_byte) ((ccc & 0xF0) >> 4); + cn[1] = (pdc_byte) (ccc & 0x0F); + } + if (col >= (int) image->info.bmp.rowbytes) + goto PDF_BMP_CORRUPT; + ccn = cn[i%2]; + if (fnibble) + { + fnibble = 0; + src->buffer_start[col] = + (pdc_byte) (ccn << 4); + } + else + { + fnibble = 1; + src->buffer_start[col] |= ccn; + col++; + } + } + if (cc % 2) cc++; + cc /= 2; + } + + /* Odd number of bytes */ + if (cc % 2) + image->info.bmp.pos++; + } + else if (cc < 2) + { + /* End of scan line or end of bitmap data*/ + for (; col < (int) image->info.bmp.rowbytes; col++) + src->buffer_start[col] = 0; + } + else if (cc == 2) + { + int cola; + + /* Run offset marker */ + if (image->info.bmp.pos >= image->info.bmp.end - 1) + goto PDF_BMP_CORRUPT; + image->info.bmp.pos++; + c = *image->info.bmp.pos; + image->info.bmp.pos++; + cc = *image->info.bmp.pos; + + /* Fill current row */ + cola = col; + for (; col < (int) image->info.bmp.rowbytes; col++) + src->buffer_start[col] = 0; + if (col - cola != (int) c) + goto PDF_BMP_CORRUPT; + + /* Number of rows to be skipped */ + image->info.bmp.skiprows = (size_t) cc; + } + + image->info.bmp.pos++; + if (col >= (int) image->info.bmp.rowbytes) + { + /* Skip end of scan line marker */ + if (image->info.bmp.pos < image->info.bmp.end - 1) + { + c = *image->info.bmp.pos; + cc = *(image->info.bmp.pos + 1); + if(cc == 0 && cc <= 1) + image->info.bmp.pos += 2; + } + break; + } + } + } + } + else + { + src->bytes_available = 0; + } + } + + return (src->bytes_available ? pdc_true : pdc_false); + + PDF_BMP_CORRUPT: + + image->corrupt = pdc_true; + src->bytes_available = 0; + return pdc_false; +} + +static void +pdf_data_source_BMP_terminate(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + + pdc_free(p->pdc, (void *) src->buffer_start); + if (image->info.bmp.bitmap != NULL) + pdc_free(p->pdc, (void *) image->info.bmp.bitmap); +} + +pdc_bool +pdf_is_BMP_file(PDF *p, pdc_file *fp) +{ + pdc_byte buf[2]; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type BMP...\n"); + + if (pdc_fread(buf, 1, 2, fp) < 2 || + strncmp((const char *) buf, PDF_BMP_STRING, 2) != 0) + { + pdc_fseek(fp, 0L, SEEK_SET); + return pdc_false; + } + return pdc_true; +} + +int +pdf_process_BMP_data( + PDF *p, + int imageslot) +{ + static const char *fn = "pdf_process_BMP_data"; + pdc_byte buf[256], *pos, *cmap, bdummy; + pdf_image *image = &p->images[imageslot]; + pdc_file *fp = image->fp; + pdc_uint32 uldummy, infosize = 0, offras = 0, planes = 0, bitmapsize = 0; + pdc_uint32 ncolors = 0, importcolors = 0, compression = PDF_BMP_RGB; + pdc_ushort usdummy, bpp = 0, bpp_pdf = 0; + pdc_sint32 width = 0, height = 0, dpi_x = 0, dpi_y = 0; + pdc_uint32 redmask = 0, greenmask = 0, bluemask = 0, ccmax; + size_t nbytes; + pdf_colorspace cs; + pdf_colormap colormap; + int i, slot, colsize = 0, errcode = 0; + + /* Error reading magic number or not a BMP file */ + if (pdf_is_BMP_file(p, image->fp) == pdc_false) + { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_BMP_ERROR; + } + + /* read file header without FileType field + */ + /* Size field of info header */ + pos = &buf[2]; + nbytes = PDF_BMP_FILE_HEADSIZE - 2 + 4; + if (!PDC_OK_FREAD(fp, pos, nbytes)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + uldummy = PDF_GET_ULONG(pos); + usdummy = PDF_GET_USHORT(pos); + usdummy = PDF_GET_USHORT(pos); + offras = PDF_GET_ULONG(pos); + infosize = PDF_GET_ULONG(pos); + + /* no support of later version than 3 */ + if (infosize != PDF_BMP_INFO_HEAD2SIZE && + infosize != PDF_BMP_INFO_HEAD3SIZE) + { + errcode = PDF_E_BMP_VERSUNSUPP; + goto PDF_BMP_ERROR; + } + + /* info header */ + pos = buf; + nbytes = infosize - 4; + if (!PDC_OK_FREAD(fp, pos, nbytes)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + if (infosize == PDF_BMP_INFO_HEAD2SIZE) + { + width = PDF_GET_SHORT(pos); + height = PDF_GET_SHORT(pos); + planes = PDF_GET_USHORT(pos); + bpp = PDF_GET_USHORT(pos); + colsize = 3; + } + else if (infosize == PDF_BMP_INFO_HEAD3SIZE) + { + width = PDF_GET_LONG(pos); + height = PDF_GET_LONG(pos); + planes = PDF_GET_USHORT(pos); + bpp = PDF_GET_USHORT(pos); + compression = PDF_GET_ULONG(pos); + bitmapsize = PDF_GET_ULONG(pos); + dpi_x = PDF_GET_LONG(pos); + dpi_y = PDF_GET_LONG(pos); + ncolors = PDF_GET_ULONG(pos); + importcolors = PDF_GET_ULONG(pos); + colsize = 4; + } + + /* compressed BMP images by bitfields */ + if (compression == PDF_BMP_BITFIELDS) + { + pos = buf; + nbytes = 3 * sizeof(pdc_uint32); + if (!PDC_OK_FREAD(fp, pos, nbytes)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + else + { + redmask = PDF_GET_ULONG(pos); + greenmask = PDF_GET_ULONG(pos); + bluemask = PDF_GET_ULONG(pos); + } + } + + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\t\tinfosize = %d\n" + "\t\t\twidth = %d\n" + "\t\t\theight = %d\n" + "\t\t\tplanes = %d\n" + "\t\t\tbpp = %d\n" + "\t\t\tcompression = %d\n" + "\t\t\tbitmapsize = %d\n" + "\t\t\tdpi_x = %d\n" + "\t\t\tdpi_y = %d\n" + "\t\t\tncolors = %d\n" + "\t\t\timportcolors = %d\n" + "\t\t\tcolsize = %d\n" + "\t\t\tredmask = 0x%08X\n" + "\t\t\tgreenmask = 0x%08X\n" + "\t\t\tbluemask = 0x%08X\n", + infosize, width, height, planes, bpp, compression, + bitmapsize, dpi_x, dpi_y, ncolors, importcolors, + colsize, redmask, greenmask, bluemask); + + image->bpc = bpp; + image->width = width; + image->height = -height; + image->dpi_x = (pdc_scalar) (PDC_INCH2METER * dpi_x); + image->dpi_y = (pdc_scalar) (PDC_INCH2METER * dpi_y); + image->info.bmp.bpp = bpp; + bpp_pdf = bpp; + + /* color map only for bpp = 1, 4, 8 */ + if (bpp < 16) + { + if (!ncolors) + ncolors = (pdc_uint32) (1 << bpp); + if (ncolors > (offras - PDF_BMP_FILE_HEADSIZE - infosize) / colsize) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + + /* allocate and read color map */ + nbytes = colsize * ncolors; + cmap = (pdc_byte *) pdc_malloc(p->pdc, nbytes, fn); + if (!PDC_OK_FREAD(fp, cmap, nbytes)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + + /* set color map (bgr) */ + pos = cmap; + for (i = 0; i < (int) ncolors; i++) + { + colormap[i][2] = PDF_GET_BYTE(pos); + colormap[i][1] = PDF_GET_BYTE(pos); + colormap[i][0] = PDF_GET_BYTE(pos); + if (infosize == PDF_BMP_INFO_HEAD3SIZE) + { + bdummy = PDF_GET_BYTE(pos); + } + } + pdc_free(p->pdc, cmap); + + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\t\tcolor map with %d colors generated\n", + ncolors); + + image->components = 1; + + cs.type = Indexed; + cs.val.indexed.base = DeviceRGB; + cs.val.indexed.palette_size = (int) ncolors; + cs.val.indexed.colormap = &colormap; + cs.val.indexed.colormap_id = PDC_BAD_ID; + slot = pdf_add_colorspace(p, &cs, pdc_false); + + image->colorspace = slot; + + + } + else + { + image->colorspace = DeviceRGB; + image->components = 3; + image->bpc = 8; + if (bpp == 16) + { + bpp = 24; + bpp_pdf = 24; + if (compression == PDF_BMP_RGB) + { + redmask = 0x00007C00; + greenmask = 0x000003E0; + bluemask = 0x0000001F; + } + } + if (bpp == 32) + { + bpp_pdf = 24; + if (compression == PDF_BMP_RGB) + { + redmask = 0x00FF0000; + greenmask = 0x0000FF00; + bluemask = 0x000000FF; + } + } + + /* maximum and movement */ + if (image->info.bmp.bpp != 24) + { + for (i = 0; i < 32; i++) + { + ccmax = (redmask >> i); + if (ccmax & 0x00000001) + break; + } + image->info.bmp.redmask = redmask; + image->info.bmp.redmax = ccmax; + image->info.bmp.redmove = i; + + + for (i = 0; i < 32; i++) + { + ccmax = (greenmask >> i); + if (ccmax & 0x00000001) + break; + } + image->info.bmp.greenmask = greenmask; + image->info.bmp.greenmax = ccmax; + image->info.bmp.greenmove = i; + + for (i = 0; i < 32; i++) + { + ccmax = (bluemask >> i); + if (ccmax & 0x00000001) + break; + } + image->info.bmp.bluemask = bluemask; + image->info.bmp.bluemax = ccmax; + image->info.bmp.bluemove = i; + } + } + + if (image->imagemask) + { + if (image->components != 1) { + errcode = PDF_E_IMAGE_BADMASK; + goto PDF_BMP_ERROR; + } + + if (p->compatibility <= PDC_1_3) { + if (image->components != 1 || image->bpc != 1) { + errcode = PDF_E_IMAGE_MASK1BIT13; + goto PDF_BMP_ERROR; + } + } else if (image->bpc > 1) { + /* images with more than one bit will be written as /SMask, + * and don't require an /ImageMask entry. + */ + image->imagemask = pdc_false; + } + image->colorspace = DeviceGray; + } + + + + /* we invert this flag later */ + if (image->ignoremask) + image->transparent = pdc_true; + + /* number of bytes per row */ + image->info.bmp.rowbytes_pdf = (size_t) ((bpp_pdf * width + 7) / 8); + image->info.bmp.rowbytes_buf = (size_t) ((bpp * width + 7) / 8); + if (bpp == 4) + image->info.bmp.rowbytes = image->info.bmp.rowbytes_buf; + else if (image->info.bmp.bpp == 16) + image->info.bmp.rowbytes = + (size_t) (4 * ((image->info.bmp.bpp * width + 31) / 32)); + else + image->info.bmp.rowbytes = (size_t) ((bpp * width) / 8); + image->info.bmp.rowbytes_pad = (size_t) (4 * ((bpp * width + 31) / 32)); + image->info.bmp.compression = compression; + image->info.bmp.skiprows = 0; + image->info.bmp.bitmap = NULL; + + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\t\tinternal variables:\n" + "\t\t\t\tbpp_pdf = %d\n" + "\t\t\t\trowbytes = %d\n" + "\t\t\t\trowbytes_buf = %d\n" + "\t\t\t\trowbytes_pdf = %d\n" + "\t\t\t\trowbytes_pad = %d\n", + bpp_pdf, image->info.bmp.rowbytes, image->info.bmp.rowbytes_buf, + image->info.bmp.rowbytes_pdf, image->info.bmp.rowbytes_pad); + + /* read whole bitmap */ + if (image->info.bmp.bpp < 24 && (image->info.bmp.bpp == 16 || + image->info.bmp.compression != PDF_BMP_RGB)) + { + if (!bitmapsize) + { + bitmapsize = (int) (pdc_file_size(fp) - pdc_ftell(fp)); + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\t\tcalculated bitmapsize = %d\n", bitmapsize); + } + + image->info.bmp.bitmap = + (pdc_byte *) pdc_malloc(p->pdc, bitmapsize, fn); + if (!PDC_OK_FREAD(fp, image->info.bmp.bitmap, bitmapsize)) + { + pdc_free(p->pdc, (void *) image->info.bmp.bitmap); + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_BMP_ERROR; + } + image->info.bmp.pos = image->info.bmp.bitmap; + image->info.bmp.end = image->info.bmp.bitmap + bitmapsize; + } + + /* offset bitmap data */ + pdc_fseek(image->fp, (pdc_sint32) offras, SEEK_SET); + + /* put image data */ + image->src.init = pdf_data_source_BMP_init; + image->src.fill = pdf_data_source_BMP_fill; + image->src.terminate = pdf_data_source_BMP_terminate; + image->src.private_data = (void *) image; + + image->use_raw = pdc_false; + image->in_use = pdc_true; + + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + if (image->corrupt) + errcode = PDF_E_IMAGE_CORRUPT; + else + return imageslot; + + PDF_BMP_ERROR: + { + const char *stemp = NULL; + + if (errcode) + stemp = pdf_get_image_filename(p, image); + + switch (errcode) + { + case PDF_E_IMAGE_MASK1BIT13: + case PDF_E_BMP_VERSUNSUPP: + case PDF_E_BMP_COMPUNSUPP: + case PDF_E_IMAGE_BADMASK: + pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0); + break; + + case PDC_E_IO_BADFORMAT: + pdc_set_errmsg(p->pdc, errcode, stemp, "BMP", 0, 0); + break; + + case PDF_E_IMAGE_CORRUPT: + pdc_set_errmsg(p->pdc, errcode, "BMP", stemp, 0, 0); + break; + + case 0: /* error code and message already set */ + break; + } + } + + return -1; +} + +#endif /* PDF_BMP_SUPPORTED */ + diff --git a/src/pdflib/pdflib/p_ccitt.c b/src/pdflib/pdflib/p_ccitt.c new file mode 100644 index 0000000..ce028b7 --- /dev/null +++ b/src/pdflib/pdflib/p_ccitt.c @@ -0,0 +1,186 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_ccitt.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * CCITT (Fax G3 and G4) processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +/* + * Do a bit-reversal of all bytes in the buffer. + * This is supported for some clients which provide + * CCITT-compressed data in a byte-reversed format. + */ + +static void +pdf_reverse_bit_order(unsigned char *buffer, size_t size) +{ + size_t i; + + /* table for fast byte reversal */ + static const pdc_byte reverse[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + }; + + if (buffer != NULL) { + for (i = 0; i < size; i++) { + buffer[i] = reverse[buffer[i]]; + } + } +} + +static void +pdf_data_source_ccitt_raw_init(PDF *p, PDF_data_source *src) +{ + (void) p; + + src->bytes_available = 0; +} + +static pdc_bool +pdf_data_source_ccitt_raw_fill(PDF *p, PDF_data_source *src) +{ + pdf_image *image; + pdc_bool ismem; + + (void) p; + + if (src->bytes_available) + return pdc_false; + + image = (pdf_image *) src->private_data; + + src->buffer_start = (pdc_byte *) + pdc_freadall(image->fp, (size_t *) &src->buffer_length, &ismem); + + if (src->buffer_length == 0) + return pdc_false; + + src->bytes_available = src->buffer_length; + src->next_byte = src->buffer_start; + + if (image->info.ccitt.BitReverse) + pdf_reverse_bit_order(src->buffer_start, src->bytes_available); + + if (ismem) + src->buffer_length = 0; + + return pdc_true; +} + +static void +pdf_data_source_ccitt_raw_terminate(PDF *p, PDF_data_source *src) +{ + if (src->buffer_length) + pdc_free(p->pdc, (void *) src->buffer_start); +} + +static int +pdf_process_ccitt_raw_data(PDF *p, int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + /* check data length for raw uncompressed images */ + if (image->compression == pdf_comp_none && image->fp) + { + pdc_off_t length = pdc_file_size(image->fp); + if (length != (image->height_pixel * + ((image->width_pixel * image->components * image->bpc + 7) / 8))) + { + pdc_set_errmsg(p->pdc, PDF_E_RAW_ILLSIZE, + pdc_errprintf(p->pdc, "%lld", length), + pdf_get_image_filename(p, image), 0, 0); + return -1; + } + } + + + + + if (image->reference == pdf_ref_direct) + { + image->src.init = pdf_data_source_ccitt_raw_init; + image->src.fill = pdf_data_source_ccitt_raw_fill; + image->src.terminate = pdf_data_source_ccitt_raw_terminate; + image->src.private_data = (void *) image; + } + + image->in_use = pdc_true; /* mark slot as used */ + + if (image->doinline) + pdf_put_inline_image(p, imageslot); + else + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + return imageslot; +} + +int +pdf_process_CCITT_data(PDF *p, int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + /* CCITT specific information */ + image->info.ccitt.BitReverse = image->bitreverse; + image->compression = pdf_comp_ccitt; + image->use_raw = pdc_true; + + return pdf_process_ccitt_raw_data(p, imageslot); +} + +int +pdf_process_RAW_data(PDF *p, int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + /* RAW specific information */ + image->info.ccitt.BitReverse = 0; + image->compression = pdf_comp_none; + + return pdf_process_ccitt_raw_data(p, imageslot); +} diff --git a/src/pdflib/pdflib/p_cid.c b/src/pdflib/pdflib/p_cid.c new file mode 100644 index 0000000..6d7766c --- /dev/null +++ b/src/pdflib/pdflib/p_cid.c @@ -0,0 +1,198 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_cid.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib CID font handling routines + * + */ + +#include "p_intern.h" +#include "p_font.h" + +#include "ft_cid.h" + + +/* +** Returns CMap slot and for standard CJK fonts: fontandle. +** +** pdc_invalidenc: predefined CMap not found +** pdc_cid or pdc_unicode: predefined CMap found +** +** *o_slot: +** >= 0: standard font found +** < 0: |error code| +*/ +pdc_bool +pdf_handle_cidfont(PDF *p, const char *fontname, const char *encoding, + pdc_encoding enc, pdf_font *font, int *o_slot, + pdc_encoding *newenc) +{ + const char *encapiname = encoding; + fnt_cmap_info cmapinfo; + const fnt_font_metric *fontmetric; + pdc_bool isidentity = pdc_false; + pdc_bool isstdfont = pdc_false; + pdc_bool iscjkcp = pdc_false; + int charcoll, slot; + + (void) enc; + (void) iscjkcp; + (void) encapiname; + + *o_slot = -1; + *newenc = pdc_invalidenc; + + + /* + * Look whether font is already in the cache. + * If font with same name and encoding is found, + * returns its slot number. + */ + + for (slot = 0; slot < p->fonts_number; slot++) + { + if (p->fonts[slot].ft.enc == pdc_cid && + p->fonts[slot].opt.fontstyle == font->opt.fontstyle && + p->fonts[slot].opt.embedding == font->opt.embedding && + !strcmp(p->fonts[slot].apiname, fontname) && + !strcmp(p->fonts[slot].ft.cmapname, encoding)) + { + *o_slot = slot; + *newenc = pdc_cid; + return pdc_true; + } + } + + /* Check the requested CMap */ + charcoll = fnt_get_predefined_cmap_info(encoding, &cmapinfo); + if (charcoll == (int) cc_none) + return pdc_true; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPredefined CMap \"%s\" found\n", encoding); + + /* Check whether this CMap is supported in the desired PDF version */ + if (cmapinfo.compatibility > p->compatibility) + { + pdc_set_errmsg(p->pdc, PDF_E_DOC_PDFVERSION, + encoding, pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0); + return pdc_false; + } + + /* For Unicode capable language wrappers only UCS2/UTF16 CMaps allowed */ + if (cmapinfo.codesize == 0 && p->pdc->unicaplang) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_NEEDUCS2, 0, 0, 0, 0); + return pdc_false; + } + + /* Check whether the font name is among the known Acrobat CJK fonts */ + charcoll = fnt_get_preinstalled_cidfont(fontname, &fontmetric); + isidentity = cmapinfo.charcoll == (int) cc_identity; + if (isidentity) + cmapinfo.charcoll = abs(charcoll); + + /* known Acrobat CID font */ + if (charcoll != (int) cc_none) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tStandard CJK font \"%s\" found\n", fontname); + + /* Selected CMap and known standard font don't match */ + if ((cmapinfo.charcoll != abs(charcoll) || + (charcoll == (int) cc_japanese && cmapinfo.codesize == -2))) + { + pdc_set_errmsg(p->pdc, PDF_E_CJK_UNSUPP_CHARCOLL, + 0, 0, 0, 0); + return pdc_false; + } + isstdfont = pdc_true; + + + /* Embedding not possible */ + if (font->opt.embedding) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_EMBEDCMAP, 0, 0, 0, 0); + return pdc_false; + } + } +#ifdef WIN32 + else if (iscjkcp && !p->pdc->ptfrun) + { + return pdc_true; + } +#endif + + + /* embedding check */ + if (!pdf_check_font_embedding(p, font, fontname)) + return pdc_false; + + /* supplement number, number of codes = (maximal) number of CIDs */ + font->supplement = fnt_get_supplement(&cmapinfo, p->compatibility); + if (isidentity) + font->supplement = -1; + font->ft.numcodes = fnt_get_maxcid(cmapinfo.charcoll, font->supplement) + 1; + + { + font->passthrough = pdc_true; + font->codesize = 0; + } + + /* CMap and default settings */ + font->ft.vertical = cmapinfo.vertical; + font->ft.cmapname = pdc_strdup(p->pdc, encoding); + if (font->outcmapname == NULL) + font->outcmapname = pdc_strdup(p->pdc, encoding); + font->ft.enc = pdc_cid; + font->iscidfont = pdc_true; + + /* Fill up the font struct */ + fnt_fill_font_metric(p->pdc, &font->ft, pdc_false, fontmetric); + + /* CID widths not available */ + font->widthsmissing = pdc_true; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\n\t%s CJK font: \"%s\"\n\tPredefined CMap: \"%s\"\n" + "\tOrdering: \"%s\"\n\tSupplement: %d\n", + font->ft.isstdfont ? "Adobe Standard" : "Custom", fontname, encoding, + fnt_get_ordering_cid(font->ft.m.charcoll), font->supplement); + + *newenc = pdc_cid; + + return pdc_true; +} + +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED +void +pdf_put_cidglyph_widths(PDF *p, pdf_font *font) +{ + if (font->opt.monospace) + { + if (font->opt.monospace != FNT_DEFAULT_CIDWIDTH) + pdc_printf(p->out, "/DW %d\n", font->opt.monospace); + } + else + { + const char **widths = fnt_get_cid_widths_array(p->pdc, &font->ft); + int i; + + pdc_puts(p->out, "/W"); + pdc_begin_array(p->out); + for (i = 0; i < FNT_CIDMETRIC_INCR - 1; i++) + pdc_puts(p->out, widths[i]); + pdc_end_array(p->out); + } +} +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ diff --git a/src/pdflib/pdflib/p_color.c b/src/pdflib/pdflib/p_color.c new file mode 100644 index 0000000..d996d06 --- /dev/null +++ b/src/pdflib/pdflib/p_color.c @@ -0,0 +1,1130 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2007 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_color.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib color routines + * + */ + +#define P_COLOR_C + +#include "p_intern.h" +#include "p_color.h" + + +static const pdc_keyconn pdf_colortype_keylist[] = +{ + {"none", color_none}, + {"gray", color_gray}, + {"rgb", color_rgb}, + {"cmyk", color_cmyk}, + {"spotname", color_spotname}, + {"spot", color_spot}, + {"pattern", color_pattern}, + {"iccbasedgray", color_iccbasedgray}, + {"iccbasedrgb", color_iccbasedrgb}, + {"iccbasedcmyk", color_iccbasedcmyk}, + {"lab", color_lab}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_colorcomp_keylist[] = +{ + {"none", 0}, + {"gray", 1}, + {"rgb", 3}, + {"cmyk", 4}, + {"spotname", 2}, + {"spot", 2}, + {"pattern", 1}, + {"iccbasedgray", 1}, + {"iccbasedrgb", 3}, + {"iccbasedcmyk", 4}, + {"lab", 3}, + {NULL, 0} +}; + +/* ------------------------ color state ----------------------- */ + +struct pdf_cstate_s +{ + pdf_color fill; + pdf_color stroke; +}; + +void +pdf_init_cstate(PDF *p) +{ + static const char fn[] = "pdf_init_cstate"; + pdf_cstate *cstate; + + if (!p->curr_ppt->cstate) + { + p->curr_ppt->cstate = (pdf_cstate *) pdc_malloc(p->pdc, + PDF_MAX_SAVE_LEVEL * sizeof(pdf_cstate), fn); + } + + cstate = &p->curr_ppt->cstate[p->curr_ppt->sl]; + + cstate->fill.cs = DeviceGray; + cstate->fill.val.gray = 0.0; + + cstate->stroke.cs = DeviceGray; + cstate->stroke.val.gray = 0.0; +} + +void +pdf_save_cstate(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + int sl = ppt->sl; + + memcpy(&ppt->cstate[sl + 1], &ppt->cstate[sl], sizeof(pdf_cstate)); +} + +pdf_color * +pdf_get_cstate(PDF *p, pdf_drawmode mode) +{ + if (mode == pdf_fill) + return &p->curr_ppt->cstate[p->curr_ppt->sl].fill; + else + return &p->curr_ppt->cstate[p->curr_ppt->sl].stroke; +} + +void +pdf_cleanup_page_cstate(PDF *p, pdf_ppt *ppt) +{ + if (ppt->cstate != NULL) + pdc_free(p->pdc, ppt->cstate); + + ppt->cstate = NULL; +} + + + +/* Avoid wrong error messages due to rounding artifacts. + * This doesn't do any harm since we truncate to 5 decimal places anyway + * when producing PDF output. + */ +#define EPSILON ((1.0 + PDF_SMALLREAL)) + +static void pdf_check_color_values(PDF *p, pdf_colorspacetype type, + pdc_scalar c1, pdc_scalar c2, pdc_scalar c3, pdc_scalar c4); + +static int +pdf_color_components(PDF *p, int slot) +{ + static const char *fn = "pdf_color_components"; + pdf_colorspace *cs; + int components = 0; + + cs = &p->colorspaces[slot]; + + switch (cs->type) { + case DeviceGray: + case Indexed: + components = 1; + break; + + case DeviceRGB: + components = 3; + break; + + case DeviceCMYK: + components = 4; + break; + + case PatternCS: + if (cs->val.pattern.base == pdc_undef) + components = 0; /* PaintType 1: colored pattern */ + else + components = pdf_color_components(p, cs->val.pattern.base); + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", slot), + pdc_errprintf(p->pdc, "%d", cs->type), 0); + } + + return components; +} /* pdf_color_components */ + +static void +pdf_write_color_values(PDF *p, pdf_color *color, pdf_drawmode drawmode) +{ + static const char *fn = "pdf_write_color_values"; + pdf_colorspace * cs = &p->colorspaces[color->cs]; + int cs_bias = p->curr_ppt->cs_bias; + int pt_bias = p->curr_ppt->pt_bias; + + switch (cs->type) + { + case DeviceGray: + { + pdc_printf(p->out, "%f", color->val.gray); + + if (drawmode == pdf_fill) + pdc_puts(p->out, " g\n"); + else if (drawmode == pdf_stroke) + pdc_puts(p->out, " G\n"); + + break; + } + + case DeviceRGB: + { + pdc_printf(p->out, "%f %f %f", + color->val.rgb.r, color->val.rgb.g, color->val.rgb.b); + + if (drawmode == pdf_fill) + pdc_puts(p->out, " rg\n"); + else if (drawmode == pdf_stroke) + pdc_puts(p->out, " RG\n"); + + break; + } + + case DeviceCMYK: + { + pdc_printf(p->out, "%f %f %f %f", + color->val.cmyk.c, color->val.cmyk.m, + color->val.cmyk.y, color->val.cmyk.k); + + if (drawmode == pdf_fill) + pdc_puts(p->out, " k\n"); + else if (drawmode == pdf_stroke) + pdc_puts(p->out, " K\n"); + + break; + } + + + case PatternCS: + { + if (drawmode == pdf_fill) + { + if (p->pattern[color->val.pattern].painttype == 1) + { + pdc_puts(p->out, "/Pattern cs"); + } + else if (p->pattern[color->val.pattern].painttype == 2) + { + pdc_printf(p->out, "/C%d cs ", cs_bias + color->cs); + pdf_write_color_values(p, + &p->curr_ppt->cstate[p->curr_ppt->sl].fill, pdf_none); + } + + pdc_printf(p->out, "/P%d scn\n", pt_bias + color->val.pattern); + } + else if (drawmode == pdf_stroke) + { + if (p->pattern[color->val.pattern].painttype == 1) + { + pdc_puts(p->out, "/Pattern CS"); + } + else if (p->pattern[color->val.pattern].painttype == 2) + { + pdc_printf(p->out, "/C%d CS ", cs_bias + color->cs); + pdf_write_color_values(p, + &p->curr_ppt->cstate[p->curr_ppt->sl].stroke, pdf_none); + } + + pdc_printf(p->out, "/P%d SCN\n", pt_bias + color->val.pattern); + } + + p->pattern[color->val.pattern].used_on_current_page = pdc_true; + break; + } + + + case Indexed: /* LATER */ + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", color->cs), + pdc_errprintf(p->pdc, "%d", cs->type), 0); + } +} /* pdf_write_color_values */ + +static pdc_bool +pdf_color_equal(PDF *p, pdf_color *c1, pdf_color *c2) +{ + pdf_colorspace *cs1; + + cs1 = &p->colorspaces[c1->cs]; + + if (c1->cs != c2->cs) + return pdc_false; + + switch (cs1->type) { + case DeviceGray: + return (c1->val.gray == c2->val.gray); + break; + + case DeviceRGB: + return (c1->val.rgb.r == c2->val.rgb.r && + c1->val.rgb.g == c2->val.rgb.g && + c1->val.rgb.b == c2->val.rgb.b); + break; + + case DeviceCMYK: + return (c1->val.cmyk.c == c2->val.cmyk.c && + c1->val.cmyk.m == c2->val.cmyk.m && + c1->val.cmyk.y == c2->val.cmyk.y && + c1->val.cmyk.k == c2->val.cmyk.k); + break; + + case Indexed: + return (c1->val.idx == c2->val.idx); + break; + + case PatternCS: + return (c1->val.pattern == c2->val.pattern); + break; + + + default: + break; + } + + return pdc_true; +} /* pdf_color_equal */ + +static pdc_bool +pdf_colorspace_equal(PDF *p, pdf_colorspace *cs1, pdf_colorspace *cs2) +{ + static const char *fn = "pdf_colorspace_equal"; + + if (cs1->type != cs2->type) + return pdc_false; + + switch (cs1->type) { + case DeviceGray: + case DeviceRGB: + case DeviceCMYK: + return pdc_true; + break; + + + case Indexed: + return ((cs1->val.indexed.base == cs2->val.indexed.base) && + (cs1->val.indexed.palette_size==cs2->val.indexed.palette_size)&& + (cs1->val.indexed.colormap_id != PDC_BAD_ID && + cs1->val.indexed.colormap_id == cs2->val.indexed.colormap_id)); + break; + + case PatternCS: + return (cs1->val.pattern.base == cs2->val.pattern.base); + break; + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, "(unknown)", + pdc_errprintf(p->pdc, "%d", cs1->type), 0); + } + + return pdc_false; +} /* pdf_colorspace_equal */ + +static void +pdf_grow_colorspaces(PDF *p) +{ + int i; + + p->colorspaces = (pdf_colorspace *) pdc_realloc(p->pdc, p->colorspaces, + sizeof(pdf_colorspace) * 2 * p->colorspaces_capacity, + "pdf_grow_colorspaces"); + + for (i = p->colorspaces_capacity; i < 2 * p->colorspaces_capacity; i++) { + p->colorspaces[i].used_on_current_page = pdc_false; + } + + p->colorspaces_capacity *= 2; +} + +int +pdf_add_colorspace(PDF *p, pdf_colorspace *cs, pdc_bool inuse) +{ + pdf_colorspace *cs_new; + static const char fn[] = "pdf_add_colorspace"; + int slot; + + for (slot = 0; slot < p->colorspaces_number; slot++) + { + if (pdf_colorspace_equal(p, &p->colorspaces[slot], cs)) + { + if (inuse) + p->colorspaces[slot].used_on_current_page = pdc_true; + return slot; + } + } + + slot = p->colorspaces_number; + + if (p->colorspaces_number >= p->colorspaces_capacity) + pdf_grow_colorspaces(p); + + cs_new = &p->colorspaces[slot]; + + cs_new->type = cs->type; + + /* don't allocate id for simple color spaces, since we don't write these */ + if (PDF_SIMPLE_COLORSPACE(cs)) { + cs_new->obj_id = PDC_BAD_ID; + cs_new->used_on_current_page = pdc_false; + + } else { + cs_new->obj_id = pdc_alloc_id(p->out); + cs_new->used_on_current_page = inuse; + } + + switch (cs_new->type) { + case DeviceGray: + case DeviceRGB: + case DeviceCMYK: + break; + + + case Indexed: + { + size_t palsize; /* palette size in bytes */ + + palsize = cs->val.indexed.palette_size * + pdf_color_components(p, cs->val.indexed.base); + + cs_new->val.indexed.base = cs->val.indexed.base; + cs_new->val.indexed.palette_size = cs->val.indexed.palette_size; + cs_new->val.indexed.colormap_id = pdc_alloc_id(p->out); + cs_new->val.indexed.colormap = + (pdf_colormap *) pdc_malloc(p->pdc, palsize, fn); + memcpy(cs_new->val.indexed.colormap, cs->val.indexed.colormap, palsize); + cs_new->val.indexed.colormap_done = pdc_false; + break; + + case PatternCS: + cs_new->val.pattern.base = cs->val.pattern.base; + break; + } + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", slot), + pdc_errprintf(p->pdc, "%d", cs_new->type), 0); + } + + p->colorspaces_number++; + + return slot; +} /* pdf_add_colorspace */ + + +static void +pdf_set_color_values(PDF *p, pdf_color *c, pdf_drawmode drawmode) +{ + pdf_color *current; + pdf_colorspace *cs; + + cs = &p->colorspaces[c->cs]; + + if (drawmode == pdf_stroke || drawmode == pdf_fillstroke) + { + current = &p->curr_ppt->cstate[p->curr_ppt->sl].stroke; + + if (!pdf_color_equal(p, current, c) || PDF_FORCE_OUTPUT()) + { + if (PDF_GET_STATE(p) != pdf_state_document) + pdf_write_color_values(p, c, pdf_stroke); + + *current = *c; + } + } + if (drawmode == pdf_fill || drawmode == pdf_fillstroke) + { + current = &p->curr_ppt->cstate[p->curr_ppt->sl].fill; + + if (!pdf_color_equal(p, current, c) || PDF_FORCE_OUTPUT()) + { + if (PDF_GET_STATE(p) != pdf_state_document) + pdf_write_color_values(p, c, pdf_fill); + + *current = *c; + } + } + + /* simple colorspaces don't get written */ + if (!PDF_SIMPLE_COLORSPACE(cs)) + cs->used_on_current_page = pdc_true; + +} /* pdf_set_color_values */ + +void +pdf_init_colorspaces(PDF *p) +{ + int i, slot; + pdf_colorspace cs; + + + p->colorspaces_number = 0; + p->colorspaces_capacity = COLORSPACES_CHUNKSIZE; + + p->colorspaces = (pdf_colorspace *) + pdc_malloc(p->pdc, sizeof(pdf_colorspace) * p->colorspaces_capacity, + "pdf_init_colorspaces"); + + for (i = 0; i < p->colorspaces_capacity; i++) { + p->colorspaces[i].used_on_current_page = pdc_false; + } + + /* + * Initialize a few slots with simple color spaces for easier use. + * These can be used without further ado: the slot number is identical + * to the enum value due to the ordering below. + */ + + cs.type = DeviceGray; + slot = pdf_add_colorspace(p, &cs, pdc_false); + cs.type = DeviceRGB; + slot = pdf_add_colorspace(p, &cs, pdc_false); + cs.type = DeviceCMYK; + slot = pdf_add_colorspace(p, &cs, pdc_false); + +} /* pdf_init_colorspaces */ + +void +pdf_write_page_colorspaces(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->cs_bias; + + for (i = 0; i < p->colorspaces_number; i++) + if (p->colorspaces[i].used_on_current_page) + total++; + + if (total > 0 || bias + ) + { + pdc_puts(p->out, "/ColorSpace"); + pdc_begin_dict(p->out); + + if (total > 0) + { + for (i = 0; i < p->colorspaces_number; i++) + { + pdf_colorspace *cs = &p->colorspaces[i]; + + if (cs->used_on_current_page) + { + cs->used_on_current_page = pdc_false; /* reset */ + + /* don't write simple color spaces as resource */ + if (!PDF_SIMPLE_COLORSPACE(cs)) + { + pdc_printf(p->out, "/C%d", bias + i); + pdc_objref(p->out, "", cs->obj_id); + } + } + } + } + + + if (!bias) + pdc_end_dict(p->out); /* color space names */ + } +} /* pdf_write_page_colorspaces */ + +void +pdf_get_page_colorspaces(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->colorspaces_number; i++) + { + pdf_colorspace *cs = &p->colorspaces[i]; + + if (cs->used_on_current_page) + { + cs->used_on_current_page = pdc_false; + + if (!PDF_SIMPLE_COLORSPACE(cs)) + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_colorspace(PDF *p, int n) +{ + p->colorspaces[n].used_on_current_page = pdc_true; +} + +void +pdf_write_function_dict(PDF *p, pdf_color *c0, pdf_color *c1, pdc_scalar N) +{ + static const char *fn = "pdf_write_function_dict"; + + pdf_colorspace *cs; + + cs = &p->colorspaces[c1->cs]; + + pdc_begin_dict(p->out); /* function dict */ + + pdc_puts(p->out, "/FunctionType 2\n"); + pdc_puts(p->out, "/Domain[0 1]\n"); + pdc_printf(p->out, "/N %f\n", N); + + switch (cs->type) { + + case DeviceGray: + pdc_puts(p->out, "/Range[0 1]\n"); + if (c0->val.gray != 0) pdc_printf(p->out, "/C0[%f]\n", c0->val.gray); + if (c1->val.gray != 1) pdc_printf(p->out, "/C1[%f]", c1->val.gray); + break; + + case DeviceRGB: + pdc_puts(p->out, "/Range[0 1 0 1 0 1]\n"); + pdc_printf(p->out, "/C0[%f %f %f]\n", + c0->val.rgb.r, c0->val.rgb.g, c0->val.rgb.b); + pdc_printf(p->out, "/C1[%f %f %f]", + c1->val.rgb.r, c1->val.rgb.g, c1->val.rgb.b); + break; + + case DeviceCMYK: + pdc_puts(p->out, "/Range[0 1 0 1 0 1 0 1]\n"); + pdc_printf(p->out, "/C0[%f %f %f %f]\n", + c0->val.cmyk.c, c0->val.cmyk.m, c0->val.cmyk.y, c0->val.cmyk.k); + pdc_printf(p->out, "/C1[%f %f %f %f]", + c1->val.cmyk.c, c1->val.cmyk.m, c1->val.cmyk.y, c1->val.cmyk.k); + break; + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, "(unknown)", + pdc_errprintf(p->pdc, "%d", cs->type), 0); + } + + pdc_end_dict_c(p->out); /* function dict */ +} /* pdf_write_function_dict */ + +void +pdf_write_colormap(PDF *p, int slot) +{ + PDF_data_source src; + pdf_colorspace *cs, *base; + pdc_id length_id; + + cs = &p->colorspaces[slot]; + + if (cs->type != Indexed || cs->val.indexed.colormap_done == pdc_true) + return; + + base = &p->colorspaces[cs->val.indexed.base]; + + pdc_begin_obj(p->out, cs->val.indexed.colormap_id); /* colormap object */ + pdc_begin_dict(p->out); + + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + + /* Length of colormap object */ + length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", length_id); + pdc_end_dict(p->out); + + src.init = NULL; + src.fill = pdf_data_source_buf_fill; + src.terminate = NULL; + + src.buffer_start = (unsigned char *) cs->val.indexed.colormap; + + src.buffer_length = (size_t) (cs->val.indexed.palette_size * + pdf_color_components(p, cs->val.indexed.base)); + + src.bytes_available = 0; + src.next_byte = NULL; + + /* Write colormap data */ + pdf_copy_stream(p, &src, pdc_true); /* colormap data */ + + pdc_end_obj(p->out); /* colormap object */ + + pdc_put_pdfstreamlength(p->out, length_id); + + /* free the colormap now that it's written */ + pdc_free(p->pdc, cs->val.indexed.colormap); + cs->val.indexed.colormap = NULL; + cs->val.indexed.colormap_done = pdc_true; +} /* pdf_write_colormap */ + +void +pdf_write_colorspace(PDF *p, int slot, pdc_bool direct) +{ + static const char *fn = "pdf_write_colorspace"; + + pdf_colorspace *cs; + int base; + + if (slot < 0 || slot >= p->colorspaces_number) + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", slot), + "(unknown)", 0); + + cs = &p->colorspaces[slot]; + + /* we always write simple colorspaces directly */ + if (PDF_SIMPLE_COLORSPACE(cs)) + direct = pdc_true; + + if (!direct) { + pdc_objref_c(p->out, cs->obj_id); + return; + } + + switch (cs->type) { + case DeviceGray: + pdc_printf(p->out, "/DeviceGray"); + break; + + case DeviceRGB: + pdc_printf(p->out, "/DeviceRGB"); + break; + + case DeviceCMYK: + pdc_printf(p->out, "/DeviceCMYK"); + break; + + + case Indexed: + base = cs->val.indexed.base; + + pdc_begin_array(p->out); + pdc_puts(p->out, "/Indexed"); + + pdf_write_colorspace(p, base, pdc_false); + + pdc_printf(p->out, " %d", cs->val.indexed.palette_size - 1); + pdc_objref_c(p->out, cs->val.indexed.colormap_id); + pdc_end_array_c(p->out); + break; + + case PatternCS: + pdc_begin_array(p->out); + pdc_printf(p->out, "/Pattern"); + pdf_write_colorspace(p, cs->val.pattern.base, pdc_false); + pdc_end_array(p->out); + break; + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", slot), + pdc_errprintf(p->pdc, "%d", cs->type), 0); + } +} /* pdf_write_colorspace */ + +void +pdf_write_doc_colorspaces(PDF *p) +{ + int i; + + for (i = 0; i < p->colorspaces_number; i++) { + pdf_colorspace *cs = &p->colorspaces[i]; + + /* don't write simple color spaces as resource */ + if (PDF_SIMPLE_COLORSPACE(cs)) + continue; + + pdc_begin_obj(p->out, cs->obj_id); + pdf_write_colorspace(p, i, pdc_true); + pdc_puts(p->out, "\n"); + pdc_end_obj(p->out); /* color space resource */ + + pdf_write_colormap(p, i); /* write pending colormaps */ + } +} + +void +pdf_cleanup_colorspaces(PDF *p) +{ + static const char *fn = "pdf_cleanup_colorspaces"; + + int i; + + if (!p->colorspaces) + return; + + for (i = 0; i < p->colorspaces_number; i++) { + pdf_colorspace *cs = &p->colorspaces[i];; + + switch (cs->type) { + case DeviceGray: + case DeviceRGB: + case DeviceCMYK: + case PatternCS: + break; + + case Indexed: + if (cs->val.indexed.colormap) + pdc_free(p->pdc, cs->val.indexed.colormap); + break; + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", i), + pdc_errprintf(p->pdc, "%d", cs->type), 0); + } + } + + pdc_free(p->pdc, p->colorspaces); + p->colorspaces = NULL; +} + + + + + +static void +pdf_check_color_values( + PDF *p, + pdf_colorspacetype type, + pdc_scalar c1, pdc_scalar c2, pdc_scalar c3, pdc_scalar c4) +{ + switch (type) { + case DeviceGray: + pdc_check_number_limits(p->pdc, "c1", c1, 0.0, EPSILON); + break; + + case DeviceRGB: + pdc_check_number_limits(p->pdc, "c1", c1, 0.0, EPSILON); + pdc_check_number_limits(p->pdc, "c2", c2, 0.0, EPSILON); + pdc_check_number_limits(p->pdc, "c3", c3, 0.0, EPSILON); + + break; + + case DeviceCMYK: + pdc_check_number_limits(p->pdc, "c1", c1, 0.0, EPSILON); + pdc_check_number_limits(p->pdc, "c2", c2, 0.0, EPSILON); + pdc_check_number_limits(p->pdc, "c3", c3, 0.0, EPSILON); + pdc_check_number_limits(p->pdc, "c4", c4, 0.0, EPSILON); + break; + + + + case PatternCS: + pdf_check_handle(p, (int) c1, pdc_patternhandle); + if (c1 == p->pattern_number - 1 && PDF_GET_STATE(p) & pdf_state_pattern) + { + pdc_error(p->pdc, PDF_E_PATTERN_SELF, 0, 0, 0, 0); + } + break; + + case Separation: + pdf_check_handle(p, (int) c1, pdc_colorhandle); + pdc_check_number_limits(p->pdc, "c2", c2, 0.0, EPSILON); + break; + + case Indexed: + default: + break; + } +} /* pdf_check_color_values */ + +static void +pdf_setcolor_internal(PDF *p, int drawmode, int colortype, + pdc_scalar c1, pdc_scalar c2, pdc_scalar c3, pdc_scalar c4, + pdf_color *fcolor) +{ + pdf_color c; + pdf_colorspace cs; + + /* TODO: synchronize the PDF/X checks below with pdf_check_pdfx_colorspaces + */ + switch (colortype) + { + case color_gray: + cs.type = DeviceGray; + c.cs = cs.type; + c.val.gray = c1; + pdf_check_color_values(p, cs.type, c1, c2, c3, c4); + break; + + case color_rgb: + cs.type = DeviceRGB; + c.cs = cs.type; + c.val.rgb.r = c1; + c.val.rgb.g = c2; + c.val.rgb.b = c3; + pdf_check_color_values(p, cs.type, c1, c2, c3, c4); + break; + + case color_cmyk: + cs.type = DeviceCMYK; + c.cs = cs.type; + c.val.cmyk.c = c1; + c.val.cmyk.m = c2; + c.val.cmyk.y = c3; + c.val.cmyk.k = c4; + pdf_check_color_values(p, cs.type, c1, c2, c3, c4); + break; + + + case color_pattern: + cs.type = PatternCS; + if (p->pdc->hastobepos) c1 -= 1; + c.val.pattern = (int) c1; + pdf_check_color_values(p, cs.type, c1, c2, c3, c4); + + if (p->pattern[c.val.pattern].painttype == 1) + { + cs.val.pattern.base = pdc_undef; + c.cs = pdf_add_colorspace(p, &cs, pdc_false); + } + else + { + cs.val.pattern.base = p->curr_ppt->cstate[p->curr_ppt->sl].fill.cs; + c.cs = pdf_add_colorspace(p, &cs, pdc_true); + } + break; + + } + + + + if (fcolor == NULL) + pdf_set_color_values(p, &c, (pdf_drawmode) drawmode); + else + *fcolor = c; +} + +static const pdc_keyconn pdf_fstype_keylist[] = +{ + {"stroke", pdf_stroke}, + {"fill", pdf_fill}, + {"fillstroke", pdf_stroke | pdf_fill}, + {"both", pdf_stroke | pdf_fill}, + {NULL, 0} +}; + +void +pdf__setcolor( + PDF *p, + const char *fstype, + const char *colorspace, + pdc_scalar c1, pdc_scalar c2, pdc_scalar c3, pdc_scalar c4) +{ + int drawmode = (int) pdf_none; + int colortype; + + if (!fstype || !*fstype) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fstype", 0, 0, 0); + + if (!colorspace || !*colorspace) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "colorspace", 0, 0, 0); + + drawmode = pdc_get_keycode_ci(fstype, pdf_fstype_keylist); + if (drawmode == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "fstype", fstype, 0, 0); + + colortype = pdc_get_keycode_ci(colorspace, pdf_colortype_keylist); + if (colortype == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "colorspace", colorspace, 0, 0); + + pdf_setcolor_internal(p, drawmode, colortype, c1, c2, c3, c4, NULL); +} + +void +pdf_set_default_color(PDF *p, pdc_bool reset) +{ + + + + if (reset) + pdf__setcolor(p, "fillstroke", "gray", 0, 0, 0, 0); +} + + +void +pdf_parse_coloropt(PDF *p, const char *optname, char **optvalue, int ns, + int maxtype, pdf_coloropt *c) +{ + int errcode = 0; + const char *stemp = NULL; + + if (ns) + { + int i, j, n, iz = 0; + double dz; + + c->type = pdc_get_keycode_ci(optvalue[0], pdf_colortype_keylist); + if (c->type == PDC_KEY_NOTFOUND || c->type > maxtype) + { + stemp = pdc_errprintf(p->pdc, + "%.*s", PDC_ERR_MAXSTRLEN, optvalue[0]); + errcode = PDC_E_OPT_ILLKEYWORD; + goto PDF_COLOPT_ERROR; + } + + if (c->type == (int) color_spotname || c->type == (int) color_spot) + { + errcode = PDF_E_UNSUPP_SPOTCOLOR; + goto PDF_COLOPT_ERROR; + } + + n = 1 + pdc_get_keycode_ci(optvalue[0], pdf_colorcomp_keylist); + if (n != ns) + { + if (c->type == (int) color_spotname) + n++; + if (n != ns) + { + stemp = pdc_errprintf(p->pdc, "%d", n); + errcode = n < ns ? PDC_E_OPT_TOOMANYVALUES : + PDC_E_OPT_TOOFEWVALUES; + goto PDF_COLOPT_ERROR; + } + } + + for (i = 0; i < 4; i++) + { + j = i + 1; + if (i >= ns - 1) + { + if (!i || c->type != (int) color_gray) + c->value[i] = 0.0; + else + c->value[i] = c->value[0]; + } + else + { + if (!i && (c->type >= (int) color_spotname && + c->type <= (int) color_pattern)) + { + c->name[0] =0; + if (pdc_str2integer(optvalue[j], 0, (pdc_sint32 *) &iz) == + pdc_false) + { + { + stemp = pdc_errprintf(p->pdc, "%.*s", + PDC_ERR_MAXSTRLEN, optvalue[j]); + errcode = PDC_E_OPT_ILLNUMBER; + goto PDF_COLOPT_ERROR; + } + } + c->value[i] = iz; + } + else + { + if (pdc_str2double(optvalue[j], &dz) == pdc_false) + { + stemp = pdc_errprintf(p->pdc, "%.*s", + PDC_ERR_MAXSTRLEN, optvalue[j]); + errcode = PDC_E_OPT_ILLNUMBER; + goto PDF_COLOPT_ERROR; + } + else + c->value[i] = dz; + } + } + } + + if (c->type <= (int) color_cmyk) + { + for (i = 0; i < ns - 1; i++) + { + if (c->value[i] < 0 || c->value[i] > EPSILON) + { + stemp = pdc_errprintf(p->pdc, "%f", c->value[i]); + errcode = PDC_E_OPT_ILLNUMBER; + goto PDF_COLOPT_ERROR; + } + } + } + } + + PDF_COLOPT_ERROR: + + if (errcode) + pdc_error(p->pdc, errcode, optname, stemp, 0, 0); +} + + +void +pdf_set_coloropt(PDF *p, int drawmode, pdf_coloropt *c) +{ + if (c->type == (int) color_none) + return; + if (c->type == (int) color_spotname) + { + pdc_error(p->pdc, PDF_E_UNSUPP_SPOTCOLOR, 0, 0, 0, 0); + } + + pdf_setcolor_internal(p, drawmode, c->type, + c->value[0], c->value[1], c->value[2], c->value[3], + NULL); +} + +void +pdf_init_coloropt(PDF *p, pdf_coloropt *c) +{ + (void) p; + + { + c->name[0] = 0; + c->type = (int) color_gray; + c->value[0] = 0; + c->value[1] = 0; + c->value[2] = 0; + c->value[3] = 0; + } +} + +void +pdf_logg_coloropt(PDF *p, pdf_coloropt *c, pdc_bool newline) +{ + const char *keyword = + pdc_get_keyword((int) c->type, pdf_colortype_keylist); + + pdc_logg(p->pdc, "{%s ", keyword); + + switch (c->type) + { + case color_gray: + case color_iccbasedgray: + case color_pattern: + case color_spot: + pdc_logg(p->pdc, "%g}", c->value[0]); + break; + + case color_rgb: + case color_iccbasedrgb: + case color_lab: + pdc_logg(p->pdc, "%g %g %g}", c->value[0], c->value[1], c->value[2]); + break; + + case color_cmyk: + case color_iccbasedcmyk: + pdc_logg(p->pdc, "%g %g %g %g}", c->value[0], c->value[1], + c->value[2], c->value[3]); + break; + + case color_spotname: + pdc_logg(p->pdc, "{%s} %g}", c->name, c->value[0]); + break; + + default: + pdc_logg(p->pdc, "}"); + break; + } + + if (newline) + pdc_logg(p->pdc, "\n"); +} diff --git a/src/pdflib/pdflib/p_color.h b/src/pdflib/pdflib/p_color.h new file mode 100644 index 0000000..d8a0fa8 --- /dev/null +++ b/src/pdflib/pdflib/p_color.h @@ -0,0 +1,109 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_color.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib color definitions + * + */ + +#ifndef P_COLOR_H +#define P_COLOR_H + +/* + * These are treated specially in the global colorspace list, and are not + * written as /ColorSpace resource since we always specify them directly. + * Pattern colorspace with base == pdc_undef means PaintType == 1. + */ +#define PDF_SIMPLE_COLORSPACE(cs) \ + ((cs)->type == DeviceGray || \ + (cs)->type == DeviceRGB || \ + (cs)->type == DeviceCMYK || \ + ((cs)->type == PatternCS && cs->val.pattern.base == pdc_undef)) + + +struct pdf_pattern_s { + pdc_id obj_id; /* object id of this pattern */ + int painttype; /* colored (1) or uncolored (2) */ + pdc_bool used_on_current_page; /* this pattern used on current page */ +}; + +typedef pdc_byte pdf_colormap[256][3]; + +typedef struct { + int cs; /* slot of underlying color space */ + + union { + pdc_scalar gray; /* DeviceGray */ + int pattern; /* Pattern */ + int idx; /* Indexed */ + struct { /* DeviceRGB */ + pdc_scalar r; + pdc_scalar g; + pdc_scalar b; + } rgb; + struct { /* DeviceCMYK */ + pdc_scalar c; + pdc_scalar m; + pdc_scalar y; + pdc_scalar k; + } cmyk; + } val; +} pdf_color; + +struct pdf_colorspace_s { + pdf_colorspacetype type; /* color space type */ + + union { + struct { /* Indexed */ + int base; /* base color space */ + pdf_colormap *colormap; /* pointer to colormap */ + pdc_bool colormap_done; /* colormap already written to output */ + int palette_size; /* # of palette entries (not bytes!) */ + pdc_id colormap_id; /* object id of colormap */ + } indexed; + + struct { /* Pattern */ + int base; /* base color space for PaintType 2 */ + } pattern; + + } val; + + pdc_id obj_id; /* object id of this colorspace */ + pdc_bool used_on_current_page; /* this resource used on current page */ +}; + +/* "color" option */ +typedef struct +{ + char name[PDF_MAX_NAMESTRING + 1]; + int type; + pdc_scalar value[4]; +} +pdf_coloropt; + + +pdf_color *pdf_get_cstate(PDF *p, pdf_drawmode mode); +void pdf_get_page_colorspaces(PDF *p, pdf_reslist *rl); +void pdf_write_function_dict(PDF *p, pdf_color *c0, pdf_color *c1, + pdc_scalar N); +int pdf_add_colorspace(PDF *p, pdf_colorspace *cs, pdc_bool inuse); +void pdf_parse_coloropt(PDF *p, const char *optname, char **optvalue, int ns, + int maxtype, pdf_coloropt *c); +void pdf_set_coloropt(PDF *p, int drawmode, pdf_coloropt *c); +void pdf_init_coloropt(PDF *p, pdf_coloropt *c); +void pdf_logg_coloropt(PDF *p, pdf_coloropt *c, pdc_bool newline); + + + +#endif /* P_COLOR_H */ + diff --git a/src/pdflib/pdflib/p_defopt.h b/src/pdflib/pdflib/p_defopt.h new file mode 100644 index 0000000..6c4a862 --- /dev/null +++ b/src/pdflib/pdflib/p_defopt.h @@ -0,0 +1,494 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_defopt.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib shared option definitions and structures + * + */ + +#ifndef P_DEFOPT_H +#define P_DEFOPT_H + +#define PDF_KEEP_TEXTLEN (1L<<0) /* keep text length */ +#define PDF_KEEP_CONTROL (1L<<1) /* keep special control character */ +#define PDF_KEEP_UNICODE (1L<<2) /* keep Unicode text */ +#define PDF_FORCE_NEWALLOC (1L<<3) /* force alloc for new text */ +#define PDF_USE_TMPALLOC (1L<<4) /* use temporary memory */ + +#define PDF_RETURN_BOXEMPTY "_boxempty" +#define PDF_RETURN_BOXFULL "_boxfull" +#define PDF_RETURN_NEXTPAGE "_nextpage" +#define PDF_RETURN_STOP "_stop" + +typedef enum +{ + is_block = (1L<<0), + is_image = (1L<<1), + is_textline = (1L<<2), + is_textflow = (1L<<3), + is_inline = (1L<<4) +} +pdf_elemflags; + +struct pdf_text_options_s +{ + pdc_scalar charspacing; + pdc_scalar charspacing_pc; + pdf_coloropt fillcolor; + int font; + pdc_scalar fontsize; + pdc_scalar fontsize_pc; + int fontsize_st; + pdc_bool glyphwarning; + pdc_scalar horizscaling; + pdc_scalar italicangle; + pdc_bool fakebold; + pdc_bool kerning; + unsigned int mask; + unsigned int pcmask; + unsigned int fontset; + pdc_bool overline; + pdc_bool strikeout; + pdf_coloropt strokecolor; + pdc_scalar strokewidth; + pdc_scalar dasharray[2]; + char *text; + int textlen; + pdc_text_format textformat; + int textrendering; + pdc_scalar textrise; + pdc_scalar textrise_pc; + pdc_scalar leading; + pdc_scalar leading_pc; + pdc_bool underline; + pdc_scalar wordspacing; + pdc_scalar wordspacing_pc; + pdc_scalar underlinewidth; + pdc_scalar underlineposition; + pdc_scalar *xadvancelist; + int nglyphs; + char *link; + char *linktype; + pdc_bool charref; + pdc_bool escapesequence; + pdc_glyphcheck glyphcheck; +}; + +typedef enum +{ + xo_filename, + xo_ignoreorientation, + xo_imagewarning, + xo_dpi, + xo_page, + xo_scale +} +pdf_xobject_optflags; + +typedef struct +{ + pdc_bool adjustpage; + pdc_bool blind; + char *filename; + int flags; + pdc_bool imagewarning; + pdc_bool ignoreorientation; + unsigned int mask; + int im; + int page; + pdc_scalar dpi[2]; + pdc_scalar scale[2]; +} +pdf_xobject_options; + +typedef enum +{ + fit_boxsize, + fit_fitmethod, + fit_margin, + fit_shrinklimit, + fit_position, + fit_orientate, + fit_rotate, + fit_matchbox, + fit_alignchar, + fit_refpoint +} +pdf_fit_optflags; + + +typedef struct +{ + pdc_scalar boxsize[2]; + pdc_fitmethod fitmethod; + int flags; + pdc_scalar margin[2]; + unsigned int mask; + unsigned int pcmask; + pdc_scalar shrinklimit; + pdc_scalar position[2]; + int orientate; + pdc_scalar refpoint[2]; + pdc_scalar rotate; + pdc_bool showborder; + pdf_mbox *matchbox; + pdc_ushort alignchar; +} +pdf_fit_options; + +typedef struct pdf_fittext_s pdf_fittext; + + +/* font option definitions */ + +#define PDF_KERNING_FLAG PDC_OPT_UNSUPP +#define PDF_SUBSETTING_FLAG PDC_OPT_UNSUPP +#define PDF_AUTOCIDFONT_FLAG PDC_OPT_UNSUPP +#define PDF_EMBEDOPENTYPE_FLAG PDC_OPT_UNSUPP +#define PDF_CHARREF_FLAG PDC_OPT_UNSUPP +#define PDF_ESCAPESEQU_FLAG PDC_OPT_UNSUPP +#define PDF_GLYPHCHECK_FLAG PDC_OPT_UNSUPP +#define PDF_VERTICAL_FLAG PDC_OPT_UNSUPP +#define PDF_REPLCHAR_FLAG PDC_OPT_UNSUPP +#define PDF_KEEPNATIVE_FLAG PDC_OPT_UNSUPP +#define PDF_STAMP_FLAG PDC_OPT_UNSUPP +#define PDF_LEADER_FLAG PDC_OPT_UNSUPP + +#define PDF_METADATA_FLAG PDC_OPT_UNSUPP + +#define PDF_CLIPPATH_FLAG PDC_OPT_UNSUPP + +#define PDF_FONT_OPTIONS1 \ +\ + {"encoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"fontname", pdc_stringlist, PDC_OPT_NONE | PDC_OPT_CONVUTF8, 1, 1, \ + 1.0, PDF_MAX_FONTNAME, NULL}, \ + + +#define PDF_FONT_OPTIONS2 \ +\ + {"autocidfont", pdc_booleanlist, PDF_AUTOCIDFONT_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"autosubsetting", pdc_booleanlist, PDF_SUBSETTING_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"embedding", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"fontstyle", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_fontstyle_pdfkeylist}, \ +\ + /* deprecated */ \ + {"fontwarning", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"monospace", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + 1.0, FNT_MAX_METRICS, NULL}, \ +\ + {"ascender", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + -FNT_MAX_METRICS, FNT_MAX_METRICS, NULL}, \ +\ + {"descender", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + -FNT_MAX_METRICS, FNT_MAX_METRICS, NULL}, \ +\ + {"capheight", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + -FNT_MAX_METRICS, FNT_MAX_METRICS, NULL}, \ +\ + {"xheight", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + -FNT_MAX_METRICS, FNT_MAX_METRICS, NULL}, \ +\ + {"linegap", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + -FNT_MAX_METRICS, FNT_MAX_METRICS, NULL}, \ +\ + {"subsetlimit", pdc_doublelist, PDF_SUBSETTING_FLAG|PDC_OPT_PERCENT, 1, 1, \ + 0.0, 100.0, NULL}, \ +\ + {"subsetminsize", pdc_doublelist, PDF_SUBSETTING_FLAG, 1, 1, \ + 0.0, PDC_FLOAT_MAX, NULL}, \ +\ + {"subsetting", pdc_booleanlist, PDF_SUBSETTING_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"unicodemap", pdc_booleanlist, PDF_AUTOCIDFONT_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"embedopentype", pdc_booleanlist, PDF_EMBEDOPENTYPE_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"keepnative", pdc_booleanlist, PDF_KEEPNATIVE_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"vertical", pdc_booleanlist, PDF_VERTICAL_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"replacementchar", pdc_unicharlist, PDF_REPLCHAR_FLAG, 1, 1, \ + 0.0, PDC_MAX_UNIVAL, NULL}, \ +\ + {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ + + +#define PDF_FONT_OPTIONS3 \ +\ + {"kerning", pdc_booleanlist, PDF_KERNING_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ + + +/* text option definitions */ + +#define PDF_TEXT_OPTIONS \ +\ + {"charspacing", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ +\ + /* deprecated */ \ + {"glyphwarning", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"fillcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, \ + 0.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"font", pdc_fonthandle, PDC_OPT_NONE, 1, 1, \ + 0, 0, NULL}, \ +\ + {"fontsize", pdc_scalarlist, \ + PDC_OPT_PERCENT | PDC_OPT_SUBOPTLIST | PDC_OPT_KEYLIST1, 1, 2, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, pdf_fontsize_keylist}, \ +\ + {"horizscaling", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ +\ + {"italicangle", pdc_scalarlist, PDC_OPT_NONE, 1, 1, \ + -89.99, 89.99, NULL}, \ +\ + {"fakebold", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"kerning", pdc_booleanlist, PDF_KERNING_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"overline", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"strikeout", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"strokecolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, \ + 0.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"strokewidth", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + 0.0, PDC_FLOAT_MAX, pdf_underlinewidth_keylist}, \ +\ + {"dasharray", pdc_scalarlist, PDC_OPT_NONE, 1, 2, \ + 0.0, PDC_FLOAT_MAX, NULL}, \ +\ + {"textformat", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_textformat_keylist}, \ +\ + {"textrendering", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + 0, PDF_LAST_TRMODE, NULL}, \ +\ + {"textrise", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ +\ + {"underline", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"wordspacing", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ +\ + {"underlinewidth", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + 0.0, PDC_FLOAT_MAX, pdf_underlinewidth_keylist}, \ +\ + {"underlineposition", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, pdf_underlineposition_keylist}, \ +\ + /* deprecated */ \ + {"weblink", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + /* deprecated */ \ + {"locallink", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + /* deprecated */ \ + {"pdflink", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"charref", pdc_booleanlist, PDF_CHARREF_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"escapesequence", pdc_booleanlist, PDF_ESCAPESEQU_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"glyphcheck", pdc_keywordlist, PDF_GLYPHCHECK_FLAG, 1, 1, \ + 0.0, 0.0, pdf_glyphcheck_keylist}, \ +\ + + +/* xobject option definitions */ + +#define PDF_XOBJECT_OPTIONS1 \ +\ + {"adjustpage", pdc_booleanlist, PDC_OPT_PDC_1_3, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"blind", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ + + +#define PDF_XOBJECT_OPTIONS2 \ +\ + {"ignoreorientation", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"ignoreclippingpath", pdc_booleanlist, PDF_CLIPPATH_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + /* deprecated */ \ + {"imagewarning", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"dpi", pdc_scalarlist, PDC_OPT_NONE, 1, 2, \ + 0.0, PDC_INT_MAX, pdf_dpi_keylist}, \ + + +#define PDF_XOBJECT_OPTIONS3 \ +\ + {"scale", pdc_scalarlist, PDC_OPT_NOZERO, 1, 2, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ + + +/* general fit option definitions */ + +#define PDF_FIT_OPTIONS1 \ +\ + {"boxsize", pdc_scalarlist, PDC_OPT_NONE, 2, 2, \ + 0, PDC_FLOAT_MAX, NULL}, \ +\ + {"margin", pdc_scalarlist, PDC_OPT_NONE, 1, 2, \ + 0, PDC_FLOAT_MAX, NULL}, \ +\ + {"shrinklimit", pdc_scalarlist, PDC_OPT_PERCENT | PDC_OPT_PERCRANGE, 1, 1, \ + 0.0, 100.0, NULL}, \ +\ + {"position", pdc_scalarlist, PDC_OPT_NONE, 1, 2, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, pdf_position_keylist}, \ +\ + {"matchbox", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ + + +#define PDF_FIT_OPTIONS2 \ +\ + {"fitmethod", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_fitmethod_keylist}, \ +\ + {"rotate", pdc_scalarlist, PDC_OPT_NONE, 1, 1, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ +\ + {"orientate", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_orientate_keylist}, \ +\ + {"showborder", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ + + +#define PDF_FIT_OPTIONS6 \ +\ + {"alignchar", pdc_unicharlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_USHRT_MAX, pdf_charname_keylist}, \ +\ + {"stamp", pdc_keywordlist, PDF_STAMP_FLAG, 1, 1, \ + 0.0, 0.0, pdf_stampdir_keylist}, \ +\ + {"leader", pdc_stringlist, PDF_LEADER_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ + + +#define PDF_FIT_OPTIONS3 \ +\ + {"refpoint", pdc_scalarlist, PDC_OPT_NONE, 2, 2, \ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, \ + + + +/* p_font.c */ +void pdf_get_font_options(PDF *p, pdf_font_options *fo, pdc_resopt *resopts); +int pdf_load_font_internal(PDF *p, pdf_font_options *fo); + +/* p_image.c */ +void pdf_init_xobject_options(PDF *p, pdf_xobject_options *xo); +void pdf_get_xobject_options(PDF *p, pdf_xobject_options *xo, + pdc_resopt *resopts); +pdc_resopt *pdf_parse_fitxobject_optlist(PDF *p, int im, + pdf_xobject_options *xo, pdf_fit_options *fit, const char *optlist); +void pdf_fit_xobject_internal(PDF *p, pdf_xobject_options *xo, + pdf_fit_options *fit, pdc_matrix *immatrix); + +/* p_mbox.c */ +void pdf_init_fit_options(PDF *p, pdc_bool fortflow, pdf_fit_options *fit); +void pdf_cleanup_fit_options(PDF *p, pdf_fit_options *fit); +void pdf_get_fit_options(PDF *p, pdc_bool fortflow, pdf_fit_options *fit, + pdc_resopt *resopts); +void pdf_get_mbox_boxheight(PDF *p, pdf_mbox *mbox, + pdc_scalar *boxheight); +pdc_bool pdf_get_mbox_clipping(PDF *p, pdf_mbox *mbox, + pdc_scalar width, pdc_scalar height, pdc_box *clipbox); +double pdf_get_mbox_info(PDF *p, pdf_mbox *mbox, const char *keyword); + +/* p_text.c */ +pdc_bool pdf_calculate_text_options(PDF *p, pdf_text_options *to, + pdc_bool force, pdc_scalar fontscale, pdc_scalar minfontsize, + pdc_scalar fontsizeref); +void pdf_set_text_options(PDF *p, pdf_text_options *to); +void pdf_init_text_options(PDF *p, pdf_text_options *to); +void pdf_get_text_options(PDF *p, pdf_text_options *to, pdc_resopt *resopts); +pdc_resopt *pdf_parse_fittextline_optlist(PDF *p, pdf_text_options *to, + pdf_fit_options *fit, const char *optlist); +int pdf_fit_textline_internal(PDF *p, pdf_fittext *fitres, + pdf_text_options *to, pdf_fit_options *fit, pdc_matrix *matrix); +void pdf_calculate_textline_size(PDF *p, pdf_text_options *to, + pdf_fit_options *fit, pdc_scalar *width, pdc_scalar *height); +pdc_bool pdf_is_horiz_orientated(pdf_fit_options *fit); +int pdf_calculate_leader_pos(PDF *p, pdf_alignment alignment, + pdf_text_options *to, int nchars,pdc_scalar *xstart, pdc_scalar *xstop, + pdc_scalar width, pdc_bool left); +void pdf_draw_leader_text(PDF *p, pdc_scalar xstart, pdc_scalar ybase, + pdc_scalar width, int nchars, pdc_byte *utext, int len, int charlen, + pdf_text_options *to); + +int pdf_get_approximate_uvlist(PDF *p, pdf_font *currfont, + pdc_encodingvector *ev, int usv, pdc_bool replace, pdc_ushort *uvlist, + pdc_ushort *cglist); +void pdf_get_input_textformat(pdf_font *currfont, + pdc_text_format *intextformat, int *convflags); +int pdf_check_textstring(PDF *p, const char *text, int len, int flags, + pdf_text_options *to, pdc_byte **outtext, int *outlen, int *outcharlen, + pdc_bool verbose); +pdc_scalar pdf_calculate_textsize(PDF *p, const pdc_byte *text, int len, + int charlen, pdf_text_options *to, int breakchar, pdc_scalar *height, + pdc_bool verbose); +pdc_scalar pdf_trim_textwidth(pdc_scalar width, pdf_text_options *to); +void pdf_place_text(PDF *p, pdc_byte *text, int len, int charlen, + pdf_text_options *to, pdc_scalar width, pdc_scalar height, + pdc_bool cont); + + + + +#endif /* P_DEFOPT_H */ + diff --git a/src/pdflib/pdflib/p_document.c b/src/pdflib/pdflib/p_document.c new file mode 100644 index 0000000..4c00aa3 --- /dev/null +++ b/src/pdflib/pdflib/p_document.c @@ -0,0 +1,1939 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_document.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib document related routines + * + */ + + +#undef MVS_TEST + +#define P_DOCUMENT_C + +/* For checking the beta expiration date */ +#include <time.h> + +#include "p_intern.h" +#include "p_image.h" +#include "p_layer.h" +#include "p_page.h" +#include "p_tagged.h" + + + + + +#if (defined(WIN32) || defined(OS2)) && !defined(WINCE) +#include <fcntl.h> +#include <io.h> +#endif + + +/* file attachment structure */ +typedef struct +{ + char *filename; + char *name; + char *description; + char *mimetype; + pdc_off_t filesize; +} +pdf_attachments; + +#define PDF_MAX_LANGCODE 8 + +/* Document open modes */ + +typedef enum +{ + open_auto, + open_none, + open_bookmarks, + open_thumbnails, + open_fullscreen, + open_attachments + +} +pdf_openmode; + +static const pdc_keyconn pdf_openmode_keylist[] = +{ + {"none", open_none}, + {"bookmarks", open_bookmarks}, + {"thumbnails", open_thumbnails}, + {"fullscreen", open_fullscreen}, + {"attachments", open_attachments}, + + {NULL, 0} +}; + +static const pdc_keyconn pdf_openmode_pdfkeylist[] = +{ + {"UseNone", open_auto}, + {"UseNone", open_none}, + {"UseOutlines", open_bookmarks}, + {"UseThumbs", open_thumbnails}, + {"FullScreen", open_fullscreen}, + {"UseAttachments", open_attachments}, + + {NULL, 0} +}; + + +/* Document page layout */ + +typedef enum +{ + layout_default, + layout_singlepage, + layout_onecolumn, + layout_twocolumnleft, + layout_twocolumnright, + layout_twopageleft, + layout_twopageright +} +pdf_pagelayout; + +static const pdc_keyconn pdf_pagelayout_pdfkeylist[] = +{ + {"Default", layout_default}, + {"SinglePage", layout_singlepage}, + {"OneColumn", layout_onecolumn}, + {"TwoColumnLeft", layout_twocolumnleft}, + {"TwoColumnRight", layout_twocolumnright}, + {"TwoPageLeft", layout_twopageleft}, + {"TwoPageRight", layout_twopageright}, + {NULL, 0} +}; + + +/* NonFullScreenPageMode */ + +static const pdc_keyconn pdf_nonfullscreen_keylist[] = +{ + {"none", open_none}, + {"bookmarks", open_bookmarks}, + {"thumbnails", open_thumbnails}, + + {NULL, 0} +}; + +typedef enum +{ + doc_none, + doc_l2r, + doc_r2l, + doc_appdefault, + doc_simplex, + doc_duplexflipshortedge, + doc_duplexfliplongedge +} +pdf_viewerprefence; + +/* Direction */ + +static const pdc_keyconn pdf_textdirection_pdfkeylist[] = +{ + {"L2R", doc_l2r}, + {"R2L", doc_r2l}, + {NULL, 0} +}; + +/* PrintScaling */ + +static const pdc_keyconn pdf_printscaling_pdfkeylist[] = +{ + {"None", doc_none}, + {"AppDefault", doc_appdefault}, + {NULL, 0} +}; + +/* Duplex */ + +static const pdc_keyconn pdf_duplex_pdfkeylist[] = +{ + {"None", doc_none}, + {"Simplex", doc_simplex}, + {"DuplexFlipShortEdge", doc_duplexflipshortedge}, + {"DuplexFlipLongEdge", doc_duplexfliplongedge}, + {NULL, 0} +}; + + + +static const pdc_keyconn pdf_pdfa_keylist[] = +{ + {NULL, 0} +}; + + + +static const pdc_keyconn pdf_pdfx_keylist[] = +{ + {NULL, 0} +}; + + +/* configurable flush points */ + +static const pdc_keyconn pdf_flush_keylist[] = +{ + {"none", pdc_flush_none}, + {"page", pdc_flush_page}, + {"content", pdc_flush_content}, + {"heavy", pdc_flush_heavy}, + {NULL, 0} +}; + +static const pdc_keyconn pl_pwencoding_keylist[] = +{ + {"ebcdic", pdc_ebcdic}, + {"ebcdic_37", pdc_ebcdic_37}, + {"ebcdic_winansi", pdc_ebcdic_winansi}, + {"pdfdoc", pdc_pdfdoc}, + {"winansi", pdc_winansi}, + {"macroman", pdc_macroman_apple}, + {NULL, 0} +}; + +#define PDF_MAXPW 0 +static const pdc_keyconn pdc_permissions_keylist[] = +{ + {NULL, 0} +}; + +#define PDF_PDFA_FLAG PDC_OPT_UNSUPP + +#define PDF_SECURITY_FLAG PDC_OPT_UNSUPP + +#define PDF_LINEARIZE_FLAG PDC_OPT_UNSUPP + +#define PDF_ICC_FLAG PDC_OPT_UNSUPP + +#define PDF_TAGGED_FLAG PDC_OPT_UNSUPP + +#define PDF_METADATA_FLAG PDC_OPT_UNSUPP + +#define PDF_UPDATE_FLAG PDC_OPT_UNSUPP + +#define PDF_DOCUMENT_OPTIONS1 \ +\ + {"pdfa", pdc_keywordlist, PDF_PDFA_FLAG, 1, 1, \ + 0.0, 0.0, pdf_pdfa_keylist}, \ +\ + {"pdfx", pdc_keywordlist, PDF_ICC_FLAG, 1, 1, \ + 0.0, 0.0, pdf_pdfx_keylist}, \ +\ + {"compatibility", pdc_keywordlist, PDC_OPT_IGNOREIF1, 1, 1, \ + 0.0, 0.0, pdf_compatibility_keylist}, \ +\ + {"flush", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_flush_keylist}, \ +\ + {"passwordencoding", pdc_keywordlist, PDF_SECURITY_FLAG, 1, 1, \ + 0.0, 0.0, pl_pwencoding_keylist}, \ +\ + {"attachmentpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \ + 0.0, PDF_MAXPW, NULL}, \ +\ + {"masterpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \ + 0.0, PDF_MAXPW, NULL}, \ +\ + {"userpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \ + 0.0, PDF_MAXPW, NULL}, \ +\ + {"permissions", pdc_keywordlist, \ + PDF_SECURITY_FLAG | PDC_OPT_BUILDOR | PDC_OPT_DUPORIGVAL, 1, 9,\ + 0.0, 0.0, pdc_permissions_keylist}, \ +\ + {"update", pdc_booleanlist, PDF_UPDATE_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"tagged", pdc_booleanlist, PDF_TAGGED_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"lang", pdc_stringlist, PDF_TAGGED_FLAG, 1, 1, \ + 0.0, PDF_MAX_LANGCODE, NULL}, \ +\ + {"search", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"groups", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \ + 0.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"optimize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"linearize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"inmemory", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1,\ + 0.0, 0.0, NULL}, \ +\ + {"tempdirname", pdc_stringlist, PDF_LINEARIZE_FLAG, 1, 1, \ + 4.0, 400.0, NULL}, \ + + +#if defined(MVS) || defined(MVS_TEST) +#define PDF_DOCUMENT_OPTIONS10 \ +\ + {"recordsize", pdc_integerlist, PDF_LINEARIZE_FLAG, 1, 1, \ + 0.0, 32768.0, NULL}, \ +\ + {"tempfilenames", pdc_stringlist, PDF_LINEARIZE_FLAG, 2, 2, \ + 4.0, 400.0, NULL}, \ + +#endif + + +#define PDF_DOCUMENT_OPTIONS2 \ +\ + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"moddate", pdc_booleanlist, PDC_OPT_NONE, 1, 1,\ + 0.0, 0.0, NULL}, \ +\ + {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"labels", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \ + 0.0, PDC_USHRT_MAX, NULL}, \ +\ + {"openmode", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_openmode_keylist}, \ +\ + {"pagelayout", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_pagelayout_pdfkeylist}, \ +\ + {"uri", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"viewerpreferences", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_USHRT_MAX, NULL}, \ +\ + {"autoxmp", pdc_booleanlist, PDF_METADATA_FLAG, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"attachments", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \ + 0.0, PDC_INT_MAX, NULL}, \ + + +/* document struct */ + +struct pdf_document_s +{ + int compatibility; /* PDF version number * 10 */ + pdc_flush_state flush; /* output flushing points */ + + + + + + + pdc_bool moddate; /* modified date will be created */ + char lang[PDF_MAX_LANGCODE + 1]; /* default natural language */ + char *action; /* document actions */ + pdf_dest *dest; /* destination as open action */ + char *uri; /* document's base url */ + char *viewerpreferences; /* option list with viewer preferences */ + pdc_bool writevpdict; /* viewer preferences dictionary + * must be written */ + pdf_openmode openmode; /* document open mode */ + pdf_pagelayout pagelayout; /* page layout within document */ + + char *searchindexname; /* file name for search index */ + char *searchindextype; /* type for search index */ + + pdf_attachments *attachments; /* temporarily file attachments */ + int nattachs; /* number of file attachments */ + + + char *filename; /* file name of document */ + size_t (*writeproc)(PDF *p, void *data, size_t size); + /* output procedure */ + FILE *fp; /* file id - deprecated */ + int len; /* length of custom */ +}; + +static pdf_document * +pdf_init_get_document(PDF *p) +{ + static const char fn[] = "pdf_init_get_document"; + + if (p->document == NULL) + { + pdf_document *doc = (pdf_document *) + pdc_malloc(p->pdc, sizeof(pdf_document), fn); + + doc->compatibility = PDF_DEF_COMPATIBILITY; + doc->flush = pdc_flush_page; + + + + + + + doc->moddate = pdc_false; + doc->lang[0] = 0; + doc->action = NULL; + doc->dest = NULL; + doc->uri = NULL; + doc->viewerpreferences = NULL; + doc->writevpdict = pdc_false; + doc->openmode = open_auto; + doc->pagelayout = layout_default; + + doc->searchindexname = NULL; + doc->searchindextype = NULL; + + doc->attachments = NULL; + doc->nattachs = 0; + + + doc->fp = NULL; + doc->filename = NULL; + doc->writeproc = NULL; + doc->len = 0; + + p->document = doc; + } + + return p->document; +} + +static void +pdf_cleanup_document_internal(PDF *p) +{ + pdf_document *doc = (pdf_document *) p->document; + + if (doc) + { + pdf_cleanup_destination(p, doc->dest); + doc->dest = NULL; + + if (doc->action) + { + pdc_free(p->pdc, doc->action); + doc->action = NULL; + } + + if (doc->uri) + { + pdc_free(p->pdc, doc->uri); + doc->uri = NULL; + } + + if (doc->viewerpreferences) + { + pdc_free(p->pdc, doc->viewerpreferences); + doc->viewerpreferences = NULL; + } + + + + + if (doc->searchindexname) + { + pdc_free(p->pdc, doc->searchindexname); + doc->searchindexname = NULL; + } + + if (doc->searchindextype) + { + pdc_free(p->pdc, doc->searchindextype); + doc->searchindextype = NULL; + } + + if (doc->filename) + { + pdc_free(p->pdc, doc->filename); + doc->filename = NULL; + } + + pdc_free(p->pdc, doc); + p->document = NULL; + } +} + + +/* ---------------------------- PDFA / PDFX -------------------------- */ + + + +void +pdf_fix_openmode(PDF *p) +{ + pdf_document *doc = pdf_init_get_document(p); + + if (doc->openmode == open_auto) + doc->openmode = open_bookmarks; +} + + + + + +/* ------------------------- viewerpreferences ----------------------- */ + +static const pdc_defopt pdf_viewerpreferences_options[] = +{ + {"centerwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"direction", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_textdirection_pdfkeylist}, + + {"displaydoctitle", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"fitwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"hidemenubar", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"hidetoolbar", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"hidewindowui", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0, NULL}, + + {"nonfullscreenpagemode", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_nonfullscreen_keylist}, + + {"viewarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_usebox_keylist}, + + {"viewclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_usebox_keylist}, + + {"printarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_usebox_keylist}, + + {"printclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_usebox_keylist}, + + {"printscaling", pdc_keywordlist, PDC_OPT_PDC_1_6, 1, 1, + 0.0, 0.0, pdf_printscaling_pdfkeylist}, + + {"duplex", pdc_keywordlist, PDC_OPT_PDC_1_7, 1, 1, + 0.0, 0.0, pdf_duplex_pdfkeylist}, + + {"picktraybypdfsize", pdc_booleanlist, PDC_OPT_PDC_1_7, 1, 1, + 0.0, 0, NULL}, + + {"printpagerange", pdc_integerlist, PDC_OPT_PDC_1_7 | PDC_OPT_EVENNUM, + 1, PDC_USHRT_MAX, 1.0, PDC_INT_MAX, NULL}, \ + + {"numcopies", pdc_integerlist, PDC_OPT_PDC_1_7, 1, 1, \ + 1.0, 5.0, NULL}, \ + + PDC_OPT_TERMINATE +}; + +static int +pdf_parse_and_write_viewerpreferences(PDF *p, const char *optlist, + pdc_bool output) +{ + pdc_resopt *resopts = NULL; + pdc_clientdata cdata; + char **strlist; + pdc_bool writevpdict = pdc_false; + pdc_bool flag; + int i, nv, inum; + + /* parsing option list */ + pdf_set_clientdata(p, &cdata); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_viewerpreferences_options, &cdata, pdc_true); + + if (pdc_get_optvalues("hidetoolbar", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/HideToolbar true\n"); + } + + if (pdc_get_optvalues("hidemenubar", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/HideMenubar true\n"); + } + + if (pdc_get_optvalues("hidewindowui", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/HideWindowUI true\n"); + } + + if (pdc_get_optvalues("fitwindow", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/FitWindow true\n"); + } + + if (pdc_get_optvalues("centerwindow", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/CenterWindow true\n"); + } + + if (pdc_get_optvalues("displaydoctitle", resopts, &flag, NULL) && flag) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/DisplayDocTitle true\n"); + } + + if (pdc_get_optvalues("nonfullscreenpagemode", resopts, &inum, NULL) && + inum != (int) open_none) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/NonFullScreenPageMode/%s\n", + pdc_get_keyword(inum, pdf_openmode_pdfkeylist)); + } + + + if (pdc_get_optvalues("direction", resopts, &inum, NULL) && + inum != (int) doc_l2r) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/Direction/%s\n", + pdc_get_keyword(inum, pdf_textdirection_pdfkeylist)); + } + + if (pdc_get_optvalues("viewarea", resopts, &inum, NULL) && + inum != (int) pdc_pbox_crop) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/ViewArea%s\n", + pdc_get_keyword(inum, pdf_usebox_pdfkeylist)); + } + + if (pdc_get_optvalues("viewclip", resopts, &inum, NULL) && + inum != (int) pdc_pbox_crop) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/ViewClip%s\n", + pdc_get_keyword(inum, pdf_usebox_pdfkeylist)); + } + + if (pdc_get_optvalues("printarea", resopts, &inum, NULL) && + inum != (int) pdc_pbox_crop) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/PrintArea%s\n", + pdc_get_keyword(inum, pdf_usebox_pdfkeylist)); + } + + if (pdc_get_optvalues("printclip", resopts, &inum, NULL) && + inum != (int) pdc_pbox_crop) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/PrintClip%s\n", + pdc_get_keyword(inum, pdf_usebox_pdfkeylist)); + } + + if (pdc_get_optvalues("printscaling", resopts, &inum, NULL) && + inum != (int) doc_appdefault) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/PrintScaling/%s\n", + pdc_get_keyword(inum, pdf_printscaling_pdfkeylist)); + } + + if (pdc_get_optvalues("duplex", resopts, &inum, NULL) && + inum != (int) doc_none) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/Duplex/%s\n", + pdc_get_keyword(inum, pdf_duplex_pdfkeylist)); + } + + if (pdc_get_optvalues("picktraybypdfsize", resopts, &flag, NULL)) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/PickTrayByPDFSize %s\n", + PDC_BOOLSTR(flag)); + } + + nv = pdc_get_optvalues("printpagerange", resopts, NULL, &strlist); + if (nv) + { + writevpdict = pdc_true; + if (output) + { + int *prs = (int *) strlist; + + pdc_printf(p->out, "/PrintPageRange"); + pdc_begin_array(p->out); + for (i = 0; i < nv; i++) + pdc_printf(p->out, "%d ", prs[i]); + pdc_end_array(p->out); + } + } + + if (pdc_get_optvalues("numcopies", resopts, &inum, NULL)) + { + writevpdict = pdc_true; + if (output) pdc_printf(p->out, "/NumCopies %d\n", inum); + } + + pdc_cleanup_optionlist(p->pdc, resopts); + + return writevpdict; +} + + +/* ------------------------- search ----------------------- */ + +static const pdc_defopt pdf_search_options[] = +{ + {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1, + 1.0, PDC_FILENAMELEN, NULL}, + + {"indextype", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + PDC_OPT_TERMINATE +}; + +static void +pdf_parse_search_optlist(PDF *p, const char *optlist) +{ + pdf_document *doc = p->document; + pdc_resopt *resopts = NULL; + + /* parsing option list */ + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_search_options, NULL, pdc_true); + + if (pdc_get_optvalues("filename", resopts, NULL, NULL)) + doc->searchindexname = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + if (pdc_get_optvalues("indextype", resopts, NULL, NULL)) + doc->searchindextype = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + else + doc->searchindextype = pdc_strdup(p->pdc, "PDX"); + + pdc_cleanup_optionlist(p->pdc, resopts); +} + +static void +pdf_write_search_indexes(PDF *p) +{ + pdf_document *doc = p->document; + + if (doc->searchindexname != NULL) + { + pdc_puts(p->out, "/Search"); + pdc_begin_dict(p->out); /* Search */ + pdc_puts(p->out, "/Indexes"); + pdc_begin_array(p->out); + pdc_begin_dict(p->out); /* Indexes */ + pdc_puts(p->out, "/Name"); + pdc_printf(p->out, "/%s", doc->searchindextype); + pdc_puts(p->out, "/Index"); + pdc_begin_dict(p->out); /* Index */ + pdc_puts(p->out, "/Type/Filespec"); + pdc_puts(p->out, "/F"); + pdf_put_pdffilename(p, doc->searchindexname); + pdc_end_dict(p->out); /* Index */ + pdc_end_dict(p->out); /* Indexes */ + pdc_end_array(p->out); + pdc_end_dict(p->out); /* Search */ + } +} + + +/* ---------------------- file attachements -------------------- */ + +static void +pdc_cleanup_attachments_tmp(void *opaque, void *mem) +{ + if (mem) + { + PDF *p = (PDF *) opaque; + pdf_document *doc = p->document; + int i; + + if (doc != NULL) + { + for (i = 0; i < doc->nattachs; i++) + { + pdf_attachments *fat = &doc->attachments[i]; + + if (fat->filename != NULL) + pdc_free(p->pdc, fat->filename); + if (fat->name != NULL) + pdc_free(p->pdc, fat->name); + if (fat->description != NULL) + pdc_free(p->pdc, fat->description); + if (fat->mimetype != NULL) + pdc_free(p->pdc, fat->mimetype); + } + + doc->attachments = NULL; + doc->nattachs = 0; + } + } +} + +static const pdc_defopt pdf_attachments_options[] = +{ + {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1, + 1.0, PDC_FILENAMELEN, NULL}, + + {"description", pdc_stringlist, PDC_OPT_PDC_1_6, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"mimetype", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + PDC_OPT_TERMINATE +}; + +static void +pdf_parse_attachments_optlist(PDF *p, char **optlists, int ns, + pdc_encoding htenc, int htcp) +{ + static const char fn[] = "pdf_parse_attachments_optlist"; + pdf_document *doc = p->document; + pdc_resopt *resopts = NULL; + pdc_clientdata cdata; + int i; + + doc->attachments = (pdf_attachments *) pdc_malloc_tmp(p->pdc, + ns * sizeof(pdf_attachments), fn, + p, pdc_cleanup_attachments_tmp); + doc->nattachs = ns; + + pdf_set_clientdata(p, &cdata); + + for (i = 0; i < ns; i++) + { + pdf_attachments *fat = &doc->attachments[i]; + + fat->filename = NULL; + fat->name = NULL; + fat->description = NULL; + fat->mimetype = NULL; + fat->filesize = 0; + } + + for (i = 0; i < ns; i++) + { + pdf_attachments *fat = &doc->attachments[i]; + + /* parsing option list */ + resopts = pdc_parse_optionlist(p->pdc, optlists[i], + pdf_attachments_options, &cdata, pdc_true); + + if (pdc_get_optvalues("filename", resopts, NULL, NULL)) + fat->filename = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + if (pdf_get_opt_textlist(p, "description", resopts, htenc, htcp, + pdc_true, NULL, &fat->description, NULL)) + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + if (pdf_get_opt_textlist(p, "name", resopts, htenc, htcp, + pdc_true, NULL, &fat->name, NULL)) + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + if (pdc_get_optvalues("mimetype", resopts, NULL, NULL)) + fat->mimetype = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + pdc_cleanup_optionlist(p->pdc, resopts); + + fat->filesize = pdf_check_file(p, fat->filename, pdc_true); + } +} + +static void +pdf_write_attachments(PDF *p) +{ + static const char fn[] = "pdf_write_attachments"; + pdf_document *doc = p->document; + pdc_id attachment_id, obj_id; + char *name; + int i; + + for (i = 0; i < doc->nattachs; i++) + { + pdf_attachments *fat = &doc->attachments[i]; + + if (fat->filesize > 0) + { + /* create file specification dictionary */ + attachment_id = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_dict(p->out); /* FS dict */ + + pdc_puts(p->out, "/Type/Filespec\n"); + pdc_printf(p->out, "/F"); + pdf_put_pdffilename(p, fat->filename); + pdc_puts(p->out, "\n"); + + if (fat->description != NULL) + { + pdc_puts(p->out, "/Desc"); + pdf_put_hypertext(p, fat->description); + pdc_puts(p->out, "\n"); + } + + obj_id = pdc_alloc_id(p->out); + pdc_puts(p->out, "/EF"); + pdc_begin_dict(p->out); + pdc_objref(p->out, "/F", obj_id); + pdc_end_dict(p->out); + + pdc_end_dict(p->out); /* FS dict */ + pdc_end_obj(p->out); + + /* embed file */ + pdf_embed_file(p, obj_id, fat->filename, fat->mimetype, + fat->filesize); + + /* insert name in tree */ + if (fat->name == NULL) + name = pdc_strdup_ext(p->pdc, fat->filename, 0, fn); + else + name = pdc_strdup_ext(p->pdc, fat->name, 0, fn); + pdf_insert_name(p, name, names_embeddedfiles, attachment_id); + } + } +} + +pdc_off_t +pdf_check_file(PDF *p, const char *filename, pdc_bool verbose) +{ + pdc_off_t filesize = 0; + const char *qualifier = "attachment "; + pdc_file *fp; + + fp = pdc_fsearch_fopen(p->pdc, filename, NULL, qualifier, + PDC_FILE_BINARY); + if (fp == NULL) + { + if (verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + else + { + filesize = pdc_file_size(fp); + pdc_fclose(fp); + + if (filesize == 0) + { + pdc_set_errmsg(p->pdc, PDC_E_IO_FILE_EMPTY, qualifier, filename, + 0, 0); + if (verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + } + + return filesize; +} + +void +pdf_embed_file(PDF *p, pdc_id obj_id, const char *filename, + const char *mimetype, pdc_off_t filesize) +{ + pdc_id length_id; + PDF_data_source src; + + pdc_begin_obj(p->out, obj_id); + pdc_begin_dict(p->out); /* F dict */ + + pdc_puts(p->out, "/Type/EmbeddedFile\n"); + + if (mimetype && *mimetype) + { + pdc_puts(p->out, "/Subtype"); + pdf_put_pdfname(p, mimetype); + pdc_puts(p->out, "\n"); + } + + pdc_puts(p->out, "/Params"); + pdc_begin_dict(p->out); /* Params */ + pdc_printf(p->out, "/Size %lld", filesize); + pdc_end_dict(p->out); /* Params */ + + if (pdc_get_compresslevel(p->out)) + { + pdc_puts(p->out, "/Filter/FlateDecode\n"); + } + + length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", length_id); + + pdc_end_dict(p->out); /* F dict */ + + /* write the file in the PDF */ + src.private_data = (void *) filename; + src.init = pdf_data_source_file_init; + src.fill = pdf_data_source_file_fill; + src.terminate = pdf_data_source_file_terminate; + src.length = (long) 0; + src.offset = (long) 0; + + + pdf_copy_stream(p, &src, pdc_true); + + + pdc_end_obj(p->out); + + pdc_put_pdfstreamlength(p->out, length_id); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); +} + + +/* ---------------------- linearize -------------------- */ + + + +/* ------------------ document options ----------------- */ + +static void +pdf_get_document_common_options(PDF *p, pdc_resopt *resopts, int fcode) +{ + pdf_document *doc = p->document; + pdc_encoding htenc; + int htcp; + char **strlist; + int i, inum, ns; + + + htenc = + pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true); + + if (pdc_get_optvalues("destination", resopts, NULL, &strlist)) + { + if (doc->dest) + pdc_free(p->pdc, doc->dest); + doc->dest = pdf_parse_destination_optlist(p, strlist[0], 1, + pdf_openaction); + } + else + { + pdf_dest *dest = pdf_get_option_destname(p, resopts, htenc, htcp); + if (dest) + { + if (doc->dest) + pdc_free(p->pdc, doc->dest); + doc->dest = dest; + } + } + + if (pdc_get_optvalues("action", resopts, NULL, NULL)) + { + if (doc->action) + pdc_free(p->pdc, doc->action); + doc->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + pdf_parse_and_write_actionlist(p, event_document, NULL, doc->action); + } + + inum = pdc_get_optvalues("labels", resopts, NULL, &strlist); + for (i = 0; i < inum; i++) + pdf_set_pagelabel(p, strlist[i], fcode); + + if (pdc_get_optvalues("openmode", resopts, &inum, NULL)) + doc->openmode = (pdf_openmode) inum; + if (doc->openmode == open_attachments && p->compatibility < PDC_1_6) + pdc_error(p->pdc, PDC_E_OPT_VERSION, "openmode=attachments", + pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0); + + if (pdc_get_optvalues("pagelayout", resopts, &inum, NULL)) + doc->pagelayout = (pdf_pagelayout) inum; + if (p->compatibility < PDC_1_5) + { + if (doc->pagelayout == layout_twopageleft) + pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageLeft", + pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0); + if (doc->pagelayout == layout_twopageright) + pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageRight", + pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0); + } + + if (pdc_get_optvalues("uri", resopts, NULL, NULL)) + { + if (doc->uri) + pdc_free(p->pdc, doc->uri); + doc->uri = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + if (pdc_get_optvalues("viewerpreferences", resopts, NULL, NULL)) + { + if (doc->viewerpreferences) + pdc_free(p->pdc, doc->viewerpreferences); + doc->viewerpreferences = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + doc->writevpdict |= + pdf_parse_and_write_viewerpreferences(p, doc->viewerpreferences, + pdc_false); + } + + if (pdc_get_optvalues("search", resopts, NULL, &strlist)) + pdf_parse_search_optlist(p, strlist[0]); + + + pdc_get_optvalues("moddate", resopts, &doc->moddate, NULL); + + + + ns = pdc_get_optvalues("attachments", resopts, NULL, &strlist); + if (ns) + pdf_parse_attachments_optlist(p, strlist, ns, htenc, htcp); +} + +static const pdc_defopt pdf_begin_document_options[] = +{ + PDF_DOCUMENT_OPTIONS1 +#if defined(MVS) || defined(MVS_TEST) + PDF_DOCUMENT_OPTIONS10 +#endif + PDF_DOCUMENT_OPTIONS2 + PDF_ERRORPOLICY_OPTION + PDC_OPT_TERMINATE +}; + + +/* + * The external callback interface requires a PDF* as the first argument, + * while the internal interface uses pdc_output* and doesn't know about PDF*. + * We use a wrapper to bridge the gap, and store the PDF* within the + * pdc_output structure opaquely. + */ + +static size_t +writeproc_wrapper(pdc_output *out, void *data, size_t size) +{ + size_t ret; + + PDF *p = (PDF *) pdc_get_opaque(out); + + ret = (p->writeproc)(p, data, size); + pdc_logg_cond(p->pdc, 1, trc_api, + "/* writeproc(data[%p], %d)[%d] */\n", data, size, ret); + return ret; +} + + + +/* ---------------------------- begin document -------------------------- */ + +static int +pdf_begin_document_internal(PDF *p, const char *optlist, pdc_bool callback) +{ + pdf_document *doc = p->document; + pdc_resopt *resopts = NULL; + char **groups = NULL; + int n_groups = 0; + pdc_bool verbose = p->debug[(int) 'o']; + pdc_outctl oc; + + (void) callback; + + verbose = pdf_get_errorpolicy(p, NULL, verbose); + + /* parsing option list */ + if (optlist && *optlist) + { + int inum; + + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_begin_document_options, NULL, pdc_true); + + verbose = pdf_get_errorpolicy(p, resopts, verbose); + + pdc_get_optvalues("compatibility", resopts, &doc->compatibility, NULL); + + if (pdc_get_optvalues("flush", resopts, &inum, NULL)) + doc->flush = (pdc_flush_state) inum; + + pdc_get_optvalues("lang", resopts, doc->lang, NULL); + + + + + + + + + n_groups = pdc_get_optvalues("groups", resopts, NULL, &groups); + } + + /* copy for easy access */ + p->compatibility = doc->compatibility; + p->pdc->compatibility = doc->compatibility; + p->flush = doc->flush; + + + + + + /* + * None of these functions must call pdc_alloc_id() or generate + * any output since the output machinery is not yet initialized! + */ + + pdf_init_pages(p, (const char **) groups, n_groups); + + /* common options */ + pdf_get_document_common_options(p, resopts, PDF_FC_BEGIN_DOCUMENT); + + + /* deprecated */ + p->bookmark_dest = pdf_init_destination(p); + + pdf_init_images(p); + pdf_init_xobjects(p); + pdf_init_fonts(p); + pdf_init_outlines(p); + pdf_init_annot_params(p); + pdf_init_colorspaces(p); + pdf_init_pattern(p); + pdf_init_shadings(p); + pdf_init_extgstates(p); + + + + + + /* create document digest */ + pdc_init_digest(p->out); + + if (!p->pdc->ptfrun) + { + if (doc->fp) + pdc_update_digest(p->out, (pdc_byte *) doc->fp, doc->len); + else if (doc->writeproc) + pdc_update_digest(p->out, (pdc_byte *) &doc->writeproc, doc->len); + else if (doc->filename) + pdc_update_digest(p->out, (pdc_byte *) doc->filename, doc->len); + } + + pdf_feed_digest_info(p); + + if (!p->pdc->ptfrun) + { + pdc_update_digest(p->out, (pdc_byte *) &p, sizeof(PDF*)); + pdc_update_digest(p->out, (pdc_byte *) p, sizeof(PDF)); + } + + + pdc_finish_digest(p->out, !p->pdc->ptfrun); + + /* preparing output struct */ + pdc_init_outctl(&oc); + oc.flush = doc->flush; + + if (doc->fp) + oc.fp = doc->fp; + else if (doc->writeproc) + { + oc.writeproc = writeproc_wrapper; + p->writeproc = doc->writeproc; + } + else if (doc->filename) + oc.filename = doc->filename; + else + oc.filename = ""; + + + + if (!pdc_init_output((void *) p, p->out, doc->compatibility, &oc)) + { + if (oc.filename && *oc.filename) + { + pdc_set_fopen_errmsg(p->pdc, + pdc_get_fopen_errnum(p->pdc, PDC_E_IO_WROPEN), "PDF ", + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, oc.filename)); + + if (verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + + pdf_cleanup_document_internal(p); + return -1; + } + + /* Write the constant /ProcSet array once at the beginning */ + p->procset_id = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_puts(p->out, "[/PDF/ImageB/ImageC/ImageI/Text]\n"); + pdc_end_obj(p->out); + + pdf_init_pages2(p); + + pdf_write_attachments(p); + + return 1; +} + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +int +pdf__begin_document(PDF *p, const char *filename, int len, const char *optlist) +{ + pdf_document *doc; + pdc_bool verbose = p->debug[(int) 'o']; + int retval; + + verbose = pdf_get_errorpolicy(p, NULL, verbose); + + + doc = pdf_init_get_document(p); + + /* file ID or filename */ + if (len == -1) + { + FILE *fp = (FILE *) filename; + + /* + * It is the callers responsibility to open the file in binary mode, + * but it doesn't hurt to make sure it really is. + * The Intel version of the Metrowerks compiler doesn't have setmode(). + */ +#if !defined(__MWERKS__) && (defined(WIN32) || defined(OS2)) +#if defined WINCE + _setmode(fileno(fp), _O_BINARY); +#else + setmode(fileno(fp), O_BINARY); +#endif +#endif + + doc->fp = fp; + doc->len = sizeof(FILE); + } + else if (filename && (*filename || len > 0)) + { + filename = pdf_convert_filename(p, filename, len, "filename", + PDC_CONV_WITHBOM); + doc->filename = pdc_strdup(p->pdc, filename); + doc->len = (int) strlen(doc->filename); + } + + retval = pdf_begin_document_internal(p, optlist, pdc_false); + + if (retval > -1) + PDF_SET_STATE(p, pdf_state_document); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n"); + + return retval; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + +void +pdf__begin_document_callback(PDF *p, + size_t (*i_writeproc)(PDF *p, void *data, size_t size), const char *optlist) +{ + size_t (*writeproc)(PDF *, void *, size_t) = i_writeproc; + pdf_document *doc; + + if (writeproc == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "writeproc", 0, 0, 0); + + doc = pdf_init_get_document(p); + + /* initializing and opening the document */ + doc->writeproc = writeproc; + doc->len = sizeof(writeproc); + + (void) pdf_begin_document_internal(p, optlist, pdc_true); + + PDF_SET_STATE(p, pdf_state_document); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n"); +} + +/* ----------------------------- name tree ----------------------------- */ + +struct pdf_name_s +{ + pdc_id obj_id; /* id of this name object */ + char * name; /* name string */ + pdf_nametree_type type; /* name tree type */ +}; + +static void +pdf_cleanup_names(PDF *p) +{ + int i; + + if (p->names == NULL) + return; + + for (i = 0; i < p->names_number; i++) + { + pdc_free(p->pdc, p->names[i].name); + } + + pdc_free(p->pdc, p->names); + p->names_number = 0; + p->names = NULL; +} + +void +pdf_insert_name(PDF *p, const char *name, pdf_nametree_type type, pdc_id obj_id) +{ + static const char fn[] = "pdf_insert_name"; + int i; + + if (p->names == NULL || p->names_number == p->names_capacity) + { + if (p->names == NULL) + { + p->names_number = 0; + p->names_capacity = NAMES_CHUNKSIZE; + p->names = (pdf_name *) pdc_malloc(p->pdc, + sizeof(pdf_name) * p->names_capacity, fn); + } + else + { + p->names_capacity *= 2; + p->names = (pdf_name *) pdc_realloc(p->pdc, p->names, + sizeof(pdf_name) * p->names_capacity, fn); + } + for (i = p->names_number; i < p->names_capacity; i++) + { + p->names[i].obj_id = PDC_BAD_ID; + p->names[i].name = NULL; + p->names[i].type = names_undef; + } + } + + /* check identity */ + for (i = 0; i < p->names_number; i++) + { + if (p->names[i].type == type && !strcmp(p->names[i].name, name)) + { + pdc_free(p->pdc, p->names[i].name); + p->names[i].name = (char *) name; + return; + } + } + + p->names[i].obj_id = obj_id; + p->names[i].name = (char *) name; + p->names[i].type = type; + p->names_number++; +} + +pdc_id +pdf_get_id_from_nametree(PDF *p, pdf_nametree_type type, const char *name) +{ + int i; + + for (i = 0; i < p->names_number; i++) + { + if (p->names[i].type == type && !strcmp(name, p->names[i].name)) + return p->names[i].obj_id; + } + + return PDC_BAD_ID; +} + +static pdc_id +pdf_write_names(PDF *p, pdf_nametree_type type) +{ + pdc_id ret = PDC_BAD_ID; + int i, ibeg = -1, iend = 0; + + for (i = 0; i < p->names_number; i++) + { + if (p->names[i].type == type) + { + if (ibeg == -1) + ibeg = i; + iend = i; + } + } + + if (ibeg > -1) + { + ret = pdc_begin_obj(p->out, PDC_NEW_ID); /* Names object */ + + pdc_begin_dict(p->out); /* Node dict */ + + /* + * Because we have only the 1 tree - the root tree + * the /Limits entry is not allowed (see chapter 3.8.5). + * + pdc_puts(p->out, "/Limits"); + pdc_begin_array(p->out); + pdf_put_hypertext(p, p->names[ibeg].name); + pdf_put_hypertext(p, p->names[iend].name); + pdc_end_array(p->out); + */ + + pdc_puts(p->out, "/Names"); + pdc_begin_array(p->out); + + for (i = ibeg; i <= iend; i++) + { + if (p->names[i].type == type) + { + pdf_put_hypertext(p, p->names[i].name); + pdc_objref(p->out, "", p->names[i].obj_id); + } + } + + pdc_end_array(p->out); + + pdc_end_dict(p->out); /* Node dict */ + + pdc_end_obj(p->out); /* Names object */ + + } + return ret; +} + +static int +name_compare( const void* a, const void* b) +{ + pdf_name *p1 = (pdf_name *) a; + pdf_name *p2 = (pdf_name *) b; + + return strcmp(p1->name, p2->name); +} + +/* ---------------------------- write document -------------------------- */ + +static pdc_id +pdf_write_pages_and_catalog(PDF *p, pdc_id orig_root_id) +{ + pdf_document *doc = p->document; + pdc_bool openact = pdc_false; + pdc_bool forpdfa = pdc_false; + pdc_id act_idlist[PDF_MAX_EVENTS]; + pdc_id root_id = PDC_BAD_ID; + pdc_id names_dests_id = PDC_BAD_ID; + pdc_id names_javascript_id = PDC_BAD_ID; + pdc_id names_ap_id = PDC_BAD_ID; + pdc_id names_embeddedfiles_id = PDC_BAD_ID; + pdc_id outintents1_id = PDC_BAD_ID; + pdc_id outintents2_id = PDC_BAD_ID; + + pdc_id pages_id = pdf_write_pages_tree(p); + pdc_id labels_id = pdf_write_pagelabels(p); + + + + (void) orig_root_id; + + /* name tree dictionaries */ + if (p->names_number) + { + + qsort(p->names, (size_t) p->names_number, sizeof(pdf_name), + name_compare); + + + names_dests_id = pdf_write_names(p, names_dests); + names_javascript_id = pdf_write_names(p, names_javascript); + names_ap_id = pdf_write_names(p, names_ap); + names_embeddedfiles_id = pdf_write_names(p, names_embeddedfiles); + } + + + (void) forpdfa; + + + + + /* write action objects */ + if (doc->action) + pdf_parse_and_write_actionlist(p, event_document, act_idlist, + (const char *) doc->action); + + root_id = pdc_begin_obj(p->out, PDC_NEW_ID); /* Catalog */ + pdc_begin_dict(p->out); + pdc_puts(p->out, "/Type/Catalog\n"); + + pdc_objref(p->out, "/Pages", pages_id); /* Pages object */ + + + if (labels_id != PDC_BAD_ID) + { + pdc_objref(p->out, "/PageLabels", labels_id); + } + + if (p->names_number) + { + pdc_printf(p->out, "/Names"); + pdc_begin_dict(p->out); /* Names */ + + if (names_dests_id != PDC_BAD_ID) + pdc_objref(p->out, "/Dests", names_dests_id); + if (names_javascript_id != PDC_BAD_ID) + pdc_objref(p->out, "/JavaScript", names_javascript_id); + if (names_ap_id != PDC_BAD_ID) + pdc_objref(p->out, "/AP", names_ap_id); + if (names_embeddedfiles_id != PDC_BAD_ID) + pdc_objref(p->out, "/EmbeddedFiles", names_embeddedfiles_id); + + pdc_end_dict(p->out); /* Names */ + } + + if (doc->writevpdict) + { + pdc_printf(p->out, "/ViewerPreferences\n"); + pdc_begin_dict(p->out); /* ViewerPreferences */ + pdf_parse_and_write_viewerpreferences(p, + doc->viewerpreferences, pdc_true); + pdc_end_dict(p->out); /* ViewerPreferences */ + } + + if (doc->pagelayout != layout_default) + pdc_printf(p->out, "/PageLayout/%s\n", + pdc_get_keyword(doc->pagelayout, pdf_pagelayout_pdfkeylist)); + + if (doc->openmode != open_auto && doc->openmode != open_none) + pdc_printf(p->out, "/PageMode/%s\n", + pdc_get_keyword(doc->openmode, pdf_openmode_pdfkeylist)); + + pdf_write_outline_root(p); /* /Outlines */ + + if (doc->action) /* /AA */ + openact = pdf_write_action_entries(p, event_document, act_idlist); + + if (doc->dest && !openact) + { + pdc_puts(p->out, "/OpenAction"); + pdf_write_destination(p, doc->dest); + } + + if (doc->uri) + { + pdc_puts(p->out, "/URI"); + pdc_begin_dict(p->out); + pdc_printf(p->out, "/Base"); + pdf_put_hypertext(p, doc->uri); + pdc_end_dict(p->out); + } + + + if (doc->lang[0]) + { + pdc_puts(p->out, "/Lang"); + pdf_put_hypertext(p, doc->lang); + pdc_puts(p->out, "\n"); + } + + /* /StructTreeRoot /MarkInfo */ + + /* /OCProperties */ + + if (outintents1_id != PDC_BAD_ID || outintents2_id != PDC_BAD_ID) + { + pdc_puts(p->out, "/OutputIntents"); + pdc_begin_array(p->out); + if (outintents1_id != PDC_BAD_ID) + pdc_objref(p->out, "", outintents1_id); + if (outintents2_id != PDC_BAD_ID) + pdc_objref(p->out, "", outintents2_id); + pdc_end_array(p->out); + } + + /* /Search */ + pdf_write_search_indexes(p); + + /* /Metadata */ + + /* not supported: /Threads /PieceInfo /Perms /Legal */ + + pdc_end_dict(p->out); /* Catalog */ + pdc_end_obj(p->out); + + return root_id; +} + + +static void +pdf_write_document(PDF *p) +{ + if (PDF_GET_STATE(p) != pdf_state_error) + { + pdf_document *doc = p->document; + pdc_id info_id = PDC_BAD_ID; + pdc_id root_id = PDC_BAD_ID; + + if (pdf_last_page(p) == 0) + pdc_error(p->pdc, PDF_E_DOC_EMPTY, 0, 0, 0, 0); + + pdf_write_attachments(p); + + + /* Write all pending document information up to xref table + trailer */ + info_id = pdf_write_info(p, doc->moddate); + + pdf_write_doc_fonts(p); /* font objects */ + pdf_write_doc_colorspaces(p); /* color space resources */ + pdf_write_doc_extgstates(p); /* ExtGState resources */ + root_id = pdf_write_pages_and_catalog(p, root_id); + pdf_write_outlines(p); + pdc_write_xref(p->out); + + pdc_write_trailer(p->out, info_id, root_id, 0, -1, -1, -1); + } + + pdc_close_output(p->out); +} + +/* ------------------------------ end document ---------------------------- */ + +void +pdf_cleanup_document(PDF *p) +{ + if (PDF_GET_STATE(p) != pdf_state_object) + { + /* Don't call pdc_cleanup_output() here because we may still need + * the buffer contents for pdf__get_buffer() after pdf__end_document(). + */ + + pdf_delete_actions(p); + + pdf_cleanup_destination(p, p->bookmark_dest); /* deprecated */ + pdf_cleanup_pages(p); + pdf_cleanup_document_internal(p); + pdf_cleanup_info(p); + pdf_cleanup_fonts(p); + pdf_cleanup_outlines(p); + pdf_cleanup_annot_params(p); + pdf_cleanup_names(p); + pdf_cleanup_colorspaces(p); + pdf_cleanup_pattern(p); + pdf_cleanup_shadings(p); + pdf_cleanup_images(p); + pdf_cleanup_xobjects(p); + pdf_cleanup_extgstates(p); + + + + + + + + + + pdf_cleanup_stringlists(p); + + PDF_SET_STATE(p, pdf_state_object); + } +} + +static const pdc_defopt pdf_end_document_options[] = +{ + PDF_DOCUMENT_OPTIONS2 + PDC_OPT_TERMINATE +}; + +void +pdf__end_document(PDF *p, const char *optlist) +{ + pdf_document *doc; + + /* check if there are any suspended pages left. + */ + pdf_check_suspended_pages(p); + + /* get document pointer */ + doc = pdf_init_get_document(p); + + if (optlist && *optlist) + { + pdc_resopt *resopts = NULL; + pdc_clientdata cdata; + + /* parsing option list */ + pdf_set_clientdata(p, &cdata); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_end_document_options, &cdata, pdc_true); + + /* get options */ + pdf_get_document_common_options(p, resopts, PDF_FC_END_DOCUMENT); + + } + + pdf_write_document(p); + + + pdf_cleanup_document(p); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End document]\n\n"); +} + +const char * +pdf__get_buffer(PDF *p, long *size) +{ + const char *ret; + pdc_off_t llsize; + + + ret = pdc_get_stream_contents(p->out, &llsize); + + if (llsize > LONG_MAX) + pdc_error(p->pdc, PDF_E_DOC_GETBUF_2GB, 0, 0, 0, 0); + + *size = (long) llsize; + return ret; +} + + + + +/*****************************************************************************/ +/** deprecated historical document functions **/ +/*****************************************************************************/ + +void +pdf_set_flush(PDF *p, const char *flush) +{ + if (p->pdc->binding != NULL && strcmp(p->pdc->binding, "C++")) + return; + + if (flush != NULL && *flush) + { + int i = pdc_get_keycode_ci(flush, pdf_flush_keylist); + if (i != PDC_KEY_NOTFOUND) + { + pdf_document *doc = pdf_init_get_document(p); + + doc->flush = (pdc_flush_state) i; + p->flush = doc->flush; + return; + } + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, flush, "flush", + 0, 0); + } +} + +void +pdf_set_uri(PDF *p, const char *uri) +{ + pdf_document *doc = pdf_init_get_document(p); + + if (doc->uri) + pdc_free(p->pdc, doc->uri); + doc->uri = pdc_strdup(p->pdc, uri); +} + + +void +pdf_set_compatibility(PDF *p, const char *compatibility) +{ + + if (compatibility != NULL && *compatibility) + { + int i = pdc_get_keycode_ci(compatibility, pdf_compatibility_keylist); + if (i != PDC_KEY_NOTFOUND) + { + pdf_document *doc = pdf_init_get_document(p); + + p->compatibility = i; + doc->compatibility = i; + p->pdc->compatibility = i; + return; + } + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, compatibility, "compatibility", + 0, 0); + } +} + +void +pdf_set_openaction(PDF *p, const char *openaction) +{ + pdf_document *doc = pdf_init_get_document(p); + + if (openaction != NULL && *openaction) + { + pdf_cleanup_destination(p, doc->dest); + doc->dest = pdf_parse_destination_optlist(p, openaction, 1, + pdf_openaction); + } +} + +void +pdf_set_openmode(PDF *p, const char *openmode) +{ + int i; + + if (openmode == NULL || !*openmode) + openmode = "none"; + + i = pdc_get_keycode_ci(openmode, pdf_openmode_keylist); + if (i != PDC_KEY_NOTFOUND) + { + pdf_document *doc = pdf_init_get_document(p); + + doc->openmode = (pdf_openmode) i; + } + else + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, openmode, "openmode", 0, 0); +} + +void +pdf_set_viewerpreference(PDF *p, const char *viewerpreference) +{ + static const char fn[] = "pdf_set_viewerpreference"; + pdf_document *doc = pdf_init_get_document(p); + char *optlist; + size_t nb1 = 0, nb2 = 0; + + if (doc->viewerpreferences) + nb1 = strlen(doc->viewerpreferences) * sizeof(char *); + nb2 = strlen(viewerpreference) * sizeof(char *); + + optlist = (char *) pdc_malloc(p->pdc, nb1 + nb2 + 2, fn); + optlist[0] = 0; + if (doc->viewerpreferences) + { + strcat(optlist, doc->viewerpreferences); + strcat(optlist, " "); + } + strcat(optlist, viewerpreference); + + if (doc->viewerpreferences) + pdc_free(p->pdc, doc->viewerpreferences); + doc->viewerpreferences = optlist; + doc->writevpdict |= + pdf_parse_and_write_viewerpreferences(p, optlist, pdc_false); +} + + + + diff --git a/src/pdflib/pdflib/p_draw.c b/src/pdflib/pdflib/p_draw.c new file mode 100644 index 0000000..dc9271e --- /dev/null +++ b/src/pdflib/pdflib/p_draw.c @@ -0,0 +1,410 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_draw.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib drawing routines + * + */ + +#include "p_intern.h" +#include "p_layer.h" +#include "p_tagged.h" + +/* Path segment operators */ + +static void +pdf_begin_path(PDF *p) +{ + if (PDF_GET_STATE(p) == pdf_state_path) + return; + + + + + pdf_end_text(p); + PDF_PUSH_STATE(p, "pdf_begin_path", pdf_state_path); +} + +static void +pdf_end_path(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + + PDF_POP_STATE(p, "pdf_end_path"); + + ppt->gstate[ppt->sl].x = 0; + ppt->gstate[ppt->sl].y = 0; +} + +/* ----------------- Basic functions for API functions --------------*/ + +void +pdf__moveto(PDF *p, pdc_scalar x, pdc_scalar y) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + ppt->gstate[ppt->sl].startx = ppt->gstate[ppt->sl].x = x; + ppt->gstate[ppt->sl].starty = ppt->gstate[ppt->sl].y = y; + + pdf_begin_path(p); + pdc_printf(p->out, "%f %f m\n", x, y); +} + +void +pdf__rmoveto(PDF *p, pdc_scalar x, pdc_scalar y) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_scalar x_0 = ppt->gstate[ppt->sl].x; + pdc_scalar y_0 = ppt->gstate[ppt->sl].y; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + pdf__moveto(p, x_0 + x, y_0 + y); +} + +void +pdf__lineto(PDF *p, pdc_scalar x, pdc_scalar y) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + pdc_printf(p->out, "%f %f l\n", x, y); + + ppt->gstate[ppt->sl].x = x; + ppt->gstate[ppt->sl].y = y; +} + +void +pdf__rlineto(PDF *p, pdc_scalar x, pdc_scalar y) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_scalar x_0 = ppt->gstate[ppt->sl].x; + pdc_scalar y_0 = ppt->gstate[ppt->sl].y; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + pdf__lineto(p, x_0 + x, y_0 + y); +} + +void +pdf__curveto(PDF *p, + pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, + pdc_scalar x_3, pdc_scalar y_3) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_check_number(p->pdc, "x_1", x_1); + pdc_check_number(p->pdc, "y_1", y_1); + pdc_check_number(p->pdc, "x_2", x_2); + pdc_check_number(p->pdc, "y_2", y_2); + pdc_check_number(p->pdc, "x_3", x_3); + pdc_check_number(p->pdc, "y_3", y_3); + + /* second c.p. coincides with final point */ + if (fabs(x_2 - x_3) < PDC_FLOAT_PREC && + fabs(y_2 - y_3) < PDC_FLOAT_PREC) + pdc_printf(p->out, "%f %f %f %f y\n", x_1, y_1, x_3, y_3); + + /* general case with four distinct points */ + else + pdc_printf(p->out, "%f %f %f %f %f %f c\n", + x_1, y_1, x_2, y_2, x_3, y_3); + + ppt->gstate[ppt->sl].x = x_3; + ppt->gstate[ppt->sl].y = y_3; +} + +void +pdf__rcurveto(PDF *p, + pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, + pdc_scalar x_3, pdc_scalar y_3) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_scalar x_0 = ppt->gstate[ppt->sl].x; + pdc_scalar y_0 = ppt->gstate[ppt->sl].y; + + pdc_check_number(p->pdc, "x_1", x_1); + pdc_check_number(p->pdc, "y_1", y_1); + pdc_check_number(p->pdc, "x_2", x_2); + pdc_check_number(p->pdc, "y_2", y_2); + pdc_check_number(p->pdc, "x_3", x_3); + pdc_check_number(p->pdc, "y_3", y_3); + + pdf__curveto(p, x_0 + x_1, y_0 + y_1, + x_0 + x_2, y_0 + y_2, + x_0 + x_3, y_0 + y_3); +} + +void +pdf_rrcurveto(PDF *p, + pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, + pdc_scalar x_3, pdc_scalar y_3) +{ + pdf__rcurveto(p, x_1, y_1, + x_1 + x_2, y_1 + y_2, + x_1 + x_2 + x_3, y_1 + y_2 + y_3); +} + +void +pdf_hvcurveto(PDF *p, pdc_scalar x_1, pdc_scalar x_2, + pdc_scalar y_2, pdc_scalar y_3) +{ + pdf_rrcurveto(p, x_1, 0, x_2, y_2, 0, y_3); +} + +void +pdf_vhcurveto(PDF *p, pdc_scalar y_1, pdc_scalar x_2, + pdc_scalar y_2, pdc_scalar x_3) +{ + pdf_rrcurveto(p, 0, y_1, x_2, y_2, x_3, 0); +} + +void +pdf__rect(PDF *p, pdc_scalar x, pdc_scalar y, + pdc_scalar width, pdc_scalar height) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + pdc_check_number(p->pdc, "width", width); + pdc_check_number(p->pdc, "height", height); + + ppt->gstate[ppt->sl].startx = ppt->gstate[ppt->sl].x = x; + ppt->gstate[ppt->sl].starty = ppt->gstate[ppt->sl].y = y; + + pdf_begin_path(p); + pdc_printf(p->out, "%f %f %f %f re\n", x, y, width, p->ydirection * height); +} + +/* 4/3 * (1-cos 45°)/sin 45° = 4/3 * sqrt(2) - 1 */ +#define ARC_MAGIC (0.552284749) + +static void +pdf_short_arc(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r, + pdc_scalar alpha, pdc_scalar beta) +{ + pdc_scalar bcp; + pdc_scalar cos_alpha, cos_beta, sin_alpha, sin_beta; + + alpha = alpha * PDC_DEG2RAD; + beta = beta * PDC_DEG2RAD; + + /* This formula yields ARC_MAGIC for alpha == 0, beta == 90 degrees */ + bcp = (4.0/3 * (1 - cos((beta - alpha)/2)) / sin((beta - alpha)/2)); + + sin_alpha = sin(alpha); + sin_beta = sin(beta); + cos_alpha = cos(alpha); + cos_beta = cos(beta); + + pdf__curveto(p, + x + r * (cos_alpha - bcp * sin_alpha), /* p1 */ + y + r * (sin_alpha + bcp * cos_alpha), + x + r * (cos_beta + bcp * sin_beta), /* p2 */ + y + r * (sin_beta - bcp * cos_beta), + x + r * cos_beta, /* p3 */ + y + r * sin_beta); +} + +static void +pdf_orient_arc(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r, + pdc_scalar alpha, pdc_scalar beta, pdc_scalar orient) +{ + pdf_ppt *ppt = p->curr_ppt; + pdc_scalar rad_a = alpha * PDC_DEG2RAD; + pdc_scalar startx = (x + r * cos(rad_a)); + pdc_scalar starty = (y + r * sin(rad_a)); + + if (PDF_GET_STATE(p) != pdf_state_path) + { + pdf__moveto(p, startx, starty); /* this enters pdf_state_path */ + } + else if ((ppt->gstate[ppt->sl].x != startx + || ppt->gstate[ppt->sl].y != starty)) + { + pdf__lineto(p, startx, starty); + } + + if (orient > 0) + { + while (beta < alpha) + beta += 360; + + if (alpha == beta) + return; + + while (beta - alpha > 90) + { + pdf_short_arc(p, x, y, r, alpha, alpha + 90); + alpha += 90; + } + } + else + { + while (alpha < beta) + alpha += 360; + + if (alpha == beta) + return; + + while (alpha - beta > 90) + { + pdf_short_arc(p, x, y, r, alpha, alpha - 90); + alpha -= 90; + } + } + + if (alpha != beta) + pdf_short_arc(p, x, y, r, alpha, beta); +} + +void +pdf__arc(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r, + pdc_scalar alpha, pdc_scalar beta) +{ + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + pdc_check_number_limits(p->pdc, "r", r, PDC_FLOAT_PREC, PDC_FLOAT_MAX); + pdc_check_number(p->pdc, "alpha", alpha); + pdc_check_number(p->pdc, "beta", beta); + + pdf_orient_arc(p, x, y, r, + p->ydirection * alpha, p->ydirection * beta, p->ydirection); +} + +void +pdf__arcn(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r, + pdc_scalar alpha, pdc_scalar beta) +{ + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + pdc_check_number_limits(p->pdc, "r", r, PDC_FLOAT_PREC, PDC_FLOAT_MAX); + pdc_check_number(p->pdc, "alpha", alpha); + pdc_check_number(p->pdc, "beta", beta); + + pdf_orient_arc(p, x, y, r, + p->ydirection * alpha, p->ydirection * beta, -p->ydirection); +} + +void +pdf__circle(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r) +{ + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + pdc_check_number_limits(p->pdc, "r", r, PDC_FLOAT_PREC, PDC_FLOAT_MAX); + + /* + * pdf_begin_path() not required since we descend to other + * path segment functions. + */ + + /* draw four Bezier curves to approximate a circle */ + pdf__moveto(p, x + r, y); + pdf__curveto(p, x + r, y + r*ARC_MAGIC, x + r*ARC_MAGIC, y + r, x, y + r); + pdf__curveto(p, x - r*ARC_MAGIC, y + r, x - r, y + r*ARC_MAGIC, x - r, y); + pdf__curveto(p, x - r, y - r*ARC_MAGIC, x - r*ARC_MAGIC, y - r, x, y - r); + pdf__curveto(p, x + r*ARC_MAGIC, y - r, x + r, y - r*ARC_MAGIC, x + r, y); + + pdf__closepath(p); +} + +void +pdf__closepath(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + + pdc_puts(p->out, "h\n"); + + ppt->gstate[ppt->sl].x = ppt->gstate[ppt->sl].startx; + ppt->gstate[ppt->sl].y = ppt->gstate[ppt->sl].starty; +} + +void +pdf__endpath(PDF *p) +{ + pdc_puts(p->out, "n\n"); + pdf_end_path(p); +} + +void +pdf__stroke(PDF *p) +{ + pdc_puts(p->out, "S\n"); + pdf_end_path(p); +} + +void +pdf__closepath_stroke(PDF *p) +{ + pdc_puts(p->out, "s\n"); + pdf_end_path(p); +} + +void +pdf__fill(PDF *p) +{ + if (p->curr_ppt->fillrule == pdf_fill_winding) + pdc_puts(p->out, "f\n"); + else if (p->curr_ppt->fillrule == pdf_fill_evenodd) + pdc_puts(p->out, "f*\n"); + + pdf_end_path(p); +} + +void +pdf__fill_stroke(PDF *p) +{ + if (p->curr_ppt->fillrule == pdf_fill_winding) + pdc_puts(p->out, "B\n"); + else if (p->curr_ppt->fillrule == pdf_fill_evenodd) + pdc_puts(p->out, "B*\n"); + + pdf_end_path(p); +} + +void +pdf__closepath_fill_stroke(PDF *p) +{ + if (p->curr_ppt->fillrule == pdf_fill_winding) + pdc_puts(p->out, "b\n"); + else if (p->curr_ppt->fillrule == pdf_fill_evenodd) + pdc_puts(p->out, "b*\n"); + + pdf_end_path(p); +} + +void +pdf__clip(PDF *p) +{ + if (p->curr_ppt->fillrule == pdf_fill_winding) + pdc_puts(p->out, "W n\n"); + else if (p->curr_ppt->fillrule == pdf_fill_evenodd) + pdc_puts(p->out, "W* n\n"); + + pdf_end_path(p); +} + diff --git a/src/pdflib/pdflib/p_encoding.c b/src/pdflib/pdflib/p_encoding.c new file mode 100644 index 0000000..af24792 --- /dev/null +++ b/src/pdflib/pdflib/p_encoding.c @@ -0,0 +1,187 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_encoding.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib encoding handling routines + * + */ + +#include "p_intern.h" +#include "p_font.h" + +void +pdf__encoding_set_char(PDF *p, const char *encoding, int slot, + const char *glyphname, int uv) +{ + int enc; + pdc_encodingvector *ev; + char given; + + if (!encoding || !*encoding) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "encoding", 0, 0, 0); + + if (slot < 0 || slot > 255) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "slot", pdc_errprintf(p->pdc, "%d", slot), 0, 0); + + if (uv < 0 || uv >= PDC_NUM_BMPVAL) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "uv", pdc_errprintf(p->pdc, "%d", uv), 0, 0); + + if (!glyphname || !*glyphname) + { + if (uv == 0) + pdc_error(p->pdc, PDF_E_ENC_GLYPHORCODE, 0, 0, 0, 0); + } + + for (enc = (int) pdc_invalidenc + 1; enc < (int) pdc_firstvarenc; enc++) + { + if (!strcmp(encoding, pdc_get_fixed_encoding_name((pdc_encoding) enc))) + pdc_error(p->pdc, PDF_E_ENC_CANTCHANGE, encoding, 0, 0, 0); + } + + if (uv == 0) + { + given = 1; + uv = (int) pdc_insert_glyphname(p->pdc, glyphname); + } + else if (!glyphname || !*glyphname) + { + given = 0; + glyphname = pdc_insert_unicode(p->pdc, (pdc_ushort) uv); + } + else + { + const char *reg_glyphname; + pdc_ushort reg_uv; + int retval; + + given = 1; + reg_glyphname = pdc_unicode2glyphname(p->pdc, (pdc_ushort) uv); + if (reg_glyphname) + { + if (strcmp(reg_glyphname, glyphname) && + p->debug[(int) 'F'] == pdc_true) + { + pdc_warning(p->pdc, PDF_E_ENC_BADGLYPH, + glyphname, + pdc_errprintf(p->pdc, "%04X", uv), + reg_glyphname, 0); + } + + /* We take the registered name */ + } + else + { + retval = pdc_glyphname2unicode(p->pdc, glyphname); + if (retval > -1) + { + reg_uv = (pdc_ushort) retval; + if (reg_uv && reg_uv != (pdc_ushort) uv && + p->debug[(int) 'F'] == pdc_true) + { + pdc_error(p->pdc, PDF_E_ENC_BADUNICODE, + pdc_errprintf(p->pdc, "%04X", uv), glyphname, + pdc_errprintf(p->pdc, "%04X", reg_uv), 0); + } + } + + /* We register the new glyph name and unicode value */ + pdc_register_glyphname(p->pdc, glyphname, (pdc_ushort) uv, + pdc_false); + } + } + + /* search for a registered encoding */ + enc = pdc_find_encoding(p->pdc, encoding); + + /* not found */ + if (enc == pdc_invalidenc) + { + ev = pdc_new_encoding(p->pdc, encoding); + ev->flags |= PDC_ENC_USER; + ev->flags |= PDC_ENC_SETNAMES; + ev->flags |= PDC_ENC_ALLOCCHARS; + + enc = pdc_insert_encoding_vector(p->pdc, ev); + } + + /* encoding vector */ + ev = pdc_get_encoding_vector(p->pdc, (pdc_encoding)enc); + if (!(ev->flags & PDC_ENC_USER)) + { + pdc_error(p->pdc, PDF_E_ENC_CANTCHANGE, encoding, 0, 0, 0); + } + else if (ev->flags & PDC_ENC_USED) + { + pdc_error(p->pdc, PDF_E_ENC_INUSE, encoding, 0, 0, 0); + } + + /* Free character name */ + if (ev->chars[slot] != NULL) + pdc_free(p->pdc, ev->chars[slot]); + + /* Saving */ + ev->codes[slot] = (pdc_ushort) uv; + if (glyphname != NULL) + ev->chars[slot] = pdc_strdup(p->pdc, glyphname); + ev->given[slot] = given; + + pdc_encoding_logg_protocol(p->pdc, ev); +} + +pdc_encoding +pdf_get_hypertextencoding_param(PDF *p, int *codepage) +{ + if (p->hypertextencoding == pdc_invalidenc) + { + p->hypertextencoding = pdf_get_hypertextencoding(p, "auto", + &p->hypertextcodepage, pdc_true); + + if (p->hypertextencoding == pdc_invalidenc) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + + if (codepage) + *codepage = p->hypertextcodepage; + + return p->hypertextencoding; +} + +pdc_encoding +pdf_get_hypertextencoding(PDF *p, const char *encoding, int *codepage, + pdc_bool verbose) +{ + pdc_encoding enc = pdc_invalidenc; + + *codepage = 0; + + if (!*encoding) + { + enc = pdc_unicode; + } + else + { + { + enc = pdc_get_encoding(p->pdc, encoding, codepage, verbose); + if (enc < 0 && enc != pdc_invalidenc && enc != pdc_unicode) + { + pdc_set_errmsg(p->pdc, PDF_E_ENC_BADHYPTEXTENC, encoding, + 0, 0, 0); + enc = pdc_invalidenc; + } + } + } + + return enc; +} diff --git a/src/pdflib/pdflib/p_fields.c b/src/pdflib/pdflib/p_fields.c new file mode 100644 index 0000000..4900b3b --- /dev/null +++ b/src/pdflib/pdflib/p_fields.c @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_fields.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib form fields handling routines + * + */ + +#define P_FIELDS_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_image.h" + + + + + + diff --git a/src/pdflib/pdflib/p_filter.c b/src/pdflib/pdflib/p_filter.c new file mode 100644 index 0000000..d5a11a6 --- /dev/null +++ b/src/pdflib/pdflib/p_filter.c @@ -0,0 +1,120 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_filter.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Compressed and uncompressed stream output + * + */ + +#include "p_intern.h" + +/* methods for constructing a data source from a file */ + +#define FILE_BUFSIZE 1024 + +void +pdf_data_source_file_init(PDF *p, PDF_data_source *src) +{ + pdc_file *fp; + + src->buffer_length = FILE_BUFSIZE; + src->buffer_start = (pdc_byte *) + pdc_malloc(p->pdc, src->buffer_length, "pdf_data_source_file_init"); + + fp = pdc_fsearch_fopen(p->pdc, (const char *) src->private_data, NULL, + "embedded ", PDC_FILE_BINARY); + + if (fp == NULL) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + + if (src->offset) + pdc_fseek(fp, src->offset, SEEK_SET); + + src->private_data = (void *) fp; + src->total = (long) 0; +} + +pdc_bool +pdf_data_source_file_fill(PDF *p, PDF_data_source *src) +{ + size_t bytes_needed; + (void) p; /* avoid compiler warning "unreferenced parameter" */ + + if (src->length != (long) 0 && src->total + FILE_BUFSIZE > src->length) + bytes_needed = (size_t) (src->length - src->total); + else + bytes_needed = FILE_BUFSIZE; + + src->next_byte = src->buffer_start; + src->bytes_available = pdc_fread(src->buffer_start, 1, + bytes_needed, (pdc_file *) (src->private_data)); + + src->total += (long) src->bytes_available; + + if (src->bytes_available == 0) + return pdc_false; + else + return pdc_true; +} + +void +pdf_data_source_file_terminate(PDF *p, PDF_data_source *src) +{ + pdc_free(p->pdc, (void *) src->buffer_start); + pdc_fclose((pdc_file *) src->private_data); + + if (src->length != (long) 0 && src->total != src->length) + pdc_error(p->pdc, PDC_E_IO_READ, "?", 0, 0, 0); +} + +/* methods for constructing a data source from a memory buffer */ + +int +pdf_data_source_buf_fill(PDF *p, PDF_data_source *src) +{ + (void) p; /* avoid compiler warning "unreferenced parameter" */ + + if (src->next_byte == NULL) { + src->next_byte = src->buffer_start; + src->bytes_available = src->buffer_length; + return pdc_true; + } + + return pdc_false; +} + +/* copy the complete contents of src to a stream */ +void +pdf_copy_stream(PDF *p, PDF_data_source *src, pdc_bool compress) +{ + int oldcompresslevel = pdc_get_compresslevel(p->out); + + if (!compress) + pdc_set_compresslevel(p->out, 0); + + if (src->init) + src->init(p, src); + + pdc_begin_pdfstream(p->out); + + while (src->fill(p, src)) + pdc_write(p->out, src->next_byte, src->bytes_available); + + pdc_end_pdfstream(p->out); + + if (src->terminate) + src->terminate(p, src); + + if (!compress) + pdc_set_compresslevel(p->out, oldcompresslevel); +} diff --git a/src/pdflib/pdflib/p_font.c b/src/pdflib/pdflib/p_font.c new file mode 100644 index 0000000..5dfce77 --- /dev/null +++ b/src/pdflib/pdflib/p_font.c @@ -0,0 +1,2513 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_font.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib font handling routines + * + */ + +#define P_FONT_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_defopt.h" +#include "p_font.h" +#include "p_tagged.h" + +#include "ft_truetype.h" + + +#define PDF_TTC_SEPARATOR ':' + +static const pdc_keyconn pdf_fonttype_pdfkeylist[] = +{ + {"Type1", fnt_Type1}, + {"MMType1", fnt_MMType1}, + {"TrueType", fnt_TrueType}, + {"Type0", fnt_CIDFontType2}, + {"Type1", fnt_Type1C}, + {"Type0", fnt_CIDFontType0}, + {"Type3", fnt_Type3}, + {NULL, 0} +}; + +typedef enum +{ + font_afm = 1, + font_pfm = 2, + font_ttot = 3, + font_pfab = 4 +} +pdf_fontfile_type; + +static const pdc_keyconn pdf_extension_names[] = +{ + {".tte", font_ttot}, + {".ttf", font_ttot}, + {".otf", font_ttot}, + {".afm", font_afm}, + {".pfm", font_pfm}, + {".ttc", font_ttot}, + {".TTE", font_ttot}, + {".TTF", font_ttot}, + {".OTF", font_ttot}, + {".AFM", font_afm}, + {".PFM", font_pfm}, + {".TTC", font_ttot}, + {".pfa", font_pfab}, + {".pfb", font_pfab}, + {".PFA", font_pfab}, + {".PFB", font_pfab}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_fontoption_keylist[] = +{ + {"fontname", fo_fontname}, + {"encoding", fo_encoding}, + {"fontstyle", fo_fontstyle}, + {"monospace", fo_monospace}, + {NULL, 0} +}; + + +void +pdf_init_font(PDF *p, pdf_font *font, pdf_font_options *fo) +{ + (void) p; + + /* font metric */ + fnt_init_font(&font->ft); + + /* font options */ + font->opt = *fo; + font->verbose = fo->fontwarning; + + font->apiname = NULL; + font->filename = NULL; + font->metricfilename = NULL; + + font->used_in_formfield = pdc_false; + font->used_in_current_doc = pdc_false; + font->used_on_current_page = pdc_false; + font->obj_id = PDC_BAD_ID; + + font->cff_offset = 0; + font->cff_length = 0; + + font->t3font = NULL; + font->hasoriginal = pdc_false; + + font->encapiname = NULL; + font->outcmapname = NULL; + font->codepage = 0; + font->towinansi = pdc_invalidenc; + font->hasnomac = pdc_false; + font->passthrough = pdc_false; + font->unibyte = pdc_false; + font->asciispace = pdc_false; + font->issemantic = pdc_false; + font->widthsmissing = pdc_false; + font->missingglyphs = 0; + font->metricflags = 0; + font->supplement = 0; + font->symenc = pdc_invalidenc; + font->replacementchar = -1; + font->replacementcode = -1; + + font->codesize = 1; + font->lastcode = -1; + font->gid0code = -1; + font->usedgids = NULL; + font->expectglyphs = pdc_false; + font->iscidfont = pdc_false; + +} + +void +pdf_cleanup_font(PDF *p, pdf_font *font) +{ + if (font->ft.imgname) + pdc_unlock_pvf(p->pdc, font->ft.imgname); + + /* font metric */ + fnt_cleanup_font(p->pdc, &font->ft); + + if (font->apiname != NULL) + { + pdc_free(p->pdc, font->apiname); + font->apiname = NULL; + } + + if (font->metricfilename != NULL) + { + pdc_free(p->pdc, font->metricfilename); + font->metricfilename = NULL; + } + + if (font->encapiname != NULL) + { + pdc_free(p->pdc, font->encapiname); + font->encapiname = NULL; + } + + if (font->outcmapname != NULL) + { + pdc_free(p->pdc, font->outcmapname); + font->outcmapname = NULL; + } + + + if (font->usedgids != NULL) + { + pdc_free(p->pdc, font->usedgids); + font->usedgids = NULL; + } + + /* Type3 font */ + if (font->t3font != NULL && font->hasoriginal) + { + pdf_cleanup_t3font(p, font->t3font); + pdc_free(p->pdc, font->t3font); + font->t3font = NULL; + } + +} + +void +pdf_init_fonts(PDF *p) +{ + p->fonts = NULL; + p->fonts_number = 0; + p->fonts_capacity = 0; + p->t3slot = -1; + + + pdc_init_encoding_info_ids(p->pdc); +} + +void +pdf_cleanup_fonts(PDF *p) +{ + int slot; + + if (p->fonts != NULL) + { + for (slot = 0; slot < p->fonts_number; slot++) + pdf_cleanup_font(p, &p->fonts[slot]); + + pdc_free(p->pdc, p->fonts); + p->fonts = NULL; + } + +} + +int +pdf_insert_font(PDF *p, pdf_font *font) +{ + static const char fn[] = "pdf_insert_font"; + int slot = p->fonts_number; + + /* insert font */ + if (p->fonts_number == p->fonts_capacity) + { + if (p->fonts_capacity == 0) + { + p->fonts_capacity = FONTS_CHUNKSIZE; + p->fonts = (pdf_font *) pdc_calloc(p->pdc, + sizeof(pdf_font) * p->fonts_capacity, fn); + } + else + { + p->fonts_capacity *= 2; + p->fonts = (pdf_font *) pdc_realloc(p->pdc, p->fonts, + sizeof(pdf_font) * p->fonts_capacity, fn); + } + } + p->fonts[slot] = *font; + + p->fonts_number++; + + return slot; +} + + +const char * +pdf_get_pdf_fontname(pdf_font *font) +{ + const char *fontname; + + fontname = fnt_get_abb_std_fontname(font->ft.name); + if (fontname == NULL) + fontname = fnt_get_abb_cjk_fontname(font->ft.name); + if (fontname == NULL) + fontname = font->ft.name; + + return (const char *) fontname; +} + +const char * +pdf_get_encoding_name(PDF *p, pdc_encoding enc, pdf_font *font) +{ + const char *apiname = pdc_get_fixed_encoding_name(enc); + if (!apiname[0] && enc >= 0) + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + apiname = (const char *) ev->apiname; + } + else if (enc == pdc_cid && font != NULL && font->outcmapname != NULL) + apiname = (const char *) font->outcmapname; + return apiname; +} + +char * +pdf_get_encoding_adaptname(PDF *p, pdc_encoding enc, pdf_font *font, + const char *fontname) +{ + static const char *fn = "pdf_get_encoding_adaptname"; + char *encname = (char *) pdf_get_encoding_name(p, enc, font); + char *adaptname = NULL; + size_t len; + + len = strlen(encname) + 1 + strlen(fontname) + 1; + adaptname = (char *) pdc_malloc_tmp(p->pdc, len, fn, 0, 0); + strcpy(adaptname, encname); + strcat(adaptname, PDC_ENC_MODSEPAR); + strcat(adaptname, fontname); + + return adaptname; +} + +pdc_encodingvector * +pdf_create_font_encoding(PDF *p, pdc_encoding enc, pdf_font *font, + const char *fontname, pdc_bool kreg) +{ + pdc_encodingvector *ev = NULL; + char *adaptname = NULL; + + adaptname = pdf_get_encoding_adaptname(p, enc, font, fontname); + + /* search for a registered encoding */ + enc = pdc_find_encoding(p->pdc, adaptname); + if (enc != pdc_invalidenc) + { + font->ft.enc = enc; + } + else + { + /* create a font encoding */ + ev = pdc_new_encoding(p->pdc, adaptname); + ev->flags |= PDC_ENC_FONT; + ev->flags |= PDC_ENC_SETNAMES; + + if (kreg) + { + enc = pdc_insert_encoding_vector(p->pdc, ev); + font->ft.enc = enc; + } + } + + pdc_free_tmp(p->pdc, adaptname); + + return ev; +} + +const char * +pdf_get_font_char_option(PDF *p, pdf_font_optflags fflags) +{ + pdf_text_options *to = p->curr_ppt->currto; + pdf_font *currfont; + + if (p->fonts_number == 0 || to->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT_PAR, + pdc_get_keyword(fflags, pdf_fontoption_keylist), 0, 0, 0); + currfont = &p->fonts[to->font]; + + switch (fflags) + { + case fo_fontname: + return (const char *) currfont->ft.name; + + case fo_encoding: + return pdf_get_encoding_name(p, currfont->ft.enc, currfont); + + case fo_fontstyle: + return pdc_get_keyword(currfont->opt.fontstyle, + pdf_fontstyle_pdfkeylist); + + default: + return NULL; + } +} + +double +pdf_get_font_float_option(PDF *p, pdf_font_optflags fflags) +{ + pdf_text_options *to = p->curr_ppt->currto; + pdf_font *currfont; + + if (p->fonts_number == 0 || to->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT_PAR, + pdc_get_keyword(fflags, pdf_fontoption_keylist), 0, 0, 0); + currfont = &p->fonts[to->font]; + + switch (fflags) + { + case fo_monospace: + return (double) currfont->opt.monospace; + + default: + return 0; + } +} + +static const pdc_keyconn pdf_courier_keylist[] = +{ + {"Courier", fnt_Normal}, + {"Courier-Bold", fnt_Bold}, + {"Courier-Oblique", fnt_Italic}, + {"Courier-BoldOblique", fnt_BoldItalic}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_helvetica_keylist[] = +{ + {"Helvetica", fnt_Normal}, + {"Helvetica-Bold", fnt_Bold}, + {"Helvetica-Oblique", fnt_Italic}, + {"Helvetica-BoldOblique", fnt_BoldItalic}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_times_keylist[] = +{ + {"Times-Roman", fnt_Normal}, + {"Times-Bold", fnt_Bold}, + {"Times-Italic", fnt_Italic}, + {"Times-BoldItalic", fnt_BoldItalic}, + {NULL, 0} +}; + +static const char * +pdf_get_fontname_core(pdf_font *font, const char *fontname, pdc_bool checktimes) +{ + const char *fname = NULL; + + /* font style for core fonts */ + if (font->opt.fontstyle != fnt_Normal) + { + if (!strcmp(fontname, "Courier")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_courier_keylist); + else if (!strcmp(fontname, "Helvetica")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_helvetica_keylist); + else if (!strcmp(fontname, "Times-Roman")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_times_keylist); + } + + if (checktimes) + { + if (!strcmp(fontname, "Times")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_times_keylist); + } + + return fname; +} + +static pdc_bool +pdf_get_metrics_core(PDF *p, pdf_font *font, const char *fontname, + pdc_encoding enc, pdc_bool checktimes) +{ + const char *fname = NULL; + const fnt_font_metric *ftm; + + fname = pdf_get_fontname_core(font, fontname, checktimes); + if (fname != NULL) + { + fontname = fname; + font->opt.fontstyle = fnt_Normal; + } + + ftm = fnt_get_core_metric(fontname); + if (ftm != NULL) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tLoading metrics data for core font \"%s\":\n", fontname); + + /* Fill up the font struct */ + fnt_fill_font_metric(p->pdc, &font->ft, + pdc_false, + ftm); + font->ft.enc = enc; + + /* all new glyph names of AGL 2.0 are missing */ + font->missingglyphs = 0xFFFFFFFF; + + /* Process metrics data */ + if (pdf_process_metrics_data(p, font, fontname)) + { + if (pdf_make_fontflag(p, font)) + { + if (!font->opt.monospace) + return pdc_true; + else + pdc_set_errmsg(p->pdc, PDC_E_OPT_IGNORED, "monospace", + 0, 0, 0); + } + } + + return pdc_false; + } + + return pdc_undef; +} + +void +pdf_font_set_missvalues(PDF *p, pdf_font *font) +{ + pdf_font_options *fo = &font->opt; + fnt_font_metric *ftm = &font->ft.m; + + (void) p; + + if (ftm->descender > 0) + ftm->descender = -(ftm->descender); + + if (fo->mask & (1L << fo_ascender)) + { + font->metricflags |= font_ascender; + ftm->ascender = fo->ascender; + } + else if (ftm->ascender <= 0) + { + font->metricflags |= font_ascender; + ftm->ascender = 720; + } + + if (fo->mask & (1L << fo_descender)) + { + font->metricflags |= font_descender; + ftm->descender = fo->descender; + } + else if (ftm->descender == FNT_MISSING_FONTVAL) + { + font->metricflags |= font_descender; + ftm->descender = (int) PDC_ROUND(-0.25 * ftm->ascender); + } + + if (fo->mask & (1L << fo_capheight)) + { + font->metricflags |= font_capheight; + ftm->capHeight = fo->capheight; + } + else if (ftm->capHeight <= 0) + { + font->metricflags |= font_capheight; + ftm->capHeight = (int) PDC_ROUND(0.93 * ftm->ascender); + } + + if (fo->mask & (1L << fo_xheight)) + { + font->metricflags |= font_xheight; + ftm->xHeight = fo->xheight; + } + else if (ftm->xHeight <= 0) + { + font->metricflags |= font_xheight; + ftm->xHeight = (int) PDC_ROUND(0.66 * ftm->ascender); + } + + if (fo->mask & (1L << fo_linegap)) + { + font->metricflags |= font_linegap; + font->ft.linegap = fo->linegap; + } + else if (font->ft.linegap == FNT_MISSING_FONTVAL) + { + font->metricflags |= font_linegap; + font->ft.linegap = (int) PDC_ROUND(0.23 * ftm->ascender); + } + + if (ftm->llx == FNT_MISSING_FONTVAL) + ftm->llx = -50; + if (ftm->lly == FNT_MISSING_FONTVAL) + ftm->lly = ftm->descender; + if (ftm->urx == FNT_MISSING_FONTVAL) + ftm->urx = 1000; + if (ftm->ury == FNT_MISSING_FONTVAL) + ftm->ury = ftm->ascender; + + /* try to fix broken entries */ + if (ftm->lly > ftm->ury) + ftm->ury = ftm->lly + ftm->ascender; + if (ftm->llx > ftm->urx) + ftm->urx = ftm->llx + 1000; +} + +pdc_bool +pdf_font_get_is_faked(pdf_font *font, pdf_font_values flag) +{ + return (font->metricflags & flag) ? pdc_true : pdc_false; +} + +double +pdf_font_get_metric_value(int value) +{ + return (double) value / 1000.0; +} + + +/* --------------------------- font processing ---------------------------- */ + +pdc_bool +pdf_make_fontflag(PDF *p, pdf_font *font) +{ + int errcode = 0; + + if (font->ft.m.type != fnt_Type3) + { + if (font->ft.m.isFixedPitch) + font->ft.m.flags |= FNT_FIXEDWIDTH; + + if (font->ft.issymbfont == pdc_false || + font->ft.enc == pdc_winansi || + font->ft.enc == pdc_macroman || + font->ft.enc == pdc_ebcdic || + font->ft.enc == pdc_ebcdic_37 || + font->ft.enc == pdc_ebcdic_winansi) + font->ft.m.flags |= FNT_ADOBESTANDARD; + else + font->ft.m.flags |= FNT_SYMBOL; + + if (font->ft.m.italicAngle < 0 || + font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + font->ft.m.flags |= FNT_ITALIC; + if (font->ft.m.italicAngle == 0 && + font->ft.m.flags & FNT_ITALIC) + font->ft.m.italicAngle = FNT_DEF_ITALICANGLE; + + /* heuristic to identify (small) caps fonts */ + if (font->ft.name && + (strstr(font->ft.name, "Caps") || + !strcmp(font->ft.name + strlen(font->ft.name) - 2, "SC"))) + font->ft.m.flags |= FNT_SMALLCAPS; + + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + font->ft.weight = FNT_FW_BOLD; + + if (strstr(font->ft.name, "Bold") || + font->ft.weight >= FNT_FW_BOLD) + font->ft.m.flags |= FNT_FORCEBOLD; + + /* determine values for FontWeight to StemV */ + if (font->ft.m.StdVW == 0) + font->ft.m.StdVW = fnt_weight2stemv(font->ft.weight); + else if (font->ft.weight == 0) + font->ft.weight = fnt_stemv2weight(font->ft.m.StdVW); + } + + fnt_font_logg_protocol(p->pdc, &font->ft); + + switch(font->ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_Type3: + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_bold; + } + + if (font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_italic; + } + + break; + + default: + if (font->opt.embedding) + { + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_bold; + } + + if (font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_italic; + } + } + break; + } + + + return errcode ? pdc_false : pdc_true; +} + +int +pdf_get_code_or_glyphid(PDF *p, pdf_font *font, pdc_encodingvector *ev, + pdc_ushort uv) +{ + if (ev != NULL) + { + int code = pdc_get_encoding_bytecode(p->pdc, ev, uv); + + if (code >= 0) + { + if (fnt_get_glyphid(code, &font->ft) <= 0) + code = 0; + } + return code; + } + + return fnt_get_glyphid((int) uv, &font->ft); +} + +void +pdf_set_replchar(PDF *p, pdf_font *font) +{ + pdc_encoding enc = font->ft.enc; + + switch (enc) + { + case pdc_glyphid: + case pdc_cid: + return; + + case pdc_builtin: + font->replacementcode = 0; + return; + + case pdc_unicode: + default: + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + pdc_ushort uv = 0; + int cg = 0; + uv = PDC_UNICODE_NBSP; + cg = pdf_get_code_or_glyphid(p, font, ev, uv); + if (cg <= 0) + { + uv = PDC_UNICODE_SPACE; + cg = pdf_get_code_or_glyphid(p, font, ev, uv); + if (cg <= 0) + { + uv = 0; + cg = 0; + } + } + + font->replacementchar = (int) uv; + font->replacementcode = cg; + } + return; + } +} + +void +pdf_font_issemantic(PDF *p, pdf_font *font) +{ + pdc_encoding enc = font->ft.enc; + pdc_ushort spacechar = 0; + + /* Flag: encoding with ASCII space for wordspacing */ + if (enc >= 0) + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + int i; + + ev->flags |= PDC_ENC_USED; + i = pdc_get_encoding_bytecode(p->pdc, ev, PDC_UNICODE_SPACE); + if (i > -1) + { + spacechar = (pdc_ushort) i; + if (spacechar == PDC_UNICODE_SPACE) + font->asciispace = pdc_true; + } + } + + /* Flag: encoding is Unicode interpretable */ + if ((enc >= 0) || + (enc == pdc_cid && font->codesize == 2) || + (enc == pdc_unicode)) + font->issemantic = pdc_true; + + /* determine code of space character */ + switch(enc) + { + case pdc_cid: + if (font->codesize == 2) + font->ft.spacechar = PDC_UNICODE_SPACE; + break; + + case pdc_unicode: + font->ft.spacechar = PDC_UNICODE_SPACE; + break; + + case pdc_glyphid: + font->ft.spacechar = + (pdc_ushort) MAX(fnt_get_glyphid(PDC_UNICODE_SPACE, &font->ft), 0); + break; + + default: + font->ft.spacechar = spacechar; + break; + } +} + +/* definitions of font options */ +static const pdc_defopt pdf_load_font_options[] = +{ + PDF_FONT_OPTIONS2 + PDF_FONT_OPTIONS3 + PDF_ERRORPOLICY_OPTION + PDC_OPT_TERMINATE +}; + +void +pdf_init_font_options(PDF *p, pdf_font_options *fo) +{ + static const char fn[] = "pdf_init_font_options"; + + if (fo == NULL) + { + p->currfo = (pdf_font_options *) pdc_malloc(p->pdc, + sizeof(pdf_font_options), fn); + + + fo = p->currfo; + } + else + { + } + + + fo->embedding = pdc_false; /* default true if CID custom font */ + fo->encoding = NULL; + fo->flags = 0; + fo->fontname = NULL; + fo->fontstyle = fnt_Normal; + fo->fontwarning = p->debug[(int) 'F']; + fo->fontwarning = pdf_get_errorpolicy(p, NULL, fo->fontwarning); + fo->mask = 0; + fo->monospace = 0; + fo->ascender = 0; + fo->descender = 0; + fo->capheight = 0; + fo->xheight = 0; + fo->linegap = 0; + fo->auxiliary = pdc_false; + +} + +void +pdf_cleanup_font_curroptions(PDF *p) +{ + if (p->currfo) + { + pdc_free(p->pdc, p->currfo); + p->currfo = NULL; + } +} + +void +pdf_cleanup_font_options(PDF *p, pdf_font_options *fo) +{ + if (fo->fontname != NULL) + { + pdc_free(p->pdc, fo->fontname); + fo->fontname = NULL; + } + + if (fo->encoding != NULL) + { + pdc_free(p->pdc, fo->encoding); + fo->encoding = NULL; + } +} + +void +pdf_parse_font_options(PDF *p, const char *optlist) +{ + pdc_resopt *resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_load_font_options, NULL, pdc_true); + + pdf_get_font_options(p, p->currfo, resopts); + pdc_cleanup_optionlist(p->pdc, resopts); +} + +void +pdf_get_font_options(PDF *p, pdf_font_options *fo, pdc_resopt *resopts) +{ + int inum; + + (void) p; + + if (fo->flags & is_block || + fo->flags & is_textline || + fo->flags & is_textflow) + { + if (pdc_get_optvalues("fontname", resopts, NULL, NULL)) + { + fo->fontname = (char *)pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + fo->mask |= (1L << fo_fontname); + } + + if (pdc_get_optvalues("encoding", resopts, NULL, NULL)) + { + fo->encoding = (char *)pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + fo->mask |= (1L << fo_encoding); + } + } + + if (pdc_get_optvalues("fontwarning", resopts, &fo->fontwarning, NULL)) + fo->mask |= (1L << fo_fontwarning); + fo->fontwarning = pdf_get_errorpolicy(p, resopts, fo->fontwarning); + + if (pdc_get_optvalues("embedding", resopts, &fo->embedding, NULL)) + fo->mask |= (1L << fo_embedding); + + + if (pdc_get_optvalues("fontstyle", resopts, &inum, NULL)) + { + fo->fontstyle = (fnt_fontstyle) inum; + fo->mask |= (1L << fo_fontstyle); + } + + if (pdc_get_optvalues("monospace", resopts, &fo->monospace, NULL)) + fo->mask |= (1L << fo_monospace); + + if (pdc_get_optvalues("ascender", resopts, &fo->ascender, NULL)) + fo->mask |= (1L << fo_ascender); + + if (pdc_get_optvalues("descender", resopts, &fo->descender, NULL)) + fo->mask |= (1L << fo_descender); + + if (pdc_get_optvalues("capheight", resopts, &fo->capheight, NULL)) + fo->mask |= (1L << fo_capheight); + + if (pdc_get_optvalues("xheight", resopts, &fo->xheight, NULL)) + fo->mask |= (1L << fo_xheight); + + if (pdc_get_optvalues("linegap", resopts, &fo->linegap, NULL)) + fo->mask |= (1L << fo_linegap); + +} + +int +pdf__load_font(PDF *p, const char *fontname, int inlen, + const char *encoding, const char *optlist) +{ + int slot; + pdf_font_options fo; + + if (encoding == NULL || *encoding == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "encoding", 0, 0, 0); + + if (fontname == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + + /* initialize */ + pdf_init_font_options(p, &fo); + + /* Converting fontname */ + fo.fontname = (char *) pdf_convert_name(p, fontname, inlen, + PDC_CONV_WITHBOM); + if (fo.fontname == NULL || *fo.fontname == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + + /* encoding */ + fo.encoding = (char *) pdc_strdup(p->pdc, encoding); + + /* parsing option list */ + if (optlist && strlen(optlist)) + { + pdc_resopt *resopts; + pdc_clientdata data; + + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_load_font_options, &data, pdc_true); + if (!resopts) + { + pdf_cleanup_font_options(p, &fo); + return -1; + } + + pdf_get_font_options(p, &fo, resopts); + pdc_cleanup_optionlist(p->pdc, resopts); + } + + slot = pdf_load_font_internal(p, &fo); + return slot; +} + +static void +pdf_check_font_identical(PDF *p, pdf_font *font, int *slot) +{ + pdf_font *oldfont = &p->fonts[*slot]; + const char *optname = NULL; + + if (!oldfont->opt.embedding && font->opt.embedding) + { + optname = "embedding"; + if (p->errorpolicy == errpol_legacy) + { + pdc_warning(p->pdc, PDF_E_FONT_NOTFULFILL, optname, optname, + 0, 0); + } + else + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOTFULFILL, optname, optname, + 0, 0); + *slot = -1; + } + } + +} + +pdc_bool +pdf_check_font_embedding(PDF *p, pdf_font *font, const char *fontname) +{ + (void) p; + (void) font; + (void) fontname; + + + + return pdc_true; +} + +int +pdf_load_font_internal(PDF *p, pdf_font_options *fo) +{ + pdc_bool logg2 = pdc_logg_is_enabled(p->pdc, 2, trc_font); + const char *fontname; + const char *encoding; + const char *encoding_aux; + pdc_encoding enc = pdc_invalidenc; + pdf_font tmpfont, *font; + const char *filename = NULL; + const char *extension = NULL; + const char *outfilename = NULL; + char *fontname_p = NULL; + char testfilename[PDF_MAX_FONTNAME + 5]; + char *sf, *mmparam, mastername[PDF_MAX_FONTNAME + 1]; + char ittc; + size_t len; + pdc_bool retval = pdc_false; + int slot = -1, i; + + /* host or UTF-8 encoded font name without BOM */ + fontname_p = pdc_utf8_to_hostbytes(p->pdc, pdc_false, fo->fontname); + if (fontname_p == NULL) + { + fontname = pdc_utf8strprint(p->pdc, fo->fontname); + } + else + { + fontname = pdc_utf8strprint(p->pdc, fontname_p); + pdc_free(p->pdc, fontname_p); + } + fontname_p = NULL; + + /* font encoding */ + encoding = fo->encoding; + encoding_aux = encoding; + + /* initialize font struct */ + font = &tmpfont; + pdf_init_font(p, font, fo); + + /* error message prefix */ + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX, fontname, encoding, 0, 0); + + + + + /* API font name */ + font->apiname = pdc_strdup(p->pdc, fontname); + + /* UTF-8 font name with BOM */ + font->ft.utf8name = pdc_strdup(p->pdc, fo->fontname); + + pdc_logg_cond(p->pdc, 1, trc_font, "\tFont UTF-8 name: \"%s\"\n", + font->ft.utf8name); + + /* specified encoding name */ + font->encapiname = pdc_strdup(p->pdc, encoding); + + /* search for a registered encoding */ + enc = pdc_find_encoding(p->pdc, encoding); + if (enc == pdc_invalidenc || enc == pdc_unicode) + { + /* search for a predefined CMap and registered fonts */ + if (!pdf_handle_cidfont(p, fontname, encoding, enc, font, &slot, &enc)) + goto PDF_PREMATURE_EXIT; + + if (enc == pdc_invalidenc) + { + /* search for a new encoding */ + enc = pdc_insert_encoding(p->pdc, encoding, &font->codepage, + font->verbose); + if (enc == pdc_invalidenc) + goto PDF_PREMATURE_EXIT; + } + else if (enc == pdc_cid) + { + if (slot == -1) + goto PDF_NEWFONT_EXIT; + else + goto PDF_PREMATURE_EXIT; + } + else if (enc == pdc_glyphid) + { + encoding_aux = "glyphid"; + } + else if (enc == pdc_unicode) + { + encoding_aux = "unicode"; + } + } + + if (pdc_strcmp(font->encapiname, encoding)) + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX2, + fontname, font->encapiname, encoding, 0); + } + encoding = encoding_aux; + + encoding = pdc_get_user_encoding(p->pdc, enc); + pdc_logg_cond(p->pdc, 1, trc_encoding, "\tFont encoding: \"%s\"\n", + encoding); + + if (enc == pdc_unicode || enc == pdc_glyphid) + { + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_UNICODE, 0, 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + + /* + * Look whether font is already in the cache. + * Look first for the auxiliary font (obj_id == -1). + * If a font with same encoding and same relevant options is found, + * return its handle. + * If a Type 3 font with the same name but different encoding + * is found, make a copy in a new slot and attach the requested encoding. + */ + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont will be searched in the PDFlib font cache\n"); + for (slot = 0; slot < p->fonts_number; slot++) + { + if (p->fonts[slot].obj_id == PDC_BAD_ID && + p->fonts[slot].ft.m.type != fnt_Type3) + { + if (font->opt.auxiliary) + goto PDF_PREMATURE_EXIT; + } + else if (!font->opt.auxiliary && + !pdc_strcmp(p->fonts[slot].apiname, fontname) && + p->fonts[slot].opt.fontstyle == font->opt.fontstyle) + { + if (p->fonts[slot].ft.m.type == fnt_Type3) + { + if (logg2) + pdc_logg(p->pdc, "\t\tType3 font [%d] found\n", slot); + + if (enc < pdc_winansi && enc != pdc_unicode) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + + slot = -1; + goto PDF_PREMATURE_EXIT; + } + + if (p->fonts[slot].ft.enc != enc) + { + if (!pdf_handle_t3font(p, fontname, enc, font, &slot)) + { + slot = -1; + goto PDF_PREMATURE_EXIT; + } + if (slot > -1) + font = &p->fonts[slot]; + goto PDF_NEWFONT_EXIT; + } + + goto PDF_PREMATURE_EXIT; + } + else if (p->fonts[slot].opt.monospace == font->opt.monospace + ) + { + if (p->fonts[slot].ft.enc == enc && + p->fonts[slot].codepage == font->codepage) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same encoding found\n", + slot); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + else + { + char *adaptname; + int kc; + + /* Comparing apiname of encoding */ + if (!pdc_stricmp(font->encapiname, + p->fonts[slot].encapiname) && + !pdc_stricmp(font->ft.cmapname, + p->fonts[slot].ft.cmapname)) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same encoding " + "apiname '%s' found\n", slot, encoding); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + + /* Name of adapted to font encoding */ + adaptname = + pdf_get_encoding_adaptname(p, enc, font, fontname); + kc = strcmp(adaptname, pdf_get_encoding_name(p, + p->fonts[slot].ft.enc, &p->fonts[slot])); + if (!kc) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same internal " + "encoding name '%s' found\n", + slot, adaptname); + pdc_free_tmp(p->pdc, adaptname); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + pdc_free_tmp(p->pdc, adaptname); + } + } + } + else if (!font->opt.auxiliary && + p->fonts[slot].ft.m.type == fnt_Type1 && + p->fonts[slot].ft.isstdfont && p->fonts[slot].ft.enc == enc) + { + /* different core font specifications */ + const char *fname = pdf_get_fontname_core(font, fontname, pdc_true); + + if ((fname != NULL && !strcmp(fname, p->fonts[slot].ft.name) && + p->fonts[slot].opt.fontstyle == fnt_Normal) || + (!strcmp(fontname, p->fonts[slot].ft.name) && + p->fonts[slot].opt.fontstyle == font->opt.fontstyle)) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same font style '%s' found\n", + slot, pdc_get_keyword(font->opt.fontstyle, + pdf_fontstyle_pdfkeylist)); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + } + } + + slot = -1; + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont not found in the PDFlib font cache\n"); + + /* embedding check */ + if (!pdf_check_font_embedding(p, font, fontname)) + { + goto PDF_PREMATURE_EXIT; + } + + /* Multiple Master handling: + * - strip MM parameters to build the master name + * - the master name is used to find the metrics + * - the instance name (client-supplied font name) is used in all places + * - although the master name is used for finding the metrics, the + * instance name is stored in the font struct. + */ + + len = strlen(fontname); + if (len > PDF_MAX_FONTNAME) + { + pdc_set_errmsg(p->pdc, FNT_E_FONT_NAMETOOLONG, + pdc_errprintf(p->pdc, "%d", PDF_MAX_FONTNAME), 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + strcpy(mastername, fontname); + + /* A Multiple Master font was requested */ + if ((mmparam = strstr(mastername, "MM_")) != NULL) + { + if (font->opt.embedding) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_EMBEDMM, 0, 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + mmparam[2] = '\0'; /* strip the parameter from the master name */ + } + + /* Font for vertical writing mode */ + fontname_p = mastername; + if (mastername[0] == '@') + { + font->ft.vertical = pdc_true; + fontname_p = &mastername[1]; + } + + /* protocol */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPDFlib font name: \"%s\"\n", fontname_p); + + /* Font file search hierarchy + * - Check "FontOutline" resource entry and check TrueType font + * - Check "FontAFM" resource entry + * - Check "FontPFM" resource entry + * - Check "HostFont" resource entry + * - Check available in-core metrics + * - Check host font + */ + retval = pdc_false; + while (1) + { +#ifdef PDF_TRUETYPE_SUPPORTED + /* Check specified TrueType file */ + filename = pdc_find_resource(p->pdc, "FontOutline", fontname_p); + if (!filename) + { + /* check for TTC font names with index */ + ittc = PDF_TTC_SEPARATOR; + sf = strrchr(fontname_p, ittc); + + if (sf != NULL) + { + *sf = 0; + filename = pdc_find_resource(p->pdc, "FontOutline", fontname_p); + *sf = ittc; + } + } + if (filename) + { + outfilename = filename; + retval = fnt_check_tt_font(p->pdc, filename, fontname_p, &font->ft, + pdc_false); + if (retval == pdc_true) + { + retval = pdf_get_metrics_tt(p, font, fontname_p, enc, filename); + break; + } + else if (retval == pdc_undef && + pdc_get_errnum(p->pdc) == PDC_E_IO_RDOPEN_NF) + { + /* file must be exist */ + retval = pdc_false; + } + if (retval == pdc_false) + break; + } +#endif /* PDF_TRUETYPE_SUPPORTED */ + + /* Check specified AFM file */ + filename = pdc_find_resource(p->pdc, "FontAFM", fontname_p); + if (filename) + { + retval = pdf_get_metrics_afm(p, font, fontname_p, enc, filename, + pdc_true); + break; + } + + /* Check specified PFM file */ + filename = pdc_find_resource(p->pdc, "FontPFM", fontname_p); + if (filename) + { + retval = pdf_get_metrics_pfm(p, font, fontname_p, enc, filename, + pdc_true); + break; + } + + + + /* Check available in-core metrics */ + retval = pdf_get_metrics_core(p, font, fontname_p, enc, pdc_false); + if (retval != pdc_undef) + break; + retval = pdc_false; + + + /* Check available in-core metrics */ + retval = pdf_get_metrics_core(p, font, fontname_p, enc, pdc_true); + if (retval != pdc_undef) + break; + retval = pdc_false; + + /* Searching for a metric file */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tSearching for font metrics data file:\n"); + + filename = testfilename; + for (i = 0; i < 100; i++) + { + extension = pdf_extension_names[i].word; + if (!extension) + break; + + strcpy(testfilename, fontname_p); + sf = strrchr(testfilename, PDF_TTC_SEPARATOR); + if (sf != NULL) + *sf = 0; + strcat(testfilename, extension); + + switch (pdf_extension_names[i].code) + { +#ifdef PDF_TRUETYPE_SUPPORTED + case font_ttot: + retval = fnt_check_tt_font(p->pdc, filename, fontname_p, + &font->ft, pdc_false); + if (retval == pdc_true) + retval = pdf_get_metrics_tt(p, font, fontname_p, enc, + filename); + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + case font_afm: + retval = pdf_get_metrics_afm(p, font, fontname_p, enc, + filename, pdc_false); + break; + + case font_pfm: + retval = pdf_get_metrics_pfm(p, font, fontname_p, enc, + filename, pdc_false); + break; + + default: + break; + } + + /* file found or error */ + if (retval != pdc_undef) + { + if (retval == pdc_true) + if (pdf_extension_names[i].code == font_ttot) + outfilename = filename; + break; + } + } + + if (retval == pdc_undef) + { + retval = pdc_false; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tMetric data file for font \"%s\" not available\n", + fontname_p); + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOMETRICS, 0, 0, 0, 0); + } + + break; + } + + /* metrics data search finished */ + + if (retval == pdc_false) + { + goto PDF_PREMATURE_EXIT; + } + + /* store instance name instead of master name in the font structure */ + if (mmparam) + { + pdc_free(p->pdc, font->ft.name); + font->ft.name = pdc_strdup(p->pdc, fontname); + pdc_free(p->pdc, font->ft.m.name); + font->ft.m.name = pdc_strdup(p->pdc, fontname); + } + + /* If embedding was requested, check font file (or raise an exception) */ + if (font->opt.embedding) + { + if (font->ft.img == NULL) + { + retval = pdc_undef; + + if (outfilename) + { + /* Font outline file specified */ + if (font->ft.m.type == fnt_Type1 || + font->ft.m.type == fnt_MMType1) + { + retval = pdf_t1open_fontfile(p, font, outfilename, NULL, + pdc_true); + } + else + { + retval = fnt_check_tt_font(p->pdc, outfilename, NULL, + &font->ft, pdc_true); + } + } + else + { + /* Searching font outline file */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tSearching for font outline data file:\n"); + + outfilename = testfilename; + for (i = 0; i < 100; i++) + { + extension = pdf_extension_names[i].word; + if (!extension) + break; + + strcpy(testfilename, fontname_p); + strcat(testfilename, extension); + + if (font->ft.m.type == fnt_Type1 || + font->ft.m.type == fnt_MMType1) + { + if (pdf_extension_names[i].code == font_pfab) + { + retval = pdf_t1open_fontfile(p, font, outfilename, + NULL, pdc_false); + } + } + else if (pdf_extension_names[i].code == font_ttot) + { + retval = fnt_check_tt_font(p->pdc, outfilename, + NULL, &font->ft, pdc_false); + } + + /* file found or error */ + if (retval != pdc_undef) + break; + } + + if (retval == pdc_undef) + { + retval = pdc_false; + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOOUTLINE, 0, 0, 0, 0); + } + } + + if (retval == pdc_false) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tOutline data file for font \"%s\" not found\n", + fontname_p); + } + else + { + if (!font->ft.img) + font->filename = font->ft.filename; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont outline data file \"%s\" available\n", + font->filename ? + font->filename : font->ft.imgname); + } + } + } + else if (font->ft.img) + { + if (!font->ft.imgname) + pdc_free(p->pdc, font->ft.img); + else + { + pdc_unlock_pvf(p->pdc, font->ft.imgname); + pdc_free(p->pdc, font->ft.imgname); + font->ft.imgname = NULL; + } + font->ft.img = NULL; + font->ft.filelen = 0; + } + + if (retval && font->opt.monospace && font->opt.embedding) + { + pdc_set_errmsg(p->pdc, PDC_E_OPT_IGNORED, "monospace", 0, 0, 0); + retval = pdc_false; + } + + if (retval == pdc_false) + { + goto PDF_PREMATURE_EXIT; + } + + PDF_NEWFONT_EXIT: + + pdf_cleanup_font_options(p, fo); + + encoding = pdc_get_user_encoding(p->pdc, font->ft.enc); + if (pdc_strcmp(font->encapiname, encoding)) + pdc_logg_cond(p->pdc, 1, trc_encoding, + "\tDetermined font encoding: \"%s\"\n", encoding); + + /* set missing font metrics values */ + pdf_font_set_missvalues(p, font); + + /* font is semantic (Unicode compatible) */ + pdf_font_issemantic(p, font); + + /* set replacement character and code */ + pdf_set_replchar(p, font); + + /* font object ID */ + if (!font->opt.auxiliary) + font->obj_id = pdc_alloc_id(p->out); + + /* Now everything is fine, insert font */ + if (slot == -1) + slot = pdf_insert_font(p, font); + + + pdc_pop_errmsg(p->pdc); + + return slot; + + + PDF_PREMATURE_EXIT: + + pdf_cleanup_font_options(p, fo); + pdf_cleanup_font(p, font); + + if (slot == -1) + { + if (font->verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + + pdc_pop_errmsg(p->pdc); + + return slot; +} + + +/* --------------------------- font writing ---------------------------- */ + +static char * +pdf_code2fontglyphname(pdf_font *font, pdc_encodingvector *ev, int code) +{ + char *glyphname; + + glyphname = ev->chars[code]; + pdc_get_alter_glyphname(ev->codes[code], font->missingglyphs, + &glyphname); + + return glyphname ? glyphname : (char *) pdc_get_notdef_glyphname(); +} + +void +pdf_transform_fontwidths(PDF *p, pdf_font *font, pdc_encodingvector *evto, + pdc_encodingvector *evfrom) +{ + int widths[256]; + pdc_ushort code2gid[256]; + int i, j; + + for (i = 0; i < 256; i++) + { + widths[i] = font->ft.m.defwidth; + code2gid[i] = 0; + } + + for (i = 0; i < 256; i++) + { + j = (int) pdc_transform_bytecode(p->pdc, evto, evfrom, (pdc_byte)i); + widths[j] = font->ft.m.widths[i]; + if (font->ft.code2gid != NULL) + code2gid[j] = font->ft.code2gid[i]; + } + + widths[0] = font->ft.m.defwidth; + memcpy(font->ft.m.widths, widths, 256 * sizeof(int)); + if (font->ft.code2gid != NULL) + memcpy(font->ft.code2gid, code2gid, 256 * sizeof(pdc_ushort)); +} + + + +static void +pdf_write_fontdescriptor( + PDF *p, + pdf_font *font, + int missingwidth, + pdc_id fontdescriptor_id, + pdc_id cidset_id, + pdc_id fontfile_id, + int nusedgids) +{ + (void) cidset_id; + (void) nusedgids; + + /* + * Font descriptor object + */ + pdc_begin_obj(p->out, fontdescriptor_id); /* font descriptor obj */ + pdc_begin_dict(p->out); /* font descriptor dict */ + + pdc_puts(p->out, "/Type/FontDescriptor\n"); + pdc_printf(p->out, "/Flags %ld\n", font->ft.m.flags); + + + pdc_printf(p->out, "/Ascent %d\n", font->ft.m.ascender); + pdc_printf(p->out, "/CapHeight %d\n", font->ft.m.capHeight); + pdc_printf(p->out, "/Descent %d\n", font->ft.m.descender); + pdc_printf(p->out, "/FontBBox[%d %d %d %d]\n", + (int) font->ft.m.llx, (int) font->ft.m.lly, + (int) font->ft.m.urx, (int) font->ft.m.ury); + + pdc_printf(p->out, "/FontName"); + pdf_put_pdfname(p, font->ft.m.name); + pdc_puts(p->out, "\n"); + + pdc_printf(p->out, "/ItalicAngle %d\n", (int) (font->ft.m.italicAngle)); + pdc_printf(p->out, "/StemV %d\n", font->ft.m.StdVW); + + if (font->ft.m.StdHW > 0) + pdc_printf(p->out, "/StemH %d\n", font->ft.m.StdHW); + + if (font->ft.m.xHeight > 0) + pdc_printf(p->out, "/XHeight %d\n", font->ft.m.xHeight); + + if (missingwidth > 0) + pdc_printf(p->out, "/MissingWidth %d\n", missingwidth); + + if (fontfile_id != PDC_BAD_ID) + { + switch(font->ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: + pdc_objref(p->out, "/FontFile", fontfile_id); + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + pdc_objref(p->out, "/FontFile2", fontfile_id); + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + pdc_objref(p->out, "/FontFile3", fontfile_id); + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + } + + + pdc_end_dict(p->out); /* font descriptor dict */ + pdc_end_obj(p->out); /* font descriptor obj */ +} + +static void +pdf_put_font(PDF *p, pdf_font *font) +{ + const char *fontname = font->ft.name; + fnt_fonttype fonttype = font->ft.m.type; + pdc_id fontdescriptor_id = PDC_BAD_ID; + pdc_id fontfile_id = PDC_BAD_ID; + pdc_id encoding_id = PDC_BAD_ID; + pdc_id cidset_id = PDC_BAD_ID; + pdc_id length_id = PDC_BAD_ID; + pdc_id descendant_id = PDC_BAD_ID; + pdc_encoding enc = font->ft.enc; + const char *encoding; + pdc_encoding_info *encinfo = NULL; + pdc_bool comp_font = pdc_false; + pdc_bool acro_fontstyle = pdc_false; + pdc_scalar a = 1.0; + PDF_data_source src; + int nusedgids = 0; + + /* save font struct members */ + pdc_encodingvector *ev = NULL; + pdc_encoding font_encoding = font->ft.enc; + int font_numcodes = font->ft.numcodes; + int font_codesize = font->codesize; + + int missingwidth = 0; + int i; + + encoding = pdc_get_user_encoding(p->pdc, enc); + if (!pdc_strcmp(font->encapiname, encoding)) + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX, + font->apiname, font->encapiname, 0, 0); + } + else + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX2, + font->apiname, font->encapiname, encoding, 0); + } + + + /* ID for embedded font */ + if (font->opt.embedding) + { + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: + case fnt_CIDFontType0: + fontfile_id = pdc_alloc_id(p->out); + break; + + default: + break; + } + } + + /* + * Font dictionary + */ + pdc_begin_obj(p->out, font->obj_id); /* font obj */ + pdc_begin_dict(p->out); /* font dict */ + pdc_puts(p->out, "/Type/Font\n"); + + /* /Subtype */ + pdc_printf(p->out, "/Subtype/%s\n", + pdc_get_keyword(fonttype, pdf_fonttype_pdfkeylist)); + comp_font = fonttype == fnt_CIDFontType0 || fonttype == fnt_CIDFontType2; + + /* Acrobat font style */ + acro_fontstyle = font->opt.fontstyle != fnt_Normal && + !(font->metricflags & (font_bold | font_italic)); + + /* /Name */ + if (fonttype == fnt_Type3 || font->used_in_formfield) + { + /* + * The name is optional, but if we include it it will show up + * in Acrobat's font info box. However, if the same font name + * is used with different encodings Acrobat 4 will not be + * able to distinguish both. For this reason we add the + * encoding name to make the font name unique. + */ + + const char *name = fontname; + + if (font->used_in_formfield) + name = pdf_get_pdf_fontname(font); + + pdc_puts(p->out, "/Name"); + pdf_put_pdfname(p, name); + pdc_puts(p->out, "\n"); + } + + /* /BaseFont */ + switch (fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + case fnt_CIDFontType2: + case fnt_CIDFontType0: + { + pdc_puts(p->out, "/BaseFont"); + pdf_put_pdfname(p, fontname); + if (font->outcmapname) + pdc_printf(p->out, "-%s", font->outcmapname); + if (acro_fontstyle && !comp_font) + pdc_printf(p->out, ",%s", pdc_get_keyword(font->opt.fontstyle, + pdf_fontstyle_pdfkeylist)); + pdc_puts(p->out, "\n"); + } + break; + + /* /FontBBox, /FontMatrix, /CharProcs /Resources */ + case fnt_Type3: + if (font->t3font->charprocs_id == PDC_BAD_ID) + pdc_error(p->pdc, PDF_E_T3_OUTLINESMISSING, fontname, 0, 0, 0); + + pdc_printf(p->out, "/FontBBox[%f %f %f %f]\n", + font->ft.bbox.llx, font->ft.bbox.lly, + font->ft.bbox.urx, font->ft.bbox.ury); + + pdc_printf(p->out, "/FontMatrix[%f %f %f %f %f %f]\n", + font->ft.matrix.a, font->ft.matrix.b, + font->ft.matrix.c, font->ft.matrix.d, + font->ft.matrix.e, font->ft.matrix.f); + pdc_objref(p->out, "/CharProcs", font->t3font->charprocs_id); + pdc_objref(p->out, "/Resources", font->t3font->res_id); + + /* We must apply a correctional factor since Type 3 fonts not + * necessarily use 1000 units per em. We apply the correction + * here, and store the 1000-based width values in the font in + * order to speed up PDF_stringwidth(). + */ + a = 1000 * font->ft.matrix.a; + break; + + default: + break; + } + + /* changing 8-bit font encoding to builtin */ + if (enc >= 0 && font->symenc != pdc_invalidenc) + { + ev = NULL; + enc = pdc_builtin; + font->ft.enc = enc; + } + + /* changing 8-bit font encoding to winansi */ + if (font->towinansi != pdc_invalidenc) + { + pdc_encodingvector *evfrom; + + ev = pdc_get_encoding_vector(p->pdc, font->towinansi); + evfrom = pdc_get_encoding_vector(p->pdc, enc); + pdf_transform_fontwidths(p, font, ev, evfrom); + + enc = font->towinansi; + font->ft.enc = enc; + } + + /* /FontDescriptor, /FirstChar, /LastChar, /Widths */ + switch (fonttype) + { + case fnt_Type1: + /* disabled, because of PDF 1.7 reference + if (font->ft.isstdfont == pdc_true) break; + */ + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + case fnt_Type3: + { + int firstchar = 0; + int lastchar = 255; + int defwidth = 0; + + if (fonttype != fnt_Type3 + ) + { + fontdescriptor_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/FontDescriptor", fontdescriptor_id); + } + + + /* determine missing width. + * Only for embedded fonts because of a bug in Acrobat, + * which arises if the font is not installed at host. + */ + if (font->opt.embedding) + { + if (fonttype != fnt_Type3) + defwidth = font->ft.m.widths[0]; + + { + for (i = 1; i < 255; i++) + { + if (font->ft.m.widths[i] != defwidth) + break; + } + if (i > 1) + firstchar = i; + for (i = 255; i > 0; i--) + { + if (i == firstchar || font->ft.m.widths[i] != defwidth) + break; + } + lastchar = i; + } + + if (firstchar > 0 || lastchar < 255) + missingwidth = (int) (defwidth / a + 0.5); + } + + pdc_printf(p->out, "/FirstChar %d\n", firstchar); + pdc_printf(p->out, "/LastChar %d\n", lastchar); + + pdc_puts(p->out, "/Widths"); + pdc_begin_array(p->out); + for (i = firstchar; i <= lastchar; i++) + { + pdc_printf(p->out, "%d", + (int) (font->ft.m.widths[i] / a + .5)); + if (i < 255) + pdc_printf(p->out, "%s", ((i + 1) % 16) ? " " : "\n"); + } + pdc_end_array(p->out); + } + break; + + default: + break; + } + + /* /Encoding */ + switch (fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + if (!font->used_in_formfield) + { + if (enc == pdc_winansi) + { + pdc_printf(p->out, "/Encoding/WinAnsiEncoding\n"); + break; + } + if (enc == pdc_macroman && font->hasnomac == pdc_false) + { + pdc_printf(p->out, "/Encoding/MacRomanEncoding\n"); + break; + } + } + case fnt_Type3: + if (enc >= 0) + { + encinfo = pdc_get_encoding_info(p->pdc, enc); + if (encinfo->id == PDC_BAD_ID) + encinfo->id = pdc_alloc_id(p->out); + encoding_id = encinfo->id; + } + + if (encoding_id != PDC_BAD_ID) + pdc_objref(p->out, "/Encoding", encoding_id); + + if (encinfo != NULL) + { + if (!encinfo->stored) + encinfo->stored = pdc_true; + else + encoding_id = PDC_BAD_ID; + } + + break; + + case fnt_CIDFontType2: + case fnt_CIDFontType0: + if (font->outcmapname) + { + pdc_printf(p->out, "/Encoding/%s\n", font->outcmapname); + } + break; + + default: + break; + } + + /* /ToUnicode . Only reasonable if nusedgids != 1 + * (== 1: only notdef character in a font subset) + */ + + + /* /DescendantFonts */ + if (comp_font == pdc_true) + { + descendant_id = pdc_alloc_id(p->out); + pdc_puts(p->out, "/DescendantFonts"); + pdc_begin_array(p->out); + pdc_objref(p->out, "", descendant_id); + pdc_end_array(p->out); + } + + pdc_end_dict(p->out); /* font dict */ + pdc_end_obj(p->out); /* font obj */ + + /* + * Encoding dictionary + */ + if (encoding_id != PDC_BAD_ID) + { + char *glyphname; + + pdc_begin_obj(p->out, encoding_id); /* encoding obj */ + pdc_begin_dict(p->out); /* encoding dict */ + + pdc_puts(p->out, "/Type/Encoding\n"); + + { + pdc_encodingvector *evb = NULL; + + pdc_set_encoding_glyphnames(p->pdc, enc); + ev = pdc_get_encoding_vector(p->pdc, enc); + + /* See Implementation Note 46. The restrictions described there + * are also valid for Acrobat versions up to now. + */ + if (fonttype != fnt_Type3 && !font->used_in_formfield) + { + if (!strncmp(ev->apiname, PDC_ENC_MODWINANSI, + strlen(PDC_ENC_MODWINANSI)) || + !strncmp(ev->apiname, PDC_ENC_ISO8859, + strlen(PDC_ENC_ISO8859)) || + !strncmp(ev->apiname, PDC_ENC_CP125, + strlen(PDC_ENC_CP125))) + { + pdc_puts(p->out, "/BaseEncoding/WinAnsiEncoding\n"); + evb = pdc_get_encoding_vector(p->pdc, pdc_winansi); + } + else if (!strncmp(ev->apiname, PDC_ENC_MODMACROMAN, + strlen(PDC_ENC_MODMACROMAN))) + { + pdc_puts(p->out, "/BaseEncoding/MacRomanEncoding\n"); + evb = pdc_get_encoding_vector(p->pdc, pdc_macroman); + } + else + { + /* /BaseEncoding/StandardEncoding */ + evb = pdc_get_encoding_vector(p->pdc, pdc_stdenc); + } + } + + if (evb != NULL) + { + int iv = -1; + for (i = 0; i < font->ft.numcodes; i++) + { + glyphname = pdf_code2fontglyphname(font, ev, i); + + /* enforce first three names because of bug in Acrobat 6 */ + if (i < 3 || + (glyphname && !evb->chars[i]) || + (!glyphname && evb->chars[i]) || + (glyphname && evb->chars[i] && + strcmp(glyphname, evb->chars[i]))) + { + if (iv == -1) + pdc_puts(p->out, "/Differences[0"); + if (i > iv + 1) + pdc_printf(p->out, "%d", i); + pdf_put_pdfname(p, glyphname); + pdc_puts(p->out, "\n"); + iv = i; + } + } + if (iv > -1) + pdc_end_array(p->out); + } + else + { + pdc_puts(p->out, "/Differences[0"); + for (i = 0; i < font->ft.numcodes; i++) + { + glyphname = pdf_code2fontglyphname(font, ev, i); + pdf_put_pdfname(p, glyphname); + pdc_puts(p->out, "\n"); + } + pdc_end_array(p->out); + } + } + + pdc_end_dict(p->out); /* encoding dict */ + pdc_end_obj(p->out); /* encoding obj */ + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + } + + + /* + * CID fonts dictionary + */ + if (descendant_id != PDC_BAD_ID) + { + pdc_begin_obj(p->out, descendant_id); /* CID font obj */ + pdc_begin_dict(p->out); /* CID font dict */ + pdc_puts(p->out, "/Type/Font\n"); + + /* /Subtype */ + if (fonttype == fnt_CIDFontType0) + pdc_puts(p->out, "/Subtype/CIDFontType0\n"); + if (fonttype == fnt_CIDFontType2) + pdc_puts(p->out, "/Subtype/CIDFontType2\n"); + + /* /BaseFont */ + pdc_puts(p->out, "/BaseFont"); + pdf_put_pdfname(p, fontname); + if (acro_fontstyle) + pdc_printf(p->out, ",%s", + pdc_get_keyword(font->opt.fontstyle, pdf_fontstyle_pdfkeylist)); + pdc_puts(p->out, "\n"); + + /* /CIDSystemInfo */ + pdc_puts(p->out, "/CIDSystemInfo<</Registry"); + pdf_put_hypertext(p, "Adobe"); + pdc_puts(p->out, "/Ordering"); + pdf_put_hypertext(p, fnt_get_ordering_cid(font->ft.m.charcoll)); + pdc_printf(p->out, "/Supplement %d>>\n", MAX(font->supplement, 0)); + + /* /FontDescriptor */ + fontdescriptor_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/FontDescriptor", fontdescriptor_id); + + + + /* /DW /W */ +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED + if (font->ft.isstdfont) + pdf_put_cidglyph_widths(p, font); +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ + + + pdc_end_dict(p->out); /* CID font dict */ + pdc_end_obj(p->out); /* CID font obj */ + + } + + + /* + * FontDescriptor dictionary + */ + if (fontdescriptor_id != PDC_BAD_ID) + pdf_write_fontdescriptor(p, font, missingwidth, fontdescriptor_id, + cidset_id, fontfile_id, nusedgids); + + + + /* + * Font embedding + */ + if (fontfile_id != PDC_BAD_ID) + { + pdc_id length1_id = PDC_BAD_ID; + pdc_id length2_id = PDC_BAD_ID; + pdc_id length3_id = PDC_BAD_ID; + pdc_bool compress = pdc_false; + + /* Prepare embedding */ + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + { + pdf_make_t1src(p, font, &src); + length1_id = pdc_alloc_id(p->out); + length2_id = pdc_alloc_id(p->out); + length3_id = pdc_alloc_id(p->out); + } + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + { + length1_id = pdc_alloc_id(p->out); + } + case fnt_Type1C: + case fnt_CIDFontType0: + case fnt_OpenType: + { + src.private_data = (void *) font->filename; + if (font->filename) + { + /* Read the font from file */ + src.init = pdf_data_source_file_init; + src.fill = pdf_data_source_file_fill; + src.terminate = pdf_data_source_file_terminate; + switch(fonttype) + { + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_OpenType: + src.offset = (long) 0; + src.length = (long) 0; + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + src.offset = font->cff_offset; + src.length = (long) font->cff_length; + break; + + default: + break; + } + } + else + { + /* Read the font from memory */ + src.init = NULL; + src.fill = pdf_data_source_buf_fill; + src.terminate = NULL; + switch(fonttype) + { + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_OpenType: + src.buffer_start = font->ft.img; + src.buffer_length = font->ft.filelen; + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + src.buffer_start = font->ft.img + font->cff_offset; + src.buffer_length = font->cff_length; + break; + + default: + break; + } + src.bytes_available = 0; + src.next_byte = NULL; + } + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + + /* Embedded font stream dictionary */ + pdc_begin_obj(p->out, fontfile_id); /* Embedded font stream obj */ + pdc_begin_dict(p->out); /* Embedded font stream dict */ + + /* /Length, /Filter */ + length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", length_id); + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: + case fnt_CIDFontType0: + case fnt_OpenType: + if (font->ft.filelen != 0L) + { + compress = pdc_true; + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + + /* /Length1, /Length2, Length3 */ + if (length1_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length1", length1_id); + if (length2_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length2", length2_id); + if (length3_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length3", length3_id); + +#ifdef PDF_TRUETYPE_SUPPORTED + /* /Subtype */ + if(fonttype == fnt_Type1C) + pdc_puts(p->out, "/Subtype/Type1C\n"); + if (fonttype == fnt_CIDFontType0) + pdc_puts(p->out, "/Subtype/CIDFontType0C\n"); + if (fonttype == fnt_OpenType) + pdc_puts(p->out, "/Subtype/OpenType\n"); +#endif /* PDF_TRUETYPE_SUPPORTED */ + + + pdc_end_dict(p->out); /* Embedded font stream dict */ + + /* Stream */ + pdf_copy_stream(p, &src, compress); + + pdc_end_obj(p->out); /* Embedded font stream obj */ + + pdc_put_pdfstreamlength(p->out, length_id); + + /* Length objects */ + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + pdf_put_length_objs(p, &src, length1_id, length2_id, length3_id); + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + if (compress) + { + pdc_begin_obj(p->out, length1_id); /* Length1 obj */ + pdc_printf(p->out, "%ld\n", (long) font->ft.filelen); + pdc_end_obj(p->out); /* Length1 obj */ + } + else + { + /* same as /Length */ + pdc_put_pdfstreamlength(p->out, length1_id); + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + } + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + /* restore font struct members */ + font->ft.enc = font_encoding; + font->ft.numcodes = font_numcodes; + font->codesize = font_codesize; + + pdc_pop_errmsg(p->pdc); +} + +void +pdf_write_doc_fonts(PDF *p) +{ + int slot; + pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_font); + + /* output pending font objects */ + for (slot = 0; slot < p->fonts_number; slot++) + { + pdf_font *font = &p->fonts[slot]; + + switch(p->fonts[slot].ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: +#endif /* PDF_TRUETYPE_SUPPORTED */ + case fnt_CIDFontType0: + case fnt_Type3: + if (font->obj_id != PDC_BAD_ID) + { + if (logg1) + { + pdc_logg(p->pdc, + "\tProcessing font %d: \"%s\" " + "with encoding \"%s\" and PDF object id %ld", + slot, font->ft.name, + pdf_get_encoding_name(p, font->ft.enc, font), + font->obj_id); + } + + if (font->ft.enc == pdc_invalidenc || + font->used_in_current_doc == pdc_false) + { + if (logg1) + pdc_logg(p->pdc, " - but not used\n", font->obj_id); + + /* + * This font has been defined, but never used in the + * document. Ignore it. However, the font's object id + * has already been allocated, so we mark the object + * as free in order to avoid a complaint of the object + * machinery. + */ + pdc_mark_free(p->out, font->obj_id); + } + else + { + if (logg1) + pdc_logg(p->pdc, "\n"); + + pdf_put_font(p, font); + } + } + break; + + default: + break; + } + } +} + +void +pdf_write_page_fonts(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->fn_bias; + + /* This doesn't really belong here, but all modules which write + * font resources also need this, so we include it here. + * Note that keeping track of ProcSets is considered obsolete + * starting with PDF 1.4, so we always include the full set which + * is written as a constant object at the beginning of the file. + */ + + pdc_objref(p->out, "/ProcSet", p->procset_id); + + for (i = 0; i < p->fonts_number; i++) + if (p->fonts[i].used_on_current_page == pdc_true) + total++; + + if (total > 0 || bias) + { + pdc_puts(p->out, "/Font"); + pdc_begin_dict(p->out); /* font resource dict */ + } + + if (total > 0) + { + for (i = 0; i < p->fonts_number; i++) + { + if (p->fonts[i].used_on_current_page == pdc_true) { + p->fonts[i].used_on_current_page = pdc_false; /* reset */ + pdc_printf(p->out, "/F%d", bias + i); + pdc_objref(p->out, "", p->fonts[i].obj_id); + } + } + + if (!bias) + pdc_end_dict(p->out); /* font resource dict */ + } +} + +void +pdf_get_page_fonts(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->fonts_number; i++) + { + if (p->fonts[i].used_on_current_page) + { + p->fonts[i].used_on_current_page = pdc_false; /* reset */ + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_font(PDF *p, int ft) +{ + p->fonts[ft].used_on_current_page = pdc_true; +} + + + diff --git a/src/pdflib/pdflib/p_font.h b/src/pdflib/pdflib/p_font.h new file mode 100644 index 0000000..3dc4d91 --- /dev/null +++ b/src/pdflib/pdflib/p_font.h @@ -0,0 +1,225 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_font.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Header file for the PDFlib font subsystem + * + */ + +#ifndef P_FONT_H +#define P_FONT_H + +#define PDF_DEFAULT_CHAR PDC_UNICODE_SPACE + +/* internal maximal length of fontnames */ +#define PDF_MAX_FONTNAME 128 + +/* last text rendering mode number */ +#define PDF_LAST_TRMODE 7 + +/* minimal number of glyphs for appropriate encoding */ +#define PDF_MIN_GLYPHS 5 + +typedef enum +{ + font_ascender = (1<<0), + font_descender = (1<<1), + font_capheight = (1<<2), + font_xheight = (1<<3), + font_linegap = (1<<4), + + font_italic = (1<<8), + font_bold = (1<<9) +} +pdf_font_values; + +typedef struct pdf_t3glyph_s pdf_t3glyph; + +/* font options */ +struct pdf_font_options_s +{ + pdc_bool embedding; + char *encoding; + int flags; + char *fontname; + fnt_fontstyle fontstyle; + pdc_bool fontwarning; + int mask; + int monospace; + int ascender; + int descender; + int capheight; + int xheight; + int linegap; + pdc_bool auxiliary; +}; + +/* Type3 font structures */ +struct pdf_t3glyph_s +{ + char *name; + pdc_id charproc_id; + pdc_scalar wx; + pdc_scalar llx; + pdc_scalar lly; + pdc_scalar urx; + pdc_scalar ury; + pdc_scalar width; + int pass; /* 0, 1, 2 */ +}; + +struct pdf_t3font_s +{ + pdf_t3glyph *glyphs; /* dynamically growing glyph table */ + int capacity; /* current number of slots */ + int next_glyph; /* next available slot */ + int curr_glyph; /* slot of current glyph */ + + pdc_id charprocs_id; /* id of /CharProcs dict */ + pdc_id res_id; /* id of /Resources dict */ + pdc_bool colorized; /* glyphs colorized */ + int pass; /* 0, 1, 2 */ + +}; + +/* pdflib font structure */ +struct pdf_font_s +{ + /* pdcore font structure */ + fnt_font ft; + + /* font options */ + pdf_font_options opt; /* pdflib font options */ + pdc_bool verbose; /* put out warning/error messages */ + + /* special font names */ + char *apiname; /* font name specified in API call */ + const char *filename; /* name of font file, copy of ft.filename */ + char *metricfilename; /* name of metric font file */ + + /* font control */ + pdc_bool used_in_formfield; /* this font is in use in form field */ + pdc_bool used_in_current_doc; /* this font is in use in current doc. */ + pdc_bool used_on_current_page; /* this font is in use on current page */ + pdc_id obj_id; /* object id of this font */ + + /* CFF table */ + long cff_offset; /* start of CFF table in font */ + size_t cff_length; /* length of CFF table in font */ + + /* Type3 font */ + pdf_t3font *t3font; /* Type3 font data */ + pdc_bool hasoriginal; /* has the original Type3 font data */ + + /* pdflib encoding and CMap properties */ + char *encapiname; /* encoding name specified in API call */ + char *outcmapname; /* output CMap namel */ + int codepage; /* OEM multi byte code-page number */ + pdc_encoding towinansi; /* convert to 'towinansi' enc. for output */ + pdc_bool hasnomac; /* TT font has no macroman cmap */ + pdc_bool passthrough; /* text will be passed through as is */ + pdc_bool unibyte; /* take Unicode encoding as byte encoding */ + pdc_bool asciispace; /* encoding has space at x20 */ + pdc_bool issemantic; /* encoding is Unicode interpretable */ + pdc_bool widthsmissing; /* GID widths not available */ + pdc_ulong missingglyphs; /* bit mask for missing new AGL glyphs */ + int metricflags; /* flags for faked font values */ + int supplement; /* supplement number of CMap + * = -1: Identity-H/V */ + pdc_encoding symenc; /* font encoding for symbol fonts */ + int replacementchar; /* replacement character */ + int replacementcode; /* replacement code or glyph id resp. */ + + /* encoding and glyph control */ + int codesize; /* code size */ + /* = 0: unknown, no Unicode CMap */ + /* = 1: 1 byte encoding */ + /* = 2: 2 byte encoding */ + int lastcode; /* AFM: last byte code for generating runtime */ + /* byte encoding. = -1: ignore */ + int gid0code; /* code für gid 0 (because of Type3 fonts) */ + pdc_byte *usedgids; /* used Glyph IDs for font subsetting */ + pdc_bool expectglyphs; /* TT: glyph id text strings are expected */ + pdc_bool iscidfont; /* is CID font */ + +}; + +/* p_truetype.c */ +pdc_bool pdf_get_metrics_tt(PDF *p, pdf_font *font, + const char *fontname, pdc_encoding enc, + const char *filename); +int pdf_check_tt_hostfont(PDF *p, const char *hostname); + +/* p_afm.c */ +pdc_bool pdf_process_metrics_data(PDF *p, pdf_font *font, + const char *fontname); +pdc_bool pdf_get_metrics_afm(PDF *p, pdf_font *font, + const char *fontname, pdc_encoding enc, + const char *filename, pdc_bool requested); + +/* p_pfm.c */ +pdc_bool pdf_check_pfm_encoding(PDF *p, pdf_font *font, + pdc_encoding enc); +pdc_bool pdf_get_metrics_pfm(PDF *p, pdf_font *font, + const char *fontname, pdc_encoding enc, + const char *filename, pdc_bool requested); + +/* p_cid.c */ +pdc_bool pdf_handle_cidfont(PDF *p, const char *fontname, + const char *encoding, pdc_encoding enc, pdf_font *font, int *o_slot, + pdc_encoding *newenc); +void pdf_put_cidglyph_widths(PDF *p, pdf_font *font); + +/* p_font.c */ +void pdf_get_page_fonts(PDF *p, pdf_reslist *rl); +void pdf_parse_font_options(PDF *p, const char *optlist); +double pdf_get_font_float_option(PDF *p, pdf_font_optflags fflags); +pdc_bool pdf_check_font_embedding(PDF *p, pdf_font *font, const char *fontname); +pdc_bool pdf_make_fontflag(PDF *p, pdf_font *font); +int pdf_get_code_or_glyphid(PDF *p, pdf_font *font, pdc_encodingvector *ev, + pdc_ushort uv); +void pdf_set_replchar(PDF *p, pdf_font *font); +void pdf_font_issemantic(PDF *p, pdf_font *font); +void pdf_font_set_missvalues(PDF *p, pdf_font *font); +pdc_bool pdf_font_get_is_faked(pdf_font *font, pdf_font_values flag); +double pdf_font_get_metric_value(int value); +const char *pdf_get_encoding_name(PDF *p, pdc_encoding enc, pdf_font *font); +const char *pdf_get_font_char_option(PDF *p, pdf_font_optflags fflags); +const char *pdf_get_pdf_fontname(pdf_font *font); +char *pdf_get_encoding_adaptname(PDF *p, pdc_encoding enc, pdf_font *font, + const char *fontname); +pdc_encodingvector *pdf_create_font_encoding(PDF *p, pdc_encoding enc, + pdf_font *font, const char *fontname, pdc_bool kreg); +void pdf_transform_fontwidths(PDF *p, pdf_font *font, + pdc_encodingvector *evto, pdc_encodingvector *evfrom); + +/* p_type1.c */ +pdc_bool pdf_t1open_fontfile(PDF *p, pdf_font *font, const char *fontname, + PDF_data_source *t1src, pdc_bool requested); +pdc_bool pdf_make_t1src(PDF *p, pdf_font *font, PDF_data_source *t1src); +void pdf_put_length_objs(PDF *p, PDF_data_source *t1src, + pdc_id length1_id, pdc_id length2_id, pdc_id length3_id); + +/* p_type3.c */ +void pdf_cleanup_t3font(PDF *p, pdf_t3font *t3font); +void pdf_init_type3(PDF *p); +pdc_bool pdf_handle_t3font(PDF *p, const char *fontname, pdc_encoding enc, + pdf_font *font, int *slot); +pdc_bool pdf_isvalid_font(PDF *p, int slot); + +/* p_subsett.c */ +int pdf_prepare_ttfont(PDF *p, pdf_font *font); + + +#endif /* P_FONT_H */ + diff --git a/src/pdflib/pdflib/p_generr.h b/src/pdflib/pdflib/p_generr.h new file mode 100644 index 0000000..166e0f7 --- /dev/null +++ b/src/pdflib/pdflib/p_generr.h @@ -0,0 +1,705 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_generr.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib error messages + * + */ + +#define P_GENERR_H + +#if pdf_genNames +#define gen(n, num, nam, msg) PDF_E_##nam = num, +#elif pdf_genInfo +#define gen(n, num, nam, msg) { n, num, msg, (const char *) 0 }, + +#else +#error invalid inclusion of generator file +#endif + + +/* -------------------------------------------------------------------- */ +/* Configuration (20xx) */ +/* -------------------------------------------------------------------- */ + +gen(0, 2000, UNSUPP_CRYPT, "Encryption not supported in PDFlib Lite") + +gen(0, 2002, UNSUPP_KERNING, "Kerning not supported in PDFlib Lite") + +gen(0, 2003, UNSUPP_FONTINFO, "Font info not supported in PDFlib Lite") + +gen(0, 2004, UNSUPP_SUBSET, "Subsetting not supported in PDFlib Lite") + +gen(0, 2006, UNSUPP_PDFX, "PDF/X not supported in PDFlib Lite") + +gen(1, 2008, UNSUPP_IMAGE, "$1 images not supported in this configuration") + +gen(0, 2010, UNSUPP_ICC, "ICC profiles not supported in PDFlib Lite") + +gen(0, 2012, UNSUPP_UNICODE, + "Unicode and glyph id addressing not supported in PDFlib Lite") + +gen(0, 2014, UNSUPP_SPOTCOLOR, "Spot colors not supported in PDFlib Lite") + +gen(0, 2016, UNSUPP_PDI, "PDF import (PDI) not supported in PDFlib Lite") + +gen(0, 2017, UNSUPP_PDI_CONFIG, + "PDF import (PDI) not supported in this configuration") + +gen(0, 2018, UNSUPP_BLOCK, + "Personalization with blocks not supported in PDFlib Lite") + +gen(0, 2019, UNSUPP_BLOCK_CONFIG, + "Personalization with blocks not supported in this configuration") + +gen(0, 2020, UNSUPP_FORMFIELDS, "Form fields not supported in PDFlib Lite") + +gen(0, 2021, UNSUPP_JAVASCRIPT, "JavaScript not supported in PDFlib Lite") + +gen(0, 2022, UNSUPP_MC, "Marked content not supported in PDFlib Lite") + +gen(0, 2024, UNSUPP_TAGGED, "Tagged PDF not supported in PDFlib Lite") + +gen(0, 2026, UNSUPP_LAYER, + "Optional content (layers) not supported in PDFlib Lite") + +gen(0, 2028, UNSUPP_TEXTFLOWS, "Textflow not supported in PDFlib Lite") + +gen(0, 2029, UNSUPP_GLYPHCHECK, + "Glyph check not supported in PDFlib Lite") + +gen(0, 2030, UNSUPP_CHARREF, + "Character references not supported in PDFlib Lite") + +gen(0, 2031, UNSUPP_ESCAPESEQU, + "Escape sequences not supported in PDFlib Lite") + +gen(0, 2032, UNSUPP_JPEG2000, + "JPEG2000 images not supported in PDFlib Lite") + +gen(0, 2033, UNSUPP_TABLES, "Tables not supported in PDFlib Lite") + +gen(0, 2034, UNSUPP_3DANNOT, "3D annotations not supported in PDFlib Lite") + +gen(0, 2035, UNSUPP_HONORLANG, + "LANG environment variable not supported in PDFlib Lite") + +gen(0, 2098, BETA_EXPIRED, + "PDFlib 6 beta expired -- get latest version at www.pdflib.com") + + +/* -------------------------------------------------------------------- */ +/* Document, page, scoping and resource (21xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 2100, DOC_SCOPE, "Function must not be called in '$1' scope") + +gen(1, 2102, DOC_FUNCUNSUPP, "Function not supported for '$1'") + +gen(2, 2104, DOC_PDFVERSION, "$1 not supported in PDF $2") + +gen(0, 2106, DOC_EMPTY, "Generated document doesn't contain any pages") + +gen(0, 2110, PAGE_SIZE_ACRO, "Page size incompatible with Acrobat") + +gen(2, 2112, PAGE_BADBOX, "Illegal $1 [$2]") + +gen(0, 2114, PAGE_ILLCHGSIZE, + "Page size cannot be changed in top-down coordinate system") + +gen(2, 2120, RES_BADRES, "Bad resource specification '$1' for category '$2'") + +gen(2, 2122, DOC_SCOPE_GET, "Can't get parameter '$1' in '$2' scope") + +gen(2, 2124, DOC_SCOPE_SET, "Can't set parameter '$1' in '$2' scope") + +gen(1, 2126, PAGE_NOSUSPEND, "Page number $1 has not been suspended") + +gen(2, 2128, PAGE_NOSUSPEND2, + "Page number $1 in group '$2' has not been suspended") + +gen(1, 2130, PAGE_ILLNUMBER, "Illegal page number $1") + +gen(1, 2132, PAGE_NOTEXIST, "Page number $1 does not exist") + +gen(2, 2134, PAGE_NOTEXIST2, "Page number $1 in group '$2' does not exist") + +gen(0, 2136, PAGE_NEEDGROUP, "No page group specified") + +gen(0, 2138, PAGE_NEEDGROUP2, + "No page group specified (use PDF_begin_page_ext)") + +gen(1, 2140, DOC_UNKNOWNGROUP, "Unknown page group '$1'") + +gen(1, 2142, DOC_GROUPMISSING, + "Page group '$1' is missing in list of option 'grouporder'") + +gen(0, 2144, DOC_OPTGROUPORDER, + "Option 'grouporder' is illegal (no page groups are specified)") + +gen(1, 2146, DOC_DUPLGROUP, + "Duplicate definition of group '$1' in option 'grouporder'") + +gen(1, 2148, DOC_ILL_LABELOPT, + "Label option '$1' is illegal for this function") + +gen(1, 2150, DOC_NEED_LABELOPT, + "Option 'labels' requires suboption '$1' if used with this function") + +gen(1, 2152, PAGE_TRANS_COMPAT, + "Page transition '$1' requires PDF version 1.5 or higher") + +gen(1, 2154, PAGE_ILLROTATE, "Option 'rotate' has illegal value $1") + +gen(0, 2156, PAGE_SUSPEND_TAGGED, + "This function must not be used in Tagged PDF mode") + +gen(0, 2158, PAGE_SEP_NOSPOT, + "Option 'separationinfo' requires 'spotname' or 'spotcolor'") + +gen(0, 2160, PAGE_SEP_ILLPAGES, + "Option 'separationinfo' must not use 'pages' if not first page in group") + +gen(0, 2162, PAGE_SEP_NOPAGES, "Option 'separationinfo' requires 'pages'") + +gen(0, 2164, PAGE_SEP_NOINFO, "Option 'separationinfo' missing") + +gen(0, 2166, DOC_SEP_INCOMPLETE, "Incomplete separation group") + +gen(0, 2168, PAGE_TOPDOWN_NODIMS, + "Must specify page dimensions with option 'topdown'") + +gen(0, 2170, PAGE_NODIMS, "No dimensions specified for this page") + +gen(0, 2172, DOC_GETBUF_2GB, + "Can't process buffers larger than 2GB on this platform") + +gen(1, 2174, PAGE_SUSPENDED, "Page number $1 is still suspended") + +gen(0, 2176, DOC_GETBUF_LIN, + "Don't fetch buffer contents before PDF_end_document() when linearizing") + +gen(1, 2178, PAGE_ILLREF, + "A link annotation refers to non-existing page '$1'") + + +/* -------------------------------------------------------------------- */ +/* Graphics and Text (22xx) */ +/* -------------------------------------------------------------------- */ + +gen(0, 2200, GSTATE_UNMATCHEDSAVE, "Unmatched save level") + +gen(0, 2202, GSTATE_RESTORE, "Invalid restore (no matching save level)") + +gen(1, 2204, GSTATE_SAVELEVEL, "Too many save levels (max. $1)") + +gen(0, 2210, PATTERN_SELF, "Can't use a pattern within its own definition") + +gen(0, 2212, SHADING13, "Smooth shadings are not supported in PDF 1.3") + +gen(1, 2220, TEMPLATE_SELF, + "Can't place template handle $1 within its own definition") + +/* UNUSED +gen(1, 2230, TEXT_UNICODENOTSHOW, + "Can't show character with Unicode value U+$1") + +gen(1, 2232, TEXT_GLYPHIDNOTSHOW, "Can't show character with glyph id $1") + +gen(1, 2233, TEXT_BUILTINNOTSHOW, + "Can't show 16-bit character $1 for builtin encoding") +*/ + +gen(1, 2234, TEXT_TOOLONG, "Text too long (max. $1)") + +gen(2, 2235, TEXT_SIZENOMATCH, + "Size ($1) of glyphwidths list doesn't match size ($2 characters) of text") + +gen(0, 2236, TEXT_TOOMANYCODES, "Too many different unicode values (> 256)") + +gen(0, 2237, TEXT_NOFONTSIZESET, "Font size not specified for text") + +gen(0, 2238, TEXT_NOFONT, "No font set for text") + +gen(0, 2239, TEXT_ITALUNSUPP, + "Parameter 'italicangle' not supported for vertical writing mode") + +gen(1, 2240, TEXT_NOFONT_PAR, "No font set for parameter '$1'") + + + + + + +/* -------------------------------------------------------------------- */ +/* Color (23xx) */ +/* -------------------------------------------------------------------- */ + +gen(0, 2300, COLOR_SPOT, +"Spot color can not be based on a Pattern, Indexed, or Separation color space") + +gen(2, 2302, COLOR_BADSPOT, "Color name '$1' not found in $2 table") + +gen(1, 2304, COLOR_SPOTBW, + "Alternate color for custom spot color '$1' is black or white") + +gen(1, 2306, COLOR_UNLIC_SPOTCOLOR, "$1 spot colors not licensed") + +gen(0, 2308, COLOR_UNSUPP_SPOTNAME, "Unicode spot color names not supported") + +gen(2, 2309, COLOR_REDEFINE_SPOTNAME, + "Option '$1': spot color '$2' has already an alternative color") + + + +/* -------------------------------------------------------------------- */ +/* Image (24xx) */ +/* -------------------------------------------------------------------- */ + +gen(2, 2400, IMAGE_CORRUPT, "Corrupt $1 image file '$2'") + +gen(3, 2402, IMAGE_NOPAGE, "Requested page $1 in $2 image '$3' not found") + +gen(2, 2404, IMAGE_BADDEPTH, + "Bad number of bits per pixel ($1) in image file '$2'") + +gen(1, 2406, IMAGE_BADMASK, + "Image '$1' not suitable as mask (more than one color component)") + +gen(2, 2407, IMAGE_NOMATCH, + "Image '$1' not suitable as mask for image '$2' (different orientation)") + +gen(1, 2408, IMAGE_MASK1BIT13, + "Image '$1' with more than 1 bit not supported as mask in PDF 1.3") + +gen(1, 2410, IMAGE_COLORMAP, "Couldn't read colormap in image '$1'") + +gen(2, 2412, IMAGE_BADCOMP, + "Bad number of color components ($1) in image '$2'") + +gen(1, 2414, IMAGE_COLORIZE, + "Can't colorize image '$1' with more than 1 component") + +gen(1, 2416, IMAGE_ICC, "Couldn't handle embedded ICC profile in image '$1'") + +gen(1, 2418, IMAGE_ICC2, + "ICC profile for image file '$1' doesn't match image data") + +gen(0, 2420, IMAGE_THUMB, "More than one thumbnail for this page") + +gen(1, 2422, IMAGE_THUMB_MULTISTRIP, + "Can't use multi-strip image $1 as thumbnail") + +gen(1, 2424, IMAGE_THUMB_CS, + "Unsupported color space in thumbnail image handle $1") + +gen(2, 2426, IMAGE_THUMB_SIZE, "Thumbnail image $1 larger than $2 pixels") + +gen(2, 2428, IMAGE_OPTUNSUPP, + "Option '$1' for image type '$2' not supported") + +gen(2, 2430, IMAGE_OPTUNREAS, + "Option '$1' for image type '$2' doesn't have any effect") + +gen(2, 2432, IMAGE_OPTBADMASK, "Option '$1' has bad image mask $2") + +gen(1, 2434, IMAGE_UNKNOWN, "Unknown image type in file '$1'") + +gen(0, 2436, IMAGE_NOADJUST, + "Option 'adjustpage' must not be used in top-down system") + +gen(1, 2437, IMAGE_OPI_ILLRECT, "Option '$1' has bad rectangle") + +gen(2, 2438, IMAGE_OPI_ILLMAPSIZE, "Option '$1': Number of values must be $2") + +gen(1, 2439, IMAGE_OPI_ILLPARALL, "Option '$1' has bad parallelogram") + +gen(2, 2440, RAW_ILLSIZE, + "Size ($1 bytes) of raw image file '$2' doesn't match specified options") + +gen(2, 2442, IMAGE_TYPUNSUPP, "Image type '$1' is not supported in PDF $2") + +gen(1, 2444, BMP_VERSUNSUPP, + "Version of BMP image file '$1' not supported") + +gen(1, 2446, BMP_COMPUNSUPP, + "Compression in BMP image file '$1' not supported") + +gen(2, 2450, JPEG_COMPRESSION, + "JPEG compression scheme $1 in file '$2' not supported in PDF") + +/* UNUSED +gen(1, 2452, JPEG_MULTISCAN, + "JPEG file '$1' contains multiple scans, which is not supported in PDF") +*/ + +gen(2, 2454, JPEG_TRANSCODE, + "Problems during JPEG transcoding in file '$1' ($2)") + +/* UNUSED +gen(1, 2460, GIF_LZWOVERFLOW, "LZW code size overflow in GIF file '$1'") + +gen(1, 2462, GIF_LZWSIZE, + "Color palette in GIF file '$1' with fewer than 128 colors not supported") + +gen(1, 2464, GIF_INTERLACED, "Interlaced GIF image '$1' not supported") + +gen(2, 2470, TIFF_UNSUPP_CS, + "Couldn't open TIFF image '$1' (unsupported color space; photometric $2)") + +gen(2, 2472, TIFF_UNSUPP_PREDICT, + "Couldn't open TIFF image '$1' (unsupported predictor tag $2)") + +gen(1, 2474, TIFF_UNSUPP_LZW, "Couldn't open LZW-compressed TIFF image '$1')") + +gen(1, 2476, TIFF_UNSUPP_LZW_PLANES, + "Couldn't open TIFF image '$1' (separate planes with LZW compression)") + +gen(1, 2478, TIFF_UNSUPP_LZW_ALPHA, + "Couldn't open TIFF image '$1' (alpha channel with LZW compression)") + +gen(2, 2480, TIFF_UNSUPP_JPEG, + "Couldn't open TIFF image '$1' (JPEG compression scheme $2)") + +gen(1, 2482, TIFF_UNSUPP_JPEG_TILED, + "Couldn't open TIFF image '$1' (tiled image with JPEG compression)") +*/ + +gen(2, 2483, TIFF_UNSUPP_COLORSPACE, + "Color space (photometric) $1 in TIFF image '$2' not supported") + +gen(1, 2484, TIFF_UNSUPP_JPEG_SEPARATE, + "Couldn't open TIFF image '$1' (JPEG with separate image planes)") + +gen(2, 2486, TIFF_UNSUPP_SEP_NONCMYK, + "Couldn't open TIFF image '$1' (unsupported inkset tag $2)") + +gen(1, 2488, TIFF_MASK_MULTISTRIP, "Can't mask multistrip TIFF image '$1'") + +gen(2, 2489, TIFF_CLIPPPATH_NOTFOUND, + "Couldn't find clipping path '$1' in TIFF image '$2'") + +gen(1, 2490, TIFF_16BITCMYK_UNSUPP, + "Compressed 16-bit CMYK TIFF image '$1' not supported") + +gen(1, 2491, TIFF_16BIT_UNSUPP, + "More than 16 bits per component in TIFF image '$1' not supported") + +gen(1, 2492, TIFF_CMYK_MASK, "Couldn't open TIFF image '$1' (CMYK with mask)") + +gen(2, 2493, TIFF_UNSUPP_COMPRESSION, + "Compression scheme $1 in TIFF image '$2' not supported") + +gen(1, 2494, JPX_FORMATUNSUPP, + "JPEG2000 flavor in image file '$1' not supported") + +gen(1, 2496, JPX_RAWDATAUNSUPP, + "Raw JPEG2000 code stream in image file '$1' not supported") + +gen(1, 2498, JPX_COMPOUNDUNSUPP, + "Compound JPEG2000 (JPM) image file '$1' not supported") + + +/* -------------------------------------------------------------------- */ +/* Font (25xx) */ +/* -------------------------------------------------------------------- */ + +gen(2, 2500, FONT_CORRUPT, "Corrupt $1 font file '$2'") + +gen(2, 2501, FONT_PREFIX, "Font '$1' with encoding '$2': ") + +gen(0, 2502, FONT_BADENC, "Font doesn't support encoding") + +gen(3, 2503, FONT_PREFIX2, "Font '$1' with encoding '$2' (changed to '$3'): ") + +gen(1, 2504, FONT_FORCEENC, + "Font doesn't support encoding (encoding '$1' will be used)") + +gen(0, 2505, FONT_NEEDUCS2, + "Encoding not supported (use Unicode-compatible CMap)") + +/* UNUSED +gen(0, 2506, FONT_FORCEEMBED, + "Font will be embedded (encoding requires CID font") +*/ + +gen(1, 2507, FONT_INAPPROPENC, + "Encoding not appropriate for the font (only $1 glyphs found)") + +/* UNUSED +gen(1, 2508, FONT_BADTEXTFORM, + "Current text format not allowed for builtin encoding") +*/ + +gen(0, 2509, FONT_FORCECVTUNI, + "Native text code (keepnative) for this font configuration will be ignored") + +gen(0, 2514, FONT_EMBEDMM, "Multiple Master font cannot be embedded") + +gen(0, 2516, FONT_NOMETRICS, "Metrics data not found") + +gen(0, 2518, FONT_NOOUTLINE, "File with outline data not found") + +/* Unused +gen(0, 2520, FONT_NOGLYPHID, "Font doesn't contain any glyph IDs") +*/ + +gen(0, 2522, FONT_FORCEEMBED2, "Metadata requires embedding") + +gen(0, 2530, CJK_UNSUPP_REGISTRY, + "Font not supported (contains non-Adobe registry in CMap)") + +gen(0, 2531, CJK_UNSUPP_CHARCOLL, + "CJK font doesn't support encoding (use a compatible predefined CMap)") + +gen(0, 2532, FONT_EMBEDCMAP, + "Standard CJK font with predefined CMap cannot be embedded") + +gen(0, 2533, FONT_ONLY_CMAP, + "Font doesn't support encoding (use predefined CMap or 'unicode' encoding)") + +/* Unused +gen(0, 2534, FONT_EMBEDSTYLE, + "Option 'fontstyle' not allowed for embedded fonts") +*/ + +gen(0, 2535, FONT_UNSUPP_CMAP, + "Font doesn't support predefined CMap") + +gen(2, 2536, FONT_UNSUPPOPTION, + "Option '$1' not supported for font type '$2'") + +gen(0, 2538, FONT_IGNOREVERTICAL, + "Option 'vertical' ignored because of predefined CMap or font name resp.") + +gen(1, 2540, T3_BADBBOX, + "Bounding box values must be 0 for colorized font") + +gen(1, 2541, T3_FONT_PREFIX, "Type3 font '$1': ") + +gen(1, 2542, T3_GLYPH, "Glyph '$1' already defined") + +gen(0, 2544, T3_FONTEXISTS, "Already exists") + +gen(0, 2545, T3_FONTSUBSET, "Font with subsetting can only be loaded once") + +gen(1, 2546, T3_GLYPHMISSING, "Outlines of glyph '$1' not defined") + +gen(1, 2547, T3_OUTLINESMISSING, "Outlines of Type3 font '$1' missing") + +gen(1, 2548, T3_UNKOWNGLYPH, "Glyph '$1' unknown") + +gen(1, 2549, T3_MISSNOTDEF, "Glyph for character '.notdef' is missing") + +gen(1, 2550, T1_BADCHARSET, + "PDFlib doesn't support encoding (dfCharSet $1 in PFM file unknown)") + +gen(1, 2551, T1_UNSUPP_FORMAT, "'$1' metrics file type not supported") + +gen(2, 2554, T1_AFMBADKEY, "Unknown key '$1' in AFM file '$2'") + +gen(1, 2558, T1_NOFONT, "'$1' is not a PostScript Type1 font file") + +gen(2, 2560, FONT_CODENOTFOUND1, + "Glyph with character code $1 not found in font '$2'") + +gen(2, 2561, FONT_CODENOTFOUNDREP1, + "Glyph with character code $1 not found in font '$2' (will be replaced)") + +gen(2, 2562, FONT_UNICODENOTFOUND, + "Glyph with Unicode value U+$1 not found in font '$2'") + +gen(2, 2563, FONT_UNICODENOTFOUNDREP, + "Glyph with Unicode value U+$1 not found in font '$2' (will be replaced)") + +gen(2, 2564, FONT_GLYPHIDNOTFOUND, + "Glyph with id $1 not found in font '$2'") + +gen(3, 2566, FONT_CODENOTFOUND2, + "Glyph with code $1 and Unicode value U+$2 not found in font '$3'") + +gen(3, 2567, FONT_CODENOTFOUNDREP2, + "Glyph with code $1 and Unicode value U+$2 not found in font '$3' " + "(will be replaced)") + +gen(2, 2569, FONT_NOTFULFILL, + "Option '$1' cannot be fulfilled (same font already loaded with no$1)") + +/* -------------------------------------------------------------------- */ +/* Encoding (26xx) */ +/* -------------------------------------------------------------------- */ + +/* MOVED to pc_generr.h, #1552 +gen(1, 2600, ENC_NOTFOUND, "Couldn't find encoding '$1'") +*/ + +gen(1, 2602, ENC_UNSUPP, "Code page '$1' not supported") + +gen(1, 2606, ENC_CANTQUERY, "Can't query encoding '$1'") + +gen(1, 2608, ENC_CANTCHANGE, "Can't change encoding '$1'") + +gen(1, 2610, ENC_INUSE, + "Encoding '$1' can't be changed since it has already been used") + +/* MOVED to pc_generr.h, #1550 +gen(2, 2612, ENC_TOOLONG, "Encoding name '$1' too long (max. $2)") + + MOVED to pc_generr.h, #1551 +gen(2, 2614, ENC_BADLINE, "Syntax error in encoding file '$1' (line '$2')") +*/ + +gen(0, 2616, ENC_GLYPHORCODE, "Glyph name or Unicode value required") + +gen(3, 2618, ENC_BADGLYPH, + "Glyph name '$1' for Unicode value U+$2 differs from AGL name '$3'") + +gen(3, 2620, ENC_BADUNICODE, + "Unicode value U+$1 for glyph name '$2' differs from AGL value U+$3") + +gen(2, 2622, ENC_BADFONT, + "Current font $1 wasn't specified with encoding '$2'") + +gen(1, 2640, ENC_BADHYPTEXTENC, "Bad hypertext encoding '$1'") + +gen(1, 2650, ENC_UNSUPPENCFORMAT, + "Parameter or option '$1' not supported in Unicode-capable languages") + +/* Unused +gen(2, 2670, CMAP_ILLCODESEQU, "Illegal code sequence in '$1' for CMap '$2'") +*/ + + + +/* -------------------------------------------------------------------- */ +/* Hypertext, form fields, actions, annotations (28xx) */ +/* -------------------------------------------------------------------- */ + +gen(2, 2802, HYP_OPTIGNORE_FORTYPE, + "Option '$1' for destination type '$2' doesn't have any effect") + +gen(1, 2804, HYP_OPTIGNORE_FORELEM, + "Option '$1' for hypertext function will be ignored") + +gen(2, 2820, FF_OPTEFFLESS_FORTYPE, + "Option '$1' for field type '$2' doesn't have any effect") + +gen(1, 2822, FF_GROUPMISSING, + "Required field group missing for radio button field '$1'") + +gen(1, 2824, FF_FONTMISSING, "Font not specified for field '$1'") + +gen(2, 2826, FF_OPTIONMISSING, + "Option '$1' not specified for field '$2'") + +gen(1, 2828, FF_CIDFONT, + "Specified font '$1' not allowed for fields (encoding not supported)") + +gen(1, 2830, FF_NOEMBEDFONT, + "Specified font '$1' not allowed for fields (must be embedded)") + +gen(1, 2832, FF_SUBSETTFONT, + "Specified font '$1' not allowed for fields (must not be subset)") + +gen(1, 2834, FF_CAPTMISSING, "No caption or icon specified for field '$1'") + +gen(0, 2836, FF_DIFFSTRLISTS, + "Options 'itemnamelist' and 'itemtextlist' contain " + "different numbers of strings") + +gen(2, 2838, FF_INVALINDEX, "Option '$1' has invalid list index '$2'") + +gen(2, 2840, FF_NOTFOUND, + "Illegal field pathname '$1' (name '$2' not found)") + +gen(2, 2842, FF_NAMEEXISTS, + "Illegal field pathname '$1' (name '$2' already exists)") + +gen(2, 2844, FF_NOTGROUP, + "Illegal field pathname '$1' ('$2' is not a field group)") + +gen(3, 2846, FF_TYPENOTMATCH, + "Type '$1' of field '$2' doesn't match type '$3' of group") + +gen(0, 2848, FF_ITEMNAMEORNOT, +"Either all or none of the buttons/checkboxes in a group can have item names") + +gen(2, 2850, FF_OPTEFFONLY, + "Option '$1' for field type '$2' only has an effect for highlight=push") + +gen(2, 2852, FF_ILLUNINAME, + "Illegal field name '$1' (Unicode names are not supported in PDF $2") + +gen(0, 2854, FF_DEMOLIMIT, + "No more than 10 fields can be created with the evaluation version") + +gen(0, 2856, FF_RICHTEXT, + "fontsize 0 not supported for fields with rich text") + +gen(2, 2860, ACT_OPTIGNORE_FORTYPE, + "Option '$1' for action type '$2' doesn't have any effect") + +gen(2, 2862, ACT_BADACTTYPE, "Action type '$1' for event '$2' not allowed") + + +gen(2, 2880, ANN_OPTEFFLESS_FORTYPE, + "Option '$1' for annotation type '$2' doesn't have any effect") + +gen(1, 2882, ANN_NOSTDFONT, + "Font '$1' not allowed for annotations (not a core or standard CJK font)") + +gen(1, 2884, ANN_BADNUMCOORD, "Option '$1' has bad number of coordinates") + +gen(1, 2886, ANN_OPTALRDEF, + "Option '$1' already defined in option 'custom'") + +gen(1, 2888, ANN_ILLCUSTOMKEY, + "Option 'custom' uses illegal key '$1' (already defined in PDF)") + + +/* -------------------------------------------------------------------- */ +/* Internal (29xx) */ +/* -------------------------------------------------------------------- */ + +gen(1, 2900, INT_BADSCOPE, "Bad scope '$1'") + +gen(1, 2902, INT_BADANNOT, "Bad annotation type '$1'") + +gen(3, 2904, INT_BADCS, +"Unknown color space (function $1, index $2, type $3)") + +gen(1, 2906, INT_BADALTERNATE, "Bad alternate color space $1") + +gen(1, 2908, INT_BADPROFILE, "Unknown number of profile components ($1)") + +gen(1, 2910, INT_SSTACK_OVER, "State stack overflow in function '$1'") + +gen(1, 2912, INT_SSTACK_UNDER, "State stack underflow in function '$1'") + +gen(3, 2914, INT_WRAPPER, "Error in PDFlib $1 wrapper function $2 ($3)") + +gen(0, 2990, OT_UNSUPP_SID2CID, + "Accented characters not supported; contact support@pdflib.com") + + + + + + + +#undef gen +#undef pdf_genNames +#undef pdf_genInfo + + + diff --git a/src/pdflib/pdflib/p_gif.c b/src/pdflib/pdflib/p_gif.c new file mode 100644 index 0000000..59d80f5 --- /dev/null +++ b/src/pdflib/pdflib/p_gif.c @@ -0,0 +1,744 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_gif.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * GIF processing for PDFlib + * + */ + +/* + * This module contains modified parts of the giftopnm.c progam in the + * netpbm package. It contained the following copyright notice: + */ + +/* +-------------------------------------------------------------------+ */ +/* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */ +/* | Permission to use, copy, modify, and distribute this software | */ +/* | and its documentation for any purpose and without fee is hereby | */ +/* | granted, provided that the above copyright notice appear in all | */ +/* | copies and that both that copyright notice and this permission | */ +/* | notice appear in supporting documentation. This software is | */ +/* | provided "as is" without express or implied warranty. | */ +/* +-------------------------------------------------------------------+ */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#ifndef PDF_GIF_SUPPORTED + +pdc_bool +pdf_is_GIF_file(PDF *p, pdc_file *fp) +{ + (void) p; + (void) fp; + + return pdc_false; +} + +int +pdf_process_GIF_data( + PDF *p, + int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "GIF", 0, 0, 0); + + return -1; +} + +/* CDPDF - added missing function */ +void +pdf_cleanup_gif(PDF *p, pdf_image *image) +{ + (void) p; + (void) image; +} + +#else + +#define LOCALCOLORMAP 0x80 +#define BitSet(byteval, bitval) (((byteval) & (bitval)) == (bitval)) + +static int ReadColorMap(pdc_core *pdc, pdc_file *fp, + int number, pdf_colormap *buffer); +static int DoExtension(PDF *p, pdf_image *image, int label); +static int GetDataBlock(PDF *p, pdf_image *image, unsigned char *buf); +static void ReadImage(PDF *p, pdf_image *image, PDF_data_source *src); + +static void +pdf_data_source_GIF_init(PDF *p, PDF_data_source *src) +{ + pdf_image *image; + + image = (pdf_image *) src->private_data; + + src->buffer_length = (size_t) (image->width * image->height * 1); + src->buffer_start = (pdc_byte *) pdc_malloc(p->pdc, src->buffer_length, + "pdf_data_source_GIF_init"); + src->bytes_available= 0; + src->next_byte = NULL; +} + +static pdc_bool +pdf_data_source_GIF_fill(PDF *p, PDF_data_source *src) +{ + pdf_image *image; + + if (src->next_byte != NULL) /* all finished in one turn */ + return pdc_false; + + image = (pdf_image *) src->private_data; + + src->next_byte = src->buffer_start; + src->bytes_available = src->buffer_length; + + PDC_TRY(p->pdc) + { + ReadImage(p, image, src); + } + PDC_CATCH(p->pdc) + { + image->corrupt = pdc_true; + } + + pdf_cleanup_gif(p, image); + + return !image->corrupt; +} + +static void +pdf_data_source_GIF_terminate(PDF *p, PDF_data_source *src) +{ + pdc_free(p->pdc, (void *) src->buffer_start); +} + +#define PDF_STRING_GIF "\107\111\106" +#define PDF_STRING_87a "\070\067\141" +#define PDF_STRING_89a "\070\071\141" + +pdc_bool +pdf_is_GIF_file(PDF *p, pdc_file *fp) +{ + unsigned char buf[3]; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type GIF...\n"); + + if (!PDC_OK_FREAD(fp, buf, 3) || + strncmp((const char *) buf, PDF_STRING_GIF, 3) != 0) + { + pdc_fseek(fp, 0L, SEEK_SET); + return pdc_false; + } + return pdc_true; +} + +int +pdf_process_GIF_data( + PDF *p, + int imageslot) +{ + unsigned char buf[16]; + char c; + int imageCount = 0; + char version[4]; + int errcode = 0; + pdf_image *image; + pdf_colorspace cs; + pdf_colormap colormap; + int slot; + + image = &p->images[imageslot]; + + image->info.gif.stack = NULL; + image->info.gif.table = NULL; + + /* we invert this flag later */ + if (image->ignoremask) + image->transparent = pdc_true; + + if (image->page == pdc_undef) + image->page = 1; + + /* Error reading magic number or not a GIF file */ + if (pdf_is_GIF_file(p, image->fp) == pdc_false) { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_GIF_ERROR; + } + + /* Version number */ + if (! PDC_OK_FREAD(image->fp, buf, 3)) { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_GIF_ERROR; + } + strncpy(version, (const char *) buf, 3); + version[3] = '\0'; + if ((strcmp(version, PDF_STRING_87a) != 0) && + (strcmp(version, PDF_STRING_89a) != 0)) { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_GIF_ERROR; + } + + /* Failed to read screen descriptor */ + if (! PDC_OK_FREAD(image->fp, buf, 7)) { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_GIF_ERROR; + } + + cs.type = Indexed; + /* size of the global color table */ + cs.val.indexed.palette_size = 2 << (buf[4] & 0x07); + cs.val.indexed.base = DeviceRGB; + cs.val.indexed.colormap = &colormap; + cs.val.indexed.colormap_id = PDC_BAD_ID; + + if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ + if (ReadColorMap(p->pdc, image->fp, + cs.val.indexed.palette_size, &colormap)) { + errcode = PDF_E_IMAGE_COLORMAP; + goto PDF_GIF_ERROR; + } + } + + /* translate the aspect ratio to PDFlib notation */ + if (buf[6] != 0) { + image->dpi_x = (pdc_scalar) (-(buf[6] + 15.0) / 64.0); + image->dpi_y = -1.0; + } + + for (/* */ ; /* */ ; /* */) { + /* EOF / read error in image data */ + if (!PDC_OK_FREAD(image->fp, &c, 1)) { + errcode = PDC_E_IO_READ; + goto PDF_GIF_ERROR; + } + +#define PDF_SEMICOLON ((char) 0x3b) /* ASCII ';' */ + + if (c == PDF_SEMICOLON) { /* GIF terminator */ + /* Not enough images found in file */ + if (imageCount < image->page) { + if (!imageCount) + errcode = PDF_E_IMAGE_CORRUPT; + else + errcode = PDF_E_IMAGE_NOPAGE; + goto PDF_GIF_ERROR; + } + break; + } + +#define PDF_EXCLAM ((char) 0x21) /* ASCII '!' */ + + if (c == PDF_EXCLAM) { /* Extension */ + if (!PDC_OK_FREAD(image->fp, &c, 1)) { + /* EOF / read error on extension function code */ + errcode = PDC_E_IO_READ; + goto PDF_GIF_ERROR; + } + DoExtension(p, image, (int) c); + continue; + } + +#define PDF_COMMA ((char) 0x2c) /* ASCII ',' */ + + if (c != PDF_COMMA) { /* Not a valid start character */ + /* Bogus character, ignoring */ + continue; + } + + ++imageCount; + + if (! PDC_OK_FREAD(image->fp, buf, 9)) { + /* Couldn't read left/top/width/height */ + errcode = PDC_E_IO_READ; + goto PDF_GIF_ERROR; + } + + image->components = 1; + image->bpc = 8; + image->width = (pdc_scalar) pdc_get_le_ushort(&buf[4]); + image->height = (pdc_scalar) pdc_get_le_ushort(&buf[6]); + +#define INTERLACE 0x40 + image->info.gif.interlace= BitSet(buf[8], INTERLACE); + + if (image->imagemask) + { + if (p->compatibility <= PDC_1_3) { + errcode = PDF_E_IMAGE_MASK1BIT13; + goto PDF_GIF_ERROR; + } else { + /* images with more than one bit will be written as /SMask, + * and don't require an /ImageMask entry. + */ + image->imagemask = pdc_false; + } + image->colorspace = DeviceGray; + } + + if (BitSet(buf[8], LOCALCOLORMAP)) { + /* The local color map may have a different size */ + cs.val.indexed.palette_size = 2 << (buf[8] & 0x07); + + if (ReadColorMap(p->pdc, image->fp, + cs.val.indexed.palette_size, &colormap)) + { + errcode = PDF_E_IMAGE_COLORMAP; + goto PDF_GIF_ERROR; + } + } + + if (imageCount == image->page) + break; + } + + image->src.init = pdf_data_source_GIF_init; + image->src.fill = pdf_data_source_GIF_fill; + image->src.terminate = pdf_data_source_GIF_terminate; + image->src.private_data = (void *) image; + + image->compression = pdf_comp_none; + image->use_raw = pdc_false; + + image->in_use = pdc_true; /* mark slot as used */ + + slot = pdf_add_colorspace(p, &cs, pdc_false); + image->colorspace = slot; + + + + + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + if (!image->corrupt) + return imageslot; + + PDF_GIF_ERROR: + { + const char *stemp = NULL; + + if (errcode) + stemp = pdf_get_image_filename(p, image); + + switch (errcode) + { + case PDC_E_IO_READ: + case PDF_E_IMAGE_COLORMAP: + case PDF_E_IMAGE_MASK1BIT13: + pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0); + break; + + case PDC_E_IO_BADFORMAT: + pdc_set_errmsg(p->pdc, errcode, stemp, "GIF", 0, 0); + break; + + case PDF_E_IMAGE_CORRUPT: + pdc_set_errmsg(p->pdc, errcode, "GIF", stemp, 0, 0); + break; + + case PDF_E_IMAGE_NOPAGE: + pdc_set_errmsg(p->pdc, errcode, + pdc_errprintf(p->pdc, "%d", image->page), "GIF", stemp, 0); + break; + + case 0: /* error code and message already set */ + break; + } + } + + return -1; +} /* pdf_open_GIF_data */ + +static int +ReadColorMap(pdc_core *pdc, pdc_file *fp, int number, pdf_colormap *buffer) +{ + int i; + unsigned char rgb[3]; + + (void) pdc; + + for (i = 0; i < number; ++i) { + if (! PDC_OK_FREAD(fp, rgb, sizeof(rgb))) { + return pdc_true; /* yk: true == error */ + } + + (*buffer)[i][0] = rgb[0] ; + (*buffer)[i][1] = rgb[1] ; + (*buffer)[i][2] = rgb[2] ; + } + return pdc_false; /* yk: false == ok. */ +} /* ReadColorMap */ + +static int +DoExtension(PDF *p, pdf_image *image, int label) +{ + pdc_byte buf[256]; + + switch ((unsigned char) label) { + case 0x01: /* Plain Text Extension */ + break; + + case 0xff: /* Application Extension */ + break; + + case 0xfe: /* Comment Extension */ + while (GetDataBlock(p, image, (unsigned char*) buf) != 0) { + /* */ + } + return pdc_false; + + case 0xf9: /* Graphic Control Extension */ + (void) GetDataBlock(p, image, (unsigned char*) buf); + + if ((buf[0] & 0x1) != 0) { + image->transparent = !image->transparent; + image->transval[0] = buf[3]; + } + + while (GetDataBlock(p, image, (unsigned char*) buf) != 0) { + /* */ ; + } + return pdc_false; + + default: + break; + } + + while (GetDataBlock(p, image, (unsigned char*) buf) != 0) { + /* */ ; + } + + return pdc_false; +} /* DoExtension */ + +/* + * A bunch of formely static variables which are now kept in the + * image structure in order to keep the GIF reader thread-safe. + */ + +/* for GetDataBlock() */ +#define ZeroDataBlock (image->info.gif.ZeroDataBlock) + +/* for initLWZ() */ +#define curbit (image->info.gif.curbit) +#define lastbit (image->info.gif.lastbit) +#define get_done (image->info.gif.get_done) +#define last_byte (image->info.gif.last_byte) +#define return_clear (image->info.gif.return_clear) + +#define sp (image->info.gif.sp) +#define code_size (image->info.gif.code_size) +#define set_code_size (image->info.gif.set_code_size) +#define max_code (image->info.gif.max_code) +#define max_code_size (image->info.gif.max_code_size) +#define clear_code (image->info.gif.clear_code) +#define end_code (image->info.gif.end_code) + +/* for nextCode() */ +#define buf (image->info.gif.buf) + +/* for nextLWZ() */ +#define stack (image->info.gif.stack) +#define table (image->info.gif.table) +#define firstcode (image->info.gif.firstcode) +#define oldcode (image->info.gif.oldcode) + +static int +GetDataBlock(PDF *p, pdf_image *image, unsigned char *lbuf) +{ + unsigned char count; + pdc_file *fp = image->fp; + + if (!PDC_OK_FREAD(fp, &count, 1)) + return -1; /* Error in getting DataBlock size */ + + ZeroDataBlock = (count == 0); + + if ((count != (unsigned char) 0) && (!PDC_OK_FREAD(fp, lbuf, count))) + { + /* Error in reading DataBlock */ + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", + pdf_get_image_filename(p, image), 0, 0); + } + + return count; +} /* GetDataBlock */ + +static void +initLWZ(PDF *p, pdf_image *image, int input_code_size) +{ +#define GIF_TABLE_SIZE (sizeof(int [2][GIF_TABLE_ELEMENTS])) +#define GIF_STACK_SIZE (sizeof(int [GIF_TABLE_ELEMENTS*2])) + + table = (int(*)[GIF_TABLE_ELEMENTS]) + pdc_malloc(p->pdc, GIF_TABLE_SIZE, "initLWZ"); + stack = (int *) pdc_malloc(p->pdc, GIF_STACK_SIZE, "initLWZ"); + + set_code_size = input_code_size; + code_size = set_code_size + 1; + clear_code = 1 << set_code_size ; + end_code = clear_code + 1; + max_code_size = 2 * clear_code; + max_code = clear_code + 2; + + curbit = lastbit = 0; + last_byte = 2; + get_done = pdc_false; + + return_clear = pdc_true; + + sp = stack; +} + +/* + * We clean up after decompressing the image; in rare cases (exception + * caused by damaged compressed data) this may also be called when + * cleaning up the full image struct. + */ +void +pdf_cleanup_gif(PDF *p, pdf_image *image) +{ + if (table) + { + pdc_free(p->pdc, table); + table = NULL; + } + if (stack) + { + pdc_free(p->pdc, stack); + stack = NULL; + } +} + +static int +nextCode(PDF *p, pdf_image *image, int codesize) +{ + static const int maskTbl[16] = { + 0x0000, 0x0001, 0x0003, 0x0007, + 0x000f, 0x001f, 0x003f, 0x007f, + 0x00ff, 0x01ff, 0x03ff, 0x07ff, + 0x0fff, 0x1fff, 0x3fff, 0x7fff, + }; + int i, j, ret, end; + + if (return_clear) { + return_clear = pdc_false; + return clear_code; + } + + end = curbit + codesize; + + if (end >= lastbit) { + int count; + + if (get_done) { + if (curbit >= lastbit) + { + /* + ERROR("ran off the end of my bits" ); + */ + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", + pdf_get_image_filename(p, image), 0, 0); + } + return -1; + } + + if (last_byte >= 2) + { + buf[0] = buf[last_byte-2]; + buf[1] = buf[last_byte-1]; + } + + if ((count = GetDataBlock(p, image, &buf[2])) == 0) + get_done = pdc_true; + + last_byte = 2 + count; + curbit = (curbit - lastbit) + 16; + lastbit = (2+count)*8 ; + + end = curbit + codesize; + } + + j = end / 8; + i = curbit / 8; + + if (i == j) + ret = buf[i]; + else if (i + 1 == j) + ret = buf[i] | (buf[i+1] << 8); + else + ret = buf[i] | (buf[i+1] << 8) | (buf[i+2] << 16); + + ret = (ret >> (curbit % 8)) & maskTbl[codesize]; + + curbit += codesize; + + return ret; +} + +#define readLWZ(p, image) ((sp > stack) ? *--sp : nextLWZ(p, image)) + +static int +nextLWZ(PDF *p, pdf_image *image) +{ + int code, incode; + int i; + + while ((code = nextCode(p, image, code_size)) >= 0) { + if (code == clear_code) { + for (i = 0; i < clear_code; ++i) { + table[0][i] = 0; + table[1][i] = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) + table[0][i] = table[1][i] = 0; + code_size = set_code_size+1; + max_code_size = 2*clear_code; + max_code = clear_code+2; + sp = stack; + do { + firstcode = oldcode = nextCode(p, image, code_size); + } while (firstcode == clear_code); + + return firstcode; + } + if (code == end_code) { + int count; + unsigned char lbuf[260]; + + if (ZeroDataBlock) + return -2; + + while ((count = GetDataBlock(p, image, lbuf)) > 0) + ; + + /* count != 0: INFO_MSG(("missing EOD in data stream")); */ + + return -2; + } + + incode = code; + + if (code >= max_code) { + *sp++ = firstcode; + code = oldcode; + } + + while (code >= clear_code) { + *sp++ = table[1][code]; + if (code == table[0][code]) + { + /* ERROR("circular table entry BIG ERROR"); */ + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", + pdf_get_image_filename(p, image), 0, 0); + } + code = table[0][code]; + } + + *sp++ = firstcode = table[1][code]; + + if ((code = max_code) <(1<<MAX_LWZ_BITS)) { + table[0][code] = oldcode; + table[1][code] = firstcode; + ++max_code; + if ((max_code >= max_code_size) && + (max_code_size < (1<<MAX_LWZ_BITS))) { + max_code_size *= 2; + ++code_size; + } + } + + oldcode = incode; + + if (sp > stack) + return *--sp; + } + return code; +} + +static void +ReadImage(PDF *p, pdf_image *image, PDF_data_source *src) +{ + unsigned char c; + int v; + unsigned int xpos = 0, ypos = 0; + pdc_byte *dp; + unsigned int h = (unsigned int) image->height; + unsigned int w = (unsigned int) image->width; + + /* + * Initialize the Compression routines + */ + ZeroDataBlock = pdc_false; + + if (!PDC_OK_FREAD(image->fp, &c, 1)) + { + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", + pdf_get_image_filename(p, image), 0, 0); + } + + initLWZ(p, image, c); + + if (image->info.gif.interlace) { + int i; + int pass = 0, step = 8; + + for (i = 0; i < (int) h; i++) { + dp = &src->buffer_start[w * ypos]; + for (xpos = 0; xpos < w; xpos++) { + if ((v = readLWZ(p, image)) < 0) + goto fini; + + *dp++ = v; + } + if ((ypos += step) >= h) { + do { + if (pass++ > 0) + step /= 2; + ypos = step / 2; + } while (ypos > h); + } + } + } else { + dp = src->buffer_start; + for (ypos = 0; ypos < h; ypos++) { + for (xpos = 0; xpos < w; xpos++) { + if ((v = readLWZ(p, image)) < 0) + goto fini; + + *dp++ = v; + } + } + } + +fini: + if (readLWZ(p, image) >= 0) + /* Too much input data in GIF file '%s', ignoring extra. */ + ; +} + +#undef fresh +#undef code_size +#undef set_code_size +#undef max_code +#undef max_code_size +#undef firstcode +#undef oldcode +#undef clear_code +#undef end_code +#undef sp +#undef table +#undef stack + +#endif /* PDF_GIF_SUPPORTED */ diff --git a/src/pdflib/pdflib/p_gstate.c b/src/pdflib/pdflib/p_gstate.c new file mode 100644 index 0000000..2b62542 --- /dev/null +++ b/src/pdflib/pdflib/p_gstate.c @@ -0,0 +1,451 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_gstate.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib routines dealing with the graphics states + * + */ + +#include "p_intern.h" + +/* ---------------------- matrix functions ----------------------------- */ + +void +pdf_concat_raw(PDF *p, pdc_matrix *m) +{ + if (pdc_is_identity_matrix(m)) + return; + + pdf_end_text(p); + + pdc_printf(p->out, "%f %f %f %f %f %f cm\n", + m->a, m->b, m->c, m->d, m->e, m->f); + + pdc_multiply_matrix(m, &p->curr_ppt->gstate[p->curr_ppt->sl].ctm); +} + +void +pdf_set_topdownsystem(PDF *p, pdc_scalar height) +{ + if (p->ydirection < 0) + { + pdc_matrix m, sm; + + pdc_translation_matrix(0, height, &m); + pdc_scale_matrix(1, -1, &sm); + pdc_multiply_matrix(&sm, &m); + pdf_concat_raw(p, &m); + } +} + +/* -------------------- Special graphics state ---------------------------- */ + +void +pdf_init_gstate(PDF *p) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + pdc_identity_matrix(&gs->ctm); + + gs->x = 0; + gs->y = 0; + + p->curr_ppt->fillrule = pdf_fill_winding; + + gs->lwidth = 1; + gs->lcap = 0; + gs->ljoin = 0; + gs->miter = 10; + gs->flatness = -1; /* -1 means "has not been set" */ + gs->dashed = pdc_false; +} + +void +pdf__save(PDF *p) +{ + pdf_ppt * ppt = p->curr_ppt; + int sl = ppt->sl; + + if (sl == PDF_MAX_SAVE_LEVEL - 1) + pdc_error(p->pdc, PDF_E_GSTATE_SAVELEVEL, + pdc_errprintf(p->pdc, "%d", PDF_MAX_SAVE_LEVEL - 1), 0, 0, 0); + + pdf_end_text(p); + pdc_puts(p->out, "q\n"); + + /* propagate states to next level */ + memcpy(&ppt->gstate[sl + 1], &ppt->gstate[sl], sizeof(pdf_gstate)); + pdf_save_cstate(p); + pdf_save_tstate(p); + ++ppt->sl; +} + +void +pdf__restore(PDF *p) +{ + if (p->curr_ppt->sl == 0) + pdc_error(p->pdc, PDF_E_GSTATE_RESTORE, 0, 0, 0, 0); + + pdf_end_text(p); + + pdc_puts(p->out, "Q\n"); + + p->curr_ppt->sl--; + + pdf_restore_currto(p); +} + +void +pdf__translate(PDF *p, pdc_scalar tx, pdc_scalar ty) +{ + pdc_matrix m; + + pdc_check_number(p->pdc, "tx", tx); + pdc_check_number(p->pdc, "ty", ty); + + if (tx == 0 && ty == 0) + return; + + pdc_translation_matrix(tx, ty, &m); + + pdf_concat_raw(p, &m); +} + +void +pdf__scale(PDF *p, pdc_scalar sx, pdc_scalar sy) +{ + pdc_matrix m; + + pdc_check_number_zero(p->pdc, "sx", sx); + pdc_check_number_zero(p->pdc, "sy", sy); + + if (sx == 1 && sy == 1) + return; + + pdc_scale_matrix(sx, sy, &m); + + pdf_concat_raw(p, &m); +} + +void +pdf__rotate(PDF *p, pdc_scalar phi) +{ + pdc_matrix m; + + pdc_check_number(p->pdc, "phi", phi); + + if (phi == 0) + return; + + pdc_rotation_matrix(p->ydirection * phi, &m); + + pdf_concat_raw(p, &m); +} + +void +pdf__skew(PDF *p, pdc_scalar alpha, pdc_scalar beta) +{ + pdc_matrix m; + + pdc_check_number(p->pdc, "alpha", alpha); + pdc_check_number(p->pdc, "beta", beta); + + if (alpha == 0 && beta == 0) + return; + + if (alpha > 360 || alpha < -360 || + alpha == -90 || alpha == -270 || + alpha == 90 || alpha == 270) + { + pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, + "alpha", pdc_errprintf(p->pdc, "%f", alpha), 0, 0); + } + + if (beta > 360 || beta < -360 || + beta == -90 || beta == -270 || + beta == 90 || beta == 270) + { + pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, + "beta", pdc_errprintf(p->pdc, "%f", beta), 0, 0); + } + + pdc_skew_matrix(p->ydirection * alpha, p->ydirection * beta, &m); + + pdf_concat_raw(p, &m); +} + +void +pdf__concat(PDF *p, pdc_scalar a, pdc_scalar b, pdc_scalar c, pdc_scalar d, + pdc_scalar e, pdc_scalar f) +{ + pdc_matrix m; + pdc_scalar det = a * d - b * c; + + pdc_check_number(p->pdc, "a", a); + pdc_check_number(p->pdc, "b", b); + pdc_check_number(p->pdc, "c", c); + pdc_check_number(p->pdc, "d", d); + pdc_check_number(p->pdc, "e", e); + pdc_check_number(p->pdc, "f", f); + + if (fabs(det) < PDF_SMALLREAL) + pdc_error(p->pdc, PDC_E_ILLARG_MATRIX, + pdc_errprintf(p->pdc, "%f %f %f %f %f %f", a, b, c, d, e, f), + 0, 0, 0); + + m.a = a; + m.b = b; + m.c = c; + m.d = d; + m.e = e; + m.f = f; + + pdf_concat_raw(p, &m); +} + +void +pdf_setmatrix_e(PDF *p, pdc_matrix *n) +{ + pdc_matrix m; + pdc_scalar det = n->a * n->d - n->b * n->c; + + if (fabs(det) < PDF_SMALLREAL) + pdc_error(p->pdc, PDC_E_ILLARG_MATRIX, + pdc_errprintf(p->pdc, "%f %f %f %f %f %f", + n->a, n->b, n->c, n->d, n->e, n->f), + 0, 0, 0); + + pdc_invert_matrix(p->pdc, &m, &p->curr_ppt->gstate[p->curr_ppt->sl].ctm); + pdc_multiply_matrix(n, &m); + pdf_concat_raw(p, &m); +} + + +void +pdf__setmatrix(PDF *p, pdc_scalar a, pdc_scalar b, pdc_scalar c, pdc_scalar d, + pdc_scalar e, pdc_scalar f) +{ + pdc_matrix n; + + pdc_check_number(p->pdc, "a", a); + pdc_check_number(p->pdc, "b", b); + pdc_check_number(p->pdc, "c", c); + pdc_check_number(p->pdc, "d", d); + pdc_check_number(p->pdc, "e", e); + pdc_check_number(p->pdc, "f", f); + + n.a = a; + n.b = b; + n.c = c; + n.d = d; + n.e = e; + n.f = f; + pdf_setmatrix_e(p, &n); +} + +/* -------------------- General graphics state ---------------------------- */ + +/* definitions of dash options */ +static const pdc_defopt pdf_dashoptions[] = +{ + {"dasharray", pdc_scalarlist, PDC_OPT_NONE, 2, PDF_MAX_DASHLENGTH, + PDC_FLOAT_PREC, PDC_FLOAT_MAX, NULL}, + + {"dashphase", pdc_scalarlist, PDC_OPT_NONE, 1, 1, 0.0, PDC_FLOAT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +void +pdf_setdashpattern_internal(PDF *p, pdc_scalar *darray, int length, + pdc_scalar phase) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + /* length == 0 or 1 means solid line */ + if (length < 2) + { + if (gs->dashed || PDF_FORCE_OUTPUT()) + { + pdc_puts(p->out, "[] 0 d\n"); + gs->dashed = pdc_false; + } + } + else + { + int i; + + pdc_begin_array(p->out); + for (i = 0; i < length; i++) + { + pdc_printf(p->out, "%f ", darray[i]); + } + pdc_end_array_c(p->out); + pdc_printf(p->out, "%f d\n", phase); + gs->dashed = pdc_true; + } +} + +void +pdf__setdash(PDF *p, pdc_scalar b, pdc_scalar w) +{ + pdc_scalar darray[2]; + int length = 2; + + pdc_check_number_limits(p->pdc, "b", b, 0.0, PDC_FLOAT_MAX); + pdc_check_number_limits(p->pdc, "w", w, 0.0, PDC_FLOAT_MAX); + + /* both zero means solid line */ + if (b == 0.0 && w == 0.0) + { + length = 0; + } + else + { + darray[0] = b; + darray[1] = w; + } + pdf_setdashpattern_internal(p, darray, length, 0); +} + +void +pdf__setdashpattern(PDF *p, const char *optlist) +{ + pdc_resopt *results; + char **strlist; + pdc_scalar *darray = NULL, phase = 0; + int length; + + /* parsing optlist */ + results = pdc_parse_optionlist(p->pdc, optlist, pdf_dashoptions, NULL, + pdc_true); + + length = pdc_get_optvalues("dasharray", results, NULL, &strlist); + darray = (pdc_scalar *) strlist; + + pdc_get_optvalues("dashphase", results, &phase, NULL); + + pdf_setdashpattern_internal(p, darray, length, phase); + + pdc_cleanup_optionlist(p->pdc, results); +} + +void +pdf__setflat(PDF *p, pdc_scalar flat) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + pdc_check_number_limits(p->pdc, "flat", flat, 0.0, 100.0); + + if (flat != gs->flatness || PDF_FORCE_OUTPUT()) + { + gs->flatness = flat; + pdc_printf(p->out, "%f i\n", flat); + } +} + +void +pdf__setlinejoin(PDF *p, int join) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + const int LAST_JOIN = 2; + + if (join < 0 || join > LAST_JOIN) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "join", pdc_errprintf(p->pdc, "%d", join), 0, 0); + + if (join != gs->ljoin || PDF_FORCE_OUTPUT()) + { + gs->ljoin = join; + pdc_printf(p->out, "%d j\n", join); + } +} + +void +pdf__setlinecap(PDF *p, int cap) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + const int LAST_CAP = 2; + + if (cap < 0 || cap > LAST_CAP) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "cap", pdc_errprintf(p->pdc, "%d", cap), 0, 0); + + if (cap != gs->lcap || PDF_FORCE_OUTPUT()) + { + gs->lcap = cap; + pdc_printf(p->out, "%d J\n", cap); + } +} + +void +pdf__setmiterlimit(PDF *p, pdc_scalar miter) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + pdc_check_number_limits(p->pdc, "miter", miter, 1.0, PDC_FLOAT_MAX); + + if (miter != gs->miter || PDF_FORCE_OUTPUT()) + { + gs->miter = miter; + pdc_printf(p->out, "%f M\n", miter); + } +} + +void +pdf__setlinewidth(PDF *p, pdc_scalar width) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + pdc_check_number_limits(p->pdc, "width", width, + PDC_FLOAT_PREC, PDC_FLOAT_MAX); + + if (width != gs->lwidth || PDF_FORCE_OUTPUT()) + { + gs->lwidth = width; + pdc_printf(p->out, "%f w\n", width); + } +} + +/* reset all gstate parameters except CTM +*/ +void +pdf_reset_gstate(PDF *p) +{ + pdf_gstate *gs = &p->curr_ppt->gstate[p->curr_ppt->sl]; + + pdf_set_default_color(p, pdc_true); + pdf__setlinewidth(p, 1); + pdf__setlinecap(p, 0); + pdf__setlinejoin(p, 0); + pdf__setmiterlimit(p, 10); + pdf__setdash(p, 0, 0); + + if (gs->flatness != -1) + pdf__setflat(p, 1); +} + +void +pdf__initgraphics(PDF *p) +{ + pdc_matrix inv_ctm; + + pdf_reset_gstate(p); + + pdc_invert_matrix(p->pdc, &inv_ctm, + &p->curr_ppt->gstate[p->curr_ppt->sl].ctm); + pdf_concat_raw(p, &inv_ctm); + + /* This also resets the CTM which guards against rounding artifacts. */ + pdf_init_gstate(p); +} diff --git a/src/pdflib/pdflib/p_hkscmyk.h b/src/pdflib/pdflib/p_hkscmyk.h new file mode 100644 index 0000000..924ad64 --- /dev/null +++ b/src/pdflib/pdflib/p_hkscmyk.h @@ -0,0 +1,28 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_hkscmyk.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib HKS spot CMYK color table + * + * HKS is a registered trademark of + * HKS (Hostmann-Steinberg, K+E, Schmincke)-Warenzeichenverband e.V. + * Germany + * + */ + +#ifndef P_HKSCMYK_H +#define P_HKSCMYK_H + + +#endif /* P_HKSCMYK_H */ + diff --git a/src/pdflib/pdflib/p_hkslab.h b/src/pdflib/pdflib/p_hkslab.h new file mode 100644 index 0000000..68f13bb --- /dev/null +++ b/src/pdflib/pdflib/p_hkslab.h @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_hkslab.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib HKS spot Lab color table + * + * HKS is a registered trademark of + * HKS (Hostmann-Steinberg, K+E, Schmincke)-Warenzeichenverband e.V. Germany + * + */ + +#ifndef P_HKSLAB_H +#define P_HKSLAB_H + + +#endif /* P_HKSTAB_H */ diff --git a/src/pdflib/pdflib/p_hyper.c b/src/pdflib/pdflib/p_hyper.c new file mode 100644 index 0000000..644e311 --- /dev/null +++ b/src/pdflib/pdflib/p_hyper.c @@ -0,0 +1,1449 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_hyper.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib routines for hypertext stuff: + * named destination, bookmarks, document info + * + */ + +#define P_HYPER_C + +#include "p_intern.h" +#include "p_color.h" + + + + +/* -------------------------- named destinations -------------------------- */ + +typedef enum +{ + fixed, + fitwindow, + fitwidth, + fitheight, + fitrect, + fitvisible, + fitvisiblewidth, + fitvisibleheight, + nameddest, + filedest +} +pdf_desttype; + +static const pdc_keyconn pdf_type_keylist[] = +{ + {"fixed", fixed}, + {"fitwindow", fitwindow}, + {"fitwidth", fitwidth}, + {"fitheight", fitheight}, + {"fitrect", fitrect}, + {"fitvisible", fitvisible}, + {"fitvisiblewidth", fitvisiblewidth}, + {"fitvisibleheight",fitvisibleheight}, + {"nameddest", nameddest}, + {"file", filedest}, + {NULL, 0} +}; + +/* Destination structure */ +struct pdf_dest_s +{ + pdf_desttype type; + char *filename; /* name of a file to be launched - deprecated */ + int remote_page; /* remote target page number */ + int pgnum; + pdc_id page; /* local target page object id */ + char *name; /* destination name, only for type=nameddest */ + int len; /* length of the name string */ + pdc_scalar zoom; /* magnification */ + pdc_scalar left; + pdc_scalar right; + pdc_scalar bottom; + pdc_scalar top; + pdc_scalar color[3]; /* rgb color of bookmark text - deprecated */ + fnt_fontstyle fontstyle; /* font style of bookmark text - deprecated */ +}; + +static const pdc_defopt pdf_destination_options[] = +{ + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"hypertextformat", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_textformat_keylist}, + + {"fitbbox", pdc_booleanlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, NULL}, + + {"fitheight", pdc_booleanlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, NULL}, + + {"fitpage", pdc_booleanlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, NULL}, + + {"fitwidth", pdc_booleanlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, NULL}, + + {"retain", pdc_booleanlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, NULL}, + + {"type", pdc_keywordlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, pdf_type_keylist}, + + {"name", pdc_stringlist, PDC_OPT_NONE, + 1, 1, 1.0, PDC_INT_MAX, NULL}, + + {"page", pdc_integerlist, PDC_OPT_NONE, + 1, 1, 0, PDC_INT_MAX, NULL}, + + {"group", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 1.0, PDF_MAX_NAMESTRING, NULL}, + + /* Acrobat 5 supports a maximum zoom of 1600%, but we allow some more */ + {"zoom", pdc_scalarlist, PDC_OPT_PERCENT, + 1, 1, 0.0, 10000, NULL}, + + {"left", pdc_scalarlist, PDC_OPT_NONE, + 1, 1, 0.0, PDF_ACRO_MAXPAGE, NULL}, + + {"right", pdc_scalarlist, PDC_OPT_NONE, + 1, 1, 0.0, PDF_ACRO_MAXPAGE, NULL}, + + {"bottom", pdc_scalarlist, PDC_OPT_REQUIRIF1, + 1, 1, 0.0, PDF_ACRO_MAXPAGE, NULL}, + + {"top", pdc_scalarlist, PDC_OPT_NONE, + 1, 1, 0.0, PDF_ACRO_MAXPAGE, NULL}, + + {"color", pdc_scalarlist, PDC_OPT_NONE, + 1, 3, 0.0, 1.0, NULL}, + + {"fontstyle", pdc_keywordlist, PDC_OPT_NONE, + 1, 1, 0.0, 0.0, pdf_fontstyle_pdfkeylist}, + + {"filename", pdc_stringlist, PDC_OPT_NONE, + 1, 1, 0.0, PDC_FILENAMELEN, NULL}, + + PDC_OPT_TERMINATE +}; + +pdf_dest * +pdf_init_destination(PDF *p) +{ + static const char fn[] = "pdf_init_destination"; + pdf_dest *dest = (pdf_dest *) pdc_malloc(p->pdc, sizeof(pdf_dest), fn); + + dest->type = fitwindow; + dest->remote_page = 0; + dest->pgnum = 0; + dest->page = PDC_BAD_ID; + dest->left = -1; + dest->right = -1; + dest->bottom = -1; + dest->top = -1; + dest->zoom = -1; + dest->name = NULL; + dest->color[0] = 0.0; + dest->color[1] = 0.0; + dest->color[2] = 0.0; + dest->fontstyle = fnt_Normal; + dest->filename = NULL; + + return dest; +} + +void +pdf_cleanup_destination(PDF *p, pdf_dest *dest) +{ + if (dest) + { + if (dest->name) + { + pdc_free(p->pdc, dest->name); + dest->name = NULL; + } + if (dest->filename) + { + pdc_free(p->pdc, dest->filename); + dest->filename = NULL; + } + + pdc_free(p->pdc, dest); + } +} + +pdf_dest * +pdf_parse_destination_optlist( + PDF *p, + const char *optlist, + int page, + pdf_destuse destuse) +{ + int minpage; + pdc_resopt *resopts; + pdc_encoding hypertextencoding; + int hypertextcodepage; + const char *keyword; + const char *type_name; + char **strlist = NULL; + int inum; + pdc_bool boolval; + + /* Defaults */ + pdf_dest *dest = pdf_init_destination(p); + + /* parse option list */ + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_destination_options, + NULL, pdc_true); + + if (pdc_get_optvalues("fitbbox", resopts, &boolval, NULL) && + boolval == pdc_true) + dest->type = fitvisible; + + if (pdc_get_optvalues("fitheight", resopts, &boolval, NULL) && + boolval == pdc_true) + dest->type = fitheight; + + if (pdc_get_optvalues("fitpage", resopts, &boolval, NULL) && + boolval == pdc_true) + dest->type = fitwindow; + + if (pdc_get_optvalues("fitwidth", resopts, &boolval, NULL) && + boolval == pdc_true) + dest->type = fitwidth; + + if (pdc_get_optvalues("retain", resopts, &boolval, NULL) && + boolval == pdc_true) + dest->type = fixed; + + if (pdc_get_optvalues("type", resopts, &inum, NULL)) + dest->type = (pdf_desttype) inum; + type_name = pdc_get_keyword(dest->type, pdf_type_keylist); + + hypertextencoding = + pdf_get_hypertextencoding_opt(p, resopts, &hypertextcodepage, pdc_true); + + keyword = "name"; + if (pdf_get_opt_textlist(p, keyword, resopts, hypertextencoding, + hypertextcodepage, pdc_true, NULL, &dest->name, NULL)) + { + if (dest->type != nameddest) + { + dest->name = NULL; + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, + type_name, 0, 0); + } + else + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + keyword = "page"; + if (pdc_get_optvalues(keyword, resopts, &page, NULL) && + dest->type == filedest) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "group"; + if (pdc_get_optvalues(keyword, resopts, NULL, &strlist)) + { + page = pdf_xlat_pageno(p, page, strlist[0]); + } + + keyword = "zoom"; + if (pdc_get_optvalues(keyword, resopts, &dest->zoom, NULL) && + dest->type != fixed) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "left"; + if (pdc_get_optvalues(keyword, resopts, &dest->left, NULL) && + (dest->type == fitwindow || dest->type == fitwidth || + dest->type == fitvisible || dest->type == fitvisiblewidth || + dest->type == nameddest || dest->type == filedest)) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "right"; + if (pdc_get_optvalues(keyword, resopts, &dest->right, NULL) && + dest->type != fitrect) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "bottom"; + if (pdc_get_optvalues(keyword, resopts, &dest->bottom, NULL) && + dest->type != fitrect) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "top"; + if (pdc_get_optvalues(keyword, resopts, &dest->top, NULL) && + (dest->type == fitwindow || dest->type == fitheight || + dest->type == fitvisible || dest->type == fitvisibleheight || + dest->type == nameddest || dest->type == filedest)) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, type_name, + 0, 0); + + keyword = "color"; + if (pdc_get_optvalues(keyword, resopts, &dest->color, NULL) && + destuse != pdf_bookmark) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORELEM, keyword, 0, 0, 0); + + keyword = "fontstyle"; + if (pdc_get_optvalues(keyword, resopts, &inum, NULL)) + { + dest->fontstyle = (fnt_fontstyle) inum; + if (destuse != pdf_bookmark) + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORELEM, keyword, 0, 0, 0); + } + + keyword = "filename"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + { + if (dest->type != filedest) + { + pdc_warning(p->pdc, PDF_E_HYP_OPTIGNORE_FORTYPE, keyword, + type_name, 0, 0); + } + else + dest->filename = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + pdc_cleanup_optionlist(p->pdc, resopts); + + switch (dest->type) + { + case fitwidth: + /* Trick: we don't know the height of a future page yet, + * so we use a "large" value for top which will do for + * most pages. If it doesn't work, not much harm is done. + */ + if (dest->top == -1) + dest->top = 10000; + break; + + case fitrect: + case fitheight: + case fitvisiblewidth: + case fitvisibleheight: + if (dest->left == -1) + dest->left = 0; + if (dest->bottom == -1) + dest->bottom = 0; + if (dest->right == -1) + dest->right = 1000; + if (dest->top == -1) + dest->top = 1000; + break; + + case nameddest: + if (destuse == pdf_nameddest) + { + pdf_cleanup_destination(p, dest); + pdc_error(p->pdc, PDC_E_OPT_ILLKEYWORD, "type", type_name, 0, 0); + } + if (dest->name == NULL) + { + pdf_cleanup_destination(p, dest); + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "name", 0, 0, 0); + } + break; + + case filedest: + if (destuse != pdf_bookmark) + { + pdf_cleanup_destination(p, dest); + pdc_error(p->pdc, PDC_E_OPT_ILLKEYWORD, "type", type_name, 0, 0); + } + if (dest->filename == NULL) + { + pdf_cleanup_destination(p, dest); + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "filename", 0, 0, 0); + } + break; + + default: + break; + } + + /* check for minpage */ + minpage = (destuse == pdf_bookmark) ? 0 : 1; + switch (destuse) + { + case pdf_nameddest: + case pdf_locallink: + if (page == 0) + { + page = pdf_current_page(p); + } + + case pdf_openaction: + case pdf_bookmark: + case pdf_remotelink: + if (page < minpage) + { + const char *stemp = pdc_errprintf(p->pdc, "%d", page); + pdf_cleanup_destination(p, dest); + pdc_error(p->pdc, PDC_E_ILLARG_HANDLE, "page", stemp, 0, 0); + } + break; + } + + dest->pgnum = page; + + if (destuse != pdf_remotelink && destuse != pdf_openaction && page != 0) + { + dest->page = pdf_get_page_id(p, page); + } + + /* remote page number */ + if (destuse == pdf_remotelink) + dest->remote_page = page; + + return dest; +} + +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma unmanaged +#endif +pdf_dest * +pdf_get_option_destname(PDF *p, pdc_resopt *resopts, + pdc_encoding hypertextencoding, + int hypertextcodepage) +{ + pdc_text_format hypertextformat = pdc_bytes; + pdf_dest *dest = NULL; + char **strlist; + int outlen; + + if (pdc_get_optvalues("destname", resopts, NULL, &strlist)) + { + dest = pdf_init_destination(p); + dest->type = nameddest; + + if (pdc_is_lastopt_utf8(resopts)) + hypertextformat = PDC_UTF8; + dest->name = pdf_convert_hypertext(p, strlist[0], 0, hypertextformat, + hypertextencoding, hypertextcodepage, + &outlen, PDC_UTF8_FLAG, pdc_true); + } + return dest; +} +#if defined(_MSC_VER) && defined(_MANAGED) +#pragma managed +#endif + + +void +pdf_write_destination(PDF *p, pdf_dest *dest) +{ + if (dest->type == nameddest) + { + pdf_put_hypertext(p, dest->name); + pdc_puts(p->out, "\n"); + return; + } + + pdc_begin_array(p->out); + + if (dest->remote_page) + { + pdc_printf(p->out, "%d", dest->remote_page - 1); /* zero-based */ + } + else + { + if (dest->page == PDC_BAD_ID) + dest->page = pdf_get_page_id(p, dest->pgnum); + + pdc_objref_c(p->out, dest->page); + } + + switch (dest->type) { + + case fixed: + pdc_puts(p->out, "/XYZ "); + + if (dest->left != -1) + pdc_printf(p->out, "%f ", dest->left); + else + pdc_puts(p->out, "null "); + + if (dest->top != -1) + pdc_printf(p->out, "%f ", dest->top); + else + pdc_puts(p->out, "null "); + + if (dest->zoom != -1) + pdc_printf(p->out, "%f", dest->zoom); + else + pdc_puts(p->out, "null"); + + break; + + case fitwindow: + pdc_puts(p->out, "/Fit"); + break; + + case fitwidth: + pdc_printf(p->out, "/FitH %f", dest->top); + break; + + case fitheight: + pdc_printf(p->out, "/FitV %f", dest->left); + break; + + case fitrect: + pdc_printf(p->out, "/FitR %f %f %f %f", + dest->left, dest->bottom, dest->right, dest->top); + break; + + case fitvisible: + pdc_puts(p->out, "/FitB"); + break; + + case fitvisiblewidth: + pdc_printf(p->out, "/FitBH %f", dest->top); + break; + + case fitvisibleheight: + pdc_printf(p->out, "/FitBV %f", dest->left); + break; + + default: + break; + } + + pdc_end_array(p->out); +} + +void +pdf__add_nameddest( + PDF *p, + const char *name, + int len, + const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdc_text_format hypertextformat = p->hypertextformat; + pdc_encoding hypertextencoding; + int hypertextcodepage; + pdc_id obj_id = PDC_BAD_ID; + char *name2 = NULL; + pdf_dest *dest; + int inum; + + if (!name) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "name", 0, 0, 0); + + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_destination_options, NULL, pdc_true); + + hypertextencoding = + pdf_get_hypertextencoding_opt(p, resopts, &hypertextcodepage, pdc_true); + + if (pdc_get_optvalues("hypertextformat", resopts, &inum, NULL)) + { + hypertextformat = (pdc_text_format) inum; + pdf_check_hypertextformat(p, hypertextformat); + } + + pdc_cleanup_optionlist(p->pdc, resopts); + + /* create hypertext string */ + name2 = pdf_convert_hypertext(p, name, len, hypertextformat, + hypertextencoding, hypertextcodepage, &len, + pdc_true, pdc_true); + if (name2 == NULL || len == 0) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "name", 0, 0, 0); + + /* parsing option list */ + dest = pdf_parse_destination_optlist(p, optlist, 0, pdf_nameddest); + + /* interrupt the content stream if we are on a page */ + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_end_contents_section(p); + + obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); /* Dest object */ + pdc_begin_dict(p->out); /* Destination dict */ + + pdc_puts(p->out, "/D"); + pdf_write_destination(p, dest); + + pdc_end_dict(p->out); /* Destination dict */ + pdc_end_obj(p->out); /* Dest object */ + + /* continue the contents stream */ + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + pdf_cleanup_destination(p, dest); + + /* insert name in tree */ + pdf_insert_name(p, name2, names_dests, obj_id); +} + + +/* -------------------------- bookmarks -------------------------- */ + +static const pdc_defopt pdf_create_bookmark_options[] = +{ + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"hypertextformat", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_textformat_keylist}, + + {"textcolor", pdc_stringlist, PDC_OPT_NONE, 2, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"fontstyle", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, pdf_fontstyle_pdfkeylist}, + + {"parent", pdc_bookmarkhandle, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"index", pdc_integerlist, PDC_OPT_NONE, 1, 1, + -1, PDC_INT_MAX, NULL}, + + {"open", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +struct pdf_outline_s { + pdc_id obj_id; /* id of this outline object */ + char *text; /* bookmark text */ + int count; /* number of open sub-entries */ + pdc_bool open; /* whether or not to display children */ + pdc_scalar textcolor[3]; /* rgb color of bookmark text */ + fnt_fontstyle fontstyle; /* font style of bookmark text */ + char *action; /* action optlist */ + pdf_dest *dest; /* outline destination */ + + /* these members control automatic ordering of bookmarks. + */ + pdc_bool in_order; /* this book mark is "in order" */ + pdc_id page_id; /* id of page where this bookmark */ + /* was defined */ + + /* the members below are indices into the p->outlines[] array. + */ + int prev; /* previous entry at this level */ + int next; /* next entry at this level */ + int parent; /* ancestor's index */ + int first; /* first sub-entry */ + int last; /* last sub-entry */ +}; + +static void +pdf_init_outline(PDF *p, pdf_outline *outline) +{ + (void) p; + + outline->obj_id = PDC_BAD_ID; + outline->text = NULL; + outline->count = 0; + outline->open = pdc_false; + outline->textcolor[0] = 0.0; + outline->textcolor[1] = 0.0; + outline->textcolor[2] = 0.0; + outline->fontstyle = fnt_Normal; + outline->action = NULL; + outline->dest = NULL; + outline->in_order = pdc_false; + outline->page_id = PDC_BAD_ID; + outline->prev = 0; + outline->next = 0; + outline->parent = 0; + outline->first = 0; + outline->last = 0; +} + +/* We can't work with pointers in the outline objects because + * the complete outline block may be reallocated. Therefore we use + * this simple mechanism for achieving indirection. + */ +#define COUNT(jndex) (p->outlines[jndex].count) +#define OPEN(jndex) (p->outlines[jndex].open) +#define IN_ORDER(jndex) (p->outlines[jndex].in_order) +#define PAGE_ID(jndex) (p->outlines[jndex].page_id) +#define LAST(jndex) (p->outlines[jndex].last) +#define PARENT(jndex) (p->outlines[jndex].parent) +#define FIRST(jndex) (p->outlines[jndex].first) +#define OBJ_ID(jndex) (p->outlines[jndex].obj_id) +#define PREV(jndex) (p->outlines[jndex].prev) +#define NEXT(jndex) (p->outlines[jndex].next) + +static int +search_forward(PDF *p, int start_page, int start_index) +{ + int idx; + + for (idx = start_index; idx != 0; idx = NEXT(idx)) + { + if (IN_ORDER(idx)) + return pdf_search_page_fwd(p, start_page, PAGE_ID(idx)); + } + + return PDC_INT_MAX; +} + +static int +search_backward(PDF *p, int start_page, int start_index) +{ + int idx; + + for (idx = start_index; idx != 0; idx = PREV(idx)) + { + if (IN_ORDER(idx)) + { + int pg = pdf_search_page_bwd(p, start_page, PAGE_ID(idx)); + + return (pg == -1) ? PDC_INT_MAX : pg; + } + } + + return -1; +} + +static int +pdf_insert_bookmark( + PDF *p, + const char *hypertext, + pdf_outline *outline, + int jndex) +{ + static const char fn[] = "pdf_insert_bookmark"; + pdf_outline *root, *self; + int parent; + int self_idx; + int pageno = pdf_current_page(p); + + /* allocation */ + if (p->outline_count == 0) + { + p->outline_capacity = OUTLINE_CHUNKSIZE; + p->outlines = (pdf_outline *) pdc_calloc(p->pdc, + sizeof(pdf_outline) * p->outline_capacity, fn); + + /* populate the root outline object */ + root = &p->outlines[0]; + pdf_init_outline(p, root); + root->obj_id = pdc_alloc_id(p->out); + root->open = pdc_true; + + /* set the open mode show bookmarks if we have at least one, + * and the client didn't already set his own open mode. + */ + pdf_fix_openmode(p); + } + else if (p->outline_count + 1 >= p->outline_capacity) + { + p->outline_capacity *= 2; + p->outlines = (pdf_outline *) pdc_realloc(p->pdc, p->outlines, + sizeof(pdf_outline) * p->outline_capacity, fn); + } + + /* copy */ + self_idx = ++p->outline_count; + self = &p->outlines[self_idx]; + memcpy(self, outline, sizeof(pdf_outline)); + + self->obj_id = pdc_alloc_id(p->out); + self->text = (char *) hypertext; + self->page_id = pdf_get_page_id(p, 0); + parent = self->parent; + + /* default destination */ + if (self->action == NULL && self->dest == NULL) + self->dest = pdf_init_destination(p); + + /* no destination */ + if (self->dest != NULL && + self->dest->name != NULL && !strlen(self->dest->name)) + { + pdf_cleanup_destination(p, self->dest); + self->dest = NULL; + } + + /* current page */ + if (self->dest) + { + /* this ugly code is for compatibility with the + ** obsolete "bookmarkdest" parameter. + */ + if (self->dest->pgnum == 0) + self->dest->pgnum = pdf_current_page(p); + + if (self->dest->pgnum == 0) + { + self->dest->pgnum = 1; + } + else if (self->dest->page == PDC_BAD_ID) + { + self->dest->page = pdf_get_page_id(p, self->dest->pgnum); + } + } + + /* special case: empty list. + */ + if (FIRST(parent) == 0) + { + if (jndex > 0) + pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", + pdc_errprintf(p->pdc, "%d", jndex), 0, 0); + + FIRST(parent) = LAST(parent) = self_idx; + self->in_order = pdc_true; + } + else switch (jndex) + { + case -2: /* insert "in order" */ + { + /* the "natural" case: append to the end if appropriate. + */ + if (pageno >= search_backward(p, -1, LAST(parent))) + { + self->prev = LAST(parent); + NEXT(LAST(parent)) = self_idx; + LAST(parent) = self_idx; + } + else + { + int idx; + int curr_pg = 1; + int next_pg; + + for (idx = FIRST(parent); idx != 0; idx = NEXT(idx)) + { + if (!IN_ORDER(idx)) + continue; + + next_pg = pdf_search_page_fwd(p, curr_pg, PAGE_ID(idx)); + + /* TODO: understand why this can happen. + */ + if (next_pg < 1) + { + idx = 0; + break; + } + + if (next_pg > pageno) + { + self->next = idx; + self->prev = PREV(idx); + PREV(idx) = self_idx; + + if (self->prev == 0) + FIRST(parent) = self_idx; + else + NEXT(self->prev) = self_idx; + + break; + } + + curr_pg = next_pg; + } + + /* if there are no "in order" bookmarks yet, + ** we simply append this one to the end. + */ + if (idx == 0) + { + self->prev = LAST(parent); + NEXT(LAST(parent)) = self_idx; + LAST(parent) = self_idx; + } + } + + self->in_order = pdc_true; + break; + } + + case -1: /* append to the end */ + { + self->prev = LAST(parent); + NEXT(LAST(parent)) = self_idx; + LAST(parent) = self_idx; + + self->in_order = + (pageno >= search_backward(p, pageno, self->prev)); + break; + } + + case 0: /* insert at the beginning */ + { + self->next = FIRST(parent); + PREV(FIRST(parent)) = self_idx; + FIRST(parent) = self_idx; + + self->in_order = + (pageno <= search_forward(p, pageno, self->next)); + break; + } + + default: /* insert before [1..LAST] */ + { + int i; + int target = FIRST(parent); + + for (i = 0; i < jndex; ++i) + { + if (target == LAST(parent)) + pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", + pdc_errprintf(p->pdc, "%d", jndex), 0, 0); + + target = NEXT(target); + } + + self->next = target; + self->prev = PREV(target); + NEXT(self->prev) = PREV(self->next) = self_idx; + + self->in_order = + ((pageno >= search_backward(p, pageno, self->prev)) && + (pageno <= search_forward(p, pageno, self->next))); + break; + } + } /* else switch */ + + /* increase the number of open sub-entries for all relevant ancestors */ + do { + COUNT(parent)++; + } while (OPEN(parent) && (parent = PARENT(parent)) != 0); + + return (self_idx); /* caller may use this as handle */ +} + +int +pdf__create_bookmark(PDF *p, const char *text, int len, const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdc_clientdata data; + pdf_outline self; + pdf_dest *dest = NULL; + pdc_text_format hypertextformat; + pdc_encoding hypertextencoding; + pdf_coloropt textcolor; + char *hypertext = NULL; + const char *keyword = NULL; + char **strlist = NULL; + int hypertextcodepage; + int ns, inum, outlen, retval = 0; + int jndex = -2; + + /* Initialize */ + pdf_init_outline(p, &self); + hypertextformat = p->hypertextformat; + hypertextencoding = p->hypertextencoding; + hypertextcodepage = p->hypertextcodepage; + + /* Parsing option list */ + if (optlist && strlen(optlist)) + { + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_create_bookmark_options, &data, pdc_true); + + hypertextencoding = + pdf_get_hypertextencoding_opt(p, resopts, &hypertextcodepage, + pdc_true); + + if (pdc_get_optvalues("hypertextformat", resopts, &inum, NULL)) + { + hypertextformat = (pdc_text_format) inum; + pdf_check_hypertextformat(p, hypertextformat); + } + + ns = pdc_get_optvalues("textcolor", resopts, NULL, &strlist); + if (ns) + { + pdf_parse_coloropt(p, "textcolor", strlist, ns, (int) color_rgb, + &textcolor); + self.textcolor[0] = textcolor.value[0]; + self.textcolor[1] = textcolor.value[1]; + self.textcolor[2] = textcolor.value[2]; + } + + if (pdc_get_optvalues("fontstyle", resopts, &inum, NULL)) + self.fontstyle = (fnt_fontstyle) inum; + + pdc_get_optvalues("parent", resopts, &self.parent, NULL); + + pdc_get_optvalues("index", resopts, &jndex, NULL); + + pdc_get_optvalues("open", resopts, &self.open, NULL); + + if (pdc_get_optvalues("destination", resopts, NULL, &strlist)) + { + self.dest = pdf_parse_destination_optlist(p, strlist[0], 0, + pdf_bookmark); + keyword = "destination"; + } + else + { + dest = pdf_get_option_destname(p, resopts, hypertextencoding, + hypertextcodepage); + if (dest) + { + self.dest = dest; + keyword = "destname"; + } + } + + if (pdc_get_optvalues("action", resopts, NULL, &strlist)) + { + if (self.dest) + { + pdf_cleanup_destination(p, self.dest); + self.dest = NULL; + pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword, "action", 0, 0); + } + + /* parsing of action list */ + pdf_parse_and_write_actionlist(p, event_bookmark, NULL, + (const char *) strlist[0]); + self.action = + (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + } + + pdc_cleanup_optionlist(p->pdc, resopts); + } + + /* create hypertext string */ + hypertext = pdf_convert_hypertext(p, text, len, hypertextformat, + hypertextencoding, hypertextcodepage, + &outlen, PDC_UTF8_FLAG, pdc_true); + if (hypertext) + retval = pdf_insert_bookmark(p, hypertext, &self, jndex); + + return retval; +} + +static void +pdf_write_outline_dict(PDF *p, int entry) +{ + pdf_outline *outline = &p->outlines[entry]; + pdc_id act_idlist[PDF_MAX_EVENTS]; + + /* write action objects */ + if (outline->action) + pdf_parse_and_write_actionlist(p, event_bookmark, act_idlist, + (const char *) outline->action); + + pdc_begin_obj(p->out, OBJ_ID(entry)); /* outline object */ + pdc_begin_dict(p->out); + + pdc_objref(p->out, "/Parent", OBJ_ID(PARENT(entry))); + + /* outline destination */ + if (outline->dest) + { + pdc_puts(p->out, "/Dest"); + pdf_write_destination(p, outline->dest); + } + + /* write Action entries */ + else if (outline->action) + pdf_write_action_entries(p, event_bookmark, act_idlist); + + pdc_puts(p->out, "/Title"); /* outline text */ + pdf_put_hypertext(p, outline->text); + pdc_puts(p->out, "\n"); + + if (PREV(entry)) + pdc_objref(p->out, "/Prev", OBJ_ID(PREV(entry))); + if (NEXT(entry)) + pdc_objref(p->out, "/Next", OBJ_ID(NEXT(entry))); + + if (FIRST(entry)) { + pdc_objref(p->out, "/First", OBJ_ID(FIRST(entry))); + pdc_objref(p->out, "/Last", OBJ_ID(LAST(entry))); + } + if (COUNT(entry)) { + if (OPEN(entry)) + pdc_printf(p->out, "/Count %d\n", COUNT(entry)); /* open */ + else + pdc_printf(p->out, "/Count %d\n", -COUNT(entry));/* closed */ + } + + /* Color */ + if (outline->textcolor[0] != 0.0 || + outline->textcolor[1] != 0.0 || + outline->textcolor[2] != 0.0) + pdc_printf(p->out, "/C[%f %f %f]\n", outline->textcolor[0], + outline->textcolor[1], + outline->textcolor[2]); + + /* FontStyle */ + if (outline->fontstyle != fnt_Normal) + { + int fontstyle = 0; + if (outline->fontstyle == fnt_Bold) + fontstyle = 2; + if (outline->fontstyle == fnt_Italic) + fontstyle = 1; + if (outline->fontstyle == fnt_BoldItalic) + fontstyle = 3; + pdc_printf(p->out, "/F %d\n", fontstyle); + } + + pdc_end_dict(p->out); + pdc_end_obj(p->out); /* outline object */ +} + +void +pdf_write_outlines(PDF *p) +{ + int i; + + if (p->outline_count == 0) /* no outlines: return */ + return; + + pdc_begin_obj(p->out, p->outlines[0].obj_id); /* root outline object */ + pdc_begin_dict(p->out); + + if (p->outlines[0].count != 0) + pdc_printf(p->out, "/Count %d\n", COUNT(0)); + pdc_objref(p->out, "/First", OBJ_ID(FIRST(0))); + pdc_objref(p->out, "/Last", OBJ_ID(LAST(0))); + + pdc_end_dict(p->out); + pdc_end_obj(p->out); /* root outline object */ + +#define PDF_FLUSH_AFTER_MANY_OUTLINES 1000 /* ca. 50-100 KB */ + for (i = 1; i <= p->outline_count; i++) { + /* reduce memory usage for many outline entries */ + if (i % PDF_FLUSH_AFTER_MANY_OUTLINES == 0) + pdc_flush_stream(p->out); + + pdf_write_outline_dict(p, i); + } +} + +void +pdf_write_outline_root(PDF *p) +{ + if (p->outline_count != 0) + pdc_objref(p->out, "/Outlines", p->outlines[0].obj_id); +} + +void +pdf_init_outlines(PDF *p) +{ + p->outline_count = 0; +} + +/* Free outline entries */ +void +pdf_cleanup_outlines(PDF *p) +{ + int i; + + if (!p->outlines || p->outline_count == 0) + return; + + /* outlines[0] is the outline root object */ + for (i = 0; i <= p->outline_count; i++) + { + if (p->outlines[i].text) + { + pdc_free(p->pdc, p->outlines[i].text); + p->outlines[i].text = NULL; + } + if (p->outlines[i].action) + { + pdc_free(p->pdc, p->outlines[i].action); + p->outlines[i].action = NULL; + } + pdf_cleanup_destination(p, p->outlines[i].dest); + p->outlines[i].dest = NULL; + } + + pdc_free(p->pdc, (void*) p->outlines); + + p->outlines = NULL; +} + + +/*****************************************************************************/ +/** deprecated historical bookmark function **/ +/*****************************************************************************/ + +int +pdf__add_bookmark(PDF *p, const char *text, int len, int parent, int open) +{ + pdf_outline self; + pdf_dest *dest = (pdf_dest *) p->bookmark_dest; + char *hypertext = NULL; + int acthdl; + int retval = 0; + + pdf_init_outline(p, &self); + + if (parent != 0) + pdf_check_handle(p, parent, pdc_bookmarkhandle); + self.parent = parent; + self.open = open; + + /* creating a Launch action - defined via bookmarkdest */ + if (dest->filename) + { + char actoptlist[2048]; + + sprintf(actoptlist, "filename {%s} ", dest->filename); + acthdl = pdf__create_action(p, "Launch", actoptlist); + if (acthdl != -1) + { + if (p->pdc->hastobepos) acthdl++; + sprintf(actoptlist, "activate %d", acthdl); + self.action = pdc_strdup(p->pdc, actoptlist); + } + } + else + { + self.dest = pdf_init_destination(p); + *self.dest = *dest; + if (dest->name) + self.dest->name = pdc_strdup(p->pdc, dest->name); + } + + memcpy(self.textcolor, dest->color, 3 * sizeof(pdc_scalar)); + self.fontstyle = dest->fontstyle; + + hypertext = pdf_convert_hypertext_depr(p, text, len); + if (hypertext) + retval = pdf_insert_bookmark(p, hypertext, &self, -1); + + return retval; +} + +/* -------------------------- document info ------------------------------- */ + +struct pdf_info_s +{ + char *key; /* ASCII string */ + char *value; /* Unicode string */ + pdf_info *next; /* next info entry */ +}; + +void +pdf_cleanup_info(PDF *p) +{ + pdf_info *info, *last; + + if (p->userinfo) + { + for (info = p->userinfo; info != NULL; /* */) + { + last = info; + info = info->next; + + pdc_free(p->pdc, last->key); + pdc_free(p->pdc, last->value); + pdc_free(p->pdc, last); + } + + p->userinfo = NULL; + } +} + +static pdf_info * +pdf_have_infokey(PDF *p, const char *key) +{ + pdf_info *info; + + for (info = p->userinfo; info != NULL; info = info->next) + { + if (strlen(info->key) == strlen(key) && !strcmp(info->key, key)) + return info; + } + + return NULL; +} + +void +pdf_feed_digest_info(PDF *p) +{ + pdf_info *info; + + if (p->userinfo) + { + for (info = p->userinfo; info != NULL; info = info->next) + { + pdc_update_digest(p->out, + (unsigned char *) info->key, strlen(info->key)); + } + } +} + +#define PDF_TRAPPED_TRUE "True" +#define PDF_TRAPPED_FALSE "False" +#define PDF_TRAPPED_UNKNOWN "Unknown" + +/* Set Info dictionary entries */ +void +pdf__set_info(PDF *p, const char *key, const char *value, int len) +{ + static const char fn[] = "pdf__set_info"; + char *key_buf, *val_buf; + pdf_info *oldentry, *newentry; + + if (key == NULL || !*key) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "key", 0, 0, 0); + + if (!strcmp(key, "Producer") || + !strcmp(key, "CreationDate") || + !strcmp(key, "ModDate")) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "key", key, 0, 0); + + /* converting key */ + key_buf = pdf_convert_name(p, key, 0, 0); + + /* convert text string */ + val_buf = pdf_convert_hypertext_depr(p, value, len); + if (!val_buf) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "value", 0, 0, 0); + + /* special handling required for "Trapped" */ + if (!strcmp(key_buf, "Trapped")) + { + if (strcmp(val_buf, PDF_TRAPPED_TRUE) && + strcmp(val_buf, PDF_TRAPPED_FALSE) && + strcmp(val_buf, PDF_TRAPPED_UNKNOWN)) + { + pdc_free(p->pdc, val_buf); + pdc_free(p->pdc, key_buf); + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + } + } + + oldentry = pdf_have_infokey(p, key_buf); + if (oldentry != NULL) + { + pdc_free(p->pdc, key_buf); + pdc_free(p->pdc, oldentry->value); + oldentry->value = val_buf; + } + else + { + newentry = (pdf_info *) + pdc_malloc(p->pdc, sizeof(pdf_info), fn); + newentry->key = key_buf; + newentry->value = val_buf; + newentry->next = p->userinfo; + + /* ordering doesn't matter so we insert at the beginning */ + p->userinfo = newentry; + } +} + + +pdc_id +pdf_write_info(PDF *p, pdc_bool moddate) +{ + char time_str[PDC_TIME_SBUF_SIZE]; + char producer[PDF_MAX_PARAMSTRING]; + pdf_info *info; + pdc_id info_id; + + + + const char *product = "PDFlib Lite"; + + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, + "[Full product name: \"%s\"]\n", product); + + info_id = pdc_begin_obj(p->out, PDC_NEW_ID); /* Info object */ + + pdc_begin_dict(p->out); + + /* + * Although it would be syntactically correct, we must not remove + * the space characters after the dictionary keys since this + * would break the PDF properties feature in Windows Explorer. + */ + + if (p->userinfo) + { + for (info = p->userinfo; info != NULL; info = info->next) + { + pdf_put_pdfname(p, info->key); + pdc_puts(p->out, " "); + + if (strcmp(info->key, "Trapped")) + pdf_put_hypertext(p, info->value); + else + pdf_put_pdfname(p, info->value); + + pdc_puts(p->out, "\n"); + } + } + + + pdc_get_timestr(time_str, pdc_false); + + /* creation date and time */ + pdc_puts(p->out, "/CreationDate "); + pdf_put_hypertext(p, time_str); + pdc_puts(p->out, "\n"); + + /* modification date and time */ + if (moddate) + { + pdc_puts(p->out, "/ModDate "); + pdf_put_hypertext(p, time_str); + pdc_puts(p->out, "\n"); + } + + /* + * If you change the /Producer entry your license to use + * PDFlib will be void! + */ + + if (p->pdc->binding) + sprintf(producer, "%s %s (%s/%s)", product, + PDFLIB_VERSIONSTRING, p->pdc->binding, PDF_PLATFORM); + else + sprintf(producer, "%s %s (%s)", product, + PDFLIB_VERSIONSTRING, PDF_PLATFORM); + + pdc_puts(p->out, "/Producer "); + pdf_put_hypertext(p, producer); + pdc_puts(p->out, "\n"); + + pdc_end_dict(p->out); + pdc_end_obj(p->out); /* Info object */ + + + + + return info_id; +} + + diff --git a/src/pdflib/pdflib/p_icc.c b/src/pdflib/pdflib/p_icc.c new file mode 100644 index 0000000..072ea55 --- /dev/null +++ b/src/pdflib/pdflib/p_icc.c @@ -0,0 +1,32 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_icc.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib ICC handling routines + * + * This software is based in part on the work of Graeme W. Gill + * + */ + +#define P_ICC_C + +#include "p_intern.h" +#include "p_color.h" + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + + + diff --git a/src/pdflib/pdflib/p_icc.h b/src/pdflib/pdflib/p_icc.h new file mode 100644 index 0000000..73fedfa --- /dev/null +++ b/src/pdflib/pdflib/p_icc.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_icc.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib ICC typedefs, structures, and enums + * + */ + +#ifndef P_ICC_H +#define P_ICC_H + + +#endif /* P_ICC_H */ + diff --git a/src/pdflib/pdflib/p_icc9809.h b/src/pdflib/pdflib/p_icc9809.h new file mode 100644 index 0000000..3ceb0f7 --- /dev/null +++ b/src/pdflib/pdflib/p_icc9809.h @@ -0,0 +1,38 @@ +/* $Id: p_icc9809.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Header file of ICC (name see note above) for ICClib and PDFlib + * + */ + +/* + * Note: Modified for use by icclib V2.00: + * + * Changed guard bands from ICC_H to ICC9809_H + * + * Replace tag last values 0xFFFFFFFFL with define icMaxTagVal, + * and define this to be -1, for better compiler compatibility. + * + * Add section to use machine specific INR & ORD to define + * the sizes of ic Numbers, if ORD is defined. + * + * Adding colorspaces 'MCH5-8' for Hexachrome and others. (Colorsync ?) + * Added the Positive/Negative and Color/BlackAndWhite Attribute bits + * + * I believe icMeasurementFlare as an enumeration is bogus in + * this file. It is meant to be a u16.16 number. + * + * Add Chromaticity Tag and Type from ICC.1A:1999-04, + * but there is no formal "icc.h" from the ICC that indicates + * what the names should be. + * + * Added Colorsync 2.5 specific VideoCardGamma defines. + * + * Graeme Gill. + */ + +/* Header file guard bands */ +#ifndef P_ICC9809_H +#define P_ICC9809_H + + +#endif /* P_ICC9809_H */ diff --git a/src/pdflib/pdflib/p_icclib.c b/src/pdflib/pdflib/p_icclib.c new file mode 100644 index 0000000..02275da --- /dev/null +++ b/src/pdflib/pdflib/p_icclib.c @@ -0,0 +1,62 @@ +/* $Id: p_icclib.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * ICClib routines for PDFlib, slightly modified from the original ICClib. + * (see below). + * + * $Log: p_icclib.c,v $ + * Revision 1.1 2008/10/17 06:11:49 scuri + * First commit - moving from LuaForge to SourceForge + * + * Revision 1.3 2007/11/06 15:48:55 scuri + * PDF Lite library updated to version "7.0.2". + * + * Revision 1.18.8.3 2007/05/23 21:15:00 york + * fixed #1230: "Performance problems in mulithreaded env with tolower/toupper". + * + * Revision 1.18.8.2 2007/05/23 19:37:21 york + * implemented pdc_isXXX() character classification macros. + * started to replace isXXX() with pdc_isXXX() in all modules. + * + * Revision 1.18.8.1 2007/03/28 12:47:10 kurt + * bug #1180 (Function prefixes missing for zlib assembler and ICC code) fixed + * names of all external functions of ICClib have the prefix "pdf_" now + * + * Revision 1.18 2004/08/05 09:11:27 rjs + * merged 6.0.x to pdflib-x + * + * Revision 1.17.2.1 2004/07/30 16:14:30 kurt + * icc_read: all free statements in the error case removed + * (because of program crash in icc_delete) + * icc_delete: more security checks + * new public function: icc_get_errmsg + * + */ + +/* + * International Color Consortium Format Library (icclib) + * For ICC profile version 3.4 + * + * Author: Graeme W. Gill + * Date: 2002/04/22 + * Version: 2.02 + * + * Copyright 1997 - 2002 Graeme W. Gill + * See Licence.txt file for conditions of use. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#ifdef __sun +#include <unistd.h> +#endif +#if defined(__IBMC__) && defined(_M_IX86) +#include <float.h> +#endif + +/* PDFlib */ +#include "pc_util.h" +#include "pc_core.h" +#include "pc_ctype.h" diff --git a/src/pdflib/pdflib/p_icclib.h b/src/pdflib/pdflib/p_icclib.h new file mode 100644 index 0000000..b300419 --- /dev/null +++ b/src/pdflib/pdflib/p_icclib.h @@ -0,0 +1,38 @@ +/* $Id: p_icclib.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * ICClib Header file icc.h for PDFlib + * + * $Log: p_icclib.h,v $ + * Revision 1.1 2008/10/17 06:11:49 scuri + * First commit - moving from LuaForge to SourceForge + * + * Revision 1.3 2007/11/06 15:48:55 scuri + * PDF Lite library updated to version "7.0.2". + * + * Revision 1.12.8.1 2007/03/28 12:47:10 kurt + * bug #1180 (Function prefixes missing for zlib assembler and ICC code) fixed + * names of all external functions of ICClib have the prefix "pdf_" now + * + * Revision 1.12 2004/08/05 09:11:27 rjs + * merged 6.0.x to pdflib-x + * + * Revision 1.11.2.1 2004/07/30 16:14:31 kurt + * icc_read: all free statements in the error case removed + * (because of program crash in icc_delete) + * icc_delete: more security checks + * new public function: icc_get_errmsg + * + * Revision 1.11 2004/06/14 10:53:19 kurt + * FEATURE defines reduced and renamed + * + * Revision 1.10 2003/03/03 12:46:43 tm + * Changed the licensing comment. + * + */ + +#ifndef P_ICCLIB_H +#define P_ICCLIB_H + + +#endif /* P_ICCLIB_H */ + diff --git a/src/pdflib/pdflib/p_image.c b/src/pdflib/pdflib/p_image.c new file mode 100644 index 0000000..fe95b1c --- /dev/null +++ b/src/pdflib/pdflib/p_image.c @@ -0,0 +1,2253 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2007 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_image.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib image routines + * + */ + +#define P_IMAGE_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_defopt.h" +#include "p_font.h" +#include "p_image.h" +#include "p_layer.h" +#include "p_tagged.h" + +static void +pdf_init_image_struct(PDF *p, pdf_image *image) +{ + (void) p; + + /********** option variables *************/ + image->verbose = p->debug[(int) 'i']; + image->verbose = pdf_get_errorpolicy(p, NULL, image->verbose); + image->bitreverse = pdc_false; + image->bpc = pdc_undef; + image->components = pdc_undef; + image->height_pixel = pdc_undef; + image->ignoremask = pdc_false; + image->ignoreorient = pdc_false; + image->doinline = pdc_false; + image->interpolate = pdc_false; + image->invert = pdc_false; + image->jpegoptimize = pdc_true; + image->passthrough = pdc_undef; + image->K = 0; + image->imagemask = pdc_false; + image->mask = pdc_undef; + image->ri = AutoIntent; + image->page = 1; + image->reference = pdf_ref_direct; + image->width_pixel = pdc_undef; + image->topdown_save = pdc_false; + image->iconname = (char *) NULL; + /*****************************************/ + + image->orientation = 1; + image->transparent = pdc_false; + image->compression = pdf_comp_none; + image->predictor = pred_default; + image->in_use = pdc_false; + image->corrupt = pdc_false; + image->fp = (pdc_file *) NULL; + image->filename = (char *) NULL; + image->params = (char *) NULL; + image->dpi_x = 0; + image->dpi_y = 0; + image->strips = 1; + image->rowsperstrip = 1; + image->colorspace = pdc_undef; + image->dochandle = pdc_undef; /* this means "not a PDI page" */ + image->use_raw = pdc_false; + image->pixelmode = pdc_undef; + image->type = pdf_img_auto; + image->transval[0] = 0; + image->transval[1] = 0; + image->transval[2] = 0; + image->transval[3] = 0; + + + /********* image-type specific stuff *****/ + /* This is ugly, but we must do it here since both the TIFF and JPEG + * modules are affected. + */ + image->info.jpeg.jpegifoffset = 0L; +} + +void +pdf_init_images(PDF *p) +{ + int im; + + p->images_capacity = IMAGES_CHUNKSIZE; + + p->images = (pdf_image *) + pdc_malloc(p->pdc, + sizeof(pdf_image) * p->images_capacity, "pdf_init_images"); + + for (im = 0; im < p->images_capacity; im++) + pdf_init_image_struct(p, &(p->images[im])); +} + +void +pdf_grow_images(PDF *p) +{ + int im; + + p->images = (pdf_image *) pdc_realloc(p->pdc, p->images, + sizeof(pdf_image) * 2 * p->images_capacity, "pdf_grow_images"); + + for (im = p->images_capacity; im < 2 * p->images_capacity; im++) + pdf_init_image_struct(p, &(p->images[im])); + + p->images_capacity *= 2; +} + +void +pdf_cleanup_image(PDF *p, int im) +{ + pdf_image *image = &p->images[im]; + + /* clean up parameter string if necessary */ + if (image->params) + { + pdc_free(p->pdc, image->params); + image->params = NULL; + } + + if (image->filename) + { + pdc_free(p->pdc, image->filename); + image->filename = NULL; + } + + if (image->fp) + { + pdc_fclose(image->fp); + image->fp = NULL; + } + + if (image->iconname) + { + pdc_free(p->pdc, image->iconname); + image->iconname = NULL; + } + + + + /* type-specific cleanups */ + if (image->type == pdf_img_gif) + pdf_cleanup_gif(p, image); + + if (image->type == pdf_img_jpeg) + pdf_cleanup_jpeg(p, image); + + /* free the image slot and prepare for next use */ + pdf_init_image_struct(p, image); +} + +void +pdf_cleanup_images(PDF *p) +{ + int im; + + if (!p->images) + return; + + /* Free images which the caller left open */ + + /* When we think of inter-document survival of images, + ** we MUST NOT FORGET that the current TIFF algorithm + ** depends on contiguous image slots for the image strips! + */ + for (im = 0; im < p->images_capacity; im++) + { + if (p->images[im].in_use) /* found used slot */ + pdf_cleanup_image(p, im); /* free image descriptor */ + } + + pdc_free(p->pdc, p->images); + p->images = NULL; +} + +void +pdf_init_xobjects(PDF *p) +{ + int idx; + + p->xobjects_number = 0; + + if (p->xobjects == (pdf_xobject *) 0) + { + p->xobjects_capacity = XOBJECTS_CHUNKSIZE; + + p->xobjects = (pdf_xobject *) + pdc_malloc(p->pdc, sizeof(pdf_xobject) * p->xobjects_capacity, + "pdf_init_xobjects"); + } + + for (idx = 0; idx < p->xobjects_capacity; idx++) + p->xobjects[idx].flags = 0; +} + +int +pdf_new_xobject(PDF *p, pdf_xobj_type type, pdc_id obj_id) +{ + static const char fn[] = "pdf_new_xobject"; + int i, slot = p->xobjects_number++; + + if (slot == p->xobjects_capacity) + { + p->xobjects = (pdf_xobject *) pdc_realloc(p->pdc, p->xobjects, + sizeof(pdf_xobject) * 2 * p->xobjects_capacity, fn); + + for (i = p->xobjects_capacity; i < 2 * p->xobjects_capacity; i++) + p->xobjects[i].flags = 0; + + p->xobjects_capacity *= 2; + } + + if (obj_id == PDC_NEW_ID) + obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); + + p->xobjects[slot].obj_id = obj_id; + p->xobjects[slot].type = type; + p->xobjects[slot].flags = xobj_flag_used; + + return slot; +} + +pdc_id +pdf_get_xobject(PDF *p, int im) +{ + if (im >= 0 && im < p->images_capacity) + { + pdf_image *img = &p->images[im]; + + if (img->in_use) + return p->xobjects[img->no].obj_id; + } + return PDC_BAD_ID; +} + +void +pdf_write_xobjects(PDF *p) +{ + if (p->xobjects_number > 0) + { + pdc_bool hit = pdc_false; + int i; + + for (i = 0; i < p->xobjects_number; ++i) + { + if (p->xobjects[i].flags & xobj_flag_write) + { + if (!hit) + { + pdc_puts(p->out, "/XObject"); + pdc_begin_dict(p->out); + hit = pdc_true; + } + + pdc_printf(p->out, "/I%d", i); + pdc_objref(p->out, "", p->xobjects[i].obj_id); + p->xobjects[i].flags &= ~xobj_flag_write; + } + } + + if (hit) + pdc_end_dict(p->out); + } +} + +void +pdf_get_page_xobjects(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->xobjects_number; i++) { + if (p->xobjects[i].flags & xobj_flag_write) { + p->xobjects[i].flags &= ~xobj_flag_write; + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_xobject(PDF *p, int n) +{ + p->xobjects[n].flags |= xobj_flag_write; +} + +void +pdf_cleanup_xobjects(PDF *p) +{ + if (p->xobjects) { + pdc_free(p->pdc, p->xobjects); + p->xobjects = NULL; + } +} + + +/* ---------------------------- put image ----------------------------------- */ + +void +pdf_put_inline_image(PDF *p, int im) +{ + static const char *fn = "pdf_put_inline_image"; + pdf_image *image; + pdc_matrix m; + PDF_data_source *src; + int i; + + image = &p->images[im]; + + /* Image object */ + + image->no = -1; + + pdf__save(p); + + pdc_scale_matrix(image->width, image->height, &m); + + pdf_concat_raw(p, &m); + + pdc_puts(p->out, "BI"); + + pdc_printf(p->out, "/W %d", (int) image->width); + pdc_printf(p->out, "/H %d", (int) image->height); + + /* Acrobat 7 and 8 require /BPC even for image masks */ + pdc_printf(p->out, "/BPC %d", image->bpc); + + if (image->imagemask == pdc_true) { + pdc_puts(p->out, "/IM true"); + + } else if (image->colorspace != pdc_undef) { + + switch (p->colorspaces[image->colorspace].type) { + case DeviceGray: + pdc_printf(p->out, "/CS/G"); + break; + + case DeviceRGB: + pdc_printf(p->out, "/CS/RGB"); + break; + + case DeviceCMYK: + pdc_printf(p->out, "/CS/CMYK"); + break; + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", image->colorspace), + pdc_errprintf(p->pdc, "%d", + (int) p->colorspaces[image->colorspace].type), + 0); + break; + } + } + + if (image->compression != pdf_comp_none) { + pdc_printf(p->out, "/F/%s", + pdc_get_keyword(image->compression, pdf_shortfilter_pdfkeylist)); + } + + /* prepare precompressed (raw) image data */ + if (image->use_raw && + (image->params || + image->predictor != pred_default || + image->compression == pdf_comp_ccitt)) { + + pdc_printf(p->out, "/DP[<<"); + + /* write EarlyChange */ + if (image->params) + pdc_puts(p->out, image->params); + + if (image->compression == pdf_comp_ccitt) { + if (image->K != 0) + pdc_printf(p->out, "/K %d", image->K); + } + + if (image->compression == pdf_comp_flate || + image->compression == pdf_comp_lzw) { + if (image->predictor != pred_default) { + pdc_printf(p->out, "/Predictor %d", (int) image->predictor); + pdc_printf(p->out, "/Columns %d", (int) image->width); + if (image->bpc != 8) + pdc_printf(p->out, "/BitsPerComponent %d", image->bpc); + + if (image->components != 1) /* 1 is default */ + pdc_printf(p->out, "/Colors %d", image->components); + } + } + + if (image->compression == pdf_comp_ccitt) { + if ((int) image->width != 1728) /* CCITT default width */ + pdc_printf(p->out, "/Columns %d", (int) image->width); + + /* /Rows is not required */ + } + pdc_puts(p->out, ">>]"); /* DecodeParms dict and array */ + } + + if (image->ri != AutoIntent) { + pdc_printf(p->out, "/Intent/%s", + pdc_get_keyword(image->ri, pdf_renderingintent_pdfkeylist)); + } + + if (image->interpolate) { + pdc_puts(p->out, "/I true"); + } + + if (image->invert) { + pdc_puts(p->out, "/D[1 0"); + for (i = 1; i < image->components; i++) + pdc_puts(p->out, " 1 0"); + pdc_puts(p->out, "]ID\n"); + + } else { + pdc_puts(p->out, " ID\n"); + } + + /* Write the actual image data to the content stream */ + + src = &image->src; + + /* We can't use pdf_copy_stream() here because it automatically + * generates a stream object, which is not correct for inline + * image data. + */ + if (src->init) + src->init(p, src); + + while (src->fill(p, src)) + pdc_write(p->out, src->next_byte, src->bytes_available); + + if (src->terminate) + src->terminate(p, src); + + /* Acrobat requires whitespace between image data and "EI" */ + pdc_puts(p->out, "\nEI\n"); + + pdf__restore(p); + + /* Do the equivalent of PDF_close_image() since the image handle + * cannot be re-used anyway. + */ + pdf_cleanup_image(p, im); +} + +void +pdf_put_image(PDF *p, int im, pdc_bool firststrip, pdc_bool checkcontentstream) +{ + static const char *fn = "pdf_put_image"; + pdc_bool logg3 = pdc_logg_is_enabled(p->pdc, 3, trc_image); + pdc_id length_id; + pdf_image *image; + int i; + pdf_compression compression; + + image = &p->images[im]; + + if (logg3) + pdc_logg(p->pdc, "\t\t\tput image %d to PDF file ...\n", im); + + /* Images may also be written to the output before the first page */ + if (checkcontentstream && PDF_GET_STATE(p) == pdf_state_page) + pdf_end_contents_section(p); + + + + pdc_logg_cond(p->pdc, 2, trc_image, + "\tpdf_put_image:\n" + "\t\t\tim = %d\n" + "\t\t\timage->colorspace = %d\n", + im, + image->colorspace); + + if (image->colorspace != pdc_undef) + pdc_logg_cond(p->pdc, 2, trc_image, + "\t\t\tcolor space type = %d\n", + (int) p->colorspaces[image->colorspace].type); + + /* Image object */ + + image->no = pdf_new_xobject(p, image_xobject, PDC_NEW_ID); + + pdc_begin_dict(p->out); /* XObject */ + + pdc_puts(p->out, "/Subtype/Image\n"); + + pdc_printf(p->out, "/Width %d\n", (int) image->width); + pdc_printf(p->out, "/Height %d\n", (int) fabs(image->height)); + + /* + * Transparency handling + */ + + /* Masking by color: single transparent color value */ + if (image->transparent && image->colorspace != pdc_undef) { + pdf_colorspace *cs = &p->colorspaces[image->colorspace]; + + switch (cs->type) { + case Indexed: + case DeviceGray: + pdc_printf(p->out,"/Mask[%d %d]\n", + (int) image->transval[0], (int) image->transval[0]); + break; + + + case DeviceRGB: + pdc_printf(p->out,"/Mask[%d %d %d %d %d %d]\n", + (int) image->transval[0], (int) image->transval[0], + (int) image->transval[1], (int) image->transval[1], + (int) image->transval[2], (int) image->transval[2]); + break; + + case DeviceCMYK: + pdc_printf(p->out,"/Mask[%d %d %d %d %d %d %d %d]\n", + (int) image->transval[0], (int) image->transval[0], + (int) image->transval[1], (int) image->transval[1], + (int) image->transval[2], (int) image->transval[2], + (int) image->transval[3], (int) image->transval[3]); + break; + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", image->colorspace), + pdc_errprintf(p->pdc, "%d", + (int) p->colorspaces[image->colorspace].type), + 0); + } + + /* Masking by position: separate bitmap mask */ + } else if (image->mask != pdc_undef && p->images[image->mask].bpc > 1) { + pdc_objref(p->out, "/SMask", + p->xobjects[p->images[image->mask].no].obj_id); + + } else if (image->mask != pdc_undef) { + pdc_objref(p->out, "/Mask", + p->xobjects[p->images[image->mask].no].obj_id); + } + + /* + * /BitsPerComponent is optional for image masks according to the + * PDF reference, but some viewers require it nevertheless. + * We must therefore always write it. + */ + if (image->type != pdf_img_jpeg2000) + pdc_printf(p->out, "/BitsPerComponent %d\n", image->bpc); + + if (image->imagemask) { + pdc_puts(p->out, "/ImageMask true\n"); + if (image->type == pdf_img_jpeg2000) + pdc_puts(p->out, "/SMaskInData 1\n"); + + } else if (image->colorspace != pdc_undef) { + + switch (p->colorspaces[image->colorspace].type) { + case DeviceGray: + break; + + case DeviceRGB: + break; + + case DeviceCMYK: + break; + + case Indexed: + break; + + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, fn, + pdc_errprintf(p->pdc, "%d", image->colorspace), + pdc_errprintf(p->pdc, "%d", + (int) p->colorspaces[image->colorspace].type), + 0); + } + + pdc_puts(p->out, "/ColorSpace"); + pdf_write_colorspace(p, image->colorspace, pdc_false); + pdc_puts(p->out, "\n"); + } + + if (image->invert) { + pdc_puts(p->out, "/Decode[1 0"); + for (i = 1; i < image->components; i++) + pdc_puts(p->out, " 1 0"); + pdc_end_array(p->out); + } + + if (image->ri != AutoIntent) { + pdc_printf(p->out, "/Intent/%s\n", + pdc_get_keyword(image->ri, pdf_renderingintent_pdfkeylist)); + } + + if (image->interpolate) { + pdc_puts(p->out, "/Interpolate true\n"); + } + + /* special case: referenced image data instead of direct data */ + if (image->reference != pdf_ref_direct) { + + if (image->compression != pdf_comp_none) { + pdc_printf(p->out, "/FFilter[/%s]\n", + pdc_get_keyword(image->compression, pdf_filter_pdfkeylist)); + } + + if (image->compression == pdf_comp_ccitt) { + pdc_puts(p->out, "/FDecodeParms[<<"); + + if ((int) image->width != 1728) /* CCITT default width */ + pdc_printf(p->out, "/Columns %d", (int) image->width); + + /* + pdc_printf(p->out, "/Rows %d", (int) fabs(image->height)); + */ + + if (image->K != 0) + pdc_printf(p->out, "/K %d", image->K); + + pdc_puts(p->out, ">>]\n"); + + } + + if (image->reference == pdf_ref_file) { + + /* LATER: make image file name platform-neutral: + * Change : to / on the Mac + * Change \ to / on Windows + */ + pdc_puts(p->out, "/F"); + pdc_put_pdfstring(p->out, image->filename, 0); + pdc_puts(p->out, "/Length 0"); + + } else if (image->reference == pdf_ref_url) { + + pdc_puts(p->out, "/F<</FS/URL/F"); + pdc_put_pdfstring(p->out, image->filename, 0); + pdc_puts(p->out, ">>/Length 0"); + } + + pdc_end_dict(p->out); /* XObject */ + + /* We must avoid pdc_begin/end_pdfstream() here in order to + * generate a really empty stream. + */ + pdc_puts(p->out, "stream\n"); /* dummy image stream */ + pdc_puts(p->out, "endstream\n"); + + pdc_end_obj(p->out); /* XObject */ + + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + return; + } + + compression = image->compression; + + /* + * Now the (more common) handling of actual image + * data to be included in the PDF output. + */ + + /* force compression if not a recognized precompressed image format */ + if ((!image->use_raw || compression == pdf_comp_none) && + pdc_get_compresslevel(p->out)) + compression = pdf_comp_flate; + + if (compression != pdf_comp_none) + pdc_printf(p->out, "/Filter/%s\n", + pdc_get_keyword(compression, pdf_filter_pdfkeylist)); + + /* prepare precompressed (raw) image data; avoid empty DecodeParms */ + if (image->use_raw && + (image->params || + image->predictor != pred_default || + compression == pdf_comp_ccitt)) { + + pdc_printf(p->out, "/DecodeParms<<"); + + /* write EarlyChange */ + if (image->params) + pdc_puts(p->out, image->params); + + if (compression == pdf_comp_ccitt) { + if (image->K != 0) + pdc_printf(p->out, "/K %d", image->K); + } + + if (compression == pdf_comp_flate || compression == pdf_comp_lzw) { + if (image->predictor != pred_default) { + pdc_printf(p->out, "/Predictor %d", (int) image->predictor); + pdc_printf(p->out, "/Columns %d", (int) image->width); + if (image->bpc != 8) + pdc_printf(p->out, "/BitsPerComponent %d", image->bpc); + + if (image->components != 1) /* 1 is default */ + pdc_printf(p->out, "/Colors %d", image->components); + } + } + + if (compression == pdf_comp_ccitt) { + if ((int) image->width != 1728) /* CCITT default width */ + pdc_printf(p->out, "/Columns %d", (int) image->width); + + /* /Rows is not required */ + } + + pdc_puts(p->out, ">>\n"); /* DecodeParms dict */ + } + + + + + /* Write the actual image data */ + length_id = pdc_alloc_id(p->out); + + pdc_objref(p->out, "/Length", length_id); + pdc_end_dict(p->out); /* XObject */ + + /* image data */ + + /* + * We must check "image->compression" here since this describes the + * actual status of the input data, as opposed to "compression" + * which describes the desired status of the output data. + */ + + pdf_copy_stream(p, &image->src, + !image->use_raw || image->compression == pdf_comp_none); + + pdc_end_obj(p->out); /* XObject */ + + pdc_put_pdfstreamlength(p->out, length_id); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + /* + * Write colormap information for indexed color spaces + */ + if (firststrip && image->colorspace != pdc_undef && + p->colorspaces[image->colorspace].type == Indexed) { + pdf_write_colormap(p, image->colorspace); + } + + if (checkcontentstream && PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); +} + + +/* ---------------------------- fit image ----------------------------------- */ + +void +pdf__fit_image(PDF *p, int im, pdc_scalar x, pdc_scalar y, const char *optlist) +{ + pdf_image *image; + int legal_states; + + pdf_check_handle(p, im, pdc_imagehandle); + + image = &p->images[im]; + + if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p) && + image->imagemask == pdc_false) + legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template; + else + legal_states = pdf_state_content; + PDF_CHECK_STATE(p, legal_states); + + if (PDF_GET_STATE(p) == pdf_state_template && im == p->templ) + pdc_error(p->pdc, PDF_E_TEMPLATE_SELF, + pdc_errprintf(p->pdc, "%d", im), 0, 0, 0); + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + pdf_place_xobject(p, im, x, y, optlist); +} + +void +pdf_init_xobject_options(PDF *p, pdf_xobject_options *xo) +{ + xo->adjustpage = pdc_false; + xo->blind = pdc_false; + xo->filename = NULL; + xo->flags = 0; + xo->imagewarning = p->debug[(int) 'i']; + xo->ignoreorientation = pdc_false; + xo->im = -1; + xo->mask = 0; + xo->dpi[0] = 0; + xo->dpi[1] = 0; + xo->page = 1; + xo->scale[0] = 1; + xo->scale[1] = 1; +} + +void +pdf_get_xobject_options(PDF *p, pdf_xobject_options *xo, pdc_resopt *resopts) +{ + int inum; + + (void) p; + + if (!(xo->flags & is_block)) + { + pdc_get_optvalues("adjustpage", resopts, &xo->adjustpage, NULL); + + pdc_get_optvalues("blind", resopts, &xo->blind, NULL); + } + + if (xo->flags & is_image) + { + if (pdc_get_optvalues("ignoreorientation", resopts, + &xo->ignoreorientation, NULL)) + xo->mask |= (1L << xo_ignoreorientation); + + + inum = pdc_get_optvalues("dpi", resopts, xo->dpi, NULL); + if (inum) + { + if (inum == 1) + xo->dpi[1] = xo->dpi[0]; + xo->mask |= (1L << xo_dpi); + } + } + + if (xo->flags & is_block) + { + if (pdc_get_optvalues("imagewarning", resopts, &xo->imagewarning, NULL)) + xo->mask |= (1L << xo_imagewarning); + } + + inum = pdc_get_optvalues("scale", resopts, xo->scale, NULL); + if (inum) + { + if (inum == 1) + xo->scale[1] = xo->scale[0]; + xo->mask |= (1L << xo_scale); + } +} + +/* definitions of fit xobject options */ +static const pdc_defopt pdf_fit_xobject_options[] = +{ + PDF_XOBJECT_OPTIONS1 + PDF_XOBJECT_OPTIONS2 + PDF_XOBJECT_OPTIONS3 + PDF_FIT_OPTIONS1 + PDF_FIT_OPTIONS2 + PDC_OPT_TERMINATE +}; + +pdc_resopt * +pdf_parse_fitxobject_optlist(PDF *p, int im, pdf_xobject_options *xo, + pdf_fit_options *fit, const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdf_image *image = &p->images[im]; + + /* initialize */ + pdf_init_xobject_options(p, xo); + xo->im = im; + if (p->xobjects[image->no].type == image_xobject) + { + xo->flags |= is_image; + xo->dpi[0] = dpi_internal; + xo->dpi[1] = dpi_internal; + xo->ignoreorientation = image->ignoreorient; + } + pdf_init_fit_options(p, pdc_false, fit); + fit->flags |= is_image; + + /* parsing option list */ + if (optlist && strlen(optlist)) + { + pdc_clientdata data; + + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_fit_xobject_options, &data, pdc_true); + + pdf_get_xobject_options(p, xo, resopts); + pdf_get_fit_options(p, pdc_false, fit, resopts); + } + + return resopts; +} + +void +pdf_place_xobject(PDF *p, int im, pdc_scalar x, pdc_scalar y, + const char *optlist) +{ + pdf_xobject_options xo; + pdf_fit_options fit; + + /* initialize */ + pdf_parse_fitxobject_optlist(p, im, &xo, &fit, optlist); + fit.refpoint[0] = x; + fit.refpoint[1] = y; + + /* put out xobject */ + if (!xo.blind) + { + pdf_end_text(p); + pdf_begin_contents_section(p); + + + + pdf__save(p); + } + + pdf_fit_xobject_internal(p, &xo, &fit, NULL); + + if (!xo.blind) + pdf__restore(p); +} + +void +pdf_fit_xobject_internal(PDF *p, pdf_xobject_options *xo, pdf_fit_options *fit, + pdc_matrix *immatrix) +{ + pdc_bool logg3 = pdc_logg_is_enabled(p->pdc, 3, trc_image); + pdf_image *image = &p->images[xo->im]; + pdf_xobject_options xo_save; + pdc_rectangle matchrect; + pdf_fit_options fit_save; + pdc_matrix m, mm, sm, ctm_save; + pdc_vector tmpscale, elemscale, fitscale, purescale; + pdc_vector elemsize, mirror, shift, relpos; + pdc_vector polyline[5]; + pdc_box fitbox, clipbox, elembox; + pdc_scalar x, y, ss; + pdc_scalar rowsize = 1, lastratio = 1; + pdc_scalar dpi_x, dpi_y, tx = 0, ty = 0, boxwidth, boxheight; + pdc_bool hasfitbox, kclip = pdc_false, kcliptiff = pdc_false; + int indangle, indmirror; + int is, ip, islast; + int imageno; + + /* initialize */ + tmpscale.x = 1; + tmpscale.y = 1; + if (image->mask != pdc_undef) + { + ctm_save = p->curr_ppt->gstate[p->curr_ppt->sl].ctm; + xo_save = *xo; + fit_save = *fit; + } + else + { + pdc_identity_matrix(&ctm_save); + } + + /* box size */ + boxwidth = fit->boxsize[0]; + boxheight = fit->boxsize[1]; + hasfitbox = boxwidth > PDC_FLOAT_PREC && boxheight > PDC_FLOAT_PREC; + + /* element size */ + elemsize.x = fabs(image->width); + elemsize.y = fabs(image->height); + + if (logg3) + pdc_logg(p->pdc, + "\t\t\tfitbox size: width=%g, height=%g\n" + "\t\t\telement size: width=%g, height=%g\n", + boxwidth, boxheight, elemsize.x, elemsize.y); + + /* clipping */ + if (!kclip) + { + kclip = pdf_get_mbox_clipping(p, fit->matchbox, elemsize.x, elemsize.y, + &clipbox); + } + + if (logg3 && kclip) + pdc_logg(p->pdc, + "\t\t\tclip box: llx=%g, lly=%g, urx=%g, ury=%g\n", + clipbox.ll.x, clipbox.ll.y, clipbox.ur.x, clipbox.ur.y); + + /* TIFF image orientation */ + if (image->orientation != 1 && !xo->ignoreorientation) + { + /* Tag Orientation = 1, 2, 3, 4, 5, 6, 7, 8 */ + const int addangle[8] = {0, 0, 180, 180, 90, 270, 270, 90}; + const int rowmirror[8] = {1, -1, 1, -1, -1, 1, -1, 1}; + + if (logg3) + pdc_logg(p->pdc, "\t\t\torientation tag: %d\n", image->orientation); + + is = image->orientation - 1; + + fit->orientate += addangle[is]; + if (fit->orientate >= 360) + fit->orientate -= 360; + tmpscale.x = rowmirror[is]; + + if (kclip) + { + switch (addangle[is]) + { + default: + elembox = clipbox; + break; + + case 90: + elembox.ll.x = clipbox.ll.y; + elembox.ll.y = elemsize.x - clipbox.ur.x; + elembox.ur.x = clipbox.ur.y; + elembox.ur.y = elemsize.x - clipbox.ll.x; + break; + + case 180: + elembox.ll.x = elemsize.x - clipbox.ur.x; + elembox.ll.y = elemsize.y - clipbox.ur.y; + elembox.ur.x = elemsize.x - clipbox.ll.x; + elembox.ur.y = elemsize.y - clipbox.ll.y; + break; + + case 270: + elembox.ll.x = elemsize.y - clipbox.ur.y; + elembox.ll.y = clipbox.ll.x; + elembox.ur.x = elemsize.y - clipbox.ll.y; + elembox.ur.y = clipbox.ur.x; + break; + } + clipbox = elembox; + + if (tmpscale.x == -1) + { + clipbox.ll.x = elemsize.x - elembox.ur.x; + clipbox.ur.x = elemsize.x - elembox.ll.x; + } + } + } + + /* Compensate inverted direction handling in TIFFReadRGBAImageOriented() */ + if (!image->use_raw && image->pixelmode == pdc_true) + { + tmpscale.y = -1; + elembox = clipbox; + clipbox.ll.y = elemsize.y - elembox.ur.y; + clipbox.ur.y = elemsize.y - elembox.ll.y; + } + + if (logg3 && kclip) + pdc_logg(p->pdc, + "\t\t\tclip box: llx=%g, lly=%g, urx=%g, ury=%g " + "(corrected)\n", + clipbox.ll.x, clipbox.ll.y, clipbox.ur.x, clipbox.ur.y); + + /* image scale */ + elemscale.x = tmpscale.x * xo->scale[0]; + elemscale.y = tmpscale.y * xo->scale[1]; + + if (logg3) + pdc_logg(p->pdc, + "\t\t\telement scaling: sx=%g, sy=%g " + "(user, correction mirroring)\n", + elemscale.x, elemscale.y); + + /* element size */ + elemsize.x = fabs(clipbox.ur.x - clipbox.ll.x); + elemsize.y = fabs(clipbox.ur.y - clipbox.ll.y); + + /* calculation of image scale and size */ + if (xo->flags & is_image) + { + tmpscale.x = 1.0; + tmpscale.y = 1.0; + if (xo->dpi[0] == dpi_internal) + { + dpi_x = image->dpi_x; + dpi_y = image->dpi_y; + if (dpi_x > 0 && dpi_y > 0) + { + tmpscale.x = 72.0 / dpi_x; + tmpscale.y = 72.0 / dpi_y; + } + else if (dpi_x < 0 && dpi_y < 0) + { + tmpscale.y = dpi_y / dpi_x; + } + } + else if (xo->dpi[0] > 0) + { + tmpscale.x = 72.0 / xo->dpi[0]; + tmpscale.y = 72.0 / xo->dpi[1]; + } + + elemscale.x *= tmpscale.x; + elemscale.y *= tmpscale.y; + rowsize = elemscale.y * image->rowsperstrip; + + if (logg3) + pdc_logg(p->pdc, + "\t\t\telement scaling: sx=%g, sy=%g " + "(relating to 72dpi)\n", + tmpscale.x, tmpscale.y); + } + + /* pure scaling without mirroring */ + purescale.x = fabs(elemscale.x); + purescale.y = fabs(elemscale.y); + + /* element size */ + elemsize.x *= purescale.x; + elemsize.y *= purescale.y; + + if (logg3) + pdc_logg(p->pdc, + "\t\t\telement size: width=%g, height=%g (scaled)\n", + elemsize.x, elemsize.y); + + if (xo->flags & is_image) + { + elemscale.x *= image->width; + elemscale.y *= image->height; + lastratio = (elemscale.y / rowsize) - (image->strips - 1); + } + + /* mirroring */ + indmirror = 0; + if (elemscale.x < 0 && elemscale.y < 0) + indmirror = 2; + else if (elemscale.x < 0) + indmirror = 1; + else if (elemscale.y < 0) + indmirror = 3; + + /* orientation */ + indangle = fit->orientate / 90; + if (indangle % 2) + { + ss = elemsize.x; + elemsize.x = elemsize.y; + elemsize.y = ss; + } + + /* box for fitting */ + fitbox.ll.x = 0; + fitbox.ll.y = 0; + fitbox.ur.x = boxwidth; + fitbox.ur.y = boxheight; + + /* relative position */ + relpos.x = fit->position[0] / 100.0; + relpos.y = fit->position[1] / 100.0; + + /* calculate image box */ + if (fit->fitmethod == pdc_tauto) + fit->fitmethod = pdc_meet; + pdc_place_element(fit->fitmethod, 1.0, &fitbox, &relpos, + &elemsize, &relpos, &elembox, &fitscale); + + if (logg3) + pdc_logg(p->pdc, + "\t\t\telement scaling: sx=%g, sy=%g " + "(relating to fitbox)\n", + fitscale.x, fitscale.y); + + /* reference point */ + x = fit->refpoint[0]; + y = fit->refpoint[1]; + + + /* adjust page size */ + if (!xo->blind && xo->adjustpage && PDF_GET_STATE(p) == pdf_state_page) + { + pdc_scalar urx, ury, width, height, theight; + + urx = 2 * x + elembox.ur.x; + ury = 2 * y + elembox.ur.y; + pdc_transform_point(&p->curr_ppt->gstate[p->curr_ppt->sl].ctm, + urx, ury, &width, &theight); + height = (p->ydirection > 0) ? theight + : pdf_get_pageheight(p) - p->ydirection * theight; + + if (height < p->ydirection * theight / 2.0) + pdc_error(p->pdc, PDF_E_IMAGE_NOADJUST, 0, 0, 0, 0); + + width = fabs(width); + height = fabs(height); + + if ((width < PDF_ACRO_MINPAGE || width > PDF_ACRO_MAXPAGE || + height < PDF_ACRO_MINPAGE || height > PDF_ACRO_MAXPAGE)) + pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0); + + pdf_set_pagebox(p, pdf_mediabox, 0, 0, width, height); + pdf_set_pagebox(p, pdf_artbox, 0, 0, 0, 0); + pdf_set_pagebox(p, pdf_bleedbox, 0, 0, 0, 0); + pdf_set_pagebox(p, pdf_cropbox, 0, 0, 0, 0); + pdf_set_pagebox(p, pdf_trimbox, 0, 0, 0, 0); + } + + /* reference point */ + pdc_translation_matrix(x, y, &m); + + /* optional rotation */ + if (fabs(fit->rotate) > PDC_FLOAT_PREC) + { + pdc_rotation_matrix(p->ydirection * fit->rotate, &mm); + pdc_multiply_matrix(&mm, &m); + } + + /* output after translation and rotation */ + if (!xo->blind) + { + /* new CTM */ + if (fit->showborder || + fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice) + { + pdf_concat_raw(p, &m); + pdc_identity_matrix(&m); + } + + /* show border */ + if (fit->showborder) + { + pdf__rect(p, 0, 0, boxwidth, boxheight); + pdf__stroke(p); + } + + /* clipping */ + if (fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice) + { + pdc_scalar cw = boxwidth; + pdc_scalar ch = boxheight; + + if (cw < PDC_FLOAT_PREC) + cw = PDF_ACRO_MAXPAGE; + if (ch < PDC_FLOAT_PREC) + ch = PDF_ACRO_MAXPAGE; + pdf__rect(p, 0, 0, cw, ch); + pdf__clip(p); + } + } + + /* translation of element box */ + elembox.ll.y *= p->ydirection; + elembox.ur.y *= p->ydirection; + pdc_box2polyline(NULL, &elembox, polyline); + ip = indangle + indmirror; + if (ip >= 4) ip -= 4; + tx = polyline[ip].x; + ty = polyline[ip].y; + pdc_translation_matrix(tx, ty, &mm); + pdc_multiply_matrix(&mm, &m); + boxwidth = elembox.ur.x - elembox.ll.x; + boxheight = elembox.ur.y - elembox.ll.y; + + /* orientation of image */ + if (fit->orientate != 0) + { + pdc_rotation_matrix(p->ydirection * fit->orientate, &mm); + pdc_multiply_matrix(&mm, &m); + if (indangle % 2) + { + ss = fitscale.x; + fitscale.x = fitscale.y; + fitscale.y = ss; + + ss = boxwidth; + boxwidth = p->ydirection * boxheight; + boxheight = p->ydirection * ss; + } + } + + /* mirroring of image */ + mirror.x = elemscale.x * fitscale.x; + elemscale.x = fabs(mirror.x); + mirror.x /= elemscale.x; + if (image->strips == 1) + mirror.y = p->ydirection * elemscale.y * fitscale.y; + else + mirror.y = p->ydirection * rowsize * fitscale.y; + elemscale.y = fabs(mirror.y); + mirror.y /= elemscale.y; + pdc_scale_matrix(mirror.x, mirror.y, &mm); + pdc_multiply_matrix(&mm, &m); + + if (logg3) + pdc_logg(p->pdc, + "\t\t\tcumulative mirroring: mx=%g, my=%g\n", + mirror.x, mirror.y); + + /* matchbox or clip path */ + if (!xo->blind && (fit->matchbox || kclip || kcliptiff)) + { + pdf_concat_raw(p, &m); + pdc_identity_matrix(&m); + + if (fit->matchbox) + { + matchrect.llx = 0; + matchrect.lly = 0; + matchrect.urx = boxwidth; + matchrect.ury = p->ydirection * boxheight; + pdf_set_mbox_rectangle(p, fit->matchbox, &matchrect, 0); + pdf_draw_mbox_rectangle(p, fit->matchbox, mbox_area | mbox_border); + + pdf_add_page_mbox(p, fit->matchbox); + } + + /* displacement of image because of clipping */ + shift = clipbox.ll; + purescale.x *= fitscale.x; + purescale.y *= fitscale.y; + if (kclip) + { + shift.x *= -purescale.x; + shift.y *= -purescale.y; + } + + if (kclip) + { + /* user clipping path */ + pdf__rect(p, 0, 0, boxwidth, boxheight); + pdf__clip(p); + } + + if (kclip) + { + pdc_translation_matrix(shift.x, shift.y, &mm); + pdc_multiply_matrix(&mm, &m); + } + } + + /* scaling of image */ + pdc_scale_matrix(elemscale.x, elemscale.y, &mm); + pdc_multiply_matrix(&mm, &m); + + /* ctm */ + if (xo->blind) + { + if (immatrix == NULL) + mm = p->curr_ppt->gstate[p->curr_ppt->sl].ctm; + else + mm = *immatrix; + pdc_multiply_matrix(&m, &mm); + } + else + { + pdf_concat_raw(p, &m); + mm = p->curr_ppt->gstate[p->curr_ppt->sl].ctm; + } + + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\t\tCTM components of image %s\"%s\":\n" + "\t\t\ta = %f\n" + "\t\t\tb = %f\n" + "\t\t\tc = %f\n" + "\t\t\td = %f\n" + "\t\t\te = %f\n" + "\t\t\tf = %f\n", + image->imagemask ? "mask " : "", + image->filename, mm.a, mm.b, mm.c, mm.d, mm.e, mm.f); + + if (!xo->blind) + pdf_cleanup_fit_options(p, fit); + + /* check image orientation */ + if (immatrix != NULL) + { + *immatrix = mm; + return; + } + if (image->mask != pdc_undef) + { + sm = ctm_save; + xo_save.im = image->mask; + xo_save.blind = pdc_true; + pdf_fit_xobject_internal(p, &xo_save, &fit_save, &sm); + + if ((sm.a * mm.a < 0) || (sm.b * mm.b < 0) || + (sm.c * mm.c < 0) || (sm.d * mm.d < 0)) + { + pdc_error(p->pdc, PDF_E_IMAGE_NOMATCH, + p->images[image->mask].filename, image->filename, 0, 0); + } + } + + if (!(xo->flags & is_image) && !xo->blind) + { + pdf_reset_gstate(p); + pdf_reset_tstate(p); + } + + + if (!xo->blind) + { + /* last strip first */ + if (image->strips > 1 && lastratio != 1.0) + { + pdc_scale_matrix(1, lastratio, &m); + pdf_concat_raw(p, &m); + } + + /* put out image strips separately if available */ + islast = image->strips - 1; + imageno = image->no + islast; + for (is = islast; is >= 0; is--) + { + pdc_printf(p->out, "/I%d Do\n", imageno); + p->xobjects[imageno].flags |= xobj_flag_write; + if (image->strips > 1 && is > 0) + { + pdc_translation_matrix(0, 1, &m); + if (is == islast && lastratio != 1.0) + { + pdc_scale_matrix(1, (1.0 / lastratio), &sm); + pdc_multiply_matrix(&sm, &m); + } + pdf_concat_raw(p, &m); + imageno--; + } + } + if (image->mask != pdc_undef) + p->xobjects[p->images[image->mask].no].flags |= xobj_flag_write; + } +} + + +/* ---------------------------- info image --------------------------------- */ + +void +pdf_get_image_size(PDF *p, int im, pdc_scalar *width, pdc_scalar *height) +{ + pdf_image *image; + + pdf_check_handle(p, im, pdc_imagehandle); + image = &p->images[im]; + + if (image->orientation < 5 || image->ignoreorient) + { + if (width) + *width = image->width; + if (height) + *height = fabs(image->height); + } + else + { + if (width) + *width = fabs(image->height); + if (height) + *height = image->width; + } +} + +void +pdf_get_image_resolution(PDF *p, int im, pdc_scalar *dpi_x, pdc_scalar *dpi_y) +{ + pdf_image *image; + + pdf_check_handle(p, im, pdc_imagehandle); + image = &p->images[im]; + + if (image->orientation < 5 || image->ignoreorient) + { + if (dpi_x) + *dpi_x = image->dpi_x; + if (dpi_y) + *dpi_y = image->dpi_y; + } + else + { + if (dpi_x) + *dpi_x = image->dpi_y; + if (dpi_y) + *dpi_y = image->dpi_x; + } +} + + +const char * +pdf_get_image_filename(PDF *p, pdf_image *image) +{ + return pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, image->filename); +} + + +/* ---------------------------- load image --------------------------------- */ + +static const pdc_keyconn pdf_extension_names[] = +{ + {".bmp", pdf_img_bmp}, + {".ccitt", pdf_img_ccitt}, + {".g3", pdf_img_ccitt}, + {".g4", pdf_img_ccitt}, + {".fax", pdf_img_ccitt}, + {".gif", pdf_img_gif}, + {".jpg", pdf_img_jpeg}, + {".jpeg", pdf_img_jpeg}, + {".jpx", pdf_img_jpeg2000}, + {".jp2", pdf_img_jpeg2000}, + {".jpf", pdf_img_jpeg2000}, + {".jpm", pdf_img_jpeg2000}, + {".j2k", pdf_img_jpeg2000}, + {".png", pdf_img_png}, + {".raw", pdf_img_raw}, + {".tif", pdf_img_tiff}, + {".tiff", pdf_img_tiff}, + {NULL, 0} +}; + +/* allowed values for options 'bpc' */ +static const pdc_keyconn pdf_bpcvalues[] = +{ + {"1", 1}, {"2", 2}, {"4", 4}, {"8", 8}, {"16", 16}, {NULL, 0} +}; + +/* allowed values for options 'components' */ +static const pdc_keyconn pdf_compvalues[] = +{ + {"1", 1}, {"3", 3}, {"4", 4}, {NULL, 0} +}; + +#define PDF_OPIOPT_FLAG PDC_OPT_UNSUPP +#define PDF_ICCOPT_FLAG PDC_OPT_UNSUPP +#define PDF_CLIPPATH_FLAG PDC_OPT_UNSUPP + +#define PDF_METADATA_FLAG PDC_OPT_UNSUPP + +#define PDF_LAYER_FLAG PDC_OPT_UNSUPP + +/* definitions of open image options */ +static const pdc_defopt pdf_open_image_options[] = +{ + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"bitreverse", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"bpc", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 16.0, pdf_bpcvalues}, + + {"components", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 4.0, + pdf_compvalues}, + + {"height", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL}, + + {"width", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL}, + + {"honoriccprofile", pdc_booleanlist, PDF_ICCOPT_FLAG, 1, 1, 0.0, 0.0, NULL}, + + /* ordering of the next three options is significant */ + + {"iccprofile", pdc_iccprofilehandle, PDF_ICCOPT_FLAG, 1, 1, 1.0, 0.0, NULL}, + + {"colorize", pdc_colorhandle, PDC_OPT_IGNOREIF1, 1, 1, 0.0, 0.0, NULL}, + + {"mask", pdc_booleanlist, PDC_OPT_IGNOREIF2, 1, 1, 0.0, 0.0, NULL}, + + {"honorclippingpath", pdc_booleanlist, PDF_CLIPPATH_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + {"clippingpathname", pdc_stringlist, PDF_CLIPPATH_FLAG, 1, 1, + 1.0, PDC_INT_MAX, NULL}, + + {"ignoremask", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"ignoreorientation", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + /* deprecated */ + {"imagewarning", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"inline", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"interpolate", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"invert", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"jpegoptimize", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"passthrough", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"K", pdc_integerlist, 0, 1, 1, -1.0, 1.0, NULL}, + + {"masked", pdc_imagehandle, 0, 1, 1, 0.0, 0.0, NULL}, + + {"page", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL}, + + {"renderingintent", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, + pdf_renderingintent_pdfkeylist}, + + {"reftype", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, pdf_reftype_keys}, + + {"template", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"iconname", pdc_stringlist, 0, 1, 1, + 1.0, PDF_MAX_NAMESTRING, NULL}, + + {"OPI-1.3", pdc_stringlist, PDF_OPIOPT_FLAG, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"OPI-2.0", pdc_stringlist, PDF_OPIOPT_FLAG | PDC_OPT_IGNOREIF1, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"layer", pdc_layerhandle, PDF_LAYER_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + PDF_ERRORPOLICY_OPTION + + PDC_OPT_TERMINATE +}; + +int +pdf__load_image( + PDF *p, + const char *type, + const char *filename, + const char *optlist) +{ + const char *keyword = NULL, *stemp1 = NULL, *stemp2 = NULL, *stemp3 = NULL; + char qualname[32], uptype[16], testfilename[PDC_FILENAMELEN + 1]; + pdc_clientdata data; + pdc_resopt *resopts; + pdc_encoding htenc; + int htcp; + pdf_image_type imgtype; + pdc_file *fp = NULL; + int colorize = pdc_undef; + pdf_image *image; + pdc_bool indjpeg = pdc_false; + pdc_bool templ = pdc_false; + pdc_bool verbose = p->debug[(int) 'i']; + int legal_states = 0; + int i, k, inum, imageslot, retval = -1, errcode = 0; + + if (type == NULL || *type == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0); + + /* parsing image type */ + k = pdc_get_keycode_ci(type, pdf_image_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0); + imgtype = (pdf_image_type) k; + type = pdc_get_keyword(imgtype, pdf_image_keylist); + + verbose = pdf_get_errorpolicy(p, NULL, verbose); + + /* filename must be already converted to UTF-8 */ + pdc_logg_cond(p->pdc, 1, trc_image, "\tImage file: \"%s\"\n", filename); + + /* search for image file */ + fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "image ", PDC_FILE_BINARY); + + /* automatic check */ + if (imgtype == pdf_img_auto) + { + pdf_tiff_info tiff_info; + + /* search for files with other extensions */ + if (fp == NULL) + { + pdc_logg_cond(p->pdc, 1, trc_image, + "\tImage file not found; searching for files " + "with alternative extensions\n"); + + for (i = 0; i < 2; i++) + { + for (k = 0; k < 100; k++) + { + const char *extension = pdf_extension_names[k].word; + if (extension) + { + strcpy(testfilename, filename); + strcpy(uptype, extension); + if (i) + pdc_strtoupper(uptype); + strcat(testfilename, uptype); + + fp = pdc_fsearch_fopen(p->pdc, testfilename, NULL, + "image ", PDC_FILE_BINARY); + if (fp != NULL) + break; + } + else + { + break; + } + } + if (fp != NULL) + break; + } + + if (fp != NULL) + { + filename = (const char *) testfilename; + pdc_logg_cond(p->pdc, 1, trc_image, + "\tImage file \"%s\" found\n", filename); + } + else + { + fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "image ", + PDC_FILE_BINARY); + } + } + + /* automatic type check */ + if (fp != NULL) + { + if (pdf_is_BMP_file(p, fp)) + imgtype = pdf_img_bmp; + else if (pdf_is_GIF_file(p, fp)) + imgtype = pdf_img_gif; + else if (pdf_is_PNG_file(p, fp)) + imgtype = pdf_img_png; + else if (pdf_is_TIFF_file(p, fp, &tiff_info, pdc_true)) + imgtype = pdf_img_tiff; + else if (pdf_is_JPEG_file(p, fp)) + imgtype = pdf_img_jpeg; + else if (pdf_is_JPX_file(p, fp)) + imgtype = pdf_img_jpeg2000; + else + { + pdc_fclose(fp); + + pdc_set_errmsg(p->pdc, PDF_E_IMAGE_UNKNOWN, filename, 0, 0, 0); + + if (verbose) + PDC_RETHROW(p->pdc); + + return -1; + } + type = pdc_get_keyword(imgtype, pdf_image_keylist); + } + } + + if (fp == NULL) + { + if (verbose) + PDC_RETHROW(p->pdc); + + return -1; + } + pdc_fclose(fp); + + strcpy(uptype, type); + pdc_strtoupper(uptype); + pdc_logg_cond(p->pdc, 1, trc_image, + "\tImage type \"%s\" detected\n", uptype); + + if (imgtype == pdf_img_jpeg2000) + { + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_JPEG2000, 0, 0, 0, 0); + + if (verbose) + PDC_RETHROW(p->pdc); + + return -1; + } + + /* find free slot */ + for (imageslot = 0; imageslot < p->images_capacity; imageslot++) + if (!p->images[imageslot].in_use) + break; + + if (imageslot == p->images_capacity) + pdf_grow_images(p); + image = &p->images[imageslot]; + + /* copy filename */ + image->filename = pdc_strdup(p->pdc, filename); + + /* inherit global flags */ + image->verbose = verbose; + image->ri = p->rendintent; + + /* parsing optlist */ + if (optlist && strlen(optlist)) + { + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_open_image_options, + &data, pdc_true); + /* save and check options */ + keyword = "imagewarning"; + pdc_get_optvalues(keyword, resopts, &image->verbose, NULL); + image->verbose = pdf_get_errorpolicy(p, resopts, image->verbose); + verbose = image->verbose; + + keyword = "reftype"; + if (pdc_get_optvalues(keyword, resopts, &inum, NULL)) + { + image->reference = (pdf_ref_type) inum; + if (image->reference != pdf_ref_direct && + imgtype != pdf_img_ccitt && + imgtype != pdf_img_jpeg && + imgtype != pdf_img_raw) + { + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype, + 0, 0); + image->reference = pdf_ref_direct; + } + } + indjpeg = (imgtype == pdf_img_jpeg && + image->reference != pdf_ref_direct) ? pdc_true : pdc_false; + + keyword = "bpc"; + if (pdc_get_optvalues(keyword, resopts, &image->bpc, NULL)) + { + if (imgtype != pdf_img_raw && !indjpeg) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + if (image->bpc == 16) + { + if (p->compatibility < PDC_1_5) + { + errcode = PDC_E_OPT_VERSION; + stemp1 = "bpc=16"; + stemp2 = pdc_get_pdfversion(p->pdc, p->compatibility); + goto PDF_IMAGE_ERROR; + } + } + } + + keyword = "components"; + if (pdc_get_optvalues(keyword, resopts, &image->components, NULL)) + { + if (imgtype != pdf_img_raw && !indjpeg) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "height"; + if (pdc_get_optvalues(keyword, resopts, &image->height_pixel, NULL)) + { + if (imgtype != pdf_img_ccitt && + imgtype != pdf_img_raw && !indjpeg) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "width"; + if (pdc_get_optvalues(keyword, resopts, &image->width_pixel, NULL)) + { + if (imgtype != pdf_img_raw && + imgtype != pdf_img_ccitt && !indjpeg) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "bitreverse"; + if (pdc_get_optvalues(keyword, resopts, &image->bitreverse, NULL)) + { + if (image->bitreverse && + (imgtype != pdf_img_ccitt || image->reference != pdf_ref_direct)) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "colorize"; + if (pdc_get_optvalues(keyword, resopts, &colorize, NULL)) + { + if (imgtype == pdf_img_jpeg2000) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + + keyword = "ignoremask"; + if (pdc_get_optvalues(keyword, resopts, &image->ignoremask, NULL)) + { + if (imgtype == pdf_img_bmp || + imgtype == pdf_img_ccitt || + imgtype == pdf_img_raw) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype, + 0, 0); + } + + keyword = "ignoreorientation"; + if (pdc_get_optvalues(keyword, resopts, &image->ignoreorient, NULL)) + { + if (imgtype == pdf_img_tiff) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype, + 0, 0); + } + + keyword = "inline"; + if (pdc_get_optvalues(keyword, resopts, + &image->doinline, NULL) && image->doinline) + { + if (imgtype != pdf_img_ccitt && + imgtype != pdf_img_jpeg && + imgtype != pdf_img_raw) + { + pdc_warning(p->pdc, + PDF_E_IMAGE_OPTUNSUPP, keyword, uptype, 0, 0); + image->doinline = pdc_false; + } + else if (image->reference != pdf_ref_direct) + { + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + image->doinline = pdc_false; + } + } + + keyword = "interpolate"; + pdc_get_optvalues(keyword, resopts, &image->interpolate, NULL); + + + keyword = "invert"; + if (pdc_get_optvalues(keyword, resopts, &image->invert, NULL)) + { + if (imgtype == pdf_img_jpeg2000) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "jpegoptimize"; + pdc_get_optvalues(keyword, resopts, &image->jpegoptimize, NULL); + + keyword = "passthrough"; + pdc_get_optvalues(keyword, resopts, &image->passthrough, NULL); + + keyword = "K"; + if (pdc_get_optvalues(keyword, resopts, &image->K, NULL)) + { + if (imgtype != pdf_img_ccitt) + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype, + 0, 0); + } + + keyword = "mask"; + pdc_get_optvalues(keyword, resopts, &image->imagemask, NULL); + + + keyword = "masked"; + if (pdc_get_optvalues(keyword, resopts, &image->mask, NULL)) + { + + + if (!p->images[image->mask].in_use || + p->images[image->mask].strips != 1 || + (p->compatibility <= PDC_1_3 && + (p->images[image->mask].imagemask != pdc_true || + p->images[image->mask].bpc != 1))) + { + errcode = PDF_E_IMAGE_OPTBADMASK; + stemp1 = keyword; + stemp2 = pdc_errprintf(p->pdc, "%d", image->mask); + goto PDF_IMAGE_ERROR; + } + + if (p->colorspaces[p->images[image->mask].colorspace].type != + DeviceGray) + { + errcode = PDF_E_IMAGE_BADMASK; + stemp1 = pdc_errprintf(p->pdc, "%s", + p->images[image->mask].filename); + goto PDF_IMAGE_ERROR; + } + } + + keyword = "renderingintent"; + if (pdc_get_optvalues(keyword, resopts, &inum, NULL)) + image->ri = (pdf_renderingintent) inum; + + keyword = "page"; + if (pdc_get_optvalues(keyword, resopts, &image->page, NULL)) + { + if (imgtype != pdf_img_tiff) + { + if (image->page == 1) + { + pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, + uptype, 0, 0); + } + else + { + errcode = PDF_E_IMAGE_NOPAGE; + stemp1 = pdc_errprintf(p->pdc, "%d", image->page); + stemp2 = uptype; + stemp3 = pdc_errprintf(p->pdc, "%s", image->filename); + goto PDF_IMAGE_ERROR; + } + } + } + + keyword = "template"; + if (pdc_get_optvalues(keyword, resopts, &templ, NULL)) + { + if (templ && image->doinline) + { + pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword, "inline", + 0, 0); + templ = pdc_false; + } + } + + htenc = + pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true); + keyword = "iconname"; + if (pdf_get_opt_textlist(p, keyword, resopts, htenc, htcp, pdc_true, + NULL, &image->iconname, NULL)) + { + if (image->doinline) + { + image->iconname = NULL; + pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword, "inline", + 0, 0); + } + else + { + pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + templ = pdc_true; + } + } + + + + } + + /* precise scope diagnosis */ + if (image->doinline) + legal_states = pdf_state_content; + else if (templ) + legal_states = pdf_state_document; + else + legal_states = pdf_state_document | pdf_state_page | pdf_state_font; + PDF_CHECK_STATE(p, legal_states); + + /* required options */ + if (imgtype == pdf_img_raw || imgtype == pdf_img_ccitt || indjpeg) + { + keyword = ""; + if (image->height_pixel == pdc_undef) + keyword = "height"; + else if (image->width_pixel == pdc_undef) + keyword = "width"; + else + { + image->width = image->width_pixel; + image->height = image->height_pixel; + } + + if (imgtype == pdf_img_ccitt) + { + image->components = 1; + image->bpc = 1; + } + if (image->bpc == pdc_undef) + keyword = "bpc"; + else if (image->components == pdc_undef) + keyword = "components"; + + if (*keyword) + { + errcode = PDC_E_OPT_NOTFOUND; + stemp1 = keyword; + goto PDF_IMAGE_ERROR; + } + } + + + + /* set colorspace */ + if (colorize != pdc_undef) + { + image->colorspace = colorize; + } + else if (image->imagemask == pdc_true) + { + image->colorspace = (int) DeviceGray; + } + else + { + switch(image->components) + { + case 1: + image->colorspace = DeviceGray; + break; + + case 3: + image->colorspace = DeviceRGB; + break; + + case 4: + image->colorspace = DeviceCMYK; + break; + + default: + break; + } + } + + /* try to open image file */ + if (image->reference == pdf_ref_direct) + { + strcpy(qualname, uptype); + strcat(qualname, " "); + image->fp = pdc_fsearch_fopen(p->pdc, image->filename, NULL, qualname, + PDC_FILE_BINARY); + if (image->fp == NULL) + goto PDF_IMAGE_ERROR; + } + + + /* set image type */ + image->type = imgtype; + + /* call working function */ + switch (imgtype) + { + case pdf_img_bmp: + retval = pdf_process_BMP_data(p, imageslot); + break; + + case pdf_img_ccitt: + retval = pdf_process_CCITT_data(p, imageslot); + break; + + case pdf_img_gif: + retval = pdf_process_GIF_data(p, imageslot); + break; + + case pdf_img_jpeg: + if (image->passthrough == pdc_undef) + image->passthrough = pdc_false; + retval = pdf_process_JPEG_data(p, imageslot); + break; + + case pdf_img_jpeg2000: + retval = pdf_process_JPX_data(p, imageslot); + break; + + case pdf_img_png: + retval = pdf_process_PNG_data(p, imageslot); + break; + + default: + case pdf_img_raw: + retval = pdf_process_RAW_data(p, imageslot); + break; + + case pdf_img_tiff: + if (image->passthrough == pdc_undef) + image->passthrough = pdc_true; + retval = pdf_process_TIFF_data(p, imageslot); + break; + } + + /* cleanup */ + if (retval == -1) + { + pdf_cleanup_image(p, imageslot); + + if (verbose) + PDC_RETHROW(p->pdc); + } + else + { + if (image->fp) + pdc_fclose(image->fp); + image->fp = NULL; + + /* logging protocol */ + if (pdc_logg_is_enabled(p->pdc, 1, trc_image)) + { + pdc_scalar width, height, dpi_x, dpi_y; + + pdf_get_image_size(p, imageslot, &width, &height); + pdf_get_image_resolution(p, imageslot, &dpi_x, &dpi_y); + + pdc_logg(p->pdc, "\tImage width: %g pixel\n" + "\tImage height: %g pixel\n" + "\tImage x resolution: %g dpi\n" + "\tImage y resolution: %g dpi\n", + width, height, dpi_x, dpi_y); + + if (imgtype == pdf_img_tiff) + pdc_logg(p->pdc, "\tOrientation tag: %d\n", + image->orientation); + + } + + if (templ) + { + retval = pdf_embed_image(p, imageslot); + pdf_cleanup_image(p, imageslot); + } + } + + return retval; + + PDF_IMAGE_ERROR: + + pdf_cleanup_image(p, imageslot); + + if (errcode) + pdc_set_errmsg(p->pdc, errcode, stemp1, stemp2, stemp3, 0); + if (verbose) + PDC_RETHROW(p->pdc); + + return retval; +} + +void +pdf__close_image(PDF *p, int image) +{ + pdf_check_handle(p, image, pdc_imagehandle); + pdf_cleanup_image(p, image); +} + + +#define MAX_THUMBNAIL_SIZE 106 + +void +pdf__add_thumbnail(PDF *p, int im) +{ + pdf_image *image; + + pdf_check_handle(p, im, pdc_imagehandle); + + if (pdf_get_thumb_id(p) != PDC_BAD_ID) + pdc_error(p->pdc, PDF_E_IMAGE_THUMB, 0, 0, 0, 0); + + image = &p->images[im]; + + if (image->strips > 1) + pdc_error(p->pdc, PDF_E_IMAGE_THUMB_MULTISTRIP, + pdc_errprintf(p->pdc, "%d", im), 0, 0, 0); + + if (image->width > MAX_THUMBNAIL_SIZE || image->height > MAX_THUMBNAIL_SIZE) + pdc_error(p->pdc, PDF_E_IMAGE_THUMB_SIZE, + pdc_errprintf(p->pdc, "%d", im), + pdc_errprintf(p->pdc, "%d", MAX_THUMBNAIL_SIZE), 0, 0); + + if (image->colorspace != (int) DeviceGray && + image->colorspace != (int) DeviceRGB && + image->colorspace != (int) Indexed) + pdc_error(p->pdc, PDF_E_IMAGE_THUMB_CS, + pdc_errprintf(p->pdc, "%d", im), 0, 0, 0); + + /* Add the image to the thumbnail key of the current page. */ + pdf_set_thumb_id(p, p->xobjects[image->no].obj_id); +} diff --git a/src/pdflib/pdflib/p_image.h b/src/pdflib/pdflib/p_image.h new file mode 100644 index 0000000..2f67649 --- /dev/null +++ b/src/pdflib/pdflib/p_image.h @@ -0,0 +1,358 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_image.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Header file for the PDFlib image subsystem + * + */ + +#ifndef P_IMAGE_H +#define P_IMAGE_H + +#ifdef HAVE_LIBTIFF +#include "tiffio.h" +#endif + +#ifdef HAVE_LIBPNG +#include "png.h" +#endif + +/* image type */ +typedef enum +{ + pdf_img_auto, + pdf_img_bmp, + pdf_img_ccitt, + pdf_img_gif, + pdf_img_jpeg, + pdf_img_jpeg2000, + pdf_img_png, + pdf_img_raw, + pdf_img_tiff +} +pdf_image_type; + +/* compression type */ +typedef enum +{ + pdf_comp_none, + pdf_comp_lzw, + pdf_comp_runlength, + pdf_comp_ccitt, + pdf_comp_dct, + pdf_comp_flate, + pdf_comp_jbig2, + pdf_comp_jpx +} +pdf_compression; + +/* image reference */ +typedef enum +{ + pdf_ref_direct, + pdf_ref_file, + pdf_ref_url +} +pdf_ref_type; + +typedef enum +{ + pred_default = 1, + pred_tiff = 2, + pred_png = 15 +} +pdf_predictor; + +#ifdef P_IMAGE_C + +const pdc_keyconn pdf_image_keylist[] = +{ + {"auto", pdf_img_auto}, + {"bmp", pdf_img_bmp}, + {"ccitt", pdf_img_ccitt}, + {"gif", pdf_img_gif}, + {"jpeg", pdf_img_jpeg}, + {"jpeg2000", pdf_img_jpeg2000}, + {"png", pdf_img_png}, + {"raw", pdf_img_raw}, + {"tiff", pdf_img_tiff}, + {NULL, 0} +}; + +const pdc_keyconn pdf_filter_pdfkeylist[] = +{ + {"", pdf_comp_none}, + {"LZWDecode", pdf_comp_lzw}, + {"RunLengthDecode", pdf_comp_runlength}, + {"CCITTFaxDecode", pdf_comp_ccitt}, + {"DCTDecode", pdf_comp_dct}, + {"FlateDecode", pdf_comp_flate}, + {"JBIG2Decode", pdf_comp_jbig2}, + {"JPXDecode", pdf_comp_jpx}, + {NULL, 0} +}; + +const pdc_keyconn pdf_shortfilter_pdfkeylist[] = +{ + {"", pdf_comp_none}, + {"LZW", pdf_comp_lzw}, + {"RL", pdf_comp_runlength}, + {"CCF", pdf_comp_ccitt}, + {"DCT", pdf_comp_dct}, + {"Fl", pdf_comp_flate}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_reftype_keys[] = +{ + {"direct", pdf_ref_direct}, + {"fileref", pdf_ref_file}, + {"url", pdf_ref_url}, + {NULL, 0} +}; + +#endif /* P_IMAGE_C */ + +/* BMP specific image information */ +typedef struct pdf_bmp_info_t { + pdc_uint32 compression; /* BMP compression */ + pdc_uint32 redmask; /* red mask */ + pdc_ushort redmax; /* red maximal value */ + pdc_ushort redmove; /* red mask's movement */ + pdc_uint32 greenmask; /* green mask */ + pdc_ushort greenmax; /* green maximal value */ + pdc_ushort greenmove; /* green mask's movement */ + pdc_uint32 bluemask; /* blue mask */ + pdc_ushort bluemax; /* blue maximal value */ + pdc_ushort bluemove; /* blue mask's movement */ + pdc_ushort bpp; /* bits per pixel */ + size_t rowbytes; /* length of row data */ + size_t rowbytes_pad; /* padded length of row data */ + size_t rowbytes_buf; /* buffer for row data */ + size_t rowbytes_pdf; /* length of row data for PDF */ + size_t skiprows; /* number of rows to be skipped */ + pdc_byte *bitmap; /* bitmap buffer */ + pdc_byte *end; /* first byte above bitmap buffer */ + pdc_byte *pos; /* current position in bitmap buffer */ +} pdf_bmp_info; + +typedef struct pdf_jpeg_segment_s pdf_jpeg_segment; + +/* JPEG specific image information */ +#define JPEG_MAX_COMPS 4 /* max number components */ +typedef struct pdf_jpeg_info_t { + const char *virtfile; /* temporary virtual file name */ + pdf_jpeg_segment *seglist; /* list of segments to be copy */ + int capacity; /* currently allocated size */ + int number; /* next available segment number */ + pdc_uint32 jpegifoffset; /* offset to JPEG data for TIFF OJPEG */ /* CDPDF - replaced toff_t by pdc_uint32 */ + pdc_byte id[JPEG_MAX_COMPS]; /* component ids */ + pdc_byte hsamp[JPEG_MAX_COMPS]; /* horizontal sampling factor */ + pdc_byte vsamp[JPEG_MAX_COMPS]; /* vertical sampling factor */ + pdc_byte table[JPEG_MAX_COMPS]; /* quant table */ +} pdf_jpeg_info; + +/* GIF specific image information */ +typedef struct pdf_gif_info_t { + int useGlobalColormap; + int interlace; + + /* LZW decompression state */ + int ZeroDataBlock; + int curbit; + int lastbit; + int get_done; + int last_byte; + int return_clear; + int *sp; + int code_size, set_code_size; + int max_code, max_code_size; + int clear_code, end_code; + pdc_byte buf[280]; + int firstcode; + int oldcode; + + /* These are dynamically malloc'ed to avoid wasting 64KB for each image */ +#define MAX_LWZ_BITS 12 +#define GIF_TABLE_ELEMENTS (1<< MAX_LWZ_BITS) + int (*table)[GIF_TABLE_ELEMENTS]; + int *stack; +} pdf_gif_info; + + +/* PNG specific image information */ +typedef struct pdf_png_info_t { + size_t nbytes; /* number of bytes left */ + /* in current IDAT chunk */ +#ifdef HAVE_LIBPNG + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 rowbytes; + pdc_byte *raster; + int cur_line; +#endif /* HAVE_LIBPNG */ +} pdf_png_info; + + +/* TIFF specific image information */ +typedef struct pdf_tiff_info_t { +#ifdef HAVE_LIBTIFF + TIFF *tif; /* pointer to TIFF data structure */ + uint32 *raster; /* frame buffer */ +#endif /* HAVE_LIBTIFF */ + + int cur_line; /* current image row or strip */ +} pdf_tiff_info; + +/* CCITT specific image information */ +typedef struct pdf_ccitt_info_t { + int BitReverse; /* reverse all bits prior to use */ +} pdf_ccitt_info; + +/* The image descriptor */ +struct pdf_image_s { + pdc_file *fp; /* image file pointer */ + char *filename; /* image file name or url */ + /* width and height in pixels, or in points for PDF pages and templates */ + pdc_scalar width; /* image width */ + pdc_scalar height; /* image height */ + int orientation; /* image orientation according TIFF */ + pdf_compression compression; /* image compression type */ + int colorspace; /* image color space */ + + /*************************** option variables *****************************/ + pdc_bool verbose; /* put out warning/error messages */ + pdc_bool bitreverse; /* bitwise reversal of all bytes */ + int bpc; /* bits per color component */ + int components; /* number of color components */ + int height_pixel; /* image height in pixel */ + int width_pixel; /* image width in pixel */ + pdc_bool ignoremask; /* ignore any transparency information*/ + pdc_bool ignoreorient; /* ignore orientation TIFF tag */ + pdc_bool doinline; /* inline image */ + pdc_bool interpolate; /* interpolate image */ + pdc_bool invert; /* reverse black and white */ + pdc_bool jpegoptimize; /* skip application segments of JPEG */ + pdc_bool passthrough; /* pass through mode for TIFF, JPEG */ + int K; /* encoding type of CCITT */ + pdc_bool imagemask; /* create a mask from a 1-bit image */ + int mask; /* image number of image mask */ + pdf_renderingintent ri; /* rendering intent of image */ + int page; /* page number of TIFF image */ + pdf_ref_type reference; /* kind of image data reference */ + pdc_bool topdown_save; /* saved topdown flag */ + char *iconname; /* icon name for template images */ + /**************************************************************************/ + + pdc_bool transparent; /* image is transparent */ + pdc_byte transval[4]; /* transparent color values */ + pdf_predictor predictor; /* predictor for lzw and flate */ + + pdc_scalar dpi_x; /* horiz. resolution in dots per inch */ + pdc_scalar dpi_y; /* vert. resolution in dots per inch */ + /* dpi is 0 if unknown */ + + pdc_bool in_use; /* image slot currently in use */ + pdc_bool corrupt; /* image is corrupt */ + + char *params; /* for TIFF */ + int strips; /* number of strips in image */ + int rowsperstrip; /* number of rows per strip */ + int pagehandle; /* PDI page handle */ + int dochandle; /* PDI document handle */ + pdc_pagebox usebox; + pdc_bool use_raw; /* use raw (compressed) image data */ + /* Only relevant for use_raw = false */ + pdc_bool pixelmode; /* Use TIFFReadRGBAImageOriented() ? */ + + pdf_image_type type; /* image type, used for cleanup */ + /* image format specific information */ + union { + pdf_bmp_info bmp; + pdf_jpeg_info jpeg; + pdf_gif_info gif; + pdf_png_info png; + pdf_tiff_info tiff; + pdf_ccitt_info ccitt; + } info; + + int no; /* PDF image number */ + PDF_data_source src; +}; + +/* xobject types */ +typedef enum { + image_xobject = 1 << 0, + form_xobject = 1 << 1, + pdi_xobject = 1 << 2 +} pdf_xobj_type; + +typedef enum { + xobj_flag_used = 1 << 0, /* in use */ + xobj_flag_write = 1 << 1 /* write at end of page */ +} pdf_xobj_flags; + +/* A PDF xobject */ +struct pdf_xobject_s { + pdc_id obj_id; /* object id of this xobject */ + int flags; /* bit mask of pdf_xobj_flags */ + pdf_xobj_type type; /* type of this xobject */ +}; + +/* p_bmp.c */ +int pdf_process_BMP_data(PDF *p, int imageslot); +pdc_bool pdf_is_BMP_file(PDF *p, pdc_file *fp); + +/* p_ccitt.c */ +int pdf_process_CCITT_data(PDF *p, int imageslot); +int pdf_process_RAW_data(PDF *p, int imageslot); + +/* p_gif.c */ +int pdf_process_GIF_data(PDF *p, int imageslot); +pdc_bool pdf_is_GIF_file(PDF *p, pdc_file *fp); +void pdf_cleanup_gif(PDF *p, pdf_image *image); + +/* p_jpeg.c */ +int pdf_process_JPEG_data(PDF *p, int imageslot); +pdc_bool pdf_is_JPEG_file(PDF *p, pdc_file *fp); +void pdf_cleanup_jpeg(PDF *p, pdf_image *image); + +/* p_jpx.c */ +int pdf_process_JPX_data(PDF *p, int imageslot); +pdc_bool pdf_is_JPX_file(PDF *p, pdc_file *fp); +void pdf_cleanup_jpx(PDF *p, pdf_image *image); + +/* p_png.c */ +int pdf_process_PNG_data(PDF *p, int imageslot); +pdc_bool pdf_is_PNG_file(PDF *p, pdc_file *fp); + +/* p_tiff.c */ +int pdf_process_TIFF_data(PDF *p, int imageslot); +pdc_bool pdf_is_TIFF_file(PDF *p, pdc_file *fp, pdf_tiff_info *tiff, + pdc_bool check); + +/* p_image.c */ +pdc_id pdf_get_xobject(PDF *p, int im); +void pdf_init_xobjects(PDF *p); +void pdf_write_xobjects(PDF *p); +void pdf_place_xobject(PDF *p, int im, pdc_scalar x, pdc_scalar y, + const char *optlist); +int pdf_new_xobject(PDF *p, pdf_xobj_type type, pdc_id obj_id); +void pdf_get_page_xobjects(PDF *p, pdf_reslist *rl); +void pdf_mark_page_xobject(PDF *p, int n); +void pdf_cleanup_xobjects(PDF *p); +const char *pdf_get_image_filename(PDF *p, pdf_image *image); + + +#endif /* P_IMAGE_H */ + diff --git a/src/pdflib/pdflib/p_intern.h b/src/pdflib/pdflib/p_intern.h new file mode 100644 index 0000000..80f92d9 --- /dev/null +++ b/src/pdflib/pdflib/p_intern.h @@ -0,0 +1,1027 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_intern.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib internal definitions + * + */ + +#ifndef P_INTERN_H +#define P_INTERN_H + +#include "pdflib.h" + +#include "ft_font.h" +#include "pc_file.h" +#include "pc_contain.h" + +#include "p_keyconn.h" + + + + +/* ------------------------ PDFlib feature configuration ------------------- */ + +/* changing the following is not recommended, and not supported */ + +/* BMP image support */ +/* #define PDF_BMP_SUPPORTED CDPDF: leave this to the IM library */ + +/* GIF image support */ +/* #define PDF_GIF_SUPPORTED CDPDF: leave this to the IM library */ + +/* JPEG image support */ +/* #define PDF_JPEG_SUPPORTED CDPDF: leave this to the IM library */ + +/* JPEG2000 image support */ +/* #define PDF_JPX_SUPPORTED CDPDF: leave this to the IM library */ + +/* PNG image support, requires HAVE_LIBZ */ +/* #define HAVE_LIBPNG CDPDF: leave this to the IM library */ + +/* TIFF image support */ +/* #define HAVE_LIBTIFF CDPDF: leave this to the IM library */ + + +/* -------------------------------- macros ------------------------------- */ + +/* + * Allocation chunk sizes. These don't affect the generated documents + * in any way. In order to save initial memory, however, you can lower + * the values. Increasing the values will bring some performance gain + * for large documents, but will waste memory for small ones. + */ +#define PAGES_CHUNKSIZE 512 /* pages */ +#define PNODES_CHUNKSIZE 64 /* page tree nodes */ +#define CONTENTS_CHUNKSIZE 64 /* page content streams */ +#define FONTS_CHUNKSIZE 16 /* document fonts */ +#define XOBJECTS_CHUNKSIZE 128 /* document xobjects */ +#define IMAGES_CHUNKSIZE 128 /* document images */ +#define OUTLINE_CHUNKSIZE 256 /* document outlines */ +#define NAMES_CHUNKSIZE 256 /* names */ +#define PDI_CHUNKSIZE 16 /* PDI instances */ +#define COLORSPACES_CHUNKSIZE 16 /* color spaces */ +#define PATTERN_CHUNKSIZE 4 /* pattern */ +#define SHADINGS_CHUNKSIZE 4 /* shadings */ +#define EXTGSTATE_CHUNKSIZE 4 /* external graphic states */ +#define T3GLYPHS_CHUNKSIZE 256 /* type 3 font glyph table */ +#define ICCPROFILE_CHUNKSIZE 4 /* ICC profiles */ +#define STRINGLISTS_CHUNKSIZE 128 /* document stringlists */ +#define ITEMS_CHUNKSIZE 256 /* PDFlib items */ +#define ITEMS_KIDS_CHUNKSIZE 64 /* PDFlib item's kids */ +#define ITEMS_MC_CHUNKSIZE 16 /* PDFlib item mc sequences */ +#define LAYER_DEP_CHUNKSIZE 16 /* PDFlib layer dependencies */ +#define RESLIST_CHUNKSIZE 16 /* per page resource list */ + +/* Acrobat 4 allows only 12 levels, but Acrobat 5 increases the limit to 28 */ +#define PDF_MAX_SAVE_LEVEL 28 /* max number of save levels */ + +#define PDF_MAX_PARAMSTRING 256 /* image parameter string */ +#define PDF_MAX_NAMESTRING 127 /* maximum name length */ +#define PDF_MAX_EVENTS 16 /* maximum number of events */ +#define PDF_MAX_DASHLENGTH 8 /* maximum number of dashes */ + +/* default PDF compatibility */ +#define PDF_DEF_COMPATIBILITY PDC_1_6 + + +/* ------------------------ typedefs and enums --------------------------- */ + +/* PDFlib error numbers. +*/ +#ifndef P_GENERR_H +enum +{ +#define pdf_genNames 1 +#include "p_generr.h" + + PDF_E_dummy +}; +#endif + +#define pdf_state_content \ + (pdf_state) (pdf_state_page | pdf_state_pattern | \ + pdf_state_template | pdf_state_glyph) + +#define pdf_state_all \ + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page | \ + pdf_state_pattern | pdf_state_template | pdf_state_path | \ + pdf_state_font | pdf_state_glyph) + +#define PDF_STATE_STACK_SIZE 4 + +/* function-like macros. +** must behave well wherever function calls are syntactically legal. +*/ +#define PDF_GET_STATE(p) \ + ((p)->state_stack[(p)->state_sp]) + +#define PDF_SET_STATE(p, s) \ + ((p)->state_stack[(p)->state_sp] = (s)) + +/* statement-like macros. +** must behave well wherever statements are syntactically legal. +*/ +#define PDF_CHECK_STATE(p, s) \ + if ((((p)->state_stack[(p)->state_sp] & (s)) != 0)) { \ + } else pdc_error((p)->pdc, \ + PDF_E_DOC_SCOPE, pdf_current_scope(p), 0, 0, 0) + +#define PDF_PUSH_STATE(p, fn, s) \ + if ((p)->state_sp == PDF_STATE_STACK_SIZE - 1) \ + pdc_error((p)->pdc, PDF_E_INT_SSTACK_OVER, fn, 0, 0, 0); \ + else \ + (p)->state_stack[++(p)->state_sp] = (s) + +#define PDF_POP_STATE(p, fn) \ + if ((p)->state_sp == 0) \ + pdc_error((p)->pdc, PDF_E_INT_SSTACK_UNDER, fn, 0, 0, 0); \ + else \ + --(p)->state_sp + + +/* -------------------------- structs ------------------------------ */ + +#ifndef PDI_DEFINED +#define PDI_DEFINED +typedef struct PDI_s PDI; /* The opaque PDI type */ +typedef struct pdi_pcos_s pdi_pcos; +typedef struct pdi_props_s pdi_props; +#endif + +typedef struct +{ + pdc_bool info_mode; + PDI * pi; + pdc_byte * data; + pdi_pcos * pcc; +} pdf_pdi; + +/* Opaque types which are detailed in the respective modules + in alphabetical order */ +typedef struct pdf_category_s pdf_category; +typedef struct pdf_colorspace_s pdf_colorspace; +typedef struct pdf_cstate_s pdf_cstate; +typedef struct pdf_dest_s pdf_dest; +typedef struct pdf_document_s pdf_document; +typedef struct pdf_extgstateresource_s pdf_extgstateresource; +typedef struct pdf_font_options_s pdf_font_options; +typedef struct pdf_font_s pdf_font; +typedef struct pdf_formfields_s pdf_formfields; +typedef struct pdf_iccprofile_s pdf_iccprofile; +typedef struct pdf_image_s pdf_image; +typedef struct pdf_info_s pdf_info; +typedef struct pdf_layers_s pdf_layers; +typedef struct pdf_linearopts_s pdf_linearopts; +typedef struct pdf_mbox_s pdf_mbox; +typedef struct pdf_name_s pdf_name; +typedef struct pdf_outline_s pdf_outline; +typedef struct pdf_pages_s pdf_pages; +typedef struct pdf_pattern_s pdf_pattern; +typedef struct pdf_reslist_s pdf_reslist; +typedef struct pdf_shading_s pdf_shading; +typedef struct pdf_t3font_s pdf_t3font; +typedef struct pdf_tags_s pdf_tags; +typedef struct pdf_text_options_s pdf_text_options; +typedef struct pdf_tstate_s pdf_tstate; +typedef struct pdf_widget_s pdf_widget; +typedef struct pdf_xobject_s pdf_xobject; + + +/* -------------------- special graphics state -------------------- */ +typedef struct { + pdc_matrix ctm; /* current transformation matrix */ + pdc_scalar x; /* current x coordinate */ + pdc_scalar y; /* current y coordinate */ + + pdc_scalar startx; /* starting x point of the subpath */ + pdc_scalar starty; /* starting y point of the subpath */ + + pdc_scalar lwidth; /* line width */ + int lcap; /* line cap style */ + int ljoin; /* line join style */ + pdc_scalar miter; /* miter limit */ + pdc_scalar flatness; /* path flatness */ + pdc_bool dashed; /* line dashing in effect */ +} pdf_gstate; + +/* ---------------------- page/pattern/template ----------------------- */ +typedef struct +{ + /* graphics, text, and color state. + */ + int sl; /* current save level */ + pdf_gstate gstate[PDF_MAX_SAVE_LEVEL]; /* graphics state */ + pdf_tstate *tstate; /* text state */ + pdf_cstate *cstate; /* color state */ + + pdf_text_options *currto; /* current text options */ + pdf_fillrule fillrule; /* nonzero or evenodd fill rule */ + + pdc_vtr * mboxes; /* matchbox chain */ + + /* in update mode, the resource numbers generally don't start + ** with 0, but with a bias value derived from the original + ** page's resources. + */ + int cs_bias; /* colorspaces */ + int eg_bias; /* extended gstates */ + int fn_bias; /* fonts */ + int pt_bias; /* patterns */ + int sh_bias; /* shadings */ + int xo_bias; /* xobjects */ +} pdf_ppt; + +/* Force graphics or color operator output, avoiding the optimization + * which checks whether the new value might be the same as the old. + * This is especially required for Type 3 glyph descriptions which + * inherit the surrounding page description's gstate parameters, + * and therefore even must write default values. + */ +#define PDF_FORCE_OUTPUT() (PDF_GET_STATE(p) == pdf_state_glyph) + +/* + * ************************************************************************* + * The core PDF context descriptor + * ************************************************************************* + */ + +struct PDF_s { + /* -------------------------- general stuff ------------------------ */ + unsigned long magic; /* poor man's integrity check */ + void (*freeproc)(PDF *p, void *mem); + pdc_core *pdc; /* core context */ + int compatibility; /* PDF version number * 10 */ + pdf_errpol errorpolicy; /* error policy */ + + + + + pdf_state state_stack[PDF_STATE_STACK_SIZE]; + int state_sp; /* state stack pointer */ + + /* ------------------- PDF Catalog dictionary --------------------- */ + pdf_document *document; /* document struct */ + + + /* ------------------- PDF Info dictionary entries ----------------- */ + pdf_info *userinfo; /* list of user-defined entries */ + + /* -------------- I/O, error handling and memory management ------------- */ + size_t (*writeproc)(PDF *p, void *data, size_t size); + void (*errorhandler)(PDF *p, int level, const char* msg); + void *opaque; /* user-specific, opaque data */ + + /* ------------------------- PDF import ---------------------------- */ + pdf_pdi *pdi; /* PDI context array */ + int pdi_capacity; /* currently allocated size */ + pdc_pagebox pdi_usebox; + pdc_bool pdi_strict; /* strict PDF parser mode */ + pdc_bstr * pdi_parmbuf; /* string buffer for pdi parms */ + + /* ------------ stuff for hypertext functions ---------- */ + pdc_encoding hypertextencoding; /* encoding of hypertexts */ + pdc_text_format hypertextformat; /* format of hypertexts */ + int hypertextcodepage; /* OEM multi byte code-page number */ + pdc_bool usercoordinates; /* interprete rectangle coordinates */ + /* of hypertext funcs. in user space */ + pdc_bool usehyptxtenc; /* use hypertextencoding */ + /* for name strings */ + + + /* ------------------- PDF output bookkeeping ------------------- */ + pdc_id procset_id; /* id of constant ProcSet array */ + pdc_output *out; /* output manager */ + pdc_id length_id; /* id of current stream's length*/ + pdc_flush_state flush; /* flush state */ + + /* ------------------- page bookkeeping ------------------- */ + pdf_pages *doc_pages; /* document wide page management */ + + /* ------------------- document resources ------------------- */ + pdf_font *fonts; /* all fonts in document */ + int fonts_capacity; /* currently allocated size */ + int fonts_number; /* next available font number */ + int t3slot; /* slot of temporary type 3 font */ + fnt_cmap_stack *cmst; /* CMap stack handle */ + + + + pdf_xobject *xobjects; /* all xobjects in document */ + int xobjects_capacity; /* currently allocated size */ + int xobjects_number; /* next available xobject slot */ + + pdf_colorspace *colorspaces; /* all color space resources */ + int colorspaces_capacity; /* currently allocated size */ + int colorspaces_number; /* next available color space number */ + + + pdf_pattern *pattern; /* all pattern resources */ + int pattern_capacity; /* currently allocated size */ + int pattern_number; /* next available pattern number */ + + pdf_shading *shadings; /* all shading resources */ + int shadings_capacity; /* currently allocated size */ + int shadings_number; /* next available shading number */ + + pdf_extgstateresource *extgstates; /* all ext. graphic state resources */ + int extgstates_capacity; /* currently allocated size */ + int extgstates_number; /* next available extgstate number */ + + pdf_image *images; /* all images in document */ + int images_capacity; /* currently allocated size */ + + pdc_vtr *actions; /* all actions in document */ + + + /* ------------------ utilities ------------------- */ + char ***stringlists; /* string lists */ + int stringlists_capacity; /* currently allocated size */ + int stringlists_number; /* next available string list number */ + int *stringlistsizes; /* sizes of string lists */ + int utilstrlist_index; /* index of utility string list */ + int utilstring_number; /* next available utility string */ + + /* ------------------- document outline tree ------------------- */ + pdf_outline *outlines; /* dynamic array of outlines */ + int outline_capacity; /* currently allocated size */ + int outline_count; /* total number of outlines */ + + /* ------------------- name tree ------------------- */ + pdf_name *names; /* page ids */ + int names_capacity; + int names_number; /* next available names number */ + + /* -------------- page/pattern/template specific stuff -------------- */ + pdf_ppt * curr_ppt; /* current ppt descriptor */ + pdc_id res_id; /* id of this pattern/templ res dict */ + + pdc_scalar ydirection; /* direction of y axis of default */ + /* system rel. to viewport (1 or -1) */ + + pdf_renderingintent rendintent; /* RenderingIntent */ + + pdc_bool preserveoldpantonenames;/* preserve old PANTONE names */ + pdc_bool spotcolorlookup; /* use internal look-up table for + * color values */ + + /* ------------------------ template stuff ----------------------- */ + int templ; /* current template if in templ. state*/ + + /* --------------- other font and text stuff ---------------- */ + + pdf_font_options *currfo; /* current font settings */ + + pdc_glyphcheck glyphcheck; /* check for unavailable glyphs */ + pdc_text_format textformat; /* text storage format */ + pdc_bool in_text; /* currently in BT/ET section */ + + /* ------------------------ miscellaneous ------------------------ */ + char debug[256]; /* debug flags */ + + + + /* ------- deprecated stuff because of deprecated parameter ---------- */ + pdf_borderstyle border_style; + pdc_scalar border_width; + pdc_scalar border_red; + pdc_scalar border_green; + pdc_scalar border_blue; + pdc_scalar border_dash1; + pdc_scalar border_dash2; + pdf_dest *bookmark_dest; + char *launchlink_parameters; + char *launchlink_operation; + char *launchlink_defaultdir; + +}; + +/* Data source for images, compression, ASCII encoding, fonts, etc. */ +typedef struct PDF_data_source_s PDF_data_source; +struct PDF_data_source_s { + pdc_byte *next_byte; + size_t bytes_available; + void (*init)(PDF *, PDF_data_source *src); + int (*fill)(PDF *, PDF_data_source *src); + void (*terminate)(PDF *, PDF_data_source *src); + + pdc_byte *buffer_start; + size_t buffer_length; + void *private_data; + long offset; /* start of data to read */ + long length; /* length of data to read */ + long total; /* total bytes read so far */ +}; + +/* ------ Private functions for library-internal use only --------- */ + + +/* + (((((OpenVMS porting note))))) + + Symbols are restricted to <= 31 bytes on OpenVMS systems.... + Please truncate new function names to fit this silly restriction! + + (((((OpenVMS porting note))))) +*/ + + + + + +/********************** + * + * p_actions.c + * + **********************/ + +int pdf__create_action(PDF *p, const char *type, const char *optlist); + +void pdf_delete_actions(PDF *p); +int pdf_get_max_action(PDF *p); +pdc_bool pdf_parse_and_write_actionlist(PDF *p, pdf_event_object eventobj, + pdc_id *act_idlist, const char *optlist); +pdc_bool pdf_write_action_entries(PDF *p, pdf_event_object eventobj, + pdc_id *act_idlist); + + +/********************** + * + * p_annots.c + * + **********************/ + +void pdf__add_launchlink(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *filename); +void pdf__add_locallink(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, int page, const char *optlist); +void pdf__add_note(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *contents, int len_cont, + const char *title, int len_title, const char *icon, int kopen); +void pdf__add_pdflink(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *filename, int page, + const char *optlist); +void pdf__add_weblink(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *url); +void pdf__attach_file(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *filename, int len_filename, + const char *description, int len_descr, const char *author, + int len_auth, const char *mimetype, const char *icon); +void pdf__create_annotation(PDF *p, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *type, const char *optlist); +void pdf__set_border_color(PDF *p, pdc_scalar red, pdc_scalar green, + pdc_scalar blue); +void pdf__set_border_dash(PDF *p, pdc_scalar b, pdc_scalar w); +void pdf__set_border_style(PDF *p, const char *style, pdc_scalar width); + +void pdf_init_annot_params(PDF *p); +void pdf_cleanup_annot_params(PDF *p); +pdc_id pdf_write_annots_root(PDF *p, pdc_vtr *annots, pdf_widget *widgetlist); +void pdf_write_page_annots(PDF *p, pdc_vtr *annots); + +void pdf_create_link(PDF *p, const char *type, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury, const char *annopts, + const char *utext, int len); + + + +/********************** + * + * p_color.c + * + **********************/ + + +void pdf__setcolor(PDF *p, const char *fstype, const char *colorspace, + pdc_scalar c1, pdc_scalar c2, pdc_scalar c3, pdc_scalar c4); + +void pdf_init_cstate(PDF *p); +void pdf_save_cstate(PDF *p); +void pdf_cleanup_page_cstate(PDF *p, pdf_ppt *ppt); +void pdf_init_colorspaces(PDF *p); +void pdf_set_default_color(PDF *p, pdc_bool reset); +void pdf_write_page_colorspaces(PDF *p); +void pdf_mark_page_colorspace(PDF *p, int n); +void pdf_write_doc_colorspaces(PDF *p); +void pdf_write_colorspace(PDF *p, int slot, pdc_bool direct); +void pdf_cleanup_colorspaces(PDF *p); +void pdf_write_colormap(PDF *p, int slot); + + +/********************** + * + * p_document.c + * + **********************/ + +int pdf__begin_document(PDF *p, const char *filename, int len, + const char *optlist); + +void pdf__begin_document_callback(PDF *p, writeproc_t writeproc, + const char *optlist); + +void pdf__end_document(PDF *p, const char *optlist); + +void pdf_cleanup_document(PDF *p); +void pdf_fix_openmode(PDF *p); +void pdf_insert_name(PDF *p, const char *name, pdf_nametree_type type, + pdc_id obj_id); +pdc_id pdf_get_id_from_nametree(PDF *p, pdf_nametree_type type, + const char *name); +char *pdf_parse_and_write_metadata(PDF *p, const char *optlist, pdc_bool output, + int *outlen); +pdc_off_t pdf_check_file(PDF *p, const char *filename, pdc_bool verbose); +void pdf_embed_file(PDF *p, pdc_id obj_id, const char *filename, + const char *mimetype, pdc_off_t filesize); + +/* deprecated functions: */ +void pdf_set_flush(PDF *p, const char *flush); +void pdf_set_uri(PDF *p, const char *uri); +void pdf_set_compatibility(PDF *p, const char *compatibility); +void pdf_set_openmode(PDF *p, const char *openmode); +void pdf_set_openaction(PDF *p, const char *openaction); +void pdf_set_viewerpreference(PDF *p, const char *viewerpreference); +const char *pdf__get_buffer(PDF *p, long *size); + + + + +/********************** + * + * p_draw.c + * + **********************/ + + +void pdf__arc(PDF *p, pdc_scalar x, pdc_scalar y, + pdc_scalar r, pdc_scalar alpha, pdc_scalar beta); +void pdf__arcn(PDF *p, pdc_scalar x, pdc_scalar y, + pdc_scalar r, pdc_scalar alpha, pdc_scalar beta); +void pdf__circle(PDF *p, pdc_scalar x, pdc_scalar y, pdc_scalar r); +void pdf__clip(PDF *p); +void pdf__closepath(PDF *p); +void pdf__closepath_fill_stroke(PDF *p); +void pdf__closepath_stroke(PDF *p); +void pdf__curveto(PDF *p, pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, pdc_scalar x_3, pdc_scalar y_3); +void pdf__endpath(PDF *p); +void pdf__fill(PDF *p); +void pdf__fill_stroke(PDF *p); +void pdf__lineto(PDF *p, pdc_scalar x, pdc_scalar y); +void pdf__rlineto(PDF *p, pdc_scalar x, pdc_scalar y); +void pdf__moveto(PDF *p, pdc_scalar x, pdc_scalar y); +void pdf__rcurveto(PDF *p, pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, pdc_scalar x_3, pdc_scalar y_3); +void pdf__rect(PDF *p, pdc_scalar x, pdc_scalar y, + pdc_scalar width, pdc_scalar height); +void pdf__rmoveto(PDF *p, pdc_scalar x, pdc_scalar y); +void pdf__stroke(PDF *p); + +void pdf_rrcurveto(PDF *p, pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar x_2, pdc_scalar y_2, pdc_scalar x_3, pdc_scalar y_3); +void pdf_hvcurveto(PDF *p, pdc_scalar x_1, pdc_scalar x_2, + pdc_scalar y_2, pdc_scalar y_3); +void pdf_vhcurveto(PDF *p, pdc_scalar y_1, pdc_scalar x_2, + pdc_scalar y_2, pdc_scalar x_3); + + +/********************** + * + * p_encoding.c + * + **********************/ + +void pdf__encoding_set_char(PDF *p, const char *encoding, int slot, + const char *glyphname, int uv); + +pdc_encoding pdf_get_hypertextencoding_param(PDF *p, int *codepage); +pdc_encoding pdf_get_hypertextencoding(PDF *p, const char *encoding, + int *codepage, pdc_bool verbose); + + + + +/********************** + * + * p_filter.c + * + **********************/ + +int pdf_data_source_buf_fill(PDF *p, PDF_data_source *src); +void pdf_data_source_file_init(PDF *p, PDF_data_source *src); +int pdf_data_source_file_fill(PDF *p, PDF_data_source *src); +void pdf_data_source_file_terminate(PDF *p, PDF_data_source *src); +void pdf_copy_stream(PDF *p, PDF_data_source *src, pdc_bool compress); + + +/********************** + * + * p_font.c + * + **********************/ + +double pdf__info_font(PDF *p, int ifont, const char *keyword, + const char *optlist); +int pdf__load_font(PDF *p, const char *fontname, int len, + const char *encoding, const char *optlist); + +void pdf_init_font_options(PDF *p, pdf_font_options *fo); +void pdf_cleanup_font_curroptions(PDF *p); +void pdf_cleanup_font_options(PDF *p, pdf_font_options *fo); +void pdf_init_font(PDF *p, pdf_font *font, pdf_font_options *fo); +void pdf_cleanup_font(PDF *p, pdf_font *font); +void pdf_init_fonts(PDF *p); +void pdf_cleanup_fonts(PDF *p); +int pdf_insert_font(PDF *p, pdf_font *font); +void pdf_write_doc_fonts(PDF *p); +void pdf_write_page_fonts(PDF *p); +void pdf_get_page_fonts(PDF *p, pdf_reslist *rl); +void pdf_mark_page_font(PDF *p, int ft); + + +/********************** + * + * p_gstate.c + * + **********************/ + +void pdf__concat(PDF *p, pdc_scalar a, pdc_scalar b, pdc_scalar c, pdc_scalar d, + pdc_scalar e, pdc_scalar f); +void pdf__initgraphics(PDF *p); +void pdf__restore(PDF *p); +void pdf__rotate(PDF *p, pdc_scalar phi); +void pdf__save(PDF *p); +void pdf__scale(PDF *p, pdc_scalar sx, pdc_scalar sy); +void pdf__setdash(PDF *p, pdc_scalar b, pdc_scalar w); +void pdf__setdashpattern(PDF *p, const char *optlist); +void pdf__setflat(PDF *p, pdc_scalar flatness); +void pdf__setlinecap(PDF *p, int linecap); +void pdf__setlinejoin(PDF *p, int linejoin); +void pdf__setlinewidth(PDF *p, pdc_scalar width); +void pdf__setmatrix(PDF *p, pdc_scalar a, pdc_scalar b, pdc_scalar c, + pdc_scalar d, pdc_scalar e, pdc_scalar f); +void pdf__setmiterlimit(PDF *p, pdc_scalar miter); +void pdf__skew(PDF *p, pdc_scalar alpha, pdc_scalar beta); +void pdf__translate(PDF *p, pdc_scalar tx, pdc_scalar ty); + +void pdf_setmatrix_e(PDF *p, pdc_matrix *n); +void pdf_init_gstate(PDF *p); +void pdf_concat_raw(PDF *p, pdc_matrix *m); +void pdf_reset_gstate(PDF *p); +void pdf_set_topdownsystem(PDF *p, pdc_scalar height); +void pdf_setdashpattern_internal(PDF *p, pdc_scalar *darray, int length, + pdc_scalar phase); + + +/********************** + * + * p_hyper.c + * + **********************/ + +int pdf__add_bookmark(PDF *p, const char *text, int len, int parent, int open); +void pdf__add_nameddest(PDF *p, const char *name, int len, const char *optlist); +int pdf__create_bookmark(PDF *p, const char *text, int len, + const char *optlist); +void pdf__set_info(PDF *p, const char *key, const char *value, int len); + +pdf_dest *pdf_init_destination(PDF *p); +pdf_dest *pdf_parse_destination_optlist(PDF *p, const char *optlist, + int page, pdf_destuse destuse); +void pdf_cleanup_destination(PDF *p, pdf_dest *dest); +void pdf_write_destination(PDF *p, pdf_dest *dest); +pdf_dest *pdf_get_option_destname(PDF *p, pdc_resopt *resopts, + pdc_encoding hypertextencoding, int hypertextcodepage); +void pdf_init_outlines(PDF *p); +void pdf_write_outlines(PDF *p); +void pdf_write_outline_root(PDF *p); +void pdf_cleanup_outlines(PDF *p); +void pdf_feed_digest_info(PDF *p); +pdc_id pdf_write_info(PDF *p, pdc_bool moddate); +void pdf_cleanup_info(PDF *p); + + + + +/********************** + * + * p_image.c + * + **********************/ + +void pdf__add_thumbnail(PDF *p, int image); +void pdf__close_image(PDF *p, int image); +void pdf__fit_image(PDF *p, int image, pdc_scalar x, pdc_scalar y, + const char *optlist); +int pdf__load_image(PDF *p, const char *imagetype, const char *filename, + const char *optlist); + +void pdf_grow_images(PDF *p); +void pdf_put_image(PDF *p, int im, pdc_bool firststrip, + pdc_bool checkcontentstream); +void pdf_put_inline_image(PDF *p, int im); +void pdf_init_images(PDF *p); +void pdf_cleanup_images(PDF *p); +void pdf_cleanup_image(PDF *p, int im); +void pdf_get_image_size(PDF *p, int im, pdc_scalar *width, pdc_scalar *height); +void pdf_get_image_resolution(PDF *p, int im, pdc_scalar *dpi_x, + pdc_scalar *dpi_y); + + + + + + +/********************** + * + * p_mbox.c + * + **********************/ + +double pdf__info_matchbox(PDF *p, const char *boxname, int len, int num, + const char *keyword); + +pdc_vtr *pdf_new_mboxes(PDF *p, pdf_mbox *mbox, pdc_vtr *mboxes); +pdf_mbox *pdf_parse_mbox_optlist(PDF *p, const char *optlist); +pdf_mbox *pdf_get_mbox(PDF *p, pdc_vtr *mboxes, const char *name, int number, + int *o_count); +void pdf_delete_mbox(PDF *p, pdf_mbox *mbox); +void pdf_add_page_mbox(PDF *p, pdf_mbox *mbox); + +pdc_bool pdf_get_mbox_drawborder(PDF *p, pdf_mbox *mbox, int keycode); +void pdf_set_mbox_rectangle(PDF *p, pdf_mbox *mbox, pdc_rectangle *rect, + int flags); +void pdf_get_mbox_rectangle(PDF *p, pdf_mbox *mbox, pdc_vector *polyline); +void pdf_draw_mbox_rectangle(PDF *p, pdf_mbox *mbox, pdc_bool saverestore); +const char *pdf_get_usematchbox(PDF *p, const char *option, const char *optval, + int *istart, int *istop); + +void pdf_set_position_values(PDF *p, pdc_scalar *i_position, int nv); + + +/********************** + * + * p_object.c + * + **********************/ + +void pdf__delete(PDF *p); + +PDF *pdf__new(errorproc_t errorhandler, allocproc_t allocproc, + reallocproc_t reallocproc, freeproc_t freeproc, void *opaque); + +const char *pdf_current_scope(PDF *p); + + +/********************** + * + * p_page.c + * + **********************/ + +void pdf__begin_page(PDF *p, pdc_scalar width, pdc_scalar height); +void pdf__begin_page_ext(PDF *p, pdc_scalar width, pdc_scalar height, + const char *optlist); +void pdf__end_page_ext(PDF *p, const char *optlist); +void pdf__resume_page(PDF *p, const char *optlist); +void pdf__suspend_page(PDF *p, const char *optlist); +void pdf_pg_resume(PDF *p, int pageno); +void pdf_pg_suspend(PDF *p); + +void pdf_init_pages(PDF *p, const char **groups, int n_groups); +void pdf_init_pages2(PDF *p); +void pdf_check_suspended_pages(PDF *p); +void pdf_cleanup_pages(PDF *p); +pdc_id pdf_get_page_id(PDF *p, int n); +int pdf_current_page(PDF *p); +int pdf_current_page_id(PDF *p); +int pdf_last_page(PDF *p); +int pdf_search_page_fwd(PDF *p, int start_page, pdc_id id); +int pdf_search_page_bwd(PDF *p, int start_page, pdc_id id); +int pdf_xlat_pageno(PDF *p, int pageno, const char *groupname); + +double pdf_get_pageheight(PDF *p); +const pdc_rectangle *pdf_get_pagebox(PDF *p, pdf_pagebox box); +void pdf_set_pagebox_llx(PDF *p, pdf_pagebox box, pdc_scalar llx); +void pdf_set_pagebox_lly(PDF *p, pdf_pagebox box, pdc_scalar lly); +void pdf_set_pagebox_urx(PDF *p, pdf_pagebox box, pdc_scalar urx); +void pdf_set_pagebox_ury(PDF *p, pdf_pagebox box, pdc_scalar ury); +void pdf_set_pagebox(PDF *p, pdf_pagebox box, pdc_scalar llx, pdc_scalar lly, + pdc_scalar urx, pdc_scalar ury); + +pdc_vtr *pdf_get_annots_list(PDF *p); +void pdf_set_annots_list(PDF *p, pdc_vtr *annots); +pdc_id pdf_get_thumb_id(PDF *p); +void pdf_set_thumb_id(PDF *p, pdc_id id); + +void pdf_begin_contents_section(PDF *p); +void pdf_end_contents_section(PDF *p); +void pdf_add_reslist(PDF *p, pdf_reslist *rl, int num); +pdc_id pdf_write_pagelabels(PDF *p); + + + +/********************** + * + * p_parameter.c + * + **********************/ + +const char *pdf__get_parameter(PDF *p, const char *key, double modifier); +double pdf__get_value(PDF *p, const char *key, double modifier); +void pdf__set_parameter(PDF *p, const char *key, const char *value); +void pdf__set_value(PDF *p, const char *key, double value); + + +/********************** + * + * p_pattern.c + * + **********************/ + +int pdf__begin_pattern(PDF *p, + pdc_scalar width, pdc_scalar height, pdc_scalar xstep, pdc_scalar ystep, + int painttype); + +void pdf__end_pattern(PDF *p); + +void pdf_init_pattern(PDF *p); +void pdf_write_page_pattern(PDF *p); +void pdf_get_page_patterns(PDF *p, pdf_reslist *rl); +void pdf_mark_page_pattern(PDF *p, int n); +void pdf_cleanup_pattern(PDF *p); +void pdf_grow_pattern(PDF *p); + + + + +/********************** + * + * p_shading.c + * + **********************/ + +int pdf__shading(PDF *p, const char *shtype, pdc_scalar x_0, pdc_scalar y_0, + pdc_scalar x_1, pdc_scalar y_1, pdc_scalar c_1, pdc_scalar c_2, + pdc_scalar c_3, pdc_scalar c_4, const char *optlist); +int pdf__shading_pattern(PDF *p, int shading, const char *optlist); +void pdf__shfill(PDF *p, int shading); + +void pdf_init_shadings(PDF *p); +void pdf_write_page_shadings(PDF *p); +void pdf_get_page_shadings(PDF *p, pdf_reslist *rl); +void pdf_mark_page_shading(PDF *p, int n); +void pdf_cleanup_shadings(PDF *p); +int pdf_get_shading_painttype(PDF *p); + + + + + + +/********************** + * + * p_template.c + * + **********************/ + +int pdf__begin_template(PDF *p, pdc_scalar width, pdc_scalar height, + const char *optlist); +void pdf__end_template(PDF *p); +int pdf_embed_image(PDF *p, int im); + + +/********************** + * + * p_text.c + * + **********************/ + +void pdf__fit_textline(PDF *p, const char *text, int len, + pdc_scalar x, pdc_scalar y, const char *optlist); +double pdf__info_textline(PDF *p, const char *text, int len, + const char *keyword, const char *optlist); +void pdf__setfont(PDF *p, int font, pdc_scalar fontsize); +void pdf__set_text_pos(PDF *p, pdc_scalar x, pdc_scalar y); +void pdf__show_text(PDF *p, const char *text, int len, pdc_bool cont); +void pdf__xshow(PDF *p, const char *text, int len, + const pdc_scalar *xadvancelist); +int pdf__show_boxed(PDF *p, const char *text, int len, + pdc_scalar left, pdc_scalar top, pdc_scalar width, pdc_scalar height, + const char *hmode, const char *feature); +pdc_scalar pdf__stringwidth(PDF *p, const char *text, int len, + int font, pdc_scalar size); + +void pdf_init_tstate(PDF *p); +void pdf_cleanup_page_tstate(PDF *p, pdf_ppt *ppt); +void pdf_save_tstate(PDF *p); +void pdf_restore_currto(PDF *p); +void pdf_set_tstate(PDF *p, pdc_scalar value, pdf_text_optflags flag); +double pdf_get_tstate(PDF *p, pdf_text_optflags tflag); +void pdf_end_text(PDF *p); +void pdf_reset_tstate(PDF *p); +int pdf_get_font(PDF *p); +void pdf_put_fieldtext(PDF *p, const char *text, int font); +int pdf_get_fontsize_option(PDF *p, int font, pdc_resopt *resopts, + pdc_scalar *fontsize); + + + + + +/********************** + * + * p_type3.c + * + **********************/ + +void pdf__begin_font(PDF *p, const char *fontname, int len, + pdc_scalar a, pdc_scalar b, pdc_scalar c, pdc_scalar d, + pdc_scalar e, pdc_scalar f, const char *optlist); +void pdf__begin_glyph(PDF *p, const char *glyphname, pdc_scalar wx, + pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury); +void pdf__end_font(PDF *p); +void pdf__end_glyph(PDF *p); + +int pdf_get_t3colorized(PDF *p); + + +/********************** + * + * p_util.c + * + **********************/ + +const char *pdf__utf32_to_utf16(PDF *p, const char *utf32string, int len, + const char *ordering, int *outlen); +const char *pdf__utf16_to_utf8(PDF *p, const char *utf16string, int len, + int *outlen); +const char *pdf__utf8_to_utf16(PDF *p, const char *utf8string, + const char *ordering, int *outlen); + +void pdf_check_textformat(PDF *p, pdc_text_format textformat); +void pdf_check_hypertextformat(PDF *p, pdc_text_format hypertextformat); +void pdf_check_hypertextencoding(PDF *p, pdc_encoding hypertextencoding); +void pdf_put_pdfname(PDF *p, const char *name); +pdc_encoding pdf_get_hypertextencoding_opt(PDF *p, pdc_resopt *resopts, + int *codepage, pdc_bool verbose); +char *pdf_convert_hypertext_depr(PDF *p, const char *text, int len); +char *pdf_convert_hypertext(PDF *p, const char *text, int len, + pdc_text_format hypertextformat, pdc_encoding hypertextencoding, + int codepage, int *outlen, pdc_bool oututf8, pdc_bool verbose); +void pdf_put_hypertext(PDF *p, const char *text); +char *pdf_convert_name(PDF *p, const char *name, int len, int flags); +const char *pdf_convert_filename(PDF *p, const char *filename, int len, + const char *paramname, int flags); +void pdf_add_resource(PDF *p, const char *category, const char *resname); +void pdf_put_pdffilename(PDF *p, const char *text); +void pdf_check_handle(PDF *p, int value, pdc_opttype type); +void pdf_set_clientdata(PDF *p, pdc_clientdata *clientdata); +void pdf_init_stringlists(PDF *p); +int pdf_insert_stringlist(PDF *p, char **stringlist, int ns); +void pdf_cleanup_stringlists(PDF *p); +int pdf_insert_utilstring(PDF *p, const char *utilstring, pdc_bool kdup); +const char *pdf_get_utilstring(PDF *p, int i); +int pdf_get_opt_textlist(PDF *p, const char *keyword, pdc_resopt *resopts, + pdc_encoding enc, int codepage, pdc_bool ishypertext, + const char *fieldname, char **text, char ***textlist); +char *pdf_get_opt_utf8name(PDF *p, const char *keyword, pdc_resopt *resopts); +pdc_bool pdf_get_errorpolicy(PDF *p, pdc_resopt *resopts, pdc_bool verbose); + + +/********************** + * + * p_xgstate.c + * + **********************/ + +int pdf__create_gstate(PDF *p, const char *optlist); +void pdf__set_gstate(PDF *p, int gstate); + +void pdf_init_extgstates(PDF *p); +void pdf_write_page_extgstates(PDF *p); +void pdf_get_page_extgstates(PDF *p, pdf_reslist *rl); +void pdf_mark_page_extgstate(PDF *p, int n); +void pdf_write_doc_extgstates(PDF *p); +void pdf_cleanup_extgstates(PDF *p); +pdc_id pdf_get_gstate_id(PDF *p, int gstate); + + + + +#endif /* P_INTERN_H */ + + + + + diff --git a/src/pdflib/pdflib/p_jpeg.c b/src/pdflib/pdflib/p_jpeg.c new file mode 100644 index 0000000..467f282 --- /dev/null +++ b/src/pdflib/pdflib/p_jpeg.c @@ -0,0 +1,1560 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_jpeg.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * JPEG processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#ifndef PDF_JPEG_SUPPORTED + +pdc_bool +pdf_is_JPEG_file(PDF *p, pdc_file *fp) +{ + (void) p; + (void) fp; + + return pdc_false; +} + +int +pdf_process_JPEG_data( + PDF *p, + int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "JPEG", 0, 0, 0); + + return -1; +} + +/* CDPDF - added missing function */ +void +pdf_cleanup_jpeg(PDF *p, pdf_image *image) +{ + (void) p; + (void) image; +} + +#else + +#include "jinclude.h" +#include "jpeglib.h" + +/* + * The following enum is stolen from the IJG JPEG library + * Comments added by tm. + * This table contains far too many names since PDFlib + * is rather simple-minded about markers. + */ + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, /* baseline DCT */ + M_SOF1 = 0xc1, /* extended sequential DCT */ + M_SOF2 = 0xc2, /* progressive DCT */ + M_SOF3 = 0xc3, /* lossless (sequential) */ + + M_SOF5 = 0xc5, /* differential sequential DCT */ + M_SOF6 = 0xc6, /* differential progressive DCT */ + M_SOF7 = 0xc7, /* differential lossless */ + + M_JPG = 0xc8, /* JPEG extensions */ + M_SOF9 = 0xc9, /* extended sequential DCT */ + M_SOF10 = 0xca, /* progressive DCT */ + M_SOF11 = 0xcb, /* lossless (sequential) */ + + M_SOF13 = 0xcd, /* differential sequential DCT */ + M_SOF14 = 0xce, /* differential progressive DCT */ + M_SOF15 = 0xcf, /* differential lossless */ + + M_DHT = 0xc4, /* define Huffman tables */ + + M_DAC = 0xcc, /* define arithmetic conditioning table */ + + M_RST0 = 0xd0, /* restart */ + M_RST1 = 0xd1, /* restart */ + M_RST2 = 0xd2, /* restart */ + M_RST3 = 0xd3, /* restart */ + M_RST4 = 0xd4, /* restart */ + M_RST5 = 0xd5, /* restart */ + M_RST6 = 0xd6, /* restart */ + M_RST7 = 0xd7, /* restart */ + + M_SOI = 0xd8, /* start of image */ + M_EOI = 0xd9, /* end of image */ + M_SOS = 0xda, /* start of scan */ + M_DQT = 0xdb, /* define quantization tables */ + M_DNL = 0xdc, /* define number of lines */ + M_DRI = 0xdd, /* define restart interval */ + M_DHP = 0xde, /* define hierarchical progression */ + M_EXP = 0xdf, /* expand reference image(s) */ + + M_APP0 = 0xe0, /* application marker, used for JFIF */ + M_APP1 = 0xe1, /* application marker, used for Exif */ + M_APP2 = 0xe2, /* application marker, used for FlashPix* + * and ICC Profiles */ + M_APP3 = 0xe3, /* application marker */ + M_APP4 = 0xe4, /* application marker */ + M_APP5 = 0xe5, /* application marker */ + M_APP6 = 0xe6, /* application marker */ + M_APP7 = 0xe7, /* application marker */ + M_APP8 = 0xe8, /* application marker, used for SPIFF */ + M_APP9 = 0xe9, /* application marker */ + M_APP10 = 0xea, /* application marker */ + M_APP11 = 0xeb, /* application marker */ + M_APP12 = 0xec, /* application marker */ + M_APP13 = 0xed, /* application marker, used by Photoshop*/ + M_APP14 = 0xee, /* application marker, used by Adobe */ + M_APP15 = 0xef, /* application marker */ + + M_JPG0 = 0xf0, /* reserved for JPEG extensions */ + M_JPG13 = 0xfd, /* reserved for JPEG extensions */ + M_COM = 0xfe, /* comment */ + + M_TEM = 0x01 /* temporary use */ + +} JPEG_MARKER; + +#define JPEG_SEGLIST_CHUNKSIZE 64 +#define JPEG_MARKER_LEN 2 +#define JPEG_LENGTH_LEN 2 +#define JPEG_BUFSIZE 0xFFFF + +struct pdf_jpeg_segment_s +{ + long pos; /* position of segment */ + size_t length; /* length of segement in byte */ +}; + +static void +pdf_register_JPEG_segment(PDF *p, pdf_image *image, long pos, size_t length) +{ + static const char fn[] = "pdf_register_JPEG_segment"; + pdf_jpeg_info *jpeg = &image->info.jpeg; + size_t len; + + pdc_logg_cond(p->pdc, 5, trc_image, + "\t\tKeep segment, position = 0x%lX, length = 0x%lX(%ld)\n", + pos, length, length); + + while(length > 0) + { + len = length; + if (len > JPEG_BUFSIZE) + len = JPEG_BUFSIZE; + + if (jpeg->number >= jpeg->capacity) + { + if (jpeg->capacity == 0) + { + jpeg->capacity = JPEG_SEGLIST_CHUNKSIZE; + jpeg->seglist = (pdf_jpeg_segment *) pdc_malloc(p->pdc, + jpeg->capacity * sizeof(pdf_jpeg_segment), fn); + } + else + { + jpeg->capacity += JPEG_SEGLIST_CHUNKSIZE; + jpeg->seglist = (pdf_jpeg_segment *) pdc_realloc(p->pdc, + jpeg->seglist, jpeg->capacity* sizeof(pdf_jpeg_segment), fn); + } + } + jpeg->seglist[jpeg->number].pos = pos; + jpeg->seglist[jpeg->number].length = len; + jpeg->number++; + + length -= len; + pos += len; + } +} + +static void +pdf_data_source_JPEG_init(PDF *p, PDF_data_source *src) +{ + static const char fn[] = "pdf_data_source_JPEG_init"; + pdf_image *image; + pdf_jpeg_info *jpeg; + + image = (pdf_image *) src->private_data; + jpeg = &image->info.jpeg; + + jpeg->capacity = jpeg->number; + jpeg->number = 0; + + src->buffer_start = (pdc_byte *) pdc_malloc(p->pdc, JPEG_BUFSIZE, fn); + src->buffer_length = JPEG_BUFSIZE; +} + +static pdc_bool +pdf_data_source_JPEG_fill(PDF *p, PDF_data_source *src) +{ + pdf_image *image; + pdf_jpeg_info *jpeg; + size_t length; + long pos; + + (void) p; + + image = (pdf_image *) src->private_data; + jpeg = &image->info.jpeg; + + if (jpeg->number < jpeg->capacity) + { + pos = jpeg->seglist[jpeg->number].pos; + length = jpeg->seglist[jpeg->number].length; + jpeg->number++; + + pdc_fseek(image->fp, pos, SEEK_SET); + src->next_byte = src->buffer_start; + src->bytes_available = + pdc_fread(src->buffer_start, 1, length, image->fp); + } + else + { + src->bytes_available = 0; + } + + if (src->bytes_available == 0) + return pdc_false; + else + return pdc_true; +} + +static void +pdf_data_source_JPEG_terminate(PDF *p, PDF_data_source *src) +{ + pdc_free(p->pdc, (void *) src->buffer_start); +} + +/********************************************************************** + * + * Decompression data source routines for the case of + * reading JPEG data from a PDFlib virtual file in + * JPEG library - analogous to ../libs/jpeg/jdatasrc.c + * + **********************************************************************/ + +typedef struct +{ + struct jpeg_source_mgr pub; /* public fields */ + pdc_file *infile; + PDF *p; /* required for logging only */ + pdf_image *image; /* required for access to the filename */ +} +pdf_source_mgr; + +typedef pdf_source_mgr * pdf_src_ptr; + +static void +pdf_init_JPEG_source (j_decompress_ptr cinfo) +{ + (void) cinfo; +} + +static boolean +pdf_fill_JPEG_input_buffer (j_decompress_ptr cinfo) +{ + pdf_src_ptr src = (pdf_src_ptr) cinfo->src; + JOCTET *buffer; + size_t nbytes; + + buffer = (JOCTET *) pdc_freadall(src->infile, &nbytes, NULL); + + src->pub.next_input_byte = buffer; + src->pub.bytes_in_buffer = nbytes; + + return TRUE; +} + +static void +pdf_skip_JPEG_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + pdf_src_ptr src = (pdf_src_ptr) cinfo->src; + + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; +} + +static void +pdf_term_JPEG_source (j_decompress_ptr cinfo) +{ + (void) cinfo; +} + +static void +pdf_jpeg_pdcread_src(j_decompress_ptr cinfo, + PDF *p, pdc_file *infile, pdf_image *image) +{ + pdf_src_ptr src; + + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(pdf_source_mgr)); + + src = (pdf_src_ptr) cinfo->src; + src->pub.init_source = pdf_init_JPEG_source; + src->pub.fill_input_buffer = pdf_fill_JPEG_input_buffer; + src->pub.skip_input_data = pdf_skip_JPEG_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = pdf_term_JPEG_source; + src->infile = infile; + src->p = p; + src->image = image; + src->pub.bytes_in_buffer = 0; + src->pub.next_input_byte = NULL; +} + +/********************************************************************** + * + * Compression data destination routines for the case of + * emitting JPEG data to a open PDFlib PDF file in + * JPEG library - analogous to ../libs/jpeg/jdatadst.c + * + **********************************************************************/ + +typedef struct +{ + struct jpeg_destination_mgr pub; + PDF *p; + pdf_image *image; /* required for access to the filename */ + JOCTET *buffer; +} +pdf_destination_mgr; + +typedef pdf_destination_mgr * pdf_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 + +static void +pdf_init_JPEG_destination (j_compress_ptr cinfo) +{ + pdf_dest_ptr dest = (pdf_dest_ptr) cinfo->dest; + + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +static boolean +pdf_empty_JPEG_output_buffer (j_compress_ptr cinfo) +{ + pdf_dest_ptr dest = (pdf_dest_ptr) cinfo->dest; + + pdc_write(dest->p->out, dest->buffer, OUTPUT_BUF_SIZE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +static void +pdf_term_JPEG_destination (j_compress_ptr cinfo) +{ + pdf_dest_ptr dest = (pdf_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + if (datacount) + pdc_write(dest->p->out, dest->buffer, datacount); +} + +static void +pdf_jpeg_pdcwrite_dest(j_compress_ptr cinfo, PDF *p, pdf_image *image) +{ + pdf_dest_ptr dest; + + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(pdf_destination_mgr)); + + dest = (pdf_dest_ptr) cinfo->dest; + dest->pub.init_destination = pdf_init_JPEG_destination; + dest->pub.empty_output_buffer = pdf_empty_JPEG_output_buffer; + dest->pub.term_destination = pdf_term_JPEG_destination; + dest->p = p; + dest->image = image; +} + +/**********************************************************************/ + +#define PDF_JMSG_LENGTH_MAX 200 + +/* + * Private replacements for libjpeg's error message function. + * They serve two purposes: + * - avoid libjpeg writing to stderr + * - write the message to the log file if logging is enabled + * One function is required for each source and destination. + */ + +static void +pdf_output_message_src(j_common_ptr cinfo) +{ + char buffer[PDF_JMSG_LENGTH_MAX]; + + /* we use this method only for decompression objects */ + j_decompress_ptr cinfo2 = (j_decompress_ptr) cinfo; + pdf_source_mgr *src = (pdf_source_mgr *) cinfo2->src; + + if (!pdc_logg_is_enabled(src->p->pdc, 5, trc_image)) + return; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + pdc_logg(src->p->pdc, "\tlibjpeg src: %s\n", buffer); +} + +static void +pdf_output_message_dst(j_common_ptr cinfo) +{ + char buffer[PDF_JMSG_LENGTH_MAX]; + + /* we use this method only for compression objects */ + j_compress_ptr cinfo2 = (j_compress_ptr) cinfo; + pdf_destination_mgr *dst = (pdf_destination_mgr *) cinfo2->dest; + + if (!pdc_logg_is_enabled(dst->p->pdc, 5, trc_image)) + return; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + pdc_logg(dst->p->pdc, "\tlibjpeg dst: %s\n", buffer); +} + +/* + * Private replacements for libjpeg's error_exit function. + * They serve three purposes: + * - avoid libjpeg exiting + * - write a message to the log file if logging is enabled + * - return control from libjpeg by raising an exception + * One function is required for each source and destination. + */ + +static void +pdf_error_exit_src(j_common_ptr cinfo) +{ + PDF *p; + pdf_image *image; + char buffer[PDF_JMSG_LENGTH_MAX]; + + /* we use this method only for decompression objects */ + j_decompress_ptr cinfo2 = (j_decompress_ptr) cinfo; + pdf_source_mgr *src = (pdf_source_mgr *) cinfo2->src; + + p = src->p; + image = src->image; + + (*cinfo->err->output_message) (cinfo); + (*cinfo->err->format_message) (cinfo, buffer); + + if (pdc_logg_is_enabled(p->pdc, 5, trc_image)) + pdc_logg(p->pdc, "\tlibjpeg (src) called error_exit routine\n"); + + /* clean up libjpeg */ + jpeg_destroy(cinfo); + + pdc_error(p->pdc, PDF_E_JPEG_TRANSCODE, + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, image->filename), + buffer, 0, 0); +} + +static void +pdf_error_exit_dst(j_common_ptr cinfo) +{ + PDF *p; + pdf_image *image; + char buffer[PDF_JMSG_LENGTH_MAX]; + + /* we use this method only for compression objects */ + j_compress_ptr cinfo2 = (j_compress_ptr) cinfo; + pdf_destination_mgr *dst = (pdf_destination_mgr *) cinfo2->dest; + + p = dst->p; + image = dst->image; + + (*cinfo->err->output_message) (cinfo); + (*cinfo->err->format_message) (cinfo, buffer); + + if (pdc_logg_is_enabled(p->pdc, 5, trc_image)) + pdc_logg(p->pdc, "\tlibjpeg (dst) called error_exit routine\n"); + + /* clean up libjpeg */ + jpeg_destroy(cinfo); + + pdc_error(p->pdc, PDF_E_JPEG_TRANSCODE, + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, image->filename), + buffer, 0, 0); +} + +static pdc_bool +pdf_data_source_JPEG_fill_transcode(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + pdc_bool logg5 = pdc_logg_is_enabled(p->pdc, 5, trc_image); + + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + jvirt_barray_ptr * src_coef_arrays; + struct jpeg_error_mgr jsrcerr, jdsterr; + + /* ---------- Setup for decompression ---------- */ + /* Initialize the JPEG decompression object with default error handling. */ + srcinfo.err = jpeg_std_error(&jsrcerr); + + /* Hook up our own message handler for logging */ + srcinfo.err->output_message = pdf_output_message_src; + + /* Hook up our own fatal error handler */ + srcinfo.err->error_exit = pdf_error_exit_src; + + /* Extended libjpeg tracing if PDFlib logging is enabled */ + if (logg5) + srcinfo.err->trace_level = 5; + + jpeg_create_decompress(&srcinfo); + + /* Specify data source for decompression analogous to jpeg_stdio_src */ + pdf_jpeg_pdcread_src(&srcinfo, p, image->fp, image); + + /* ---------- Setup for compression ---------- */ + /* Initialize the JPEG compression object with default error handling. */ + dstinfo.err = jpeg_std_error(&jdsterr); + + /* Hook up our own message handler for logging */ + dstinfo.err->output_message = pdf_output_message_dst; + + /* Hook up our own fatal error handler */ + dstinfo.err->error_exit = pdf_error_exit_dst; + + /* Extended libjpeg tracing if PDFlib logging is enabled */ + if (logg5) + dstinfo.err->trace_level = 5; + + jpeg_create_compress(&dstinfo); + + PDC_TRY(p->pdc) + { + /* ---------- start transcoding ---------- */ + + /* Read file header */ + if (jpeg_read_header(&srcinfo, TRUE) != JPEG_HEADER_OK) + { + if (logg5) + pdc_logg(p->pdc, "\tlibjpeg couldn't read header\n"); + + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "JPEG", + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, + image->filename), 0, 0); + } + + /* Read source file as DCT coefficients */ + src_coef_arrays = jpeg_read_coefficients(&srcinfo); + if (src_coef_arrays == NULL) + { + if (logg5) + pdc_logg(p->pdc, "\tlibjpeg couldn't read coefficients\n"); + + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "JPEG", + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, + image->filename), 0, 0); + } + + /* Initialize destination compression parameters from source values */ + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + /* Specify data destination for compression analogous to + * jpeg_stdio_dest + */ + pdf_jpeg_pdcwrite_dest(&dstinfo, p, image); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, src_coef_arrays); + + /* Finish compression */ + /* DON'T change the order! */ + jpeg_finish_compress(&dstinfo); + (void) jpeg_finish_decompress(&srcinfo); + } + PDC_CATCH(p->pdc) + { + image->corrupt = pdc_true; + } + + /* Release memory */ + jpeg_destroy_compress(&dstinfo); + jpeg_destroy_decompress(&srcinfo); + + /* All done. Check for errors */ + if (jsrcerr.num_warnings != 0 && logg5) + { + /* + * We don't really care about problems in the input since + * they will be fixed by transcoding. Log them, but don't throw an + * exception. + */ + pdc_logg(p->pdc, + "\tlibjpeg total: %d corrupt data warning(s)\n", + jsrcerr.num_warnings); + } + + if (jdsterr.num_warnings != 0) + { + char buffer[PDF_JMSG_LENGTH_MAX]; + + /* + * Errors in the output are rare, but fatal. Log them, + * and unconditionally throw an exception. + */ + if (logg5) + { + pdc_logg(p->pdc, "\tlibjpeg: %d warning(s) for output\n", + jdsterr.num_warnings); + } + + (dstinfo.err->format_message) ((j_common_ptr) &dstinfo, buffer); + pdc_set_errmsg(p->pdc, PDF_E_JPEG_TRANSCODE, + pdf_get_image_filename(p, image), buffer, 0, 0); + + image->corrupt = pdc_true; + } + + return pdc_false; +} + +static pdc_ushort +get_ushort(pdc_file *fp) +{ + pdc_byte c[2]; + + c[0] = (pdc_byte) pdc_fgetc(fp); + c[1] = (pdc_byte) pdc_fgetc(fp); + + return pdc_get_be_ushort(c); +} + +#define CHECK_LENGTH 1024L + +pdc_bool +pdf_is_JPEG_file(PDF *p, pdc_file *fp) +{ + long pos = 0L; + int c; + long start = (long) pdc_ftell(fp); + long check_length = start + CHECK_LENGTH; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type JPEG...\n"); + +#if !defined(MVS) || !defined(I370) + /* Tommy's special trick for Macintosh JPEGs: simply skip some */ + /* hundred bytes at the beginning of the file! */ + do + { + do /* skip if not FF */ + { + c = pdc_fgetc(fp); + pos++; + + } + while (!pdc_feof(fp) && c != 0xFF && pos < check_length); + + if (pdc_feof(fp) || pos >= check_length) + { + pdc_fseek(fp, start, SEEK_SET); + return pdc_false; + } + + do /* skip repeated FFs */ + { + c = pdc_fgetc(fp); + pos++; + } + while (c == 0xFF && pos < check_length); + + /* remember start position */ + pos = (pdc_off_t1) pdc_ftell(fp); + if (pos < 0L || pos >= check_length) + { + pdc_fseek(fp, start, SEEK_SET); + return pdc_false; + } + + pos -= JPEG_MARKER_LEN; /* subtract marker length */ + + if (c == M_SOI) + { + pdc_fseek(fp, pos, SEEK_SET); + break; + } + } + while (!pdc_feof(fp)); +#endif /* !MVS || !I370 */ + +#define BOGUS_LENGTH 768 + /* If we are that far from the start we consider the image as damaged if: + * - OJPEG-TIFF: it does not start at the alleged data offset + * - any other flavor: it has too much garbage at the beginning + */ + if (pdc_feof(fp) || pos > (start ? start : BOGUS_LENGTH)) + { + pdc_fseek(fp, start, SEEK_SET); + return pdc_false; + } + + return pdc_true; +} + +/* This function should be moved to p_color.c once it gets used by other + * image modules as well. + */ + +static void +pdf_log_colorspace(PDF *p, int slot) +{ + pdf_colorspace *cs; + + if (slot < 0 || slot >= p->colorspaces_number) + { + pdc_logg(p->pdc, " Bad color space slot %d", slot); + } + + cs = &p->colorspaces[slot]; + + switch (cs->type) { + case DeviceGray: + pdc_logg(p->pdc, "/DeviceGray"); + break; + + case DeviceRGB: + pdc_logg(p->pdc, "/DeviceRGB"); + break; + + case DeviceCMYK: + pdc_logg(p->pdc, "/DeviceCMYK"); + break; + + + case Indexed: + pdc_logg(p->pdc, "/Indexed"); + break; + + case PatternCS: + pdc_logg(p->pdc, "/Pattern"); + break; + + default: + pdc_logg(p->pdc, "%d (unknown)", cs->type); + } +} + +/* open JPEG image and analyze marker */ +int +pdf_process_JPEG_data( + PDF *p, + int imageslot) +{ + int c, unit; + unsigned long length, len = 0, slen; +#define APP_MAX 255 + pdc_byte appstring[APP_MAX]; + const char *filename = NULL; + pdc_bool ismem = pdc_false; + void *filebase = NULL; + size_t filelen; + pdf_image *image; + int transform = 0; + pdc_bool marker_found = pdc_false; + pdc_bool markers_done = pdc_false; + pdc_bool need_transcode = pdc_false; + pdc_bool logg5 = pdc_logg_is_enabled(p->pdc, 5, trc_image); + long pos = 0, endpos = 0; + long adobe_pos = 0, adobe_len = 0; + int errint = 0; + int errcode = 0; + + image = &p->images[imageslot]; + image->compression = pdf_comp_dct; + image->use_raw = pdc_true; + image->info.jpeg.virtfile = NULL; + image->info.jpeg.seglist = NULL; + image->info.jpeg.capacity = 0; + image->info.jpeg.number = 0; + + need_transcode = !image->passthrough; + + if (logg5) + { + pdc_logg(p->pdc, "\tjpegoptimize = %s\n", + image->jpegoptimize ? "true" : "false"); + if (need_transcode) + pdc_logg(p->pdc, "\ttranscoding...\n"); + else + pdc_logg(p->pdc, "\ttranscoding disabled by passthrough option\n"); + } + + /* jpeg file not available */ + if (image->reference != pdf_ref_direct) + { + + + image->in_use = pdc_true; /* mark slot as used */ + pdf_put_image(p, imageslot, pdc_true, pdc_true); + return imageslot; + } + + if (!pdc_file_isvirtual(image->fp)) + { + /* read whole file */ + filebase = (void *) pdc_freadall(image->fp, &filelen, &ismem); + if (filebase == NULL) + { + errcode = PDC_E_IO_READ; + goto PDF_JPEG_ERROR; + } + pdc_fclose(image->fp); + + /* temporary memory */ + pdc_insert_mem_tmp(p->pdc, filebase, 0, 0); + + /* create virtual image file */ + filename = "__jpeg__image__data__"; + pdc__create_pvf(p->pdc, filename, filebase, filelen, ""); + image->info.jpeg.virtfile = filename; + + if (logg5) + { + pdc_logg(p->pdc, "\tVirtual file created, " + "length = 0x%lX(%ld)\n", filelen, filelen); + } + + /* open virtual file */ + image->fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "", + PDC_FILE_BINARY); + } + + if (image->info.jpeg.jpegifoffset) + { + /* Just to be sure: if we were handed a OJPEG-compressed TIFF with + * an offset we let libjpeg transcode. + */ + need_transcode = pdc_true; + + if (logg5) + { + pdc_logg(p->pdc, + "\ttranscoding because of OJPEG-compressed TIFF\n"); + pdc_logg(p->pdc, + "\tseeking to base offset 0x%lX(%ld) (TIFF with OJPEG)\n", + image->info.jpeg.jpegifoffset, image->info.jpeg.jpegifoffset); + } + pdc_fseek(image->fp, image->info.jpeg.jpegifoffset, SEEK_SET); + } + + if (pdf_is_JPEG_file(p, image->fp) == pdc_false) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + + /* JPEG marker loop */ + while (1) + { + /* look for next JPEG Marker */ + if (!markers_done) + { + do /* repeat if FF/00 */ + { + do /* skip to FF */ + { + if (pdc_feof(image->fp)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + c = pdc_fgetc(image->fp); + } + while (c != 0xFF); + + do /* skip repeated FFs */ + { + if (pdc_feof(image->fp)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + c = pdc_fgetc(image->fp); + } + while (c == 0xFF); + } + while (c == 0); + + /* start of new segment */ + pos = (pdc_off_t1) pdc_ftell(image->fp) - JPEG_MARKER_LEN; + + /* skip garbage at the start of image data */ + if (!marker_found && pos > 0) + { + if (logg5 && pos > (long) image->info.jpeg.jpegifoffset) + { + pdc_logg(p->pdc, "\t0x%lX(%ld) bytes garbage " + "at start of image\n", pos, pos); + } + + /* we must create a new virtual file */ + if (image->info.jpeg.virtfile == 0) + { + /* read whole file */ + filebase = (void *) pdc_freadall(image->fp, + &filelen, &ismem); + if (filebase == NULL) + { + errcode = PDC_E_IO_READ; + goto PDF_JPEG_ERROR; + } + + /* temporary memory */ + pdc_insert_mem_tmp(p->pdc, filebase, 0, 0); + + filename = "__jpeg__image__data__"; + } + else + { + /* delete virtual file */ + pdc__delete_pvf(p->pdc, image->info.jpeg.virtfile); + } + + /* [re]create virtual file */ + filelen -= pos; + memmove(filebase, (char *) filebase + pos, filelen); + pdc__create_pvf(p->pdc, filename, filebase, filelen, ""); + image->info.jpeg.virtfile = filename; + + if (logg5) + { + pdc_logg(p->pdc, "\tVirtual file created, " + "length = 0x%lX(%ld)\n", + filelen, filelen); + } + /* [re]open virtual file */ + pdc_fclose(image->fp); + image->fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "", + PDC_FILE_BINARY); + + /* restart with the cleaned file */ + continue; + } + length = 0; + marker_found = pdc_true; + } + else + { + /* enforcing end of image */ + pos = (pdc_off_t1) pdc_ftell(image->fp); + pdc_fseek(image->fp, 0L, SEEK_END); + endpos = (pdc_off_t1) pdc_ftell(image->fp) - JPEG_MARKER_LEN; + length = endpos - pos; + c = M_EOI; + } + + /* analyzing JPEG Marker */ + switch (c) + { + /* markers which are not supported in PDF 1.3 and above */ + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + { + if (logg5) + { + pdc_logg(p->pdc, "\tMarker 0x%X(SOF%d) found - " + "not supported\n", c, c - M_SOF0); + } + errint = c; + errcode = PDF_E_JPEG_COMPRESSION; + } + goto PDF_JPEG_ERROR; + + /* markers without any parameters */ + case M_SOI: + case M_TEM: + case M_EOI: + case M_RST0: + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + { + if (logg5) + { + pdc_logg(p->pdc, "\tMarker 0x%X", c); + if (c == M_EOI) + pdc_logg(p->pdc, "(EOI)"); + pdc_logg(p->pdc, " found - no contents\n"); + } + pdf_register_JPEG_segment(p, image, pos, + (size_t) (length + JPEG_MARKER_LEN)); + } + break; + + /* skip segment if jpegoptimize = true, otherwise keep */ + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + case M_COM: + { + if (logg5) + { + pdc_logg(p->pdc, "\tMarker 0x%X", c); + if (c == M_COM) + pdc_logg(p->pdc, "(COM) found\n"); + else + pdc_logg(p->pdc, "(APP%d) found\n", c - M_APP0); + } + + length = get_ushort(image->fp); + if (!image->jpegoptimize) + pdf_register_JPEG_segment(p, image, pos, + (size_t) (length + JPEG_MARKER_LEN)); + else if (logg5) + pdc_logg(p->pdc, "\t\tSkip segment, position=0x%lX, " + "length=0x%lX(%ld)\n", + pos, length, length); + + /* We may have to register the Adobe marker later */ + if (c == M_APP14) + { + adobe_pos = pos; + adobe_len = length; + } + + length -= JPEG_LENGTH_LEN; + } + break; + + /* keep segment unconditionally */ + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF10: + case M_SOS: + default: + { + if (logg5) + { + pdc_logg(p->pdc, "\tMarker 0x%X", c); + if (c == M_SOS) + pdc_logg(p->pdc, "(SOS) found\n"); + else if (c <= M_SOF15) + pdc_logg(p->pdc, "(SOF%d) found\n", c - M_SOF0); + else + pdc_logg(p->pdc, " found\n"); + } + + length = get_ushort(image->fp); + pdf_register_JPEG_segment(p, image, pos, + (size_t) (length + JPEG_MARKER_LEN)); + length -= JPEG_LENGTH_LEN; + } + break; + } + + /* end of image */ + if (c == M_EOI) + { + if (logg5) + { + pdc_logg(p->pdc, "\tEnd of image\n"); + } + break; + } + + /* processing JPEG Marker */ + switch (c) + { + /* check for frame header markers */ + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF10: + { + int comp; + + image->bpc = pdc_fgetc(image->fp); + image->height = (pdc_scalar) get_ushort(image->fp); + image->width = (pdc_scalar) get_ushort(image->fp); + image->components = pdc_fgetc(image->fp); + length -= 6; + + for (comp=0; comp<image->components; comp++) + { + pdc_byte b; + + /* We don't support more than 4 components */ + if (comp==JPEG_MAX_COMPS) break; + + image->info.jpeg.id[comp] = pdc_fgetc(image->fp); + b = pdc_fgetc(image->fp); + image->info.jpeg.hsamp[comp] = (b >> 4) & 0x0F; + image->info.jpeg.vsamp[comp] = b & 0x0F; + image->info.jpeg.table[comp] = pdc_fgetc(image->fp); + length -= 3; + } + + /* + * No need to read more markers since multiscan detection + * not required for single-component images. + */ + if (image->components == 1) + markers_done = pdc_true; + + if (logg5) + { + pdc_logg(p->pdc, "\t\tbpc = %d\n", image->bpc); + pdc_logg(p->pdc, "\t\theight = %g\n", image->height); + pdc_logg(p->pdc, "\t\twidth = %g\n", image->width); + pdc_logg(p->pdc, "\t\tcomponents = %d\n", + image->components); + + for (comp=0; comp<image->components; comp++) + { + if (comp==JPEG_MAX_COMPS) + { + pdc_logg(p->pdc, "\t\tMore components found\n"); + break; + } + + if (pdc_logg_isprint((int) image->info.jpeg.id[comp])) + { + pdc_logg(p->pdc, + "\t\tcomponent 0x%x (name='%c'): " + "%dhx%dv table=%d\n", + image->info.jpeg.id[comp], + image->info.jpeg.id[comp], + image->info.jpeg.hsamp[comp], + image->info.jpeg.vsamp[comp], + image->info.jpeg.table[comp]); + } + else + { + pdc_logg(p->pdc, + "\t\tcomponent 0x%x: %dhx%dv table=%d\n", + image->info.jpeg.id[comp], + image->info.jpeg.hsamp[comp], + image->info.jpeg.vsamp[comp], + image->info.jpeg.table[comp]); + } + } + } + } + break; + + /* check for JFIF marker with resolution */ + case M_APP0: + { + len = MIN(APP_MAX, length); + if (!PDC_OK_FREAD(image->fp, appstring, len)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + length -= len; + + /* Check for JFIF application marker and read density values + * per JFIF spec version 1.02. + */ + +#define PDF_STRING_JFIF "\x4A\x46\x49\x46" + + slen = strlen(PDF_STRING_JFIF); + if (len > slen && + !strncmp(PDF_STRING_JFIF, (char *) appstring, slen)) + { + /* resolution unit and resolution */ + unit = appstring[7]; + image->dpi_x = (pdc_scalar) + pdc_get_be_ushort(&appstring[8]); + image->dpi_y = (pdc_scalar) + pdc_get_be_ushort(&appstring[10]); + +#define JFIF_ASPECT_RATIO 0 /* JFIF unit byte: aspect ratio only */ +#define JFIF_DOTS_PER_INCH 1 /* JFIF unit byte: dots per inch */ +#define JFIF_DOTS_PER_CM 2 /* JFIF unit byte: dots per cm */ + + switch (unit) + { + case JFIF_DOTS_PER_INCH: + break; + + case JFIF_DOTS_PER_CM: + image->dpi_x *= 100 * PDC_INCH2METER; + image->dpi_y *= 100 * PDC_INCH2METER; + break; + + case JFIF_ASPECT_RATIO: + image->dpi_x *= -1; + image->dpi_y *= -1; + break; + + /* unknown ==> ignore */ + default: + break; + } + + if (logg5) + { + pdc_logg(p->pdc, "\t\tJFIF marker found\n"); + pdc_logg(p->pdc, "\t\tJFIF density unit: %d", unit); + + switch (unit) + { + case JFIF_DOTS_PER_INCH: + pdc_logg(p->pdc, " (inch)\n"); + break; + + case JFIF_DOTS_PER_CM: + pdc_logg(p->pdc, " (cm)\n"); + break; + + case JFIF_ASPECT_RATIO: + pdc_logg(p->pdc, " (aspect ratio)\n"); + break; + + default: + pdc_logg(p->pdc, " (unknown; ignored)\n"); + break; + } + pdc_logg(p->pdc, "\t\tJFIF x resolution = %g\n", + image->dpi_x); + pdc_logg(p->pdc, "\t\tJFIF y resolution = %g\n", + image->dpi_y); + } + } + } + break; + + + /* check for Adobe marker */ + case M_APP14: + { + len = MIN(APP_MAX, length); + if (!PDC_OK_FREAD(image->fp, appstring, len)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + length -= len; + + /* + * Check for Adobe application marker. It is known + * (per Adobe's TN5116) + * to contain the string "Adobe" at the start + * of the APP14 marker. + */ + +#define PDF_STRING_Adobe "\x41\x64\x6F\x62\x65" + + slen = strlen(PDF_STRING_Adobe); + if (len > slen && + !strncmp(PDF_STRING_Adobe, (char *) appstring, slen)) + { + if (logg5) + { + pdc_byte *val = appstring+slen; + + pdc_logg(p->pdc, "\t\tAdobe marker found\n"); + + if (len >= 12) + { + pdc_logg(p->pdc, "\t\tversion = 0x%02X 0x%02X\n", + (unsigned char) val[0], (unsigned char) val[1]); + pdc_logg(p->pdc, "\t\tflags0 = 0x%02X 0x%02X\n", + (unsigned char) val[2], (unsigned char) val[3]); + pdc_logg(p->pdc, "\t\tflags1 = 0x%02X 0x%02X\n", + (unsigned char) val[4], (unsigned char) val[5]); + pdc_logg(p->pdc, "\t\tcolor transform = 0x%02X\n", + val[6]); + } + } + if (len >= 12) + transform = appstring[slen+6]; + + /* Keep Adobe marker for transform == 2 (YCCK) */ + if (transform == 2) + { + if (logg5) + pdc_logg(p->pdc, + "\t\tYCCK color space: Keep Adobe marker\n"); + + pdf_register_JPEG_segment(p, image, + adobe_pos, (size_t) (adobe_len + JPEG_MARKER_LEN)); + } + } + } + break; + + /* check for start of scan marker */ + case M_SOS: + { + pdc_byte comps = pdc_fgetc(image->fp); + length -= 1; + + if (logg5) + { + pdc_logg(p->pdc, "\t\tNumber of components in scan = " + "%d\n", comps); + } + + /* + * If the scan doesn't contain all components it must be + * a multiscan image, which doesn't work in Acrobat. + */ + + if (comps < image->components) + { + need_transcode = pdc_true; + if (logg5) + { + pdc_logg(p->pdc, + "\ttranscoding because of multiscan\n"); + } + } + + markers_done = pdc_true; + } + break; + + default: + break; + } + + /* jump to the next marker */ + if (length > 0) + { + if (pdc_fseek(image->fp, (long) length, SEEK_CUR) == -1) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + } + } + + /* do some sanity checks with the parameters */ + if (image->height <= 0 || image->width <= 0 || image->components <= 0) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_JPEG_ERROR; + } + + if (image->bpc != 8) + { + errint = image->bpc; + errcode = PDF_E_IMAGE_BADDEPTH; + goto PDF_JPEG_ERROR; + } + + { + switch (image->components) { + case 1: + /* spot color may have been applied */ + if (image->colorspace == pdc_undef) + image->colorspace = DeviceGray; + break; + + case 3: + image->colorspace = DeviceRGB; + break; + + case 4: + image->colorspace = DeviceCMYK; + break; + + default: + errint = image->components; + errcode = PDF_E_IMAGE_BADCOMP; + goto PDF_JPEG_ERROR; + } + } + + + + if (image->imagemask) + { + if (image->components != 1) + { + errcode = PDF_E_IMAGE_BADMASK; + goto PDF_JPEG_ERROR; + } + + if (p->compatibility <= PDC_1_3) + { + errcode = PDF_E_IMAGE_MASK1BIT13; + goto PDF_JPEG_ERROR; + } + else + { + /* images with more than one bit will be written as /SMask, + * and don't require an /ImageMask entry. + */ + image->imagemask = pdc_false; + } + } + + if (logg5) + { + pdc_logg(p->pdc, "\tColorspace="); + pdf_log_colorspace(p, image->colorspace); + pdc_logg(p->pdc, "\n"); + } + + /* special handling for CMYK JPEG files */ + if (image->components == 4) + { + /* CMYK JPEGs use inverse polarity */ + image->invert = !image->invert; + if (logg5) + pdc_logg(p->pdc, + "\tinverting image because of 4 components\n"); + + /* Adobe and other CMYK JPEGs always require transcoding */ + need_transcode = pdc_true; + if (logg5) + pdc_logg(p->pdc, + "\ttranscoding image because of 4 components\n"); + + } + + image->in_use = pdc_true; /* mark slot as used */ + + if (need_transcode) + { + if (logg5) + { + pdc_logg(p->pdc, "\tcalling libjpeg for transcoding\n"); + } + image->src.init = NULL; + image->src.fill = pdf_data_source_JPEG_fill_transcode; + image->src.terminate = NULL; + } + else + { + image->src.init = pdf_data_source_JPEG_init; + image->src.fill = pdf_data_source_JPEG_fill; + image->src.terminate = pdf_data_source_JPEG_terminate; + } + + image->src.private_data = (void *) image; + + if (image->doinline) + pdf_put_inline_image(p, imageslot); + else + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + if (!image->corrupt) + { + pdf_cleanup_jpeg(p, image); + + return imageslot; + } + + PDF_JPEG_ERROR: + { + const char *stemp = NULL; + + if (errcode) + stemp = pdf_get_image_filename(p, image); + + + switch (errcode) + { + case PDC_E_IO_READ: + case PDF_E_IMAGE_ICC: + case PDF_E_IMAGE_ICC2: + case PDF_E_IMAGE_COLORIZE: + case PDF_E_IMAGE_BADMASK: + case PDF_E_IMAGE_MASK1BIT13: + pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0); + break; + + case PDC_E_IO_BADFORMAT: + pdc_set_errmsg(p->pdc, errcode, stemp, "JPEG", 0, 0); + break; + + case PDF_E_IMAGE_CORRUPT: + pdc_set_errmsg(p->pdc, errcode, "JPEG", stemp, 0, 0); + break; + + case PDF_E_JPEG_COMPRESSION: + case PDF_E_IMAGE_BADDEPTH: + case PDF_E_IMAGE_BADCOMP: + pdc_set_errmsg(p->pdc, errcode, + pdc_errprintf(p->pdc, "%d", errint), stemp, 0, 0); + break; + + case 0: /* error code and message already set */ + break; + } + } + + pdf_cleanup_jpeg(p, image); + + return -1; +} + +void +pdf_cleanup_jpeg(PDF *p, pdf_image *image) +{ + if (image->info.jpeg.virtfile != NULL) + { + (void) pdc__delete_pvf(p->pdc, image->info.jpeg.virtfile); + image->info.jpeg.virtfile = NULL; + } + + if (image->info.jpeg.seglist != NULL) + { + pdc_free(p->pdc, image->info.jpeg.seglist); + image->info.jpeg.seglist = NULL; + } +} + + +#endif /* PDF_JPEG_SUPPORTED */ diff --git a/src/pdflib/pdflib/p_jpx.c b/src/pdflib/pdflib/p_jpx.c new file mode 100644 index 0000000..73e364c --- /dev/null +++ b/src/pdflib/pdflib/p_jpx.c @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_jpx.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * JPEG2000 processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#ifndef PDF_JPX_SUPPORTED + +pdc_bool +pdf_is_JPX_file(PDF *p, pdc_file *fp) +{ + (void) p; + (void) fp; + + return pdc_false; +} + +int +pdf_process_JPX_data( + PDF *p, + int imageslot) +{ + (void) imageslot; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "JPEG2000", 0, 0, 0); + + return -1; +} + +#else + + +pdc_bool +pdf_is_JPX_file(PDF *p, pdc_file *fp) +{ + (void) p; + (void) fp; + + return pdc_false; +} + +int +pdf_process_JPX_data( + PDF *p, + int imageslot) +{ + (void) imageslot; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "JPEG2000", 0, 0, 0); + + return -1; +} + + + +#endif /* PDF_JPX_SUPPORTED */ + diff --git a/src/pdflib/pdflib/p_kerning.c b/src/pdflib/pdflib/p_kerning.c new file mode 100644 index 0000000..bc711ba --- /dev/null +++ b/src/pdflib/pdflib/p_kerning.c @@ -0,0 +1,21 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_kerning.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib kerning routines + * + */ + +#include "p_intern.h" +#include "p_font.h" + diff --git a/src/pdflib/pdflib/p_keyconn.h b/src/pdflib/pdflib/p_keyconn.h new file mode 100644 index 0000000..a56d783 --- /dev/null +++ b/src/pdflib/pdflib/p_keyconn.h @@ -0,0 +1,827 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_keyconn.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib shared keys connection lists + * + */ + +#ifndef P_KEYCONN_H +#define P_KEYCONN_H + +/* + * ------------- enumerations for pdc_keyconn tables ------------------ + */ + +typedef enum +{ + pdf_state_object = (1<<0), /* outside any document */ + pdf_state_document = (1<<1), /* document */ + pdf_state_page = (1<<2), /* page description in a document */ + pdf_state_pattern = (1<<3), /* pattern in a document */ + pdf_state_template = (1<<4), /* template in a document */ + pdf_state_path = (1<<5), /* path in a page description */ + pdf_state_font = (1<<6), /* font definition */ + pdf_state_glyph = (1<<7), /* glyph description in a Type3 font */ + pdf_state_glyphmetric = (1<<8), /* glyph metric in a Type3 font */ + pdf_state_glyphignore = (1<<9), /* glyph will be ignored without error */ + pdf_state_error = (1<<10) /* in error cleanup */ +} +pdf_state; + +typedef enum +{ + errpol_legacy = -1, + errpol_return = 0, + errpol_exception = 1 +} +pdf_errpol; + +typedef enum +{ + names_undef = 0, + names_3dannots, /* internal for named 3D annotations */ + names_dests, + names_javascript, + names_ap, + names_embeddedfiles +} +pdf_nametree_type; + +typedef enum +{ + event_formfield, + event_annotation, + event_bookmark, + event_page, + event_document +} +pdf_event_object; + +typedef enum +{ + pdf_openaction, + pdf_bookmark, + pdf_remotelink, + pdf_locallink, + pdf_nameddest +} +pdf_destuse; + +typedef enum +{ + pdf_3dview_first = -1, + pdf_3dview_last = -2, + pdf_3dview_next = -3, + pdf_3dview_previous = -4, + pdf_3dview_default = -5 +} +pdf_3dviewoptions; + +typedef enum +{ + pdf_none = 0, + pdf_fill, + pdf_stroke, + pdf_fillstroke +} +pdf_drawmode; + +typedef enum +{ + pdf_fill_winding, + pdf_fill_evenodd +} +pdf_fillrule; + +typedef enum +{ + NoColor = -1, + DeviceGray = 0, + DeviceRGB, + DeviceCMYK, + CalGray, + CalRGB, + Lab, + ICCBased, + Indexed, + PatternCS, + Separation, + DeviceN +} +pdf_colorspacetype; + +typedef enum +{ + color_undefgray = -1, + color_none = 0, + color_gray, + color_rgb, + color_cmyk, + color_spotname, + color_spot, + color_pattern, + color_iccbasedgray, + color_iccbasedrgb, + color_iccbasedcmyk, + color_lab, + + color_max /* for pdf_parse_coloropt */ +} +pdf_colortype; + +typedef enum +{ + AutoIntent = 0, + AbsoluteColorimetric, + RelativeColorimetric, + Saturation, + Perceptual +} +pdf_renderingintent; + +/* only up to 32 values permitted! */ +typedef enum +{ + fo_autocidfont, + fo_autosubsetting, + fo_embedding, + fo_encoding, + fo_fontname, + fo_fontstyle, + fo_fontwarning, + fo_kerning, + fo_monospace, + fo_subsetlimit, + fo_subsetminsize, + fo_subsetting, + fo_unicodemap, + fo_embedopentype, + fo_vertical, + fo_keepnative, + fo_replacementchar, + fo_ascender, + fo_descender, + fo_capheight, + fo_xheight, + fo_linegap +} +pdf_font_optflags; + +/* only up to 32 values permitted! */ +typedef enum +{ + to_charspacing, + to_fillcolor, + to_font, + to_fontsize, + to_fontsize_st, + to_deffont, + to_glyphwarning, + to_horizscaling, + to_italicangle, + to_fakebold, + to_kerning, + to_overline, + to_strikeout, + to_strokecolor, + to_strokewidth, + to_dasharray, + to_text, + to_textformat, + to_textrendering, + to_textrise, + to_leading, + to_underline, + to_wordspacing, + to_underlinewidth, + to_underlineposition, + to_charref, + to_escapesequence, + to_glyphcheck, + + to_textx, + to_texty +} +pdf_text_optflags; + +typedef enum +{ + border_solid, + border_dashed, + border_beveled, + border_inset, + border_underline +} +pdf_borderstyle; + +typedef enum +{ + label_none, + label_123, + label_IVX, + label_ivx, + label_ABC, + label_abc +} +pdf_labelstyle; + +typedef enum { + BM_None = 0, + BM_Normal = (1<<0), + BM_Multiply = (1<<1), + BM_Screen = (1<<2), + BM_Overlay = (1<<3), + BM_Darken = (1<<4), + BM_Lighten = (1<<5), + BM_ColorDodge = (1<<6), + BM_ColorBurn = (1<<7), + BM_HardLight = (1<<8), + BM_SoftLight = (1<<9), + BM_Difference = (1<<10), + BM_Exclusion = (1<<11), + BM_Hue = (1<<12), + BM_Saturation = (1<<13), + BM_Color = (1<<14), + BM_Luminosity = (1<<15) +} +pdf_blendmode; + +/* these values are used directly as indices into +** a page's boxes[] array. +*/ +typedef enum +{ + pdf_artbox, + pdf_bleedbox, + pdf_cropbox, + pdf_mediabox, + pdf_trimbox +} pdf_pagebox; + +typedef enum +{ + tabs_none, + tabs_fitbox, + tabs_validarea +} +pdf_showtabs; + +typedef enum +{ + text_noalign, + text_left, + text_center, + text_right, + text_justify, + text_lastauto, + text_fulljustify, + text_decimal, + text_top, + text_bottom, + text_grid +} +pdf_alignment; + +typedef enum +{ + text_nofit, + text_clip, + text_shrink, + text_split, + text_spread, + text_auto +} +pdf_adjustmethod; + +typedef enum +{ + text_relative, + text_typewriter, + text_ruler +} +pdf_hortabmethod; + +typedef enum +{ + text_none = -90000, + text_textrise = -70000, + text_xheight = -60000, + text_descender = -50000, + text_capheight = -40000, + text_ascender = -30000, + text_fontsize = -20000, + text_leading = -10000 +} +pdf_charmetric; + +typedef enum +{ + mbox_none = 0, + mbox_openleft = (1<<0), + mbox_openright = (1<<1), + mbox_openbottom = (1<<2), + mbox_opentop = (1<<3), + mbox_border = (1<<4), + mbox_area = (1<<5), + mbox_saverestore = (1<<6), + mbox_statleft = (1<<7), + mbox_statright = (1<<8), + mbox_statbottom = (1<<9), + mbox_stattop = (1<<10) +} +pdf_mbox_flags; + +typedef enum +{ + quadd_left = 0, + quadd_center = 1, + quadd_right = 2 +} +pdf_quadding; + +typedef enum +{ + disp_visible = (1<<2), + disp_hidden = (1<<1), + disp_noview = (1<<5), + disp_noprint = 0 +} +pdf_display; + +typedef enum +{ + high_none, + high_invert, + high_outline, + high_push +} +pdf_highlight; + +typedef enum +{ + pos_left = 1000, + pos_bottom = 2000, + pos_center = 50, + pos_right = 1100, + pos_top = 2100 +} +pdf_position; + +typedef enum +{ + dpi_none = -999999, + dpi_internal = 0 +} +pdf_dpi_states; + +typedef enum +{ + trans_none, + trans_split, + trans_blinds, + trans_box, + trans_wipe, + trans_dissolve, + trans_glitter, + trans_replace, + + TRANS_1_5, + trans_fly = TRANS_1_5, + trans_push, + trans_cover, + trans_uncover, + trans_fade +} +pdf_transition; + + +/* + * -------- pdc_keyconn tables shared by more than one c file ---------- + */ + +#if defined(P_MBOX_C) + +static const pdc_keyconn pdf_mbox_keylist[] = +{ + {"all", -1}, + {NULL, 0} +}; + +#endif /* P_MBOX_C */ + + +#if defined(P_DOCUMENT_C) || defined(P_PARAMS_C) + +static const pdc_keyconn pdf_compatibility_keylist[] = +{ + {"1.3", PDC_1_3}, + {"1.4", PDC_1_4}, + {"1.5", PDC_1_5}, + {"1.6", PDC_1_6}, + {"1.7", PDC_1_7}, + {NULL, 0} +}; + +#endif /* P_DOCUMENT_C || P_PARAMS_C */ + + +#if defined(P_ACTIONS_C) || defined(P_PAGE_C) + +static const pdc_keyconn pdf_transition_keylist[] = +{ + {"none", trans_none}, + {"split", trans_split}, + {"blinds", trans_blinds}, + {"box", trans_box}, + {"wipe", trans_wipe}, + {"dissolve", trans_dissolve}, + {"glitter", trans_glitter}, + {"replace", trans_replace}, + {"fly", trans_fly}, + {"push", trans_push}, + {"cover", trans_cover}, + {"uncover", trans_uncover}, + {"fade", trans_fade}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_transition_pdfkeylist[] = +{ + {"R", trans_none}, + {"Split", trans_split}, + {"Blinds", trans_blinds}, + {"Box", trans_box}, + {"Wipe", trans_wipe}, + {"Dissolve", trans_dissolve}, + {"Glitter", trans_glitter}, + {"R", trans_replace}, + {"Fly", trans_fly}, + {"Push", trans_push}, + {"Cover", trans_cover}, + {"Uncover", trans_uncover}, + {"Fade", trans_fade}, + {NULL, 0} +}; + +#endif /* P_ACTIONS_C || P_PAGE_C */ + + +#if defined(P_IMAGE_C) || defined(P_PARAMS_C) || defined(P_XGSTATE_C) + +static const pdc_keyconn pdf_renderingintent_pdfkeylist[] = +{ + {"Auto", AutoIntent}, + {"AbsoluteColorimetric", AbsoluteColorimetric}, + {"RelativeColorimetric", RelativeColorimetric}, + {"Saturation", Saturation}, + {"Perceptual", Perceptual}, + {NULL, 0} +}; + +#endif /* P_IMAGE_C || P_PARAMS_C || P_XGSTATE_C */ + + +#if defined(P_MBOX_C) || defined(P_XGSTATE_C) + +static const pdc_keyconn pdf_linecap_keylist[] = +{ + {"butt", 0}, + {"round", 1}, + {"projecting", 2}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_linejoin_keylist[] = +{ + {"miter", 0}, + {"round", 1}, + {"bevel", 2}, + {NULL, 0} +}; + +#endif /* P_MBOX_C || P_XGSTATE_C */ + + +#if defined(P_DOCUMENT_C) || defined(P_PARAMS_C) || defined(P_PDI_C) + +static const pdc_keyconn pdf_usebox_keylist[] = +{ + {"art", pdc_pbox_art}, + {"bleed", pdc_pbox_bleed}, + {"crop", pdc_pbox_crop}, + {"media", pdc_pbox_media}, + {"trim", pdc_pbox_trim}, + {NULL, 0} +}; + +#endif /* P_DOCUMENT_C || P_PARAMS_C || P_PDI_C */ + +#if defined(P_DOCUMENT_C) || defined(P_PDI_C) + +static const pdc_keyconn pdf_usebox_pdfkeylist[] = +{ + {"/ArtBox", pdc_pbox_art }, + {"/BleedBox", pdc_pbox_bleed }, + {"/CropBox", pdc_pbox_crop }, + {"/MediaBox", pdc_pbox_media }, + {"/TrimBox", pdc_pbox_trim }, + {NULL, 0} +}; + +#endif /* P_DOCUMENT_C || P_PDI_C */ + + +#if defined(P_BLOCK_C) || defined(P_IMAGE_C) + +static const pdc_keyconn pdf_dpi_keylist[] = +{ + {"none", dpi_none}, + {"internal", dpi_internal}, + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_IMAGE_C */ + +#if defined(P_BLOCK_C) || defined(P_TEXT_C) + +static const pdc_keyconn pdf_stampdir_keylist[] = +{ + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_TEXT_C */ + + + + +#if defined(P_MBOX_C) || defined(P_TEXTFLOW_C) +static const pdc_keyconn pdf_boxheight_keylist[] = +{ + {"none", text_none}, + {"baseline", text_none}, + {"textrise", text_textrise}, + {"xheight", text_xheight}, + {"descender", text_descender}, + {"capheight", text_capheight}, + {"ascender", text_ascender}, + {"fontsize", text_fontsize}, + {"leading", text_leading}, + {NULL, 0} +}; + +#endif /* P_MBOX_C || P_TEXTFLOW_C */ + + +#if defined(P_BLOCK_C) || defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_charname_keylist[] = +{ + {"none", 0}, + {NULL, 0} +}; + +#define PDF_UNDERLINEWIDTH_AUTO 0 +static const pdc_keyconn pdf_underlinewidth_keylist[] = +{ + {"auto", PDF_UNDERLINEWIDTH_AUTO}, + {NULL, 0} +}; + +#define PDF_UNDERLINEPOSITION_AUTO 1000000 +static const pdc_keyconn pdf_underlineposition_keylist[] = +{ + {"auto", PDF_UNDERLINEPOSITION_AUTO}, + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_BLOCK_C)|| defined(P_PARAMS_C) || \ + defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_glyphcheck_keylist[] = +{ + {"none", text_nocheck}, + {"error", text_error}, + {"replace", text_replace}, + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_PARAMS_C || P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_BLOCK_C) || defined(P_FIELDS_C) || \ + defined(P_IMAGE_C) || defined(P_TEXT_C) + +static const pdc_keyconn pdf_position_keylist[] = +{ + {"left", pos_left}, + {"bottom", pos_bottom}, + {"center", pos_center}, + {"right", pos_right}, + {"top", pos_top}, + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_FIELDS_C || P_IMAGE_C || P_TEXT_C */ + + +#if defined(P_BLOCK_C) || defined(P_FIELDS_C) || \ + defined(P_IMAGE_C) || defined(P_TABLE_C) || \ + defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_fitmethod_keylist[] = +{ + {"nofit", pdc_nofit}, + {"clip", pdc_clip}, + {"auto", pdc_tauto}, +#if !defined (P_TEXTFLOW_C) + {"slice", pdc_slice}, + {"meet", pdc_meet}, + {"entire", pdc_entire}, +#endif + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_FIELDS_C || P_IMAGE_C || P_TABLE_C || + P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_ANNOTS_C) || defined(P_BLOCK_C) || defined(P_FIELDS_C) || \ + defined(P_IMAGE_C) || defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_orientate_keylist[] = +{ + {"north", 0}, + {"west", 90}, + {"south", 180}, + {"east", 270}, + {NULL, 0} +}; + +#endif /* P_ANNOTS_C || P_BLOCK_C || P_FIELDS_C || + P_IMAGE_C || P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_ANNOTS_C) || defined(P_BLOCK_C) || defined(P_FIELDS_C) || \ + defined(P_MBOX_C) || defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_fontsize_keylist[] = +{ + {"auto", 0}, + {"xheight", text_xheight}, + {"capheight", text_capheight}, + {"ascender", text_ascender}, + {"bodyheight", text_fontsize}, + {NULL, 0} +}; + +#endif /* P_ANNOTS_C P_BLOCK_C || P_FIELDS_C || + P_MBOX_C || P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_BLOCK_C) || defined(P_FONT_C) || defined(P_HYPER_C) || \ + defined(P_MBOX_C) || defined(P_TEXT_C) || defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_fontstyle_pdfkeylist[] = +{ + {"Normal", fnt_Normal}, + {"Bold", fnt_Bold}, + {"Italic", fnt_Italic}, + {"BoldItalic", fnt_BoldItalic}, + {NULL, 0} +}; + +#endif /* P_BLOCK_C || P_FONT_C || P_HYPER_C || + P_MBOX_C || P_TEXT_C || P_TEXTFLOW_C */ + + +#if defined(P_ANNOTS_C) || defined(P_FIELDS_C) + +static const pdc_keyconn pdf_quadding_keylist[] = +{ + {"left", quadd_left}, + {"center", quadd_center}, + {"right", quadd_right}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_display_keylist[] = +{ + {"visible", disp_visible}, + {"hidden", disp_hidden}, + {"noview", disp_noview}, + {"noprint", disp_noprint}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_highlight_keylist[] = +{ + {"none", high_none}, + {"invert", high_invert}, + {"outline", high_outline}, + {"push", high_push}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_highlight_pdfkeylist[] = +{ + {"N", high_none}, + {"I", high_invert}, + {"O", high_outline}, + {"P", high_push}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_borderstyle_keylist[] = +{ + {"solid", border_solid}, + {"dashed", border_dashed}, + {"beveled", border_beveled}, + {"inset", border_inset}, + {"underline", border_underline}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_borderstyle_pdfkeylist[] = +{ + {"S", border_solid}, + {"D", border_dashed}, + {"B", border_beveled}, + {"I", border_inset}, + {"U", border_underline}, + {NULL, 0} +}; + +#endif /* P_ANNOTS_C || P_FIELDS_C */ + + +#if defined(P_3D_C) || defined(P_BLOCK_C) || defined(P_FIELDS_C) || \ + defined(P_HYPER_C) || defined(P_LAYER_C) || defined(P_PARAMS_C) || \ + defined(P_TEXT_C) || defined(P_TEXTFLOW_C) || defined(P_UTIL_C) || \ + defined(P_XMP_C) + +/* original in pc_unicode.h */ +static const pdc_keyconn pdf_textformat_keylist[] = +{ + {"auto", pdc_auto}, + {"auto2", pdc_auto2}, + {"bytes", pdc_bytes}, + {"bytes2", pdc_bytes2}, + {"utf8", pdc_utf8}, + {"utf16", pdc_utf16}, + {"utf16be", pdc_utf16be}, + {"utf16le", pdc_utf16le}, + {NULL, 0} +}; + +#endif /* P_3D_C || P_BLOCK_C || P_FIELDS_C || P_HYPER_C || + P_LAYER_C || P_PARAMS_C || P_TEXT_C || P_TEXTFLOW_C || + P_UTIL_C || P_XMP_C */ + + +#if defined(P_DOCUMENT_C) || \ + defined(P_3D_C) || \ + defined(P_ACTIONS_C) || \ + defined(P_BLOCK_C) || \ + defined(P_FIELDS_C) || \ + defined(P_FONT_C) || \ + defined(P_ICC_C) || \ + defined(P_IMAGE_C) || \ + defined(P_PARAMS_C) || \ + defined(P_PDI_C) || \ + defined(P_TABLE_C) || \ + defined(P_TEMPLATE_C) || \ + defined(P_TEXT_C) || \ + defined(P_TEXTFLOW_C) + +static const pdc_keyconn pdf_errpol_keylist[] = +{ + {"legacy", errpol_legacy}, + {"return", errpol_return}, + {"exception", errpol_exception}, + {NULL, 0} +}; + +#define PDF_ERRORPOLICY_OPTION \ +\ + {"errorpolicy", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0, 0, pdf_errpol_keylist}, \ + +#endif + + +#endif /* P_KEYCONN_H */ + diff --git a/src/pdflib/pdflib/p_layer.c b/src/pdflib/pdflib/p_layer.c new file mode 100644 index 0000000..1600a5b --- /dev/null +++ b/src/pdflib/pdflib/p_layer.c @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + *---------------------------------------------------------------------------*/ + +/* $Id: p_layer.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib optional content routines + * + */ + +#define P_LAYER_C + +#include "p_intern.h" +#include "p_layer.h" +#include "p_tagged.h" + + + + + + + + + + + + + + diff --git a/src/pdflib/pdflib/p_layer.h b/src/pdflib/pdflib/p_layer.h new file mode 100644 index 0000000..74d51eb --- /dev/null +++ b/src/pdflib/pdflib/p_layer.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_layer.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib marked content header + * + */ + +#ifndef P_LAYER_H +#define P_LAYER_H + + +#endif /* P_LAYER_H */ + diff --git a/src/pdflib/pdflib/p_mbox.c b/src/pdflib/pdflib/p_mbox.c new file mode 100644 index 0000000..db6ffff --- /dev/null +++ b/src/pdflib/pdflib/p_mbox.c @@ -0,0 +1,943 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_mbox.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib matchbox related routines + * + */ + +#define P_MBOX_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_defopt.h" + +static const pdc_defopt pdf_create_mbox_options[] = +{ + {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"boxheight", pdc_scalarlist, PDC_OPT_NONE, 2, 2, + 0.0, PDC_FLOAT_MAX, pdf_boxheight_keylist}, + + {"clipping", pdc_scalarlist, PDC_OPT_PERCENT, 4, 4, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + + {"innerbox", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"openrect", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"fillcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"strokecolor", pdc_stringlist, PDC_OPT_NONE, 1, 5, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"borderwidth", pdc_scalarlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_FLOAT_MAX, NULL}, + + {"dasharray", pdc_scalarlist, PDC_OPT_NONE, 0, PDF_MAX_DASHLENGTH, + PDC_FLOAT_PREC, PDC_FLOAT_MAX, NULL}, + + {"dashphase", pdc_scalarlist, PDC_OPT_NONE, 1, 1, + 0.0, PDC_FLOAT_MAX, NULL}, + + {"linecap", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 0.0, 2.0, pdf_linecap_keylist}, + + {"linejoin", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 0.0, 2.0, pdf_linejoin_keylist}, + + {"drawleft", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"drawbottom", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"drawright", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"drawtop", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"margin", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"offsetleft", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"offsetbottom", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"offsetright", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + {"offsettop", pdc_scalarlist, PDC_OPT_PERCENT, 1, 1, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +struct pdf_mbox_s +{ + char *name; + pdc_rectangle rect; + pdc_matrix ctm; + pdc_scalar boxheight[2]; + pdc_scalar clipping[4]; + pdc_bool percentclipping[4]; + pdc_bool innerbox; + pdc_bool openrect; + pdf_coloropt fillcolor; + pdf_coloropt strokecolor; + pdc_scalar borderwidth; + int linecap; + int linejoin; + pdc_scalar dasharray[PDF_MAX_DASHLENGTH]; + int dashlength; + pdc_scalar dashphase; + pdc_bool drawleft; + pdc_bool drawbottom; + pdc_bool drawright; + pdc_bool drawtop; + pdc_scalar offsetleft; + pdc_bool percentleft; + pdc_scalar offsetbottom; + pdc_bool percentbottom; + pdc_scalar offsetright; + pdc_bool percentright; + pdc_scalar offsettop; + pdc_bool percenttop; +}; + +static void +pdf_reclaim_mbox(void *item) +{ + pdf_mbox *mbox = (pdf_mbox *) item; + + mbox->name = NULL; + pdc_rect_init(&mbox->rect, 0, 0, 0, 0); + pdc_identity_matrix(&mbox->ctm); + mbox->boxheight[0] = (pdc_scalar) text_capheight; + mbox->boxheight[1] = (pdc_scalar) text_none; + mbox->clipping[0] = 0; + mbox->clipping[1] = 0; + mbox->clipping[2] = 1; + mbox->clipping[3] = 1; + mbox->percentclipping[0] = pdc_true; + mbox->percentclipping[1] = pdc_true; + mbox->percentclipping[2] = pdc_true; + mbox->percentclipping[3] = pdc_true; + mbox->innerbox = pdc_false; + mbox->openrect = pdc_false; + mbox->fillcolor.type = (int) color_none; + mbox->strokecolor.type = (int) color_none; + mbox->borderwidth = 0.0; + mbox->linecap = 0; + mbox->linejoin = 0; + mbox->dasharray[0] = 0.0; + mbox->dasharray[1] = 0.0; + mbox->dashlength = 0; + mbox->dashphase = 0; + mbox->drawleft = pdc_true; + mbox->drawbottom = pdc_true; + mbox->drawright = pdc_true; + mbox->drawtop = pdc_true; + mbox->offsetleft = 0.0; + mbox->percentleft = pdc_false; + mbox->offsetbottom = 0.0; + mbox->percentbottom = pdc_false; + mbox->offsetright = 0.0; + mbox->percentright = pdc_false; + mbox->offsettop = 0.0; + mbox->percenttop = pdc_false; +} + +static void +pdf_release_mbox(void *context, void *item) +{ + PDF *p = (PDF *) context; + pdf_mbox *mbox = (pdf_mbox *) item; + + if (mbox->name != NULL) + { + pdc_free(p->pdc, mbox->name); + mbox->name = NULL; + } +} + +static pdc_ced pdf_mbox_ced = +{ + sizeof(pdf_mbox), pdf_reclaim_mbox, pdf_release_mbox, NULL +}; + +static pdc_vtr_parms pdf_mbox_parms = +{ + 0, 10, 10 +}; + +pdc_vtr * +pdf_new_mboxes(PDF *p, pdf_mbox *mbox, pdc_vtr *mboxes) +{ + static const char fn[] = "pdf_new_mboxes"; + char *name = mbox->name; + + if (mboxes == NULL) + mboxes = pdc_vtr_new(p->pdc, &pdf_mbox_ced, p, &pdf_mbox_parms); + + if (mbox->name != NULL) + mbox->name = pdc_strdup_ext(p->pdc, mbox->name, 0, fn); + pdc_vtr_push(mboxes, *mbox, pdf_mbox); + + mbox->name = name; + + return mboxes; +} + +void +pdf_add_page_mbox(PDF *p, pdf_mbox *mbox) +{ + /* save current trafo matrix */ + mbox->ctm = p->curr_ppt->gstate[p->curr_ppt->sl].ctm; + + if (mbox->name && strlen(mbox->name)) + { + pdc_vtr *mboxes_new; + pdc_vtr *mboxes = p->curr_ppt->mboxes; + + mboxes_new = pdf_new_mboxes(p, mbox, mboxes); + if (mboxes_new != mboxes) + p->curr_ppt->mboxes = mboxes_new; + + } +} + +void +pdf_delete_mbox(PDF *p, pdf_mbox *mbox) +{ + if (mbox != NULL) + { + pdf_release_mbox(p, mbox); + pdc_free(p->pdc, mbox); + } +} + +pdf_mbox * +pdf_get_mbox(PDF *p, pdc_vtr *mboxes, const char *name, int number, + int *o_count) +{ + pdf_mbox *o_mbox = NULL; + int count = 0; + + if (mboxes == NULL) + mboxes = p->curr_ppt->mboxes; + + if (mboxes != NULL) + { + if (name == NULL && number <= 0) + { + count = pdc_vtr_size(mboxes); + } + else + { + int i, n = pdc_vtr_size(mboxes); + + for (i = 0; i < n; i++) + { + pdf_mbox *mbox = (pdf_mbox *) &pdc_vtr_at(mboxes, i, pdf_mbox); + + if (name == NULL || !pdc_strcmp(name, mbox->name)) + { + count++; + if (o_count == NULL && count == number) + { + o_mbox = mbox; + break; + } + } + } + } + } + + if (o_count != NULL) + *o_count = count; + + return o_mbox; +} + +pdf_mbox * +pdf_parse_mbox_optlist(PDF *p, const char *optlist) +{ + static const char fn[] = "pdf_parse_mbox_optlist"; + pdc_resopt *resopts = NULL; + pdf_mbox *mbox; + char **strlist = NULL; + pdc_scalar margin; + int i, ns; + + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_create_mbox_options, + NULL, pdc_true); + + mbox = (pdf_mbox *) pdc_malloc(p->pdc, sizeof(pdf_mbox), fn); + pdf_reclaim_mbox(mbox); + + if (pdc_get_optvalues("name", resopts, NULL, NULL)) + mbox->name = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + pdc_get_optvalues("boxheight", resopts, mbox->boxheight, NULL); + if (pdc_get_optvalues("clipping", resopts, mbox->clipping, NULL)) + { + for (i = 0; i < 4; i++) + mbox->percentclipping[i] = pdc_is_lastopt_percent(resopts, i) ? + pdc_true : pdc_false; + } + + + pdc_get_optvalues("innerbox", resopts, &mbox->innerbox, NULL); + pdc_get_optvalues("openrect", resopts, &mbox->openrect, NULL); + + ns = pdc_get_optvalues("fillcolor", resopts, NULL, &strlist); + if (ns) + pdf_parse_coloropt(p, "fillcolor", strlist, ns, (int) color_max, + &mbox->fillcolor); + + pdf_init_coloropt(p, &mbox->strokecolor); + ns = pdc_get_optvalues("strokecolor", resopts, NULL, &strlist); + if (ns) + pdf_parse_coloropt(p, "strokecolor", strlist, ns, (int) color_max, + &mbox->strokecolor); + + pdc_get_optvalues("borderwidth", resopts, &mbox->borderwidth, NULL); + mbox->dashlength = + pdc_get_optvalues("dasharray", resopts, mbox->dasharray, NULL); + pdc_get_optvalues("dashphase", resopts, &mbox->dashphase, NULL); + pdc_get_optvalues("linecap", resopts, &mbox->linecap, NULL); + pdc_get_optvalues("linejoin", resopts, &mbox->linejoin, NULL); + + pdc_get_optvalues("drawleft", resopts, &mbox->drawleft, NULL); + pdc_get_optvalues("drawbottom", resopts, &mbox->drawbottom, NULL); + pdc_get_optvalues("drawright", resopts, &mbox->drawright, NULL); + pdc_get_optvalues("drawtop", resopts, &mbox->drawtop, NULL); + + if (pdc_get_optvalues("margin", resopts, &margin, NULL)) + { + mbox->offsetleft = margin; + mbox->percentleft = pdc_is_lastopt_percent(resopts, 0); + + mbox->offsetbottom = margin; + mbox->percentbottom = pdc_is_lastopt_percent(resopts, 0); + + mbox->offsetright = -margin; + mbox->percentright = pdc_is_lastopt_percent(resopts, 0); + + mbox->offsettop = -margin; + mbox->percenttop = pdc_is_lastopt_percent(resopts, 0); + } + + if (pdc_get_optvalues("offsetleft", resopts, &mbox->offsetleft, NULL)) + { + mbox->percentleft = pdc_is_lastopt_percent(resopts, 0); + } + if (pdc_get_optvalues("offsetbottom", resopts, &mbox->offsetbottom, NULL)) + { + mbox->percentbottom = pdc_is_lastopt_percent(resopts, 0); + } + if (pdc_get_optvalues("offsetright", resopts, &mbox->offsetright, NULL)) + { + mbox->percentright = pdc_is_lastopt_percent(resopts, 0); + } + if (pdc_get_optvalues("offsettop", resopts, &mbox->offsettop, NULL)) + { + mbox->percenttop = pdc_is_lastopt_percent(resopts, 0); + } + + pdc_cleanup_optionlist(p->pdc, resopts); + + return mbox; +} + +void +pdf_get_mbox_boxheight(PDF *p, pdf_mbox *mbox, pdc_scalar *boxheight) +{ + (void) p; + + if (mbox == NULL) + { + boxheight[0] = (pdc_scalar) text_capheight; + boxheight[1] = (pdc_scalar) text_none; + } + else + { + boxheight[0] = mbox->boxheight[0]; + boxheight[1] = mbox->boxheight[1]; + } +} + +pdc_bool +pdf_get_mbox_clipping(PDF *p, pdf_mbox *mbox, + pdc_scalar width, pdc_scalar height, + pdc_box *clipbox) +{ + (void) p; + + if (mbox == NULL) + { + clipbox->ll.x = 0; + clipbox->ll.y = 0; + clipbox->ur.x = width; + clipbox->ur.y = height; + } + else + { + if (mbox->percentclipping[0]) + clipbox->ll.x = mbox->clipping[0] * width; + else + clipbox->ll.x = mbox->clipping[0]; + + if (mbox->percentclipping[1]) + clipbox->ll.y = mbox->clipping[1] * height; + else + clipbox->ll.y = mbox->clipping[1]; + + if (mbox->percentclipping[2]) + clipbox->ur.x = mbox->clipping[2] * width; + else + clipbox->ur.x = mbox->clipping[2]; + + if (mbox->percentclipping[3]) + clipbox->ur.y = mbox->clipping[3] * height; + else + clipbox->ur.y = mbox->clipping[3]; + } + + return (clipbox->ll.x != 0 || clipbox->ll.y != 0 || + clipbox->ur.x != width || clipbox->ur.y != height) ? + pdc_true : pdc_false; +} + +void +pdf_set_mbox_rectangle(PDF *p, pdf_mbox *mbox, pdc_rectangle *rect, int flags) +{ + pdc_scalar width, height; + + (void) p; + + mbox->rect = *rect; + + width = mbox->rect.urx - mbox->rect.llx; + height = mbox->rect.ury - mbox->rect.lly; + + if (!(flags & mbox_statleft)) + { + if (mbox->percentleft) + mbox->rect.llx += mbox->offsetleft * width; + else + mbox->rect.llx += mbox->offsetleft; + } + + if (!(flags & mbox_statbottom)) + { + if (mbox->percentbottom) + mbox->rect.lly += mbox->offsetbottom * height; + else + mbox->rect.lly += mbox->offsetbottom; + } + + if (!(flags & mbox_statright)) + { + if (mbox->percentright) + mbox->rect.urx += mbox->offsetright * width; + else + mbox->rect.urx += mbox->offsetright; + } + + if (!(flags & mbox_stattop)) + { + if (mbox->percenttop) + mbox->rect.ury += mbox->offsettop * height; + else + mbox->rect.ury += mbox->offsettop; + } +} + +double +pdf_get_mbox_info(PDF *p, pdf_mbox *mbox, const char *keyword) +{ + (void) p; + + + if (!strcmp(keyword, "openrect")) + return (double) mbox->openrect; + + if (!strcmp(keyword, "innerbox")) + return (double) mbox->innerbox; + + return 0; +} + +pdc_bool +pdf_get_mbox_drawborder(PDF *p, pdf_mbox *mbox, int keycode) +{ + pdc_bool drawborder = mbox->borderwidth > 0 && + mbox->strokecolor.type != (int) color_none; + + (void) p; + + switch (keycode) + { + case mbox_openleft: + return drawborder && mbox->drawleft; + + case mbox_openright: + return drawborder && mbox->drawright; + + case mbox_openbottom: + return drawborder && mbox->drawbottom; + + case mbox_opentop: + return drawborder && mbox->drawtop; + } + + return pdc_false; +} + +void +pdf_get_mbox_rectangle(PDF *p, pdf_mbox *mbox, pdc_vector *polyline) +{ + pdc_matrix ctminv; + + pdc_invert_matrix(p->pdc, &ctminv, + &p->curr_ppt->gstate[p->curr_ppt->sl].ctm); + pdc_multiply_matrix(&mbox->ctm, &ctminv); + pdc_rect2polyline(&ctminv, &mbox->rect, polyline); +} + +void +pdf_draw_mbox_rectangle(PDF *p, pdf_mbox *mbox, int flags) +{ + pdc_bool drawleft, drawright, drawbottom, drawtop; + pdc_bool saverestore = (flags & mbox_saverestore) && + ((flags & mbox_area && + mbox->fillcolor.type != (int) color_none) || + (flags & mbox_border && + mbox->strokecolor.type != (int) color_none && mbox->borderwidth > 0)); + + if (saverestore) + pdf__save(p); + + if (flags & mbox_area && mbox->fillcolor.type != (int) color_none && + mbox->rect.llx != mbox->rect.urx && + mbox->rect.lly != mbox->rect.ury) + { + pdf_set_coloropt(p, pdf_fill, &mbox->fillcolor); + pdf__moveto(p, mbox->rect.llx, mbox->rect.lly); + pdf__lineto(p, mbox->rect.urx, mbox->rect.lly); + pdf__lineto(p, mbox->rect.urx, mbox->rect.ury); + pdf__lineto(p, mbox->rect.llx, mbox->rect.ury); + pdf__lineto(p, mbox->rect.llx, mbox->rect.lly); + pdf__fill(p); + } + + if (flags & mbox_border && + mbox->strokecolor.type != (int) color_none && mbox->borderwidth > 0) + { + pdf_set_coloropt(p, pdf_stroke, &mbox->strokecolor); + pdf__setlinewidth(p, mbox->borderwidth); + pdf_setdashpattern_internal(p, mbox->dasharray, mbox->dashlength, + mbox->dashphase); + pdf__setlinecap(p, mbox->linecap); + pdf__setlinejoin(p, mbox->linejoin); + + drawbottom = mbox->drawbottom && + (!(flags & mbox_openbottom) || !mbox->openrect); + if (drawbottom) + { + pdf__moveto(p, mbox->rect.llx, mbox->rect.lly); + pdf__lineto(p, mbox->rect.urx, mbox->rect.lly); + } + + drawright = mbox->drawright && + (!(flags & mbox_openright) || !mbox->openrect); + if (drawright) + { + if (!drawbottom) + pdf__moveto(p, mbox->rect.urx, mbox->rect.lly); + pdf__lineto(p, mbox->rect.urx, mbox->rect.ury); + } + + drawtop = mbox->drawtop && + (!(flags & mbox_opentop) || !mbox->openrect); + if (drawtop) + { + if (!drawright) + pdf__moveto(p, mbox->rect.urx, mbox->rect.ury); + pdf__lineto(p, mbox->rect.llx, mbox->rect.ury); + } + + drawleft = mbox->drawleft && + (!(flags & mbox_openleft) || !mbox->openrect); + if (drawleft) + { + if (!drawtop) + pdf__moveto(p, mbox->rect.llx, mbox->rect.ury); + if (drawbottom && drawright && drawtop) + pdf__closepath(p); + else + pdf__lineto(p, mbox->rect.llx, mbox->rect.lly); + } + + pdf__stroke(p); + } + + if (saverestore) + pdf__restore(p); +} + +const char * +pdf_get_usematchbox(PDF *p, const char *option, const char *optval, + int *istart, int *istop) +{ + const char *boxname = NULL, *stemp = NULL; + char **strlist = NULL; + int errcode = 0; + int k, ir, ns, irect = 1, nrect = 0; + + ns = pdc_split_stringlist(p->pdc, optval, NULL, PDC_SPLIT_ISOPTLIST, + &strlist); + if (ns) + { + boxname = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, strlist[0]); + + /* number of rectangles */ + pdf_get_mbox(p, NULL, boxname, 0, &nrect); + + if (ns == 2) + { + stemp = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, + strlist[1]); + + /* rectangle number or all rectangles */ + if (!pdc_str2integer(stemp, 0, &ir)) + { + k = pdc_get_keycode_ci(stemp, pdf_mbox_keylist); + if (k == PDC_KEY_NOTFOUND) + { + errcode = PDC_E_OPT_ILLKEYWORD; + goto PDF_USEMATCHBOX_ERROR; + } + } + else if (ir <= 0) + { + errcode = PDC_E_OPT_ILLINTEGER; + goto PDF_USEMATCHBOX_ERROR; + } + else + { + irect = ir; + nrect = MIN(irect, nrect); + } + } + else + { + irect = 1; + } + } + + PDF_USEMATCHBOX_ERROR: + + pdc_cleanup_stringlist(p->pdc, strlist); + + if (errcode) + pdc_error(p->pdc, errcode, option, stemp, 0, 0); + + *istart = irect; + *istop = nrect; + + return boxname; +} + +static const pdc_keyconn pdf_info_keylist[] = +{ + {"count", 0}, + {"exists", 1}, + {"width", 2}, + {"height", 3}, + {"x1", 4}, + {"y1", 5}, + {"x2", 6}, + {"y2", 7}, + {"x3", 8}, + {"y3", 9}, + {"x4", 10}, + {"y4", 11}, + {NULL, 0} +}; + +double +pdf__info_matchbox(PDF *p, const char *boxname, int len, int num, + const char *keyword) +{ + pdf_mbox *mbox; + char *cname; + double mbinfo = 0; + int infokey, count; + + if (boxname == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "boxname", 0, 0, 0); + + if (keyword == NULL || *keyword == '0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "keyword", 0, 0, 0); + + /* Converting boxname */ + cname = pdf_convert_name(p, boxname, len, 0); + if (cname == NULL || *cname == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "boxname", 0, 0, 0); + boxname = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, cname); + pdc_free(p->pdc, cname); + + infokey = pdc_get_keycode_ci(keyword, pdf_info_keylist); + if (infokey == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "keyword", keyword, 0, 0); + + /* count */ + if (!infokey) + { + pdf_get_mbox(p, NULL, boxname, num, &count); + mbinfo = (double) count; + } + else + { + if (num < 1) + pdc_error(p->pdc, PDC_E_ILLARG_INT, "num", + pdc_errprintf(p->pdc, "%d", num), 0, 0); + + mbox = pdf_get_mbox(p, NULL, boxname, num, NULL); + if (mbox != NULL) + { + pdc_vector polyline[5]; + + if (infokey > 1) + pdf_get_mbox_rectangle(p, mbox, polyline); + + switch (infokey) + { + case 1: + mbinfo = 1; + break; + + case 2: + mbinfo = pdc_get_vector_length(&polyline[0], &polyline[1]); + break; + + case 3: + mbinfo = pdc_get_vector_length(&polyline[0], &polyline[3]); + break; + + case 4: + mbinfo = polyline[0].x; + break; + + case 5: + mbinfo = polyline[0].y; + break; + + case 6: + mbinfo = polyline[1].x; + break; + + case 7: + mbinfo = polyline[1].y; + break; + + case 8: + mbinfo = polyline[2].x; + break; + + case 9: + mbinfo = polyline[2].y; + break; + + case 10: + mbinfo = polyline[3].x; + break; + + case 11: + mbinfo = polyline[3].y; + break; + } + } + } + + return mbinfo; +} + + +/* -------------------------- fit functions --------------------------- */ + +void +pdf_init_fit_options(PDF *p, pdc_bool fortflow, pdf_fit_options *fit) +{ + (void) p; + (void) fortflow; + + fit->boxsize[0] = 0; + fit->boxsize[1] = 0; + fit->flags = 0; + fit->fitmethod = pdc_nofit; + fit->margin[0] = 0; + fit->margin[1] = 0; + fit->mask = 0; + fit->pcmask = 0; + fit->shrinklimit = 0.75; + fit->position[0] = 0; + fit->position[1] = 0; + fit->orientate = 0; + fit->rotate = 0; + fit->refpoint[0] = 0; + fit->refpoint[1] = 0; + fit->showborder = pdc_false; + fit->matchbox = NULL; + fit->alignchar = 0; +} + +void +pdf_cleanup_fit_options(PDF *p, pdf_fit_options *fit) +{ + pdf_delete_mbox(p, fit->matchbox); + fit->matchbox = NULL; + + +} + +void +pdf_set_position_values(PDF *p, pdc_scalar *i_position, int nv) +{ + pdc_scalar position[2]; + int i, ipos; + + (void) p; + + position[0] = 0; + position[1] = 0; + + for (i = 0; i < nv; i++) + { + ipos = (int) i_position[i]; + switch(ipos) + { + case pos_left: + case pos_right: + position[0] = i_position[i] - pos_left; + break; + + case pos_bottom: + case pos_top: + position[1] = i_position[i] - pos_bottom; + break; + + default: + position[i] = i_position[i]; + break; + } + } + + if (nv == 1) + position[1] = position[0]; + + i_position[0] = position[0]; + i_position[1] = position[1]; +} + + +void +pdf_get_fit_options(PDF *p, pdc_bool fortflow, pdf_fit_options *fit, + pdc_resopt *resopts) +{ + char **strlist = NULL; + int inum; + + (void) fortflow; + + if (pdc_get_optvalues("fitmethod", resopts, &inum, NULL)) + { + fit->fitmethod = (pdc_fitmethod) inum; + fit->mask |= (1L << fit_fitmethod); + } + + if (pdc_get_optvalues("rotate", resopts, &fit->rotate, NULL)) + fit->mask |= (1L << fit_rotate); + + if (pdc_get_optvalues("orientate", resopts, &fit->orientate, NULL)) + fit->mask |= (1L << fit_orientate); + + pdc_get_optvalues("showborder", resopts, &fit->showborder, NULL); + + if (fit->flags & is_textline) + { + inum = pdc_get_optvalues("margin", resopts, fit->margin, NULL); + if (inum) + { + if (inum == 1) + fit->margin[1] = fit->margin[0]; + fit->mask |= (1L << fit_margin); + } + + if (pdc_get_optvalues("alignchar", resopts, &inum, NULL)) + { + fit->alignchar = (pdc_ushort) inum; + fit->mask |= (1L << fit_alignchar); + } + + } + + if (fit->flags & is_block) + { + if (pdc_get_optvalues("refpoint", resopts, fit->refpoint, NULL)) + fit->mask |= (1L << fit_refpoint); + } + + + if (fit->flags & is_block || !(fit->flags & is_textflow)) + { + if (pdc_get_optvalues("boxsize", resopts, fit->boxsize, NULL)) + fit->mask |= (1L << fit_boxsize); + + if (pdc_get_optvalues("shrinklimit", resopts, &fit->shrinklimit, NULL)) + fit->mask |= (1L << fit_shrinklimit); + + inum = pdc_get_optvalues("position", resopts, fit->position, NULL); + if (inum) + { + pdf_set_position_values(p, fit->position, inum); + fit->mask |= (1L << fit_position); + } + + if (pdc_get_optvalues("matchbox", resopts, NULL, &strlist)) + { + fit->matchbox = pdf_parse_mbox_optlist(p, strlist[0]); + fit->mask |= (1L << fit_matchbox); + } + } +} + +pdc_bool +pdf_is_horiz_orientated(pdf_fit_options *fit) +{ + return (fit->orientate == 0 || fit->orientate == 180) ? + pdc_true : pdc_false; +} + diff --git a/src/pdflib/pdflib/p_object.c b/src/pdflib/pdflib/p_object.c new file mode 100644 index 0000000..8ff285c --- /dev/null +++ b/src/pdflib/pdflib/p_object.c @@ -0,0 +1,257 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_object.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib PDF object functions + * + */ + +#define P_OBJECT_C + +#include "p_intern.h" +#include "p_image.h" + + + +static const pdc_keyconn pdf_scope_keylist[] = +{ + {"object", pdf_state_object}, + {"document", pdf_state_document}, + {"page", pdf_state_page}, + {"pattern", pdf_state_pattern}, + {"template", pdf_state_template}, + {"path", pdf_state_path}, + {"font", pdf_state_font}, + {"glyph", pdf_state_glyph}, + {"glyphmetric", pdf_state_glyphmetric}, + {"glyphignore", pdf_state_glyphignore}, + {"error", pdf_state_error}, + {NULL, 0} +}; + +static pdc_error_info pdf_errors[] = +{ +#define pdf_genInfo 1 +#include "p_generr.h" +}; + +#define N_PDF_ERRORS (sizeof pdf_errors / sizeof (pdc_error_info)) + +const char * +pdf_current_scope(PDF *p) +{ + const char *scopename = + pdc_get_keyword(PDF_GET_STATE(p), pdf_scope_keylist); + + if (!scopename) + pdc_error(p->pdc, PDF_E_INT_BADSCOPE, + pdc_errprintf(p->pdc, " (0x%08X)", PDF_GET_STATE(p)), 0, 0, 0); + + return (char *) scopename; /* be happy, compiler! */ +} + +/* p may be NULL on the first call - we don't use it anyway */ +static void * +default_malloc(PDF *p, size_t size, const char *caller) +{ + void *ret = malloc(size); + + (void) p; + (void) caller; + + return ret; +} + +static void * +default_realloc(PDF *p, void *mem, size_t size, const char *caller) +{ + void *ret = realloc(mem, size); + + (void) p; + (void) caller; + + return ret; +} + +static void +default_free(PDF *p, void *mem) +{ + (void) p; + + free(mem); +} + +PDF * +pdf__new( + void (*errorhandler)(PDF *p, int type, const char *msg), + void* (*allocproc)(PDF *p, size_t size, const char *caller), + void* (*reallocproc)(PDF *p, void *mem, size_t size, const char *caller), + void (*freeproc)(PDF *p, void *mem), + void *opaque) +{ + PDF * p; + pdc_core * pdc; + + /* If allocproc is NULL, all entries are supplied internally by PDFlib */ + if (allocproc == NULL) { + allocproc = default_malloc; + reallocproc = default_realloc; + freeproc = default_free; + } + + p = (PDF *) (*allocproc) (NULL, sizeof(PDF), "PDF_new"); + + if (p == NULL) + return NULL; + + /* + * Guard against crashes when PDF_delete is called without any + * PDF_open_*() in between. + */ + memset((void *)p, 0, (size_t) sizeof(PDF)); + + /* these two are required by PDF_get_opaque() */ + p->magic = PDC_MAGIC; + p->opaque = opaque; + + pdc = pdc_new_core( + (pdc_error_fp) errorhandler, + (pdc_alloc_fp) allocproc, + (pdc_realloc_fp) reallocproc, + (pdc_free_fp) freeproc, p, + PDFLIB_PRODUCTNAME, + PDFLIB_VERSIONSTRING); + + if (pdc == NULL) + { + (*freeproc)(p, p); + return NULL; + } + + pdc_register_errtab(pdc, PDC_ET_PDFLIB, pdf_errors, N_PDF_ERRORS); + fnt_register_errtab(pdc); + + PDC_TRY(pdc) + { + p->freeproc = freeproc; + p->pdc = pdc; + p->compatibility = PDF_DEF_COMPATIBILITY; + p->errorpolicy = errpol_legacy; + + p->userinfo = NULL; + p->document = NULL; + + p->errorhandler = errorhandler; + + p->flush = pdc_flush_page; + + p->hypertextencoding= pdc_invalidenc; + p->hypertextformat = pdc_auto; + p->hypertextcodepage= 0; + p->usercoordinates = pdc_false; + p->usehyptxtenc = pdc_false; + + p->currfo = NULL; + p->curr_ppt = NULL; + + p->glyphcheck = text_nocheck; + p->textformat = pdc_auto; + p->in_text = pdc_false; + + + p->rendintent = AutoIntent; + p->preserveoldpantonenames = pdc_false; + p->spotcolorlookup = pdc_true; + p->ydirection = 1; + p->names = NULL; + p->names_capacity = 0; + p->xobjects = NULL; + p->state_sp = 0; + p->doc_pages = NULL; + + p->actions = NULL; + + + + + + PDF_SET_STATE(p, pdf_state_object); + + /* all debug flags are cleared by default + * because of the above memset... */ + + /* ...but warning messages for non-fatal errors should be set, + * as well as font warnings -- the client must explicitly disable these. + */ + p->debug[(int) 'e'] = pdc_true; + p->debug[(int) 'F'] = pdc_true; + p->debug[(int) 'I'] = pdc_true; + + pdf_init_stringlists(p); + pdf_init_font_options(p, NULL); + + p->out = pdc_boot_output(p->pdc); + + + } + PDC_CATCH(pdc) + { + pdc_delete_core(pdc); + return (PDF *) 0; + } + return p; +} /* pdf__new */ + + +/* + * PDF_delete must be called for cleanup in case of error, + * or when the client is done producing PDF. + * It should never be called more than once for a given PDF, although + * we try to guard against duplicated calls. + * + * Note: all pdf_cleanup_*() functions may safely be called multiple times. + */ + +void +pdf__delete(PDF *p) +{ + /* + * Close the output stream, because it could be open + */ + pdc_close_output(p->out); + + /* + * Clean up page-related stuff if necessary. Do not raise + * an error here since we may be called from the error handler. + */ + pdf_cleanup_document(p); + pdf_cleanup_stringlists(p); + pdf_cleanup_font_curroptions(p); + pdc_cleanup_output(p->out, pdc_false); + + + + + if (p->out) + pdc_free(p->pdc, p->out); + + /* we never reach this point if (p->pdc == NULL). + */ + pdc_delete_core(p->pdc); + + /* free the PDF structure and try to protect against duplicated calls */ + + p->magic = 0L; /* we don't reach this with the wrong magic */ + (*p->freeproc)(p, (void *) p); +} + diff --git a/src/pdflib/pdflib/p_opi.c b/src/pdflib/pdflib/p_opi.c new file mode 100644 index 0000000..94cb435 --- /dev/null +++ b/src/pdflib/pdflib/p_opi.c @@ -0,0 +1,21 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_opi.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib OPI routines + * + */ + +#include "p_intern.h" +#include "p_image.h" + diff --git a/src/pdflib/pdflib/p_page.c b/src/pdflib/pdflib/p_page.c new file mode 100644 index 0000000..c03aaf3 --- /dev/null +++ b/src/pdflib/pdflib/p_page.c @@ -0,0 +1,2261 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_page.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib page related routines + * + */ + +#define P_PAGE_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_image.h" +#include "p_layer.h" +#include "p_page.h" +#include "p_tagged.h" + + + +#define PDF_N_PAGE_BOXES 5 + +static const pdc_keyconn pdf_labelstyle_pdfkeylist[] = +{ + {"none", label_none}, + {"D", label_123}, + {"R", label_IVX}, + {"r", label_ivx}, + {"A", label_ABC}, + {"a", label_abc}, + {NULL, 0} +}; + +typedef enum +{ + tabo_none, + tabo_row, + tabo_column, + tabo_structure +} +pdf_taborder; + +static const pdc_keyconn pdf_taborder_keylist[] = +{ + {"none", tabo_none}, + {"row", tabo_row}, + {"column", tabo_column}, + {"structure", tabo_structure}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_taborder_pdfkeylist[] = +{ + {"R", tabo_row}, + {"C", tabo_column}, + {"S", tabo_structure}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_colorspace_pdfkeylist[] = +{ + {"DeviceGray", color_gray}, + {"DeviceRGB", color_rgb}, + {"DeviceCMYK", color_cmyk}, + {NULL, 0} +}; + +typedef struct +{ + pdf_colortype colorspace; /* color space */ + pdc_bool isolated; /* isolated flag I */ + pdc_bool knockout; /* knockout flag K */ +} pg_transgroup; + +typedef struct +{ + pdf_labelstyle style; /* page label style */ + char * prefix; /* page label prefix */ + int start; /* page label numbering start */ + /* 0 means "no label" */ +} pg_label; + +typedef struct +{ + char * name; /* group name */ + int n_pages; /* # of pages in this group */ + int capacity; /* # of pages reserved */ + int start; /* 1-based physical page number */ + pg_label label; +} pg_group; + +/* per page resource list +*/ +struct pdf_reslist_s +{ + int * list; /* resource numbers */ + int capacity; + int length; +}; + +/* current, or suspended page. +*/ +typedef struct +{ + pdf_ppt ppt; + + /* list of content stream IDs. + */ + pdc_id * contents_ids; + int contents_ids_capacity; + int next_content; + + pdc_vtr * annots; /* annotation chain */ + + /* local values of global parameters. + */ + pdc_scalar ydir; /* p->ydirection */ + + /* resource lists. + */ + pdf_reslist rl_colorspaces; + pdf_reslist rl_extgstates; + pdf_reslist rl_fonts; + pdf_reslist rl_layers; + pdf_reslist rl_patterns; + pdf_reslist rl_shadings; + pdf_reslist rl_xobjects; +} pdf_page; + + +/* PDF page object. +*/ +typedef struct +{ + pg_label label; + pdc_id id; /* object id for this page */ + pdf_page * pg; /* NULL if this page is not suspended */ + + /* object ids (PDC_BAD_ID if not present). + */ + pdc_id annots_id; /* id of page's /Annots entry */ + pdc_id contents_id; /* id of page's /Contents entry */ + pdc_id res_id; /* id of page's /Resources entry */ + pdc_id thumb_id; /* id of page's /Thumb entry */ + + int rotate; /* page's /Rotate entry */ + int transition; /* page transition type, or -1 */ + int taborder; /* page taborder type */ + double duration; /* page display duration, or -1 */ + pdc_scalar userunit; /* page user unit */ + char * action; /* "action" option string */ + + pg_transgroup tgroup; /* transparency group definition */ + + + pdc_id * act_idlist; /* action object ids */ + pdc_rectangle * boxes[PDF_N_PAGE_BOXES]; /* MediaBox etc. */ +} page_obj; + + +struct pdf_pages_s +{ + pdf_page *curr_pg; + pdc_bool have_labels; + pdc_bool have_groups; + pdc_bool in_csect; /* currently in contents section */ + int last_suspended; /* 1-based page number or -1 */ + pdf_ppt default_ppt; /* pseudo-ppt (for document scope) */ + + /* as long as we support the old global parameters in addition to + ** the new options, we have to save their values on entry to + ** begin/resume_page(), and restore them during end/suspend_page(). + */ + pdc_scalar old_ydir; /* p->ydirection */ + + /* deprecated parameters. + */ + int transition; /* page transition type */ + double duration; /* page display duration */ + + /* page descriptors in physical page order. + */ + page_obj * pages; /* page ids and suspended page descr */ + int pages_capacity; + int current_page; /* current page number (1-based) */ + int last_page; /* last page number allocated yet */ + int max_page; /* highest page number pre-allocated yet */ + + /* page groups. + */ + pg_group * groups; + int groups_capacity; + int n_groups; + + pdc_id *pnodes; /* page tree node ids */ + int pnodes_capacity; /* current # of entries in pnodes */ + int current_pnode; /* current node number (0-based) */ + int current_pnode_kids; /* current # of kids in current node */ +}; + + +static const pdc_rectangle pdf_null_rect = +{ + 0, 0, 0, 0 +}; + + +/*********************** initialization & cleanup ***********************/ + +static void +pdf_init_ppt(PDF *p, pdc_bool new_ppt) +{ + pdf_ppt *ppt = p->curr_ppt; + + if (new_ppt) + { + ppt->cstate = 0; + ppt->tstate = 0; + + ppt->mboxes = (pdc_vtr *) 0; + + ppt->cs_bias = 0; + ppt->eg_bias = 0; + ppt->fn_bias = 0; + ppt->pt_bias = 0; + ppt->sh_bias = 0; + ppt->xo_bias = 0; + } + + ppt->sl = 0; + + pdf_init_tstate(p); + pdf_init_gstate(p); + pdf_init_cstate(p); +} /* pdf_init_ppt */ + +static void +pdf_reset_ppt(pdf_ppt *ppt) +{ + if (ppt->mboxes) + { + pdc_vtr_delete(ppt->mboxes); + ppt->mboxes = (pdc_vtr *) 0; + } +} + +static void +pdf_delete_page(PDF *p, pdf_page *pg) +{ + if (pg != 0) + { + pdf_cleanup_page_cstate(p, &pg->ppt); + pdf_cleanup_page_tstate(p, &pg->ppt); + pdf_reset_ppt(&pg->ppt); + + if (pg->contents_ids) + pdc_free(p->pdc, pg->contents_ids); + + if (pg->annots) + { + pdc_vtr_delete(pg->annots); + pg->annots = (pdc_vtr *) 0; + } + + if (pg->rl_colorspaces.list) + pdc_free(p->pdc, pg->rl_colorspaces.list); + if (pg->rl_extgstates.list) + pdc_free(p->pdc, pg->rl_extgstates.list); + if (pg->rl_fonts.list) + pdc_free(p->pdc, pg->rl_fonts.list); + if (pg->rl_layers.list) + pdc_free(p->pdc, pg->rl_layers.list); + if (pg->rl_patterns.list) + pdc_free(p->pdc, pg->rl_patterns.list); + if (pg->rl_shadings.list) + pdc_free(p->pdc, pg->rl_shadings.list); + if (pg->rl_xobjects.list) + pdc_free(p->pdc, pg->rl_xobjects.list); + + pdc_free(p->pdc, pg); + } +} /* pdf_delete_page */ + + +static void +pdf_init_page_obj(page_obj *po) +{ + int i; + + po->id = PDC_BAD_ID; + po->pg = (pdf_page *) 0; + po->label.start = 0; + po->label.prefix = (char *) 0; + + po->tgroup.colorspace = color_none; + po->tgroup.isolated = pdc_false; + po->tgroup.knockout = pdc_false; + + po->annots_id = PDC_BAD_ID; + po->contents_id = PDC_BAD_ID; + po->res_id = PDC_BAD_ID; + po->thumb_id = PDC_BAD_ID; + po->transition = -1; + po->duration = -1; + po->taborder = (int) tabo_none; + po->userunit = 1.0; + po->action = (char *) 0; + + po->rotate = 0; + + po->act_idlist = (pdc_id *) 0; + for (i = 0; i < PDF_N_PAGE_BOXES; ++i) + po->boxes[i] = (pdc_rectangle *) 0; +} /* pdf_init_page_obj */ + + +static void +pdf_grow_pages(PDF *p) +{ + static const char fn[] = "pdf_grow_pages"; + + pdf_pages *dp = p->doc_pages; + int i; + + dp->pages = (page_obj *) pdc_realloc(p->pdc, dp->pages, + 2 * sizeof (page_obj) * dp->pages_capacity, fn); + + for (i = dp->pages_capacity; i < dp->pages_capacity * 2; i++) + pdf_init_page_obj(&dp->pages[i]); + + dp->pages_capacity *= 2; +} /* pdf_grow_pages */ + + +void +pdf_init_pages(PDF *p, const char **groups, int n_groups) +{ + static const char fn[] = "pdf_init_pages"; + + int i, k; + pdf_pages * dp = (pdf_pages *) pdc_malloc(p->pdc, sizeof (pdf_pages), fn); + + p->doc_pages = dp; + + dp->have_labels = pdc_false; + dp->have_groups = (n_groups != 0); + dp->n_groups = 0; + dp->last_suspended = 0; + dp->in_csect = pdc_false; + dp->transition = (int) trans_none; + dp->duration = 0; + + dp->pages = (page_obj *) 0; + dp->pnodes = (pdc_id *) 0; + + dp->pages_capacity = PAGES_CHUNKSIZE; + dp->pages = (page_obj *) + pdc_malloc(p->pdc, sizeof (page_obj) * dp->pages_capacity, fn); + + /* mark ids to allow for pre-allocation of page ids */ + for (i = 0; i < dp->pages_capacity; i++) + pdf_init_page_obj(&dp->pages[i]); + + dp->current_page = 0; + dp->last_page = 0; + dp->max_page = 0; + dp->curr_pg = (pdf_page *) 0; + + dp->pnodes_capacity = PNODES_CHUNKSIZE; + dp->pnodes = (pdc_id *) + pdc_malloc(p->pdc, sizeof (pdc_id) * dp->pnodes_capacity, fn); + + dp->current_pnode = 0; + dp->current_pnode_kids = 0; + + /* clients may set char/word spacing and horizontal scaling outside pages + ** for PDF_stringwidth() calculations, and they may set a color for use + ** in PDF_makespotcolor(). that's what default_ppt is good for. + */ + p->curr_ppt = &dp->default_ppt; + pdf_init_ppt(p, pdc_true); + + for (i = 0; i < n_groups - 1; ++i) + for (k = i + 1; k < n_groups; ++k) + if (strcmp(groups[i], groups[k]) == 0) + { + pdc_error(p->pdc, PDF_E_DOC_DUPLGROUP, groups[i], 0, 0, 0); + } + + dp->n_groups = n_groups; + dp->groups = (pg_group *) (n_groups ? + pdc_malloc(p->pdc, sizeof (pg_group) * n_groups, fn) : 0); + + for (i = 0; i < n_groups; ++i) + { + dp->groups[i].name = pdc_strdup(p->pdc, groups[i]); + dp->groups[i].n_pages = 0; + dp->groups[i].capacity = 0; + dp->groups[i].start = 1; + dp->groups[i].label.prefix = (char *) 0; + dp->groups[i].label.start = 0; + } +} /* pdf_init_pages */ + + +void pdf_check_suspended_pages(PDF *p) +{ + int i; + pdf_pages * dp = p->doc_pages; + + for (i = 0; i <= dp->last_page; ++i) + { + if (dp->pages[i].pg != (pdf_page *) 0) + { + pdc_error(p->pdc, PDF_E_PAGE_SUSPENDED, + pdc_errprintf(p->pdc, "%d", i), 0, 0, 0); + } + } +} /* pdf_check_suspended_pages */ + + +void +pdf_cleanup_pages(PDF *p) +{ + if (p->doc_pages != (pdf_pages *) 0) + { + int i; + pdf_pages * dp = p->doc_pages; + + if (dp->groups) + { + for (i = 0; i < dp->n_groups; ++i) + { + if (dp->groups[i].name) + pdc_free(p->pdc, dp->groups[i].name); + + if (dp->groups[i].label.prefix) + pdc_free(p->pdc, dp->groups[i].label.prefix); + } + + pdc_free(p->pdc, dp->groups); + } + + if (dp->curr_pg) + pdf_delete_page(p, dp->curr_pg); + + if (dp->pages) + { + for (i = 0; i <= dp->last_page; ++i) + { + int k; + page_obj *po = &dp->pages[i]; + + if (po->label.prefix) + pdc_free(p->pdc, po->label.prefix); + + if (po->action) + pdc_free(p->pdc, po->action); + + + if (po->pg != (pdf_page *) 0) + pdf_delete_page(p, po->pg); + + if (po->act_idlist != (pdc_id *) 0) + pdc_free(p->pdc, po->act_idlist); + + for (k = 0; k < PDF_N_PAGE_BOXES; ++k) + { + if (po->boxes[k] != (pdc_rectangle *) 0) + pdc_free(p->pdc, po->boxes[k]); + } + } + + pdc_free(p->pdc, dp->pages); + } + + if (dp->pnodes) + { + pdc_free(p->pdc, dp->pnodes); + } + + if (p->curr_ppt != 0) + { + pdf_cleanup_page_cstate(p, &dp->default_ppt); + pdf_cleanup_page_tstate(p, &dp->default_ppt); + } + + pdc_free(p->pdc, p->doc_pages); + p->doc_pages = (pdf_pages *) 0; + } +} /* pdf_cleanup_pages */ + + +/******************** page group & labels management ********************/ + +static pg_group * +find_group(pdf_pages *dp, const char *name) +{ + int i; + + for (i = 0; i < dp->n_groups; ++i) + if (strcmp(dp->groups[i].name, name) == 0) + return &dp->groups[i]; + + return (pg_group *) 0; +} /* find_group */ + + +static void +grow_group(PDF *p, pg_group *group, int pageno, int n) +{ + pdf_pages * dp = p->doc_pages; + int i; + + while (dp->max_page + n >= dp->pages_capacity) + pdf_grow_pages(p); + + if (dp->max_page >= pageno) + { + memmove(&dp->pages[pageno + n], &dp->pages[pageno], + (dp->max_page - pageno + 1) * sizeof (page_obj)); + + for (i = pageno; i < pageno + n; ++i) + pdf_init_page_obj(&dp->pages[i]); + } + + dp->max_page += n; + + if (dp->last_page >= pageno) + dp->last_page += n; + + if (dp->current_page >= pageno) + dp->current_page += n; + + group->capacity += n; + + for (i = group - dp->groups + 1; i < dp->n_groups; ++i) + dp->groups[i].start += n; +} + + +/* translate the group-relative pageno to an absolute page number. +** as a side effect, the group gets enlarged as needed if pageno +** exceeds the current number of pages in the group. +*/ +int +pdf_xlat_pageno(PDF *p, int pageno, const char *groupname) +{ + pdf_pages * dp = p->doc_pages; + pg_group * group = (pg_group *) 0; + + if (groupname && *groupname) + { + if ((group = find_group(dp, groupname)) == (pg_group *) 0) + pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, groupname, 0, 0, 0); + } + + if (group) + { + if (pageno < 1) + pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST2, + pdc_errprintf(p->pdc, "%d", pageno), group->name, 0, 0); + + if (pageno > group->capacity) + grow_group(p, group, group->start + group->capacity, + pageno - group->capacity); + + pageno = group->start + pageno - 1; + } + else + { + if (dp->have_groups && pageno != 0) + pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP, 0, 0, 0, 0); + } + + return pageno; +} + + +/* TODO (york): get rid of this function. +*/ +void +pdf_init_pages2(PDF *p) +{ + pdf_pages * dp = p->doc_pages; + + dp->pnodes[0] = pdc_alloc_id(p->out); +} /* pdf_init_pages2 */ + + +static const pdc_defopt pdf_pagelabel_options[] = +{ + {"pagenumber", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 1.0, PDC_INT_MAX, NULL}, + + {"group", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 1.0, PDF_MAX_NAMESTRING, NULL}, + + {"style", pdc_keywordlist, PDC_OPT_CASESENS, 1, 1, + 0.0, 0.0, pdf_labelstyle_pdfkeylist}, + + {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"prefix", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 0.0, PDF_MAX_NAMESTRING, NULL}, + + {"start", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 1.0, PDC_INT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +void +pdf_set_pagelabel(PDF *p, const char *optlist, int pageno) +{ + pdf_pages * dp = p->doc_pages; + pg_label * lp; + pdc_resopt *resopts = NULL; + char ** strlist; + int inum; + + int page = 0; + char * groupname = NULL; + pdf_labelstyle style = label_none; + pdc_encoding htenc; + int htcp; + char * prefix = NULL; + int start = 1; + + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_pagelabel_options, + NULL, pdc_true); + + switch (pageno) + { + case PDF_FC_BEGIN_DOCUMENT: + if (pdc_get_optvalues("group", resopts, NULL, &strlist)) + groupname = strlist[0]; + else + pdc_error(p->pdc, PDF_E_DOC_NEED_LABELOPT, "group", 0, 0, 0); + + if (pdc_get_optvalues("pagenumber", resopts, &page, NULL)) + pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, + "pagenumber", 0, 0, 0); + break; + + case PDF_FC_END_DOCUMENT: + if (pdc_get_optvalues("group", resopts, NULL, &strlist)) + pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, "group", 0, 0, 0); + + if (!pdc_get_optvalues("pagenumber", resopts, &page, NULL)) + pdc_error(p->pdc, PDF_E_DOC_NEED_LABELOPT, + "pagenumber", 0, 0, 0); + + break; + + default: + if (pdc_get_optvalues("group", resopts, NULL, &strlist)) + pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, "group", 0, 0, 0); + + if (pdc_get_optvalues("pagenumber", resopts, &page, NULL)) + pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, + "pagenumber", 0, 0, 0); + + page = pageno; + break; + } + + if (pdc_get_optvalues("style", resopts, &inum, NULL)) + style = (pdf_labelstyle) inum; + + htenc = pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true); + + pdf_get_opt_textlist(p, "prefix", resopts, htenc, htcp, + pdc_true, NULL, &prefix, NULL); + pdc_get_optvalues("start", resopts, &start, NULL); + + dp->have_labels = pdc_true; + + if (groupname) + { + pg_group *group; + + if ((group = find_group(dp, groupname)) == (pg_group *) 0) + pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, groupname, 0, 0, 0); + + lp = &group->label; + } + else + { + if (dp->last_page < page) + pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST, + pdc_errprintf(p->pdc, "%d", page), 0, 0, 0); + + lp = &dp->pages[page].label; + } + + lp->style = style; + lp->start = start; + + if (prefix) + { + if (lp->prefix) + pdc_free(p->pdc, lp->prefix); + + lp->prefix = pdc_strdup(p->pdc, prefix); + } +} /* pdf_set_pagelabel */ + + +static void +write_label(PDF *p, pg_label *label, int pageno) +{ + pdc_printf(p->out, "%d", pageno); + pdc_begin_dict(p->out); + + if (label->style != label_none) + { + pdc_printf(p->out, "/S/%s", + pdc_get_keyword(label->style, pdf_labelstyle_pdfkeylist)); + } + + if (label->prefix) + { + pdc_printf(p->out, "/P"); + pdf_put_hypertext(p, label->prefix); + } + + if (label->start != 1) + pdc_printf(p->out, "/St %d", label->start); + + pdc_end_dict(p->out); +} /* write_label */ + + +pdc_id +pdf_write_pagelabels(PDF *p) +{ + pdf_pages * dp = p->doc_pages; + pdc_id result; + int i, k; + + if (!dp->have_labels || dp->last_page == 0) + return PDC_BAD_ID; + + result = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_dict(p->out); + + pdc_printf(p->out, "/Nums"); + pdc_begin_array(p->out); + + /* generate default label if page 1 doesn't have one: + */ + if (dp->pages[1].label.start == 0 && + (dp->n_groups == 0 || dp->groups[0].label.start == 0)) + { + pdc_puts(p->out, "0"); + pdc_begin_dict(p->out); + pdc_puts(p->out, "/S/D"); /* 1-based decimal w/o prefix */ + pdc_end_dict(p->out); + } + + if (dp->n_groups == 0) + { + for (i = 1; i <= dp->last_page; ++i) + if (dp->pages[i].label.start != 0) + write_label(p, &dp->pages[i].label, i - 1); + } + else + { + for (i = 0; i < dp->n_groups; ++i) + { + pg_group *gp = &dp->groups[i]; + + if (gp->label.start != 0 && gp->n_pages != 0) + { + /* if present, the page label beats the group label. + */ + if (dp->pages[gp->start].label.start == 0) + write_label(p, &gp->label, gp->start - 1); + } + + for (k = gp->start; k < gp->start + gp->n_pages; ++k) + if (dp->pages[k].label.start != 0) + write_label(p, &dp->pages[k].label, k - 1); + } + } + + pdc_end_array_c(p->out); + pdc_end_dict(p->out); + pdc_end_obj(p->out); + + return result; +} /* pdf_write_pagelabels */ + +static const pdc_defopt pdf_transgroup_options[] = +{ + {"CS", pdc_keywordlist, PDC_OPT_NONE, 1, 1, + 1.0, PDC_INT_MAX, pdf_colorspace_pdfkeylist}, + + {"I", pdc_booleanlist, PDC_OPT_NONE, 1, 1, + 0.0, 0.0, NULL}, + + {"K", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ + + PDC_OPT_TERMINATE +}; + +static void +pdf_set_transgroup(PDF *p, const char *optlist, int pageno) +{ + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[pageno]; + pdc_resopt *resopts = NULL; + int inum; + + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_transgroup_options, + NULL, pdc_true); + + if (pdc_get_optvalues("CS", resopts, &inum, NULL)) + po->tgroup.colorspace = (pdf_colortype) inum; + + pdc_get_optvalues("I", resopts, &po->tgroup.isolated, NULL); + pdc_get_optvalues("K", resopts, &po->tgroup.knockout, NULL); +} + +static void +write_transgroup(PDF *p, int pageno) +{ + pdf_pages * dp = p->doc_pages; + page_obj *po = &dp->pages[pageno]; + + pdc_puts(p->out, "/Group"); + pdc_begin_dict(p->out); + pdc_printf(p->out, "/S/Transparency/CS/%s", + pdc_get_keyword(po->tgroup.colorspace, + pdf_colorspace_pdfkeylist)); + + if (po->tgroup.isolated) + pdc_printf(p->out, "/I true"); + + if (po->tgroup.knockout) + pdc_printf(p->out, "/K true"); + + pdc_end_dict(p->out); +} + + +/************************** utility functions ***************************/ + +/* get the id of an existing or future page. +** pageno == 0 means current page. note that pdf_get_page_id(0) returns +** PDC_BAD_ID if no page has been opened yet, whereas pdf_current_page_id() +** returns a pre-allocated id for page 1 in this case. +*/ +pdc_id +pdf_get_page_id(PDF *p, int pageno) +{ + pdf_pages *dp = p->doc_pages; + + if (pageno == 0) + { + return dp->pages[dp->current_page].id; + } + else + { + while (pageno >= dp->pages_capacity) + pdf_grow_pages(p); + + /* preallocate page object id for a later page + */ + if (dp->pages[pageno].id == PDC_BAD_ID) + dp->pages[pageno].id = pdc_alloc_id(p->out); + + return dp->pages[pageno].id; + } +} /* pdf_get_page_id */ + +int +pdf_current_page(PDF *p) +{ + pdf_pages *dp = p->doc_pages; + + return dp ? dp->current_page : 0; +} /* pdf_current_page */ + +/* get the id of the current page. if there are no pages in the +** document yet, an id will be pre-allocated for page 1. +*/ +int +pdf_current_page_id(PDF *p) +{ + pdf_pages *dp = p->doc_pages; + + if (dp->current_page != 0) + return dp->pages[dp->current_page].id; + else + return pdf_get_page_id(p, 1); +} /* pdf_current_page_id */ + +int +pdf_last_page(PDF *p) +{ + return p->doc_pages->last_page; +} /* pdf_last_page */ + +int +pdf_search_page_fwd(PDF *p, int start_page, pdc_id id) +{ + pdf_pages * dp = p->doc_pages; + int i; + + for (i = start_page; i <= dp->last_page; ++i) + { + if (dp->pages[i].id == id) + return i; + } + + return -1; +} /* pdf_search_page_fwd */ + +int +pdf_search_page_bwd(PDF *p, int start_page, pdc_id id) +{ + pdf_pages * dp = p->doc_pages; + int i; + + if (start_page == -1) + start_page = dp->last_page; + + for (i = start_page; i > 0; --i) + { + if (dp->pages[i].id == id) + return i; + } + + return -1; +} /* pdf_search_page_bwd */ + + +double +pdf_get_pageheight(PDF *p) +{ + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + return po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly; +} /* pdf_get_pageheight */ + +void +pdf_set_pagebox( + PDF * p, + pdf_pagebox box, + pdc_scalar llx, + pdc_scalar lly, + pdc_scalar urx, + pdc_scalar ury) +{ + static const char fn[] = "pdf_set_pagebox"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box] == (pdc_rectangle *) 0) + { + po->boxes[box] = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + } + + pdc_rect_init(po->boxes[box], llx, lly, urx, ury); +} /* pdf_set_pagebox */ + +void +pdf_set_pagebox_llx(PDF *p, pdf_pagebox box, pdc_scalar llx) +{ + static const char fn[] = "pdf_set_pagebox_llx"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box] == (pdc_rectangle *) 0) + { + po->boxes[box] = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + + pdc_rect_init(po->boxes[box], 0, 0, 0, 0); + } + + po->boxes[box]->llx = llx; +} /* pdf_set_pagebox_llx */ + +void +pdf_set_pagebox_lly(PDF *p, pdf_pagebox box, pdc_scalar lly) +{ + static const char fn[] = "pdf_set_pagebox_lly"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box] == (pdc_rectangle *) 0) + { + po->boxes[box] = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + + pdc_rect_init(po->boxes[box], 0, 0, 0, 0); + } + + po->boxes[box]->lly = lly; +} /* pdf_set_pagebox_lly */ + +void +pdf_set_pagebox_urx(PDF *p, pdf_pagebox box, pdc_scalar urx) +{ + static const char fn[] = "pdf_set_pagebox_urx"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box] == (pdc_rectangle *) 0) + { + po->boxes[box] = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + + pdc_rect_init(po->boxes[box], 0, 0, 0, 0); + } + + po->boxes[box]->urx = urx; +} /* pdf_set_pagebox_urx */ + +void +pdf_set_pagebox_ury(PDF *p, pdf_pagebox box, pdc_scalar ury) +{ + static const char fn[] = "pdf_set_pagebox_ury"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box] == (pdc_rectangle *) 0) + { + po->boxes[box] = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + + pdc_rect_init(po->boxes[box], 0, 0, 0, 0); + } + + po->boxes[box]->ury = ury; +} /* pdf_set_pagebox_ury */ + +const pdc_rectangle * +pdf_get_pagebox(PDF *p, pdf_pagebox box) +{ + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + if (po->boxes[box]) + return po->boxes[box]; + else + return &pdf_null_rect; +} /* pdf_get_pagebox */ + +pdc_vtr * +pdf_get_annots_list(PDF *p) +{ + pdf_pages * dp = p->doc_pages; + + return dp->curr_pg->annots; +} /* pdf_get_annots_list */ + +void +pdf_set_annots_list(PDF *p, pdc_vtr *annots) +{ + pdf_pages * dp = p->doc_pages; + + if (dp->curr_pg) + dp->curr_pg->annots = annots; +} /* pdf_set_annots_list */ + + +pdc_id +pdf_get_thumb_id(PDF *p) +{ + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + return po->thumb_id; +} /* pdf_get_thumb_id */ + +void +pdf_set_thumb_id(PDF *p, pdc_id id) +{ + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + po->thumb_id = id; +} /* pdf_set_thumb_id */ + + +/************************* contents sections ***************************/ + +void +pdf_begin_contents_section(PDF *p) +{ + pdf_page *pg = p->doc_pages->curr_pg; + + if (PDF_GET_STATE(p) != pdf_state_page || p->doc_pages->in_csect) + return; + + p->doc_pages->in_csect = pdc_true; + + if (pg->next_content >= pg->contents_ids_capacity) { + pg->contents_ids_capacity *= 2; + pg->contents_ids = (pdc_id *) pdc_realloc(p->pdc, pg->contents_ids, + sizeof(pdc_id) * pg->contents_ids_capacity, + "pdf_begin_contents_section"); + } + + pg->contents_ids[pg->next_content] = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_dict(p->out); + p->length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", p->length_id); + + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + + pdc_end_dict(p->out); + + pdc_begin_pdfstream(p->out); + + pg->next_content++; +} /* pdf_begin_contents_section */ + + +void +pdf_end_contents_section(PDF *p) +{ + if (!p->doc_pages->in_csect) + return; + + p->doc_pages->in_csect = pdc_false; + + pdf_end_text(p); + pdc_end_pdfstream(p->out); + pdc_end_obj(p->out); + + pdc_put_pdfstreamlength(p->out, p->length_id); +} /* pdf_end_contents_section */ + + +/************************* page tree generation *************************/ + +static void +pdf_write_pnode(PDF *p, + pdc_id node_id, + pdc_id parent_id, + page_obj *kids, + int n_kids, + int n_pages) +{ + pdc_begin_obj(p->out, node_id); + pdc_begin_dict(p->out); + pdc_puts(p->out, "/Type/Pages\n"); + pdc_printf(p->out, "/Count %d\n", n_pages); + + if (parent_id != PDC_BAD_ID) + pdc_objref(p->out, "/Parent", parent_id); + + pdc_puts(p->out, "/Kids"); + pdc_begin_array(p->out); + + do + { + pdc_objref_c(p->out, kids->id); + ++kids; + } while (--n_kids > 0); + + pdc_end_array_c(p->out); + pdc_end_dict(p->out); + pdc_end_obj(p->out); +} /* pdf_write_pnode */ + +#define N_KIDS 10 + +static pdc_id +pdf_get_pnode_id(PDF *p) +{ + static const char fn[] = "pdf_get_pnode_id"; + + pdf_pages *dp = p->doc_pages; + + if (dp->current_pnode_kids == N_KIDS) + { + if (++dp->current_pnode == dp->pnodes_capacity) + { + dp->pnodes_capacity *= 2; + dp->pnodes = (pdc_id *) pdc_realloc(p->pdc, dp->pnodes, + sizeof (pdc_id) * dp->pnodes_capacity, fn); + } + + dp->pnodes[dp->current_pnode] = pdc_alloc_id(p->out); + dp->current_pnode_kids = 1; + } + else + ++dp->current_pnode_kids; + + return dp->pnodes[dp->current_pnode]; +} /* pdf_get_pnode_id */ + +static pdc_id +write_pages_tree(PDF *p, + pdc_id parent_id, + pdc_id *pnodes, + page_obj *pages, + int n_pages) +{ + if (n_pages <= N_KIDS) + { + /* this is a near-to-leaf node. use the pre-allocated id + ** from dp->pnodes. + */ + pdf_write_pnode(p, *pnodes, parent_id, pages, n_pages, n_pages); + return *pnodes; + } + else + { + pdc_id node_id = pdc_alloc_id(p->out); + page_obj kids[N_KIDS]; + int n_kids, rest; + int tpow = N_KIDS; + int i; + + /* tpow < n_pages <= tpow*N_KIDS + */ + while (tpow * N_KIDS < n_pages) + tpow *= N_KIDS; + + n_kids = n_pages / tpow; + rest = n_pages % tpow; + + for (i = 0; i < n_kids; ++i, pnodes += tpow / N_KIDS, pages += tpow) + { + kids[i].id = write_pages_tree(p, node_id, pnodes, pages, tpow); + } + + if (rest) + { + kids[i].id = write_pages_tree(p, node_id, pnodes, pages, rest); + ++n_kids; + } + + pdf_write_pnode(p, node_id, parent_id, kids, n_kids, n_pages); + return node_id; + } +} /* write_pages_tree */ + +static void +pdf_write_box(PDF *p, pdc_rectangle *box, const char *name) +{ + if (!box || pdc_rect_isnull(box)) + return; + + if (box->urx <= box->llx || box->ury <= box->lly) + { + pdc_error(p->pdc, PDF_E_PAGE_BADBOX, name, + pdc_errprintf(p->pdc, "%f %f %f %f", + box->llx, box->lly, box->urx, box->ury), 0, 0); + } + + pdc_printf(p->out, "/%s[%f %f %f %f]\n", + name, box->llx, box->lly, box->urx, box->ury); +} /* pdf_write_box */ + +pdc_id +pdf_write_pages_tree(PDF *p) +{ + int i; + pdf_pages * dp = p->doc_pages; + + for (i = dp->last_page + 1; i < dp->pages_capacity; ++i) + { + if (dp->pages[i].id != PDC_BAD_ID) + { + pdc_error(p->pdc, PDF_E_PAGE_ILLREF, + pdc_errprintf(p->pdc, "%d", i), 0, 0, 0); + } + } + + for (i = 1; i <= dp->last_page; ++i) + { + page_obj *po = &dp->pages[i]; + + pdc_begin_obj(p->out, po->id); + pdc_begin_dict(p->out); + pdc_puts(p->out, "/Type/Page\n"); + pdc_objref(p->out, "/Parent", pdf_get_pnode_id(p)); + + if (po->annots_id != PDC_BAD_ID) + pdc_objref(p->out, "/Annots", po->annots_id); + + if (po->contents_id != PDC_BAD_ID) + pdc_objref(p->out, "/Contents", po->contents_id); + + if (po->res_id != PDC_BAD_ID) + pdc_objref(p->out, "/Resources", po->res_id); + + if (po->thumb_id != PDC_BAD_ID) + pdc_objref(p->out, "/Thumb", po->thumb_id); + + if (po->duration > 0) + pdc_printf(p->out, "/Dur %f\n", po->duration); + + if (po->taborder != (int) tabo_none) + pdc_printf(p->out, "/Tabs/%s\n", + pdc_get_keyword(po->taborder, pdf_taborder_pdfkeylist)); + + if (po->userunit > 1.0) + pdc_printf(p->out, "/UserUnit %f\n", po->userunit); + + if (po->rotate > 0) + pdc_printf(p->out, "/Rotate %d\n", po->rotate); + + if (po->action) + pdf_write_action_entries(p, event_page, po->act_idlist); + + + + + if (po->transition != trans_none) + { + pdc_puts(p->out, "/Trans"); + pdc_begin_dict(p->out); + pdc_printf(p->out, "/S/%s", + pdc_get_keyword(po->transition, pdf_transition_pdfkeylist)); + + pdc_end_dict(p->out); + } + + if (po->tgroup.colorspace != color_none) + write_transgroup(p, i); + + pdf_write_box(p, po->boxes[pdf_artbox], "ArtBox"); + pdf_write_box(p, po->boxes[pdf_bleedbox], "BleedBox"); + pdf_write_box(p, po->boxes[pdf_cropbox], "CropBox"); + pdf_write_box(p, po->boxes[pdf_mediabox], "MediaBox"); + pdf_write_box(p, po->boxes[pdf_trimbox], "TrimBox"); + + pdc_end_dict(p->out); + pdc_end_obj(p->out); + } + + return write_pages_tree(p, PDC_BAD_ID, dp->pnodes, dp->pages + 1, + dp->last_page); +} /* pdf_write_pages_tree */ + + +/**************************** resource lists ****************************/ + +static void +pdf_init_reslist(pdf_reslist *rl) +{ + rl->length = 0; + rl->capacity = 0; + rl->list = (int *) 0; +} /* pdf_init_reslist */ + +void +pdf_add_reslist(PDF *p, pdf_reslist *rl, int num) +{ + static const char fn[] = "pdf_add_reslist"; + + if (rl->length == rl->capacity) + { + if (rl->capacity == 0) + { + rl->capacity = RESLIST_CHUNKSIZE; + rl->list = (int *) + pdc_malloc(p->pdc, rl->capacity * sizeof (pdf_reslist), fn); + } + else + { + rl->capacity *= 2; + rl->list = (int *) pdc_realloc(p->pdc, + rl->list, rl->capacity * sizeof (pdf_reslist), fn); + } + } + + rl->list[rl->length++] = num; +} /* pdf_add_reslist */ + + +/****************************** begin_page ******************************/ + +/* begin_page_ext() only: +*/ +#define PDF_ICC_FLAG PDC_OPT_UNSUPP +#define PDF_SPOT_FLAG PDC_OPT_UNSUPP + +#define PDF_METADATA_FLAG PDC_OPT_UNSUPP + +static const pdc_defopt pdf_sepinfo_options[] = +{ + {"pages", pdc_integerlist, PDC_OPT_NONE, 1, 1, + 1.0, PDC_INT_MAX, NULL}, + + {"spotname", pdc_stringlist, PDC_OPT_NONE, 1, 1, + 1.0, PDF_MAX_NAMESTRING, NULL}, + + {"spotcolor", pdc_colorhandle, PDC_OPT_NONE, 1, 1, + 1.0, PDC_INT_MAX, NULL}, + + PDC_OPT_TERMINATE +}; + +#define PDF_PAGE_OPTIONS1 \ +\ + {"topdown", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, NULL}, \ +\ + {"defaultgray", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"defaultrgb", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"defaultcmyk", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"separationinfo", pdc_stringlist, PDF_SPOT_FLAG, 1, 1, \ + 0.0, PDC_USHRT_MAX, NULL}, \ + +/* begin_page_ext() and resume_page(): +*/ +#define PDF_PAGE_OPTIONS2 \ +\ + {"group", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 1.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"pagenumber", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + 1.0, PDC_INT_MAX, NULL}, \ + +/* begin_page_ext() and end_page_ext(): +*/ +static const pdc_keyconn pdf_pagedim_keylist[] = +{ + { "a0.width", (int) a0_width }, + { "a0.height", (int) a0_height }, + { "a1.width", (int) a1_width }, + { "a1.height", (int) a1_height }, + { "a2.width", (int) a2_width }, + { "a2.height", (int) a2_height }, + { "a3.width", (int) a3_width }, + { "a3.height", (int) a3_height }, + { "a4.width", (int) a4_width }, + { "a4.height", (int) a4_height }, + { "a5.width", (int) a5_width }, + { "a5.height", (int) a5_height }, + { "a6.width", (int) a6_width }, + { "a6.height", (int) a6_height }, + { "b5.width", (int) b5_width }, + { "b5.height", (int) b5_height }, + { "letter.width", (int) letter_width }, + { "letter.height", (int) letter_height }, + { "legal.width", (int) legal_width }, + { "legal.height", (int) legal_height }, + { "ledger.width", (int) ledger_width }, + { "ledger.height", (int) ledger_height }, + { "11x17.width", (int) p11x17_width }, + { "11x17.height", (int) p11x17_height }, + { NULL, 0 } +}; + +typedef enum +{ + pdf_unit_mm = -1000, + pdf_unit_cm = -100, + pdf_unit_m = -1 +} +pdf_page_unit; + +static const pdc_keyconn pdf_userunit_keylist[] = +{ + { "mm", pdf_unit_mm }, + { "cm", pdf_unit_cm }, + { "m", pdf_unit_m }, + + { NULL, 0 } +}; + + +#define PDF_PAGE_OPTIONS3 \ +\ + {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 1.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"artbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\ +\ + {"bleedbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\ +\ + {"cropbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\ +\ + {"duration", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\ + 0.0, PDC_FLOAT_MAX, NULL},\ +\ + {"height", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\ + 0.0, PDC_FLOAT_MAX, pdf_pagedim_keylist},\ +\ + {"label", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 0.0, PDC_USHRT_MAX, NULL}, \ +\ + {"mediabox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\ +\ + {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \ + 0.0, PDC_INT_MAX, NULL}, \ +\ + {"rotate", pdc_integerlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 270, NULL}, \ +\ + {"transition", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \ + 0.0, 0.0, pdf_transition_keylist}, \ +\ + {"transparencygroup", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ + 1.0, PDF_MAX_NAMESTRING, NULL}, \ +\ + {"taborder", pdc_keywordlist, PDC_OPT_PDC_1_5, 1, 1, \ + 0.0, 0.0, pdf_taborder_keylist}, \ +\ + {"trimbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\ + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\ +\ + {"userunit", pdc_scalarlist, PDC_OPT_PDC_1_6, 1, 1,\ + 1.0, 75000, pdf_userunit_keylist},\ +\ + {"width", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\ + 0.0, PDC_FLOAT_MAX, pdf_pagedim_keylist},\ + +/* common helper function for pdf__begin_page_ext() and pdf__resume_page(). +** returns the target group (if any) and the target page number. the +** page number is relative to the group (if available). page number -1 +** means "no page number". +*/ +static pg_group * +get_page_options2(PDF *p, pdc_resopt *resopts, int *pageno) +{ + pdf_pages * dp = p->doc_pages; + pg_group * group = (pg_group *) 0; + char ** strlist; + + *pageno = -1; + + if (pdc_get_optvalues("pagenumber", resopts, pageno, NULL)) + { + if (*pageno <= 0) + pdc_error(p->pdc, PDF_E_PAGE_ILLNUMBER, + pdc_errprintf(p->pdc, "%d", *pageno), 0, 0, 0); + } + + if (pdc_get_optvalues("group", resopts, NULL, &strlist)) + { + if ((group = find_group(dp, strlist[0])) == (pg_group *) 0) + pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, strlist[0], 0, 0, 0); + } + + if (group) + { + if (*pageno > group->n_pages) + pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST2, + pdc_errprintf(p->pdc, "%d", *pageno), group->name, 0, 0); + } + else + { + if (dp->have_groups) + pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP, 0, 0, 0, 0); + + if (*pageno > dp->last_page) + pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST, + pdc_errprintf(p->pdc, "%d", *pageno), 0, 0, 0); + } + + return group; +} /* get_page_options2 */ + +static pdc_rectangle * +pdf_new_box(PDF *p, const pdc_rectangle *box) +{ + static const char fn[] = "pdf_new_box"; + + pdc_rectangle *result = (pdc_rectangle *) + pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn); + + if (box) + *result = *box; + else + pdc_rect_init(result, 0, 0, 0, 0); + return result; +} /* pdf_new_box */ + +/* common helper function for pdf__begin_page_ext() and pdf__end_page_ext(). +*/ +static void +get_page_options3(PDF *p, pdc_resopt *resopts, pdc_bool end_page) +{ + pdf_pages * dp = p->doc_pages; + int pageno = dp->current_page; + page_obj * po = &dp->pages[pageno]; + pdc_scalar width; + pdc_scalar height; + pdc_bool has_width; + pdc_bool has_height; + pdc_bool has_mediabox; + pdc_rectangle box; + char **slist; + + if (pdc_get_optvalues("action", resopts, NULL, NULL)) + { + po->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + pdf_parse_and_write_actionlist(p, event_page, NULL, + (char *) po->action); + } + + if (pdc_get_optvalues("artbox", resopts, &box, NULL)) + po->boxes[pdf_artbox] = pdf_new_box(p, &box); + if (pdc_get_optvalues("bleedbox", resopts, &box, NULL)) + po->boxes[pdf_bleedbox] = pdf_new_box(p, &box); + if (pdc_get_optvalues("cropbox", resopts, &box, NULL)) + po->boxes[pdf_cropbox] = pdf_new_box(p, &box); + if (pdc_get_optvalues("trimbox", resopts, &box, NULL)) + po->boxes[pdf_trimbox] = pdf_new_box(p, &box); + + pdc_get_optvalues("taborder", resopts, &po->taborder, NULL); + pdc_get_optvalues("duration", resopts, &po->duration, NULL); + pdc_get_optvalues("userunit", resopts, &po->userunit, NULL); + if (po->userunit < 1.0) + po->userunit = 72.0 / (PDC_INCH2METER * fabs(po->userunit)); + + if (pdc_get_optvalues("label", resopts, NULL, NULL)) + { + char *pagelabel = pdf_get_opt_utf8name(p, "label", resopts); + pdf_set_pagelabel(p, pagelabel, pageno); + pdc_free(p->pdc, pagelabel); + } + + if (pdc_get_optvalues("transparencygroup", resopts, NULL, &slist)) + pdf_set_transgroup(p, slist[0], pageno); + + /* the "width" and "height" options must be processed BEFORE the + ** "mediabox" option, since the latter dominates over the formers. + */ + has_width = pdc_get_optvalues("width", resopts, &width, NULL); + has_height = pdc_get_optvalues("height", resopts, &height, NULL); + + if (has_width) + po->boxes[pdf_mediabox]->urx = po->boxes[pdf_mediabox]->llx + width; + + if (has_height) + po->boxes[pdf_mediabox]->ury = po->boxes[pdf_mediabox]->lly + height; + + has_mediabox = + pdc_get_optvalues("mediabox", resopts, po->boxes[pdf_mediabox], NULL); + + width = po->boxes[pdf_mediabox]->urx - po->boxes[pdf_mediabox]->llx; + height = po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly; + + if (p->ydirection == -1) + { + if (end_page) + { + if (has_mediabox || has_width || has_height) + pdc_error(p->pdc, PDF_E_PAGE_ILLCHGSIZE, 0, 0, 0, 0); + } + else + { + if (width == 0 || height == 0) + pdc_error(p->pdc, PDF_E_PAGE_TOPDOWN_NODIMS, 0, 0, 0, 0); + + if ((height < PDF_ACRO_MINPAGE || width < PDF_ACRO_MINPAGE || + height > PDF_ACRO_MAXPAGE || width > PDF_ACRO_MAXPAGE)) + pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0); + } + } + + + pdc_get_optvalues("rotate", resopts, &po->rotate, NULL); + switch (po->rotate) + { + case 0: case 90: case 180: case 270: + break; + + default: + pdc_error(p->pdc, PDF_E_PAGE_ILLROTATE, + pdc_errprintf(p->pdc, "%d", po->rotate), 0, 0, 0); + } + + pdc_get_optvalues("transition", resopts, &po->transition, NULL); + if (po->transition >= (int) TRANS_1_5 && p->compatibility < PDC_1_5) + pdc_error(p->pdc, PDF_E_PAGE_TRANS_COMPAT, + pdc_get_keyword(po->transition, pdf_transition_keylist), 0, 0, 0); +} /* get_page_options3 */ + + + +static const pdc_defopt pdf_begin_page_ext_options[] = +{ + PDF_PAGE_OPTIONS1 + PDF_PAGE_OPTIONS2 + PDF_PAGE_OPTIONS3 + + PDC_OPT_TERMINATE +}; + + +void +pdf__begin_page_ext( + PDF * p, + pdc_scalar width, + pdc_scalar height, + const char *optlist) +{ + static const char fn[] = "pdf__begin_page_ext"; + + pdf_pages * dp = p->doc_pages; + pdf_page * pg; + page_obj * po; + + + pdc_resopt *resopts = NULL; + pg_group * group = (pg_group *) 0; + int pageno = -1; + + pdc_check_number_limits(p->pdc, "width", width, 0.0, PDC_FLOAT_MAX); + pdc_check_number_limits(p->pdc, "height", height, 0.0, PDC_FLOAT_MAX); + + if (optlist && *optlist) + { + pdc_clientdata cdata; + + pdf_set_clientdata(p, &cdata); + resopts = pdc_parse_optionlist(p->pdc, + optlist, pdf_begin_page_ext_options, &cdata, pdc_true); + + group = get_page_options2(p, resopts, &pageno); + } + + if (group) + { + if (pageno == -1) + pageno = group->start + group->n_pages; + else + pageno = group->start + pageno - 1; + + if (++group->n_pages > group->capacity) + { + grow_group(p, group, pageno, 1); + } + else if (pageno < group->start + group->n_pages - 1) + { + memmove(&dp->pages[pageno + 1], &dp->pages[pageno], + (group->start + group->n_pages - pageno) * sizeof (page_obj)); + + pdf_init_page_obj(&dp->pages[pageno]); + } + + if (dp->last_page < group->start + group->n_pages - 1) + dp->last_page = group->start + group->n_pages - 1; + } + else + { + if (dp->last_page + 1 >= dp->pages_capacity) + pdf_grow_pages(p); + + ++dp->last_page; + + if (dp->last_page > dp->max_page) + ++dp->max_page; + + if (pageno == -1) + pageno = dp->last_page; + + if (pageno != dp->last_page) + { + memmove(&dp->pages[pageno + 1], &dp->pages[pageno], + (dp->max_page - pageno) * sizeof (page_obj)); + + pdf_init_page_obj(&dp->pages[pageno]); + } + } + + po = &dp->pages[pageno]; + dp->current_page = pageno; + + /* no id has been preallocated */ + if (po->id == PDC_BAD_ID) + po->id = pdc_alloc_id(p->out); + + pg = dp->curr_pg = (pdf_page *) pdc_malloc(p->pdc, sizeof (pdf_page), fn); + p->curr_ppt = &pg->ppt; + + pg->contents_ids = (pdc_id *) 0; + pg->annots = (pdc_vtr *) 0; + + /* save and take over global parameters. + */ + pg->ydir = dp->old_ydir = p->ydirection; + + pg->rl_colorspaces.list = (int *) 0; + pg->rl_extgstates.list = (int *) 0; + pg->rl_fonts.list = (int *) 0; + pg->rl_layers.list = (int *) 0; + pg->rl_patterns.list = (int *) 0; + pg->rl_shadings.list = (int *) 0; + pg->rl_xobjects.list = (int *) 0; + + pg->contents_ids_capacity = CONTENTS_CHUNKSIZE; + pg->contents_ids = (pdc_id *) pdc_malloc(p->pdc, + sizeof(pdc_id) * pg->contents_ids_capacity, fn); + + /* might be overwritten by options */ + po->boxes[pdf_mediabox] = pdf_new_box(p, 0); + pdc_rect_init(po->boxes[pdf_mediabox], 0, 0, width, height); + + if (resopts) + { + pdc_bool topdown = pdc_false; + + if (pdc_get_optvalues("topdown", resopts, &topdown, NULL)) + p->ydirection = pg->ydir = topdown ? -1 : 1; + + + get_page_options3(p, resopts, pdc_false); + } + + /* initialize the current ppt descriptor. p->ydirection + ** must be set before pdf_init_ppt()! + */ + pdf_init_ppt(p, pdc_true); + + pg->next_content = 0; + + pdf_init_reslist(&pg->rl_colorspaces); + pdf_init_reslist(&pg->rl_extgstates); + pdf_init_reslist(&pg->rl_fonts); + pdf_init_reslist(&pg->rl_layers); + pdf_init_reslist(&pg->rl_patterns); + pdf_init_reslist(&pg->rl_shadings); + pdf_init_reslist(&pg->rl_xobjects); + + PDF_SET_STATE(p, pdf_state_page); + + pdf_begin_contents_section(p); + + /* top-down y coordinates */ + pdf_set_topdownsystem(p, pdf_get_pageheight(p)); + + /* set color differing from PDF default */ + pdf_set_default_color(p, pdc_false); + + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin page #%d]\n", + dp->current_page); + +} /* pdf__begin_page_ext */ + + +void +pdf__begin_page( + PDF * p, + pdc_scalar width, + pdc_scalar height) +{ + if (p->doc_pages->have_groups) + pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP2, 0, 0, 0, 0); + + pdf__begin_page_ext(p, width, height, 0); +} /* pdf__begin_page */ + + +/*************************** suspend & resume ***************************/ + +void +pdf_pg_suspend(PDF *p) +{ + pdf_pages *dp = p->doc_pages; + + if (PDF_GET_STATE(p) != pdf_state_page) + { + dp->last_suspended = -1; + } + else + { + pdf_page *pg = dp->curr_pg; + + pdf_end_contents_section(p); + + /* restore global parms. + */ + p->ydirection = dp->old_ydir; + + pdf_get_page_colorspaces(p, &pg->rl_colorspaces); + pdf_get_page_extgstates(p, &pg->rl_extgstates); + pdf_get_page_fonts(p, &pg->rl_fonts); + pdf_get_page_patterns(p, &pg->rl_patterns); + pdf_get_page_shadings(p, &pg->rl_shadings); + pdf_get_page_xobjects(p, &pg->rl_xobjects); + + dp->pages[dp->current_page].pg = pg; + dp->curr_pg = (pdf_page *) 0; + dp->last_suspended = dp->current_page; + + /* restore the default ppt for out-of-page usage. + */ + p->curr_ppt = &dp->default_ppt; + } + + pdf_init_ppt(p, pdc_false); +} /* pdf_pg_suspend */ + + +static const pdc_defopt pdf_suspend_page_options[] = +{ + PDC_OPT_TERMINATE +}; + +void +pdf__suspend_page(PDF *p, const char *optlist) +{ + if (optlist && *optlist) + { + pdc_resopt *resopts = pdc_parse_optionlist(p->pdc, + optlist, pdf_suspend_page_options, NULL, pdc_true); + + (void) resopts; + } + + pdf_pg_suspend(p); + PDF_SET_STATE(p, pdf_state_document); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Suspend page #%d]\n", + p->doc_pages->current_page); +} /* pdf__suspend_page */ + + +void +pdf_pg_resume(PDF *p, int pageno) +{ + pdf_pages *dp = p->doc_pages; + + pdf_reset_ppt(p->curr_ppt); + + if (pageno == -1) + { + pageno = dp->last_suspended; + dp->last_suspended = -1; + } + + if (pageno == -1) + { + PDF_SET_STATE(p, pdf_state_document); + } + else + { + pdf_page *pg; + int i; + + /* prevent error cleanup from killing the same page twice. + */ + pg = dp->curr_pg = dp->pages[pageno].pg; + dp->pages[pageno].pg = (pdf_page *) 0; + + dp->current_page = pageno; + p->curr_ppt = &pg->ppt; + + PDF_SET_STATE(p, pdf_state_page); + + /* save global parameters and replace them + ** with the page specific ones. + */ + dp->old_ydir = p->ydirection; + + p->ydirection = pg->ydir; + + pdf_begin_contents_section(p); + + /* mark global resources as "used on current page". + */ + for (i = 0; i < pg->rl_colorspaces.length; ++i) + pdf_mark_page_colorspace(p, pg->rl_colorspaces.list[i]); + + for (i = 0; i < pg->rl_extgstates.length; ++i) + pdf_mark_page_extgstate(p, pg->rl_extgstates.list[i]); + + for (i = 0; i < pg->rl_fonts.length; ++i) + pdf_mark_page_font(p, pg->rl_fonts.list[i]); + + + for (i = 0; i < pg->rl_patterns.length; ++i) + pdf_mark_page_pattern(p, pg->rl_patterns.list[i]); + + for (i = 0; i < pg->rl_shadings.length; ++i) + pdf_mark_page_shading(p, pg->rl_shadings.list[i]); + + for (i = 0; i < pg->rl_xobjects.length; ++i) + pdf_mark_page_xobject(p, pg->rl_xobjects.list[i]); + } +} /* pdf_pg_resume */ + + +static const pdc_defopt pdf_resume_page_options[] = +{ + PDF_PAGE_OPTIONS2 + + PDC_OPT_TERMINATE +}; + +void +pdf__resume_page(PDF *p, const char *optlist) +{ + pdf_pages * dp = p->doc_pages; + pg_group * group = (pg_group *) 0; + int pageno = -1; /* logical page number */ + int physno; /* physical page number */ + + if (optlist && *optlist) + { + pdc_resopt *resopts = pdc_parse_optionlist(p->pdc, + optlist, pdf_resume_page_options, NULL, pdc_true); + + group = get_page_options2(p, resopts, &pageno); + } + + if (group) + { + if (pageno == -1) + pageno = group->n_pages; + + physno = group->start + pageno - 1; + } + else + { + if (pageno == -1) + pageno = dp->last_page; + + physno = pageno; + } + + if (dp->pages[physno].pg == (pdf_page *) 0) + { + if (group) + { + pdc_error(p->pdc, PDF_E_PAGE_NOSUSPEND2, + pdc_errprintf(p->pdc, "%d", pageno), group->name, 0, 0); + } + else + { + pdc_error(p->pdc, PDF_E_PAGE_NOSUSPEND, + pdc_errprintf(p->pdc, "%d", pageno), 0, 0, 0); + } + } + + pdf_pg_resume(p, physno); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Resume page #%d]\n", physno); + +} /* pdf__resume_page */ + + +/******************************* end_page *******************************/ + + +static const pdc_defopt pdf_end_page_ext_options[] = +{ + PDF_PAGE_OPTIONS3 + + PDC_OPT_TERMINATE +}; + +void +pdf__end_page_ext(PDF *p, const char *optlist) +{ + static const char fn[] = "pdf__end_page_ext"; + + pdf_pages * dp = p->doc_pages; + page_obj * po = &dp->pages[dp->current_page]; + + pdc_scalar width; + pdc_scalar height; + pdf_page * pg; + pdf_ppt * ppt = p->curr_ppt; + int i; + + + if (optlist && *optlist) + { + pdc_resopt *resopts = pdc_parse_optionlist(p->pdc, + optlist, pdf_end_page_ext_options, NULL, pdc_true); + + get_page_options3(p, resopts, pdc_true); + } + + width = po->boxes[pdf_mediabox]->urx - po->boxes[pdf_mediabox]->llx; + height = po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly; + + if (width == 0 || height == 0) + pdc_error(p->pdc, PDF_E_PAGE_NODIMS, 0, 0, 0, 0); + + if ((height < PDF_ACRO_MINPAGE || width < PDF_ACRO_MINPAGE || + height > PDF_ACRO_MAXPAGE || width > PDF_ACRO_MAXPAGE)) + pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0); + + + + + /* check whether PDF_save() and PDF_restore() calls are balanced */ + if (ppt->sl > 0) + pdc_error(p->pdc, PDF_E_GSTATE_UNMATCHEDSAVE, 0, 0, 0, 0); + + /* TODO (york): avoid memory leak in error case. */ + pg = dp->curr_pg; + + + pdf_end_contents_section(p); + + + /* if no "duration" or "transition" options have been specified + ** for this page, fall back on the (deprecated) global parameters. + */ + if (po->duration == -1) + po->duration = dp->duration; + + if (po->transition == -1) + po->transition = dp->transition; + + if (pg->next_content > 0) + { + if (pg->next_content == 1) + { + po->contents_id = pg->contents_ids[0]; + } + else + { + po->contents_id = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_array(p->out); + + for (i = 0; i < pg->next_content; ++i) + { + pdc_objref_c(p->out, pg->contents_ids[i]); + } + + pdc_end_array(p->out); + pdc_end_obj(p->out); + } + } + + if (po->action) + { + po->act_idlist = (pdc_id *) + pdc_malloc(p->pdc, PDF_MAX_EVENTS * sizeof (pdc_id), fn); + + pdf_parse_and_write_actionlist(p, event_page, po->act_idlist, + po->action); + } + + po->annots_id = pdf_write_annots_root(p, pg->annots, NULL); + + /* resources dictionary + */ + po->res_id = pdc_begin_obj(p->out, PDC_NEW_ID); + + pdc_begin_dict(p->out); + + pdf_write_page_fonts(p); /* Font resources */ + + pdf_write_page_colorspaces(p); /* ColorSpace resources */ + + pdf_write_page_pattern(p); /* Pattern resources */ + + pdf_write_page_shadings(p); /* Shading resources */ + + pdf_write_xobjects(p); /* XObject resources */ + + pdf_write_page_extgstates(p); /* ExtGState resources */ + + + pdc_end_dict(p->out); + pdc_end_obj(p->out); + + if (pg->annots != (pdc_vtr *) 0) + pdf_write_page_annots(p, pg->annots); /* Annotation dicts */ + + + /* restore global parms. + */ + p->ydirection = dp->old_ydir; + + /* restore the default ppt for out-of-page usage. + */ + p->curr_ppt = &dp->default_ppt; + pdf_init_ppt(p, pdc_false); + PDF_SET_STATE(p, pdf_state_document); + pdf_delete_page(p, pg); + dp->curr_pg = (pdf_page *) 0; + + if (p->flush & (pdc_flush_page | pdc_flush_content)) + pdc_flush_stream(p->out); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End page #%d]\n", + dp->current_page); + +} /* pdf__end_page_ext */ + + +/*****************************************************************************/ +/** deprecated historical page functions **/ +/*****************************************************************************/ + +/* set page display duration for current and future pages */ + +void +pdf_set_duration(PDF *p, double t) +{ + p->doc_pages->duration = t; +} + +/* set transition mode for current and future pages */ + +void +pdf_set_transition(PDF *p, const char *transition) +{ + int i; + + if (transition == NULL || !*transition) + transition = "none"; + + i = pdc_get_keycode_ci(transition, pdf_transition_keylist); + + if (i == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, transition, "transition", 0, 0); + + if (i >= (int) TRANS_1_5 && p->compatibility < PDC_1_5) + pdc_error(p->pdc, PDF_E_PAGE_TRANS_COMPAT, + pdc_get_keyword(i, pdf_transition_keylist), 0, 0, 0); + + p->doc_pages->transition = i; +} + diff --git a/src/pdflib/pdflib/p_page.h b/src/pdflib/pdflib/p_page.h new file mode 100644 index 0000000..3f496e4 --- /dev/null +++ b/src/pdflib/pdflib/p_page.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_page.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Header file for the PDFlib page system + * + */ + +#ifndef P_PAGE_H +#define P_PAGE_H + +/* the "pageno" parameter for function pdf_set_pagelabel() can take +** negative values, indicating the calling function. +*/ +#define PDF_FC_BEGIN_DOCUMENT -1 +#define PDF_FC_END_DOCUMENT -2 +void pdf_set_pagelabel(PDF *p, const char *optlist, int pageno); + +pdc_id pdf_write_pages_tree(PDF *p); + +void pdf_set_transition(PDF *p, const char *type); +void pdf_set_duration(PDF *p, double t); + +#endif /* P_PAGE_H */ diff --git a/src/pdflib/pdflib/p_pantlab.h b/src/pdflib/pdflib/p_pantlab.h new file mode 100644 index 0000000..79c35cc --- /dev/null +++ b/src/pdflib/pdflib/p_pantlab.h @@ -0,0 +1,28 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_pantlab.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib PANTONE spot LAB color table derived from + * PANTONE MATCHING SYSTEM + * + * PANTONE and PANTONE MATCHING SYSTEM is a registered trademark of + * Pantone,Inc. + * + */ + +#ifndef P_PANTLAB_H +#define P_PANTLAB_H + + +#endif /* P_PANTAB_H */ + diff --git a/src/pdflib/pdflib/p_params.c b/src/pdflib/pdflib/p_params.c new file mode 100644 index 0000000..e55a8b1 --- /dev/null +++ b/src/pdflib/pdflib/p_params.c @@ -0,0 +1,1306 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_params.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib parameter handling + * + */ + +#define P_PARAMS_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_image.h" +#include "p_page.h" +#include "p_tagged.h" + +static const pdc_keyconn pdf_fillrule_keylist[] = +{ + {"winding", pdf_fill_winding }, + {"evenodd", pdf_fill_evenodd }, + {NULL, 0} +}; + +/* + * PDF_get_parameter() and PDF_set_parameter() deal with strings, + * PDF_get_value() and PDF_set_value() deal with numerical values. + */ + +typedef struct +{ + char * name; /* parameter name */ + pdc_bool mod_zero; /* PDF_get_() modifier argument must be 0 */ + pdc_bool check_scope; /* check following scope for PDF_get_...() */ + int scope; /* bit mask of legal states */ + +} +pdf_parm_descr; + +static pdf_parm_descr parms[] = +{ +#define pdf_gen_parm_descr 1 +#include "p_params.h" +#undef pdf_gen_parm_descr + + { "", 0, 0, 0 } +}; + +enum +{ +#define pdf_gen_parm_enum 1 +#include "p_params.h" +#undef pdf_gen_parm_enum + + PDF_PARAMETER_LIMIT +}; + +static int +pdf_get_index(PDF *p, const char *key, pdc_bool setpar) +{ + int i; + + if (key == NULL || !*key) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "key", 0, 0, 0); + + for (i = 0; i < PDF_PARAMETER_LIMIT; ++i) + { + if (pdc_stricmp(key, parms[i].name) == 0) + { + if ((setpar || parms[i].check_scope) && + (p->state_stack[p->state_sp] & parms[i].scope) == 0) + pdc_error(p->pdc, PDF_E_DOC_SCOPE_SET, key, + pdf_current_scope(p), 0, 0); + return i; + } + } + + if (i == PDF_PARAMETER_LIMIT) + pdc_error(p->pdc, PDC_E_PAR_UNKNOWNKEY, key, 0, 0, 0); + + return -1; +} + +static pdc_bool +pdf_bool_value(PDF *p, const char *key, const char *value) +{ + if (!pdc_stricmp(value, "true")) + return pdc_true; + + if (!pdc_stricmp(value, "false")) + return pdc_false; + + pdc_error(p->pdc, PDC_E_ILLARG_BOOL, key, value, 0, 0); + + return pdc_false; /* compilers love it */ +} + +void +pdf__set_parameter(PDF *p, const char *key, const char *value) +{ + pdc_pagebox usebox = pdc_pbox_none; + pdc_text_format textformat = pdc_auto; + char optlist[512]; + pdf_ppt *ppt; + int i, k; + + i = pdf_get_index(p, key, pdc_true); + + if (value == NULL) value = ""; + + ppt = p->curr_ppt; + + switch (i) + { + case PDF_PARAMETER_PDIUSEBOX: + case PDF_PARAMETER_VIEWAREA: + case PDF_PARAMETER_VIEWCLIP: + case PDF_PARAMETER_PRINTAREA: + case PDF_PARAMETER_PRINTCLIP: + k = pdc_get_keycode_ci(value, pdf_usebox_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + usebox = (pdc_pagebox) k; + strcpy(optlist, key); + strcat(optlist, " "); + strcat(optlist, value); + break; + + case PDF_PARAMETER_TEXTFORMAT: + case PDF_PARAMETER_HYPERTEXTFORMAT: + k = pdc_get_keycode_ci(value, pdf_textformat_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + textformat = (pdc_text_format) k; + break; + } + + switch (i) + { + case PDF_PARAMETER_SEARCHPATH: + case PDF_PARAMETER_FONTAFM: + case PDF_PARAMETER_FONTPFM: + case PDF_PARAMETER_FONTOUTLINE: + case PDF_PARAMETER_HOSTFONT: + case PDF_PARAMETER_ENCODING: + case PDF_PARAMETER_ICCPROFILE: + case PDF_PARAMETER_STANDARDOUTPUTINTENT: + { + pdf_add_resource(p, key, value); + break; + } + + case PDF_PARAMETER_DEBUG: + { + const unsigned char *c; + + for (c = (const unsigned char *) value; *c; c++) + p->debug[(int) *c] = 1; + break; + } + + case PDF_PARAMETER_NODEBUG: + { + const unsigned char *c; + + for (c = (const unsigned char *) value; *c; c++) + p->debug[(int) *c] = 0; + break; + } + + case PDF_PARAMETER_BINDING: + if (!p->pdc->binding) + p->pdc->binding = pdc_strdup(p->pdc, value); + break; + + case PDF_PARAMETER_OBJORIENT: + p->pdc->objorient = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_HASTOBEPOS: + p->pdc->hastobepos = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_PTFRUN: + p->pdc->ptfrun = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_SMOKERUN: + p->pdc->smokerun = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_UNICAPLANG: + p->pdc->unicaplang = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_ERRORPOLICY: + k = pdc_get_keycode_ci(value, pdf_errpol_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + p->errorpolicy = (pdf_errpol) k; + break; + + case PDF_PARAMETER_UNDERLINE: + pdf_set_tstate(p, (double) pdf_bool_value(p, key, value), + to_underline); + break; + + case PDF_PARAMETER_OVERLINE: + pdf_set_tstate(p, (double) pdf_bool_value(p, key, value), + to_overline); + break; + + case PDF_PARAMETER_STRIKEOUT: + pdf_set_tstate(p, (double) pdf_bool_value(p, key, value), + to_strikeout); + break; + + case PDF_PARAMETER_KERNING: + pdc_warning(p->pdc, PDF_E_UNSUPP_KERNING, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_FAKEBOLD: + pdf_set_tstate(p, (double) pdf_bool_value(p, key, value), + to_fakebold); + break; + + + case PDF_PARAMETER_RESOURCEFILE: + pdc_set_resourcefile(p->pdc, value); + break; + + case PDF_PARAMETER_RENDERINGINTENT: + k = pdc_get_keycode_ci(value, pdf_renderingintent_pdfkeylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + p->rendintent = (pdf_renderingintent) k; + break; + + case PDF_PARAMETER_PRESERVEOLDPANTONENAMES: + p->preserveoldpantonenames = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_SPOTCOLORLOOKUP: + p->spotcolorlookup = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_PDISTRICT: + p->pdi_strict = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_TOPDOWN: + if (pdf_bool_value(p, key, value)) + p->ydirection = -1.0; + else + p->ydirection = 1.0; + break; + + case PDF_PARAMETER_USERCOORDINATES: + p->usercoordinates = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_USEHYPERTEXTENCODING: + p->usehyptxtenc = pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_TEXTFORMAT: + pdf_check_textformat(p, textformat); + p->textformat = textformat; + if (p->curr_ppt) + pdf_set_tstate(p, (double) textformat, to_textformat); + break; + + case PDF_PARAMETER_HYPERTEXTFORMAT: + pdf_check_hypertextformat(p, textformat); + p->hypertextformat = textformat; + break; + + case PDF_PARAMETER_HYPERTEXTENCODING: + { + p->hypertextencoding = + pdf_get_hypertextencoding(p, value, &p->hypertextcodepage, + pdc_true); + pdf_check_hypertextencoding(p, p->hypertextencoding); + break; + } + + case PDF_PARAMETER_CHARREF: + pdc_warning(p->pdc, PDF_E_UNSUPP_CHARREF, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_ESCAPESEQUENCE: + pdc_warning(p->pdc, PDF_E_UNSUPP_ESCAPESEQU, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_HONORLANG: + pdc_warning(p->pdc, PDF_E_UNSUPP_HONORLANG, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_GLYPHCHECK: + pdc_warning(p->pdc, PDF_E_UNSUPP_GLYPHCHECK, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_FILLRULE: + k = pdc_get_keycode_ci(value, pdf_fillrule_keylist); + if (k == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + ppt->fillrule = (pdf_fillrule) k; + break; + + case PDF_PARAMETER_LOGGING: + pdc_set_logg_options(p->pdc, value); + break; + + case PDF_PARAMETER_LOGMSG: + pdc_logg_cond(p->pdc, 1, trc_user, value); + break; + + case PDF_PARAMETER_TRACEMSG: + /* do nothing -- client-supplied string will show up + * in the log file + */ + break; + + case PDF_PARAMETER_NODEMOSTAMP: + break; + + case PDF_PARAMETER_SERIAL: + case PDF_PARAMETER_LICENCE: + case PDF_PARAMETER_LICENSE: + break; + + case PDF_PARAMETER_LICENCEFILE: + case PDF_PARAMETER_LICENSEFILE: + break; + + case PDF_PARAMETER_AUTOSPACE: + pdc_warning(p->pdc, PDF_E_UNSUPP_TAGGED, 0, 0, 0, 0); + break; + +/*****************************************************************************/ +/** deprecated historical parameters **/ +/*****************************************************************************/ + + case PDF_PARAMETER_OPENWARNING: + p->debug[(int) 'o'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_FONTWARNING: + p->debug[(int) 'F'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_ICCWARNING: + p->debug[(int) 'I'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_IMAGEWARNING: + p->debug[(int) 'i'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_PDIWARNING: + p->debug[(int) 'p'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_HONORICCPROFILE: + p->debug[(int) 'e'] = (char) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_GLYPHWARNING: + p->debug[(int) 'g'] = (char) pdf_bool_value(p, key, value); + if (p->curr_ppt) + pdf_set_tstate(p, (double) pdf_bool_value(p, key, value), + to_glyphwarning); + break; + + case PDF_PARAMETER_TRACE: + { + pdc_bool bv = pdf_bool_value(p, key, value); + if (bv) + pdc_set_logg_options(p->pdc, ""); + else + pdc_set_logg_options(p->pdc, "disable"); + break; + } + + case PDF_PARAMETER_TRACEFILE: + strcpy(optlist, "filename "); + strcat(optlist, value); + pdc_set_logg_options(p->pdc, optlist); + break; + + case PDF_PARAMETER_WARNING: + break; + + case PDF_PARAMETER_MASTERPASSWORD: + pdc_warning(p->pdc, PDF_E_UNSUPP_CRYPT, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_USERPASSWORD: + pdc_warning(p->pdc, PDF_E_UNSUPP_CRYPT, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_PERMISSIONS: + pdc_warning(p->pdc, PDF_E_UNSUPP_CRYPT, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_COMPATIBILITY: + pdf_set_compatibility(p, value); + break; + + case PDF_PARAMETER_FLUSH: + pdf_set_flush(p, value); + break; + + case PDF_PARAMETER_PDFX: + pdc_warning(p->pdc, PDF_E_UNSUPP_PDFX, 0, 0, 0, 0); + break; + + case PDF_PARAMETER_HIDETOOLBAR: + case PDF_PARAMETER_HIDEMENUBAR: + case PDF_PARAMETER_HIDEWINDOWUI: + case PDF_PARAMETER_FITWINDOW: + case PDF_PARAMETER_CENTERWINDOW: + case PDF_PARAMETER_DISPLAYDOCTITLE: + if (pdf_bool_value(p, key, value)) + pdf_set_viewerpreference(p, key); + break; + + case PDF_PARAMETER_NONFULLSCREENPAGEMODE: + if (!pdc_stricmp(value, "useoutlines")) + pdf_set_viewerpreference(p, "nonfullscreenpagemode bookmarks"); + else if (!pdc_stricmp(value, "usethumbs")) + pdf_set_viewerpreference(p, "nonfullscreenpagemode thumbnails"); + else if (!pdc_stricmp(value, "usenone")) + pdf_set_viewerpreference(p, "nonfullscreenpagemode none"); + else + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + break; + + case PDF_PARAMETER_DIRECTION: + if (!pdc_stricmp(value, "r2l")) + pdf_set_viewerpreference(p, "direction r2l"); + else if (!pdc_stricmp(value, "l2r")) + pdf_set_viewerpreference(p, "direction l2r"); + else + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, value, key, 0, 0); + break; + + case PDF_PARAMETER_VIEWAREA: + case PDF_PARAMETER_VIEWCLIP: + case PDF_PARAMETER_PRINTAREA: + case PDF_PARAMETER_PRINTCLIP: + pdf_set_viewerpreference(p, optlist); + break; + + case PDF_PARAMETER_OPENACTION: + pdf_set_openaction(p, value); + break; + + case PDF_PARAMETER_OPENMODE: + pdf_set_openmode(p, value); + break; + + case PDF_PARAMETER_BOOKMARKDEST: + pdf_cleanup_destination(p, p->bookmark_dest); + p->bookmark_dest = + pdf_parse_destination_optlist(p, value, 0, pdf_bookmark); + break; + + case PDF_PARAMETER_INHERITGSTATE: + (void) pdf_bool_value(p, key, value); + break; + + case PDF_PARAMETER_TRANSITION: + pdf_set_transition(p, value); + break; + + case PDF_PARAMETER_BASE: + pdf_set_uri(p, value); + break; + + case PDF_PARAMETER_LAUNCHLINK_PARAMETERS: + if (p->launchlink_parameters) { + pdc_free(p->pdc, p->launchlink_parameters); + p->launchlink_parameters = NULL; + } + p->launchlink_parameters = pdc_strdup(p->pdc, value); + break; + + case PDF_PARAMETER_LAUNCHLINK_OPERATION: + if (p->launchlink_operation) { + pdc_free(p->pdc, p->launchlink_operation); + p->launchlink_operation = NULL; + } + p->launchlink_operation = pdc_strdup(p->pdc, value); + break; + + case PDF_PARAMETER_LAUNCHLINK_DEFAULTDIR: + if (p->launchlink_defaultdir) { + pdc_free(p->pdc, p->launchlink_defaultdir); + p->launchlink_defaultdir = NULL; + } + p->launchlink_defaultdir = pdc_strdup(p->pdc, value); + break; + + case PDF_PARAMETER_PDIUSEBOX: + p->pdi_usebox = usebox; + break; + + case PDF_PARAMETER_AUTOSUBSETTING: + case PDF_PARAMETER_AUTOCIDFONT: + case PDF_PARAMETER_UNICODEMAP: + pdc_warning(p->pdc, PDF_E_UNSUPP_UNICODE, 0, 0, 0, 0); + break; + + default: + pdc_error(p->pdc, PDC_E_PAR_UNKNOWNKEY, key, 0, 0, 0); + break; + } /* switch */ +} /* pdf__set_parameter */ + +static double +pdf_value(PDF *p, const char *key, double value, int minver) +{ + if (p->compatibility < minver) + pdc_error(p->pdc, PDC_E_PAR_VERSION, + key, pdc_get_pdfversion(p->pdc, minver), 0, 0); + + return value; +} + +static double +pdf_pos_value(PDF *p, const char *key, double value, int minver) +{ + if (p->compatibility < minver) + pdc_error(p->pdc, PDC_E_PAR_VERSION, + key, pdc_get_pdfversion(p->pdc, minver), 0, 0); + + if (value <= 0) + pdc_error(p->pdc, PDC_E_PAR_ILLVALUE, + pdc_errprintf(p->pdc, "%f", value), key, 0, 0); + + return value; +} + +void +pdf__set_value(PDF *p, const char *key, double value) +{ + int i; + int ivalue = (int) value; + pdf_ppt *ppt; + + i = pdf_get_index(p, key, pdc_true); + + ppt = p->curr_ppt; + + pdc_check_number(p->pdc, "value", value); + + switch (i) + { + case PDF_PARAMETER_COMPRESS: + if (ivalue < 0 || ivalue > 9) + pdc_error(p->pdc, PDC_E_PAR_ILLVALUE, + pdc_errprintf(p->pdc, "%f", value), key, 0, 0); + + if (pdc_get_compresslevel(p->out) != ivalue) + { + /* + * We must restart the compression engine and start a new + * contents section if we're in the middle of a page. + */ + if (PDF_GET_STATE(p) == pdf_state_page) { + pdf_end_contents_section(p); + pdc_set_compresslevel(p->out, ivalue); + pdf_begin_contents_section(p); + } else + pdc_set_compresslevel(p->out, ivalue); + } + + break; + + case PDF_PARAMETER_FLOATDIGITS: + if (3 <= ivalue && ivalue <= 6) + { + p->pdc->floatdigits = ivalue; + } + else + pdc_error(p->pdc, PDC_E_PAR_ILLVALUE, + pdc_errprintf(p->pdc, "%d", ivalue), key, 0, 0); + break; + + /* TODO (york): take /CropBox into account? + */ + case PDF_PARAMETER_PAGEWIDTH: + { + const pdc_rectangle *box = pdf_get_pagebox(p, pdf_mediabox); + + if (p->ydirection == -1) + pdc_error(p->pdc, PDF_E_PAGE_ILLCHGSIZE, 0, 0, 0, 0); + + if (value < PDF_ACRO_MINPAGE || value > PDF_ACRO_MAXPAGE) + pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0); + + pdf_set_pagebox_urx(p, pdf_mediabox, + box->llx + pdf_pos_value(p, key, value, PDC_1_3)); + break; + } + + /* TODO (york): take /CropBox into account? + */ + case PDF_PARAMETER_PAGEHEIGHT: + { + const pdc_rectangle *box = pdf_get_pagebox(p, pdf_mediabox); + + if (p->ydirection == -1) + pdc_error(p->pdc, PDF_E_PAGE_ILLCHGSIZE, 0, 0, 0, 0); + + if (value < PDF_ACRO_MINPAGE || value > PDF_ACRO_MAXPAGE) + pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0); + + pdf_set_pagebox_ury(p, pdf_mediabox, + box->lly + pdf_pos_value(p, key, value, PDC_1_3)); + break; + } + + case PDF_PARAMETER_CROPBOX_LLX: + pdf_set_pagebox_llx(p, pdf_cropbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_CROPBOX_LLY: + pdf_set_pagebox_lly(p, pdf_cropbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_CROPBOX_URX: + pdf_set_pagebox_urx(p, pdf_cropbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_CROPBOX_URY: + pdf_set_pagebox_ury(p, pdf_cropbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_BLEEDBOX_LLX: + pdf_set_pagebox_llx(p, pdf_bleedbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_BLEEDBOX_LLY: + pdf_set_pagebox_lly(p, pdf_bleedbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_BLEEDBOX_URX: + pdf_set_pagebox_urx(p, pdf_bleedbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_BLEEDBOX_URY: + pdf_set_pagebox_ury(p, pdf_bleedbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_TRIMBOX_LLX: + pdf_set_pagebox_llx(p, pdf_trimbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_TRIMBOX_LLY: + pdf_set_pagebox_lly(p, pdf_trimbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_TRIMBOX_URX: + pdf_set_pagebox_urx(p, pdf_trimbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_TRIMBOX_URY: + pdf_set_pagebox_ury(p, pdf_trimbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_ARTBOX_LLX: + pdf_set_pagebox_llx(p, pdf_artbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_ARTBOX_LLY: + pdf_set_pagebox_lly(p, pdf_artbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_ARTBOX_URX: + pdf_set_pagebox_urx(p, pdf_artbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_ARTBOX_URY: + pdf_set_pagebox_ury(p, pdf_artbox, + pdf_value(p, key, value, PDC_1_3)); + break; + + case PDF_PARAMETER_LEADING: + pdf_set_tstate(p, value, to_leading); + break; + + case PDF_PARAMETER_TEXTRISE: + pdf_set_tstate(p, value, to_textrise); + break; + + case PDF_PARAMETER_HORIZSCALING: + pdf_set_tstate(p, value /100, to_horizscaling); + break; + + case PDF_PARAMETER_ITALICANGLE: + pdf_set_tstate(p, value, to_italicangle); + break; + + case PDF_PARAMETER_TEXTRENDERING: + pdf_set_tstate(p, value, to_textrendering); + break; + + case PDF_PARAMETER_CHARSPACING: + pdf_set_tstate(p, value, to_charspacing); + break; + + case PDF_PARAMETER_WORDSPACING: + pdf_set_tstate(p, value, to_wordspacing); + break; + + case PDF_PARAMETER_UNDERLINEWIDTH: + pdf_set_tstate(p, value, to_underlinewidth); + break; + + case PDF_PARAMETER_UNDERLINEPOSITION: + pdf_set_tstate(p, value, to_underlineposition); + break; + + case PDF_PARAMETER_DEFAULTGRAY: + break; + + case PDF_PARAMETER_DEFAULTRGB: + break; + + case PDF_PARAMETER_DEFAULTCMYK: + break; + + case PDF_PARAMETER_SETCOLOR_ICCPROFILEGRAY: + break; + + case PDF_PARAMETER_SETCOLOR_ICCPROFILERGB: + break; + + case PDF_PARAMETER_SETCOLOR_ICCPROFILECMYK: + break; + +/*****************************************************************************/ +/** deprecated historical parameters **/ +/*****************************************************************************/ + + case PDF_PARAMETER_SUBSETLIMIT: + case PDF_PARAMETER_SUBSETMINSIZE: + { + pdc_warning(p->pdc, PDF_E_UNSUPP_SUBSET, 0, 0, 0, 0); + break; + } + + case PDF_PARAMETER_DURATION: + pdf_set_duration(p, value); + break; + + default: + pdc_error(p->pdc, PDC_E_PAR_UNKNOWNKEY, key, 0, 0, 0); + break; + } /* switch */ +} /* pdf__set_value */ + +double +pdf__get_value(PDF *p, const char *key, double mod) +{ + int i = -1; + int imod = (int) mod; + double result = 0; + const pdc_rectangle *box = NULL; + pdf_ppt *ppt; + + i = pdf_get_index(p, key, pdc_false); + + if (parms[i].mod_zero && mod != 0) + pdc_error(p->pdc, PDC_E_PAR_ILLVALUE, + pdc_errprintf(p->pdc, "%f", mod), key, 0, 0); + + ppt = p->curr_ppt; + + switch (i) + { + case PDF_PARAMETER_IMAGEWIDTH: + case PDF_PARAMETER_IMAGEHEIGHT: + case PDF_PARAMETER_RESX: + case PDF_PARAMETER_RESY: + case PDF_PARAMETER_ORIENTATION: + if (p->pdc->hastobepos) imod -= 1; + pdf_check_handle(p, imod, pdc_imagehandle); + break; + + case PDF_PARAMETER_FONTMAXCODE: + case PDF_PARAMETER_CAPHEIGHT: + case PDF_PARAMETER_ASCENDER: + case PDF_PARAMETER_DESCENDER: + case PDF_PARAMETER_XHEIGHT: + if (p->pdc->hastobepos) imod -= 1; + pdf_check_handle(p, imod, pdc_fonthandle); + break; + } + + switch (i) + { + case PDF_PARAMETER_COMPRESS: + result = (double) pdc_get_compresslevel(p->out); + break; + + case PDF_PARAMETER_FLOATDIGITS: + result = (double) p->pdc->floatdigits; + break; + + /* TODO (york): take /CropBox into account? + */ + case PDF_PARAMETER_PAGEWIDTH: + box = pdf_get_pagebox(p, pdf_mediabox); + result = box->urx - box->llx; + break; + + /* TODO (york): take /CropBox into account? + */ + case PDF_PARAMETER_PAGEHEIGHT: + box = pdf_get_pagebox(p, pdf_mediabox); + result = box->ury - box->lly; + break; + + case PDF_PARAMETER_CROPBOX_LLX: + box = pdf_get_pagebox(p, pdf_cropbox); + result = box->llx; + break; + + case PDF_PARAMETER_CROPBOX_LLY: + box = pdf_get_pagebox(p, pdf_cropbox); + result = box->lly; + break; + + case PDF_PARAMETER_CROPBOX_URX: + box = pdf_get_pagebox(p, pdf_cropbox); + result = box->urx; + break; + + case PDF_PARAMETER_CROPBOX_URY: + box = pdf_get_pagebox(p, pdf_cropbox); + result = box->ury; + break; + + case PDF_PARAMETER_BLEEDBOX_LLX: + box = pdf_get_pagebox(p, pdf_bleedbox); + result = box->llx; + break; + + case PDF_PARAMETER_BLEEDBOX_LLY: + box = pdf_get_pagebox(p, pdf_bleedbox); + result = box->lly; + break; + + case PDF_PARAMETER_BLEEDBOX_URX: + box = pdf_get_pagebox(p, pdf_bleedbox); + result = box->urx; + break; + + case PDF_PARAMETER_BLEEDBOX_URY: + box = pdf_get_pagebox(p, pdf_bleedbox); + result = box->ury; + break; + + case PDF_PARAMETER_TRIMBOX_LLX: + box = pdf_get_pagebox(p, pdf_trimbox); + result = box->llx; + break; + + case PDF_PARAMETER_TRIMBOX_LLY: + box = pdf_get_pagebox(p, pdf_trimbox); + result = box->lly; + break; + + case PDF_PARAMETER_TRIMBOX_URX: + box = pdf_get_pagebox(p, pdf_trimbox); + result = box->urx; + break; + + case PDF_PARAMETER_TRIMBOX_URY: + box = pdf_get_pagebox(p, pdf_trimbox); + result = box->ury; + break; + + case PDF_PARAMETER_ARTBOX_LLX: + box = pdf_get_pagebox(p, pdf_artbox); + result = box->llx; + break; + + case PDF_PARAMETER_ARTBOX_LLY: + box = pdf_get_pagebox(p, pdf_artbox); + result = box->lly; + break; + + case PDF_PARAMETER_ARTBOX_URX: + box = pdf_get_pagebox(p, pdf_artbox); + result = box->urx; + break; + + case PDF_PARAMETER_ARTBOX_URY: + box = pdf_get_pagebox(p, pdf_artbox); + result = box->ury; + break; + + case PDF_PARAMETER_IMAGEWIDTH: + pdf_get_image_size(p, imod, (double *) &result, NULL); + break; + + case PDF_PARAMETER_IMAGEHEIGHT: + pdf_get_image_size(p, imod, NULL, (double *) &result); + break; + + case PDF_PARAMETER_RESX: + pdf_get_image_resolution(p, imod, (double *) &result, NULL); + break; + + case PDF_PARAMETER_RESY: + pdf_get_image_resolution(p, imod, NULL, (double *) &result); + break; + + case PDF_PARAMETER_ORIENTATION: + result = (double) (p->images[imod].orientation); + break; + + + case PDF_PARAMETER_CURRENTX: + result = (double) (ppt->gstate[ppt->sl].x); + break; + + case PDF_PARAMETER_CURRENTY: + result = (double) (ppt->gstate[ppt->sl].y); + break; + + case PDF_PARAMETER_CTM_A: + result = (double) (ppt->gstate[ppt->sl].ctm.a); + break; + + case PDF_PARAMETER_CTM_B: + result = (double) (ppt->gstate[ppt->sl].ctm.b); + break; + + case PDF_PARAMETER_CTM_C: + result = (double) (ppt->gstate[ppt->sl].ctm.c); + break; + + case PDF_PARAMETER_CTM_D: + result = (double) (ppt->gstate[ppt->sl].ctm.d); + break; + + case PDF_PARAMETER_CTM_E: + result = (double) (ppt->gstate[ppt->sl].ctm.e); + break; + + case PDF_PARAMETER_CTM_F: + result = (double) (ppt->gstate[ppt->sl].ctm.f); + break; + + case PDF_PARAMETER_TEXTX: + result = pdf_get_tstate(p, to_textx); + break; + + case PDF_PARAMETER_TEXTY: + result = pdf_get_tstate(p, to_texty); + break; + + case PDF_PARAMETER_UNDERLINEWIDTH: + result = pdf_get_tstate(p, to_underlinewidth); + break; + + case PDF_PARAMETER_UNDERLINEPOSITION: + result = pdf_get_tstate(p, to_underlineposition); + break; + + case PDF_PARAMETER_WORDSPACING: + result = pdf_get_tstate(p, to_wordspacing); + break; + + case PDF_PARAMETER_CHARSPACING: + result = pdf_get_tstate(p, to_charspacing); + break; + + case PDF_PARAMETER_HORIZSCALING: + result = 100 * pdf_get_tstate(p, to_horizscaling); + break; + + case PDF_PARAMETER_ITALICANGLE: + result = pdf_get_tstate(p, to_italicangle); + break; + + case PDF_PARAMETER_TEXTRISE: + result = pdf_get_tstate(p, to_textrise); + break; + + case PDF_PARAMETER_LEADING: + result = pdf_get_tstate(p, to_leading); + break; + + case PDF_PARAMETER_TEXTRENDERING: + result = pdf_get_tstate(p, to_textrendering); + break; + + case PDF_PARAMETER_FONTSIZE: + result = pdf_get_tstate(p, to_fontsize); + break; + + case PDF_PARAMETER_FONT: + result = pdf_get_tstate(p, to_font); + if (p->pdc->hastobepos) result += 1; + break; + + case PDF_PARAMETER_MONOSPACE: + result = pdf_get_font_float_option(p, fo_monospace); + break; + + case PDF_PARAMETER_FONTMAXCODE: + result = (double) (p->fonts[imod].ft.numcodes - 1); + break; + + case PDF_PARAMETER_ASCENDER: + result = pdf_font_get_metric_value(p->fonts[imod].ft.m.ascender); + break; + + case PDF_PARAMETER_DESCENDER: + result = pdf_font_get_metric_value(p->fonts[imod].ft.m.descender); + break; + + case PDF_PARAMETER_CAPHEIGHT: + result = pdf_font_get_metric_value(p->fonts[imod].ft.m.capHeight); + break; + + case PDF_PARAMETER_XHEIGHT: + result = pdf_font_get_metric_value(p->fonts[imod].ft.m.xHeight); + break; + + + default: + pdc_error(p->pdc, PDC_E_PAR_UNSUPPKEY, key, 0, 0, 0); + break; + } /* switch */ + + return result; +} /* pdf__get_value */ + +const char * +pdf__get_parameter(PDF *p, const char *key, double mod) +{ + int i = -1; + int imod = (int) mod; + const char *result = ""; + pdf_ppt *ppt; + + i = pdf_get_index(p, key, pdc_false); + + if (parms[i].mod_zero && mod != 0) + pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, + pdc_errprintf(p->pdc, "%f", mod), key, 0, 0); + + ppt = p->curr_ppt; + + switch (i) + { + case PDF_PARAMETER_CAPHEIGHTFAKED: + case PDF_PARAMETER_ASCENDERFAKED: + case PDF_PARAMETER_DESCENDERFAKED: + case PDF_PARAMETER_XHEIGHTFAKED: + if (p->pdc->hastobepos) imod -= 1; + pdf_check_handle(p, imod, pdc_fonthandle); + break; + } + + switch (i) + { + case PDF_PARAMETER_BINDING: + result = p->pdc->binding; + break; + + case PDF_PARAMETER_OBJORIENT: + result = PDC_BOOLSTR(p->pdc->objorient); + break; + + case PDF_PARAMETER_HASTOBEPOS: + result = PDC_BOOLSTR(p->pdc->hastobepos); + break; + + case PDF_PARAMETER_PTFRUN: + result = PDC_BOOLSTR(p->pdc->ptfrun); + break; + + case PDF_PARAMETER_SMOKERUN: + result = PDC_BOOLSTR(p->pdc->smokerun); + break; + + case PDF_PARAMETER_UNICAPLANG: + result = PDC_BOOLSTR(p->pdc->unicaplang); + break; + + + case PDF_PARAMETER_CONFIGURATION: + result = "lite"; + break; + + case PDF_PARAMETER_ERRORPOLICY: + result = pdc_get_keyword(p->errorpolicy, pdf_errpol_keylist); + break; + + case PDF_PARAMETER_PDIUSEBOX: + result = pdc_get_keyword(p->pdi_usebox, pdf_usebox_keylist); + break; + + case PDF_PARAMETER_SEARCHPATH: + case PDF_PARAMETER_FONTAFM: + case PDF_PARAMETER_FONTPFM: + case PDF_PARAMETER_FONTOUTLINE: + case PDF_PARAMETER_HOSTFONT: + case PDF_PARAMETER_ENCODING: + case PDF_PARAMETER_ICCPROFILE: + case PDF_PARAMETER_STANDARDOUTPUTINTENT: + result = pdc_find_resource_nr(p->pdc, key, imod); + break; + + case PDF_PARAMETER_FONTNAME: + result = pdf_get_font_char_option(p, fo_fontname); + break; + + case PDF_PARAMETER_FONTENCODING: + result = pdf_get_font_char_option(p, fo_encoding); + break; + + case PDF_PARAMETER_FONTSTYLE: + result = pdf_get_font_char_option(p, fo_fontstyle); + break; + + case PDF_PARAMETER_ASCENDERFAKED: + result = PDC_BOOLSTR(pdf_font_get_is_faked(&p->fonts[imod], + font_ascender)); + break; + + case PDF_PARAMETER_DESCENDERFAKED: + result = PDC_BOOLSTR(pdf_font_get_is_faked(&p->fonts[imod], + font_descender)); + break; + + case PDF_PARAMETER_CAPHEIGHTFAKED: + result = PDC_BOOLSTR(pdf_font_get_is_faked(&p->fonts[imod], + font_capheight)); + break; + + case PDF_PARAMETER_XHEIGHTFAKED: + result = PDC_BOOLSTR(pdf_font_get_is_faked(&p->fonts[imod], + font_xheight)); + break; + + + case PDF_PARAMETER_UNDERLINE: + result = PDC_BOOLSTR((int) pdf_get_tstate(p, to_underline)); + break; + + case PDF_PARAMETER_OVERLINE: + result = PDC_BOOLSTR((int) pdf_get_tstate(p, to_overline)); + break; + + case PDF_PARAMETER_STRIKEOUT: + result = PDC_BOOLSTR((int) pdf_get_tstate(p, to_strikeout)); + break; + + /* deprecated */ + case PDF_PARAMETER_INHERITGSTATE: + result = PDC_BOOLSTR(pdc_false); + break; + + case PDF_PARAMETER_SCOPE: + result = pdf_current_scope(p); + break; + + case PDF_PARAMETER_TEXTFORMAT: + result = pdc_get_keyword(p->textformat, pdf_textformat_keylist); + break; + + case PDF_PARAMETER_HYPERTEXTFORMAT: + result = pdc_get_keyword(p->hypertextformat,pdf_textformat_keylist); + break; + + case PDF_PARAMETER_HYPERTEXTENCODING: + result = pdf_get_encoding_name(p, p->hypertextencoding, NULL); + break; + + case PDF_PARAMETER_RESOURCEFILE: + result = pdc_get_resourcefile(p->pdc); + break; + + /* deprecated */ + case PDF_PARAMETER_WARNING: + result = PDC_BOOLSTR(0); + break; + + case PDF_PARAMETER_OPENWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'o']); + break; + + case PDF_PARAMETER_FONTWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'F']); + break; + + case PDF_PARAMETER_ICCWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'I']); + break; + + case PDF_PARAMETER_IMAGEWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'i']); + break; + + case PDF_PARAMETER_PDIWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'p']); + break; + + case PDF_PARAMETER_HONORICCPROFILE: + result = PDC_BOOLSTR((int) p->debug[(int) 'e']); + break; + + case PDF_PARAMETER_GLYPHWARNING: + result = PDC_BOOLSTR((int) p->debug[(int) 'g']); + break; + + case PDF_PARAMETER_RENDERINGINTENT: + result = pdc_get_keyword(p->rendintent, + pdf_renderingintent_pdfkeylist); + break; + + case PDF_PARAMETER_PRESERVEOLDPANTONENAMES: + result = PDC_BOOLSTR(p->preserveoldpantonenames); + break; + + case PDF_PARAMETER_SPOTCOLORLOOKUP: + result = PDC_BOOLSTR(p->spotcolorlookup); + break; + + case PDF_PARAMETER_PDISTRICT: + result = PDC_BOOLSTR(p->pdi_strict); + break; + + case PDF_PARAMETER_TOPDOWN: + result = PDC_BOOLSTR((p->ydirection == -1.0)); + break; + + case PDF_PARAMETER_USERCOORDINATES: + result = PDC_BOOLSTR(p->usercoordinates); + break; + + case PDF_PARAMETER_USEHYPERTEXTENCODING: + result = PDC_BOOLSTR(p->usehyptxtenc); + break; + + + + case PDF_PARAMETER_FILLRULE: + result = pdc_get_keyword(ppt->fillrule, pdf_fillrule_keylist); + break; + + + + case PDF_PARAMETER_COMPATIBILITY: + result = pdc_get_keyword(p->compatibility, + pdf_compatibility_keylist); + break; + + case PDF_PARAMETER_STRING: + pdf_check_handle(p, imod, pdc_stringhandle); + result = pdf_get_utilstring(p, imod); + break; + + default: + pdc_error(p->pdc, PDC_E_PAR_UNSUPPKEY, key, 0, 0, 0); + break; + } /* switch */ + + return result ? result : ""; +} /* pdf__get_parameter */ + + diff --git a/src/pdflib/pdflib/p_params.h b/src/pdflib/pdflib/p_params.h new file mode 100644 index 0000000..12bbf6d --- /dev/null +++ b/src/pdflib/pdflib/p_params.h @@ -0,0 +1,373 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_params.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib parameter table + * + */ + +#if pdf_gen_parm_enum +#define pdf_gen1(code, name, zero, check, scope) PDF_PARAMETER_##code, +#elif pdf_gen_parm_descr +#define pdf_gen1(code, name, zero, check, scope) \ + { name, zero, check, scope }, +#else +#error invalid inclusion of generator file +#endif + +/* + * Deprecated and unsupported parameters: + * dep7 Deprecated since PDFlib 7 + * dep6 Deprecated since PDFlib 6 + * dep5 Deprecated since PDFlib 5 + * unsupp Unsupported (internal use, dysfunctional, or other) + */ + +/* + List of unsupported control characters for the "debug" parameter: + 2 disable the search for the Windows color directory via mscms.dll + e extract embedded ICC profiles from image files + F throw an exception in PDF_load_font (dep7); + g throw an exception in PDF_fit_textline and PDF_show (dep7) + h disable host font processing + i throw an exception in PDF_load_image (dep7) + I throw an exception in PDF_load_iccprofile (dep7); + o throw an exception in PDF_begin_document (dep7) + p throw an exception in PDF_open_pdi (dep7) + + On by default: e F I +*/ + + +/* + * ---------------------------------------------------------------------- + * Setup + * ---------------------------------------------------------------------- + */ + +pdf_gen1(OPENWARNING, "openwarning", 1, 1, pdf_state_all) /* dep6 */ +pdf_gen1(COMPRESS, "compress", 1, 1, + pdf_state_page | pdf_state_document) +pdf_gen1(FLUSH, "flush", 1, 1, pdf_state_all) /* dep6 */ +pdf_gen1(RESOURCEFILE, "resourcefile", 1, 1, pdf_state_all) +pdf_gen1(COMPATIBILITY, "compatibility",1, 0, pdf_state_object) /* dep6 */ +pdf_gen1(PDFX, "pdfx", 1, 0, pdf_state_object) /* dep6 */ +pdf_gen1(SEARCHPATH, "SearchPath", 0, 1, pdf_state_all) +pdf_gen1(ASCIIFILE, "asciifile", 1, 1, pdf_state_all) +pdf_gen1(WARNING, "warning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(ERRORPOLICY, "errorpolicy", 1, 1, pdf_state_all) +pdf_gen1(NODEMOSTAMP, "nodemostamp", 1, 0, pdf_state_object) +pdf_gen1(LICENSE, "license", 1, 0, pdf_state_object) +pdf_gen1(LICENCE, "licence", 1, 0, pdf_state_object) /* unsupp */ +pdf_gen1(LICENSEFILE, "licensefile", 1, 0, pdf_state_object) +pdf_gen1(LICENCEFILE, "licencefile", 1, 0, pdf_state_object) /* unsupp */ +pdf_gen1(TRACE, "trace", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(TRACEFILE, "tracefile", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(TRACEMSG, "tracemsg", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(LOGGING, "logging", 1, 1, pdf_state_all) +pdf_gen1(LOGMSG, "logmsg", 1, 1, pdf_state_all) +pdf_gen1(CHARREF, "charref", 1, 1, pdf_state_all) +pdf_gen1(ESCAPESEQUENCE,"escapesequence",1,1, pdf_state_all) +pdf_gen1(HONORLANG, "honorlang", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(STRING, "string", 0, 1, pdf_state_all) +pdf_gen1(SCOPE, "scope", 1, 1, pdf_state_all) + +pdf_gen1(SERIAL, "serial", 1, 0, pdf_state_object) /* unsupp */ +pdf_gen1(FLOATDIGITS, "floatdigits", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(BINDING, "binding", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(OBJORIENT, "objorient", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(HASTOBEPOS, "hastobepos", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(UNICAPLANG, "unicaplang", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(DEBUG, "debug", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(NODEBUG, "nodebug", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(PTFRUN, "ptfrun", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(SMOKERUN, "smokerun", 1, 1, pdf_state_all) /* unsupp */ +pdf_gen1(CONFIGURATION, "configuration",1, 1, pdf_state_all) /* unsupp */ + + +/* + * ---------------------------------------------------------------------- + * Versioning (cf. pdflib.c) + * ---------------------------------------------------------------------- + */ + +pdf_gen1(MAJOR, "major", 1, 1, pdf_state_all) +pdf_gen1(MINOR, "minor", 1, 1, pdf_state_all) +pdf_gen1(REVISION, "revision", 1, 1, pdf_state_all) +pdf_gen1(VERSION, "version", 1, 1, pdf_state_all) + + +/* + * ---------------------------------------------------------------------- + * Page + * ---------------------------------------------------------------------- + */ + +/* all of the following group are dep6 */ + +pdf_gen1(PAGEWIDTH, "pagewidth", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(PAGEHEIGHT, "pageheight", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(CROPBOX_LLX, "CropBox/llx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(CROPBOX_LLY, "CropBox/lly", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(CROPBOX_URX, "CropBox/urx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(CROPBOX_URY, "CropBox/ury", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(BLEEDBOX_LLX, "BleedBox/llx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(BLEEDBOX_LLY, "BleedBox/lly", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(BLEEDBOX_URX, "BleedBox/urx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(BLEEDBOX_URY, "BleedBox/ury", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(TRIMBOX_LLX, "TrimBox/llx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(TRIMBOX_LLY, "TrimBox/lly", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(TRIMBOX_URX, "TrimBox/urx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(TRIMBOX_URY, "TrimBox/ury", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(ARTBOX_LLX, "ArtBox/llx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(ARTBOX_LLY, "ArtBox/lly", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(ARTBOX_URX, "ArtBox/urx", 1, 1, pdf_state_page | pdf_state_path) +pdf_gen1(ARTBOX_URY, "ArtBox/ury", 1, 1, pdf_state_page | pdf_state_path) + + +/* + * ---------------------------------------------------------------------- + * Font + * ---------------------------------------------------------------------- + */ + +pdf_gen1(FONTAFM, "FontAFM", 0, 1, pdf_state_all) +pdf_gen1(FONTPFM, "FontPFM", 0, 1, pdf_state_all) +pdf_gen1(FONTOUTLINE, "FontOutline", 0, 1, pdf_state_all) +pdf_gen1(HOSTFONT, "HostFont", 0, 1, pdf_state_all) +pdf_gen1(ENCODING, "Encoding", 0, 1, pdf_state_all) +pdf_gen1(FONTWARNING, "fontwarning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(FONT, "font", 1, 1, pdf_state_content) +pdf_gen1(FONTSIZE, "fontsize", 1, 1, pdf_state_content) + +pdf_gen1(SUBSETLIMIT, "subsetlimit", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(SUBSETMINSIZE, "subsetminsize",1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(AUTOSUBSETTING,"autosubsetting",1,1, pdf_state_all) /* dep7 */ +pdf_gen1(AUTOCIDFONT, "autocidfont", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(UNICODEMAP, "unicodemap", 1, 1, pdf_state_all) /* dep7 */ + +pdf_gen1(FONTNAME, "fontname", 1, 1, pdf_state_content) /* dep7 */ +pdf_gen1(FONTSTYLE, "fontstyle", 1, 1, pdf_state_content) /* dep7 */ +pdf_gen1(FONTENCODING, "fontencoding", 1, 1, pdf_state_content) /* dep7 */ +pdf_gen1(MONOSPACE, "monospace", 1, 1, pdf_state_content) /* dep7 */ +pdf_gen1(FONTMAXCODE, "fontmaxcode", 0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(ASCENDER, "ascender", 0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(DESCENDER, "descender", 0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(CAPHEIGHT, "capheight", 0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(XHEIGHT, "xheight", 0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(ASCENDERFAKED, "ascenderfaked",0, 1, pdf_state_all) /* dep7 */ +pdf_gen1(DESCENDERFAKED,"descenderfaked",0,1, pdf_state_all) /* dep7 */ +pdf_gen1(CAPHEIGHTFAKED,"capheightfaked",0,1, pdf_state_all) /* dep7 */ +pdf_gen1(XHEIGHTFAKED, "xheightfaked", 0,1, pdf_state_all) /* dep7 */ + + +/* + * ---------------------------------------------------------------------- + * Text + * ---------------------------------------------------------------------- + */ + +pdf_gen1(TEXTX, "textx", 1, 1, pdf_state_content) +pdf_gen1(TEXTY, "texty", 1, 1, pdf_state_content) +pdf_gen1(LEADING, "leading", 1, 1, pdf_state_content) +pdf_gen1(TEXTRISE, "textrise", 1, 1, pdf_state_content) +pdf_gen1(HORIZSCALING, "horizscaling", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(TEXTRENDERING, "textrendering",1, 1, pdf_state_content) +pdf_gen1(CHARSPACING, "charspacing", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(WORDSPACING, "wordspacing", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(ITALICANGLE, "italicangle", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(FAKEBOLD, "fakebold", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(UNDERLINEWIDTH,"underlinewidth", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(UNDERLINEPOSITION,"underlineposition", 1, 1, + pdf_state_content | pdf_state_document) +pdf_gen1(UNDERLINE, "underline", 1, 1, pdf_state_content) +pdf_gen1(OVERLINE, "overline", 1, 1, pdf_state_content) +pdf_gen1(STRIKEOUT, "strikeout", 1, 1, pdf_state_content) +pdf_gen1(KERNING, "kerning", 1, 1, pdf_state_all) +pdf_gen1(TEXTFORMAT, "textformat", 1, 1, pdf_state_all) +pdf_gen1(GLYPHWARNING, "glyphwarning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(GLYPHCHECK, "glyphcheck", 1, 1, pdf_state_all) + + +/* + * ---------------------------------------------------------------------- + * Graphics + * ---------------------------------------------------------------------- + */ + +pdf_gen1(CURRENTX, "currentx", 1, 1, + pdf_state_content | pdf_state_path) +pdf_gen1(CURRENTY, "currenty", 1, 1, + pdf_state_content | pdf_state_path) +pdf_gen1(FILLRULE, "fillrule", 1, 1, pdf_state_content) +pdf_gen1(TOPDOWN, "topdown", 1, 0, pdf_state_document) +pdf_gen1(CTM_A, "ctm_a", 1, 1, pdf_state_content) +pdf_gen1(CTM_B, "ctm_b", 1, 1, pdf_state_content) +pdf_gen1(CTM_C, "ctm_c", 1, 1, pdf_state_content) +pdf_gen1(CTM_D, "ctm_d", 1, 1, pdf_state_content) +pdf_gen1(CTM_E, "ctm_e", 1, 1, pdf_state_content) +pdf_gen1(CTM_F, "ctm_f", 1, 1, pdf_state_content) + + +/* + * ---------------------------------------------------------------------- + * Color + * ---------------------------------------------------------------------- + */ + +pdf_gen1(SETCOLOR_ICCPROFILEGRAY, "setcolor:iccprofilegray", 1, 1, + pdf_state_document | pdf_state_content) +pdf_gen1(SETCOLOR_ICCPROFILERGB, "setcolor:iccprofilergb", 1, 1, + pdf_state_document | pdf_state_content) +pdf_gen1(SETCOLOR_ICCPROFILECMYK, "setcolor:iccprofilecmyk", 1, 1, + pdf_state_document | pdf_state_content) +pdf_gen1(IMAGE_ICCPROFILE,"image:iccprofile", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) +pdf_gen1(ICCWARNING, "iccwarning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(HONORICCPROFILE, "honoriccprofile", 1, 1, pdf_state_all) +pdf_gen1(ICCCOMPONENTS, "icccomponents", 0, 1, pdf_state_all) +pdf_gen1(ICCPROFILE, "ICCProfile", 0, 1, pdf_state_all) +pdf_gen1(STANDARDOUTPUTINTENT, "StandardOutputIntent", 0, 1, pdf_state_all) +pdf_gen1(RENDERINGINTENT, "renderingintent", 1, 1, pdf_state_all) + +/* 3 x dep6 */ +pdf_gen1(DEFAULTRGB, "defaultrgb", 1, 1, + pdf_state_content | pdf_state_path) +pdf_gen1(DEFAULTGRAY, "defaultgray", 1, 1, + pdf_state_content | pdf_state_path) +pdf_gen1(DEFAULTCMYK, "defaultcmyk", 1, 1, + pdf_state_content | pdf_state_path) + +pdf_gen1(PRESERVEOLDPANTONENAMES, "preserveoldpantonenames", 1, 1, + pdf_state_all) +pdf_gen1(SPOTCOLORLOOKUP, "spotcolorlookup", 1, 1, + pdf_state_all) + +/* + * ---------------------------------------------------------------------- + * Image + * ---------------------------------------------------------------------- + */ + +pdf_gen1(IMAGEWARNING, "imagewarning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(IMAGEWIDTH, "imagewidth", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) +pdf_gen1(IMAGEHEIGHT, "imageheight", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) +pdf_gen1(RESX, "resx", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) +pdf_gen1(RESY, "resy", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) +pdf_gen1(ORIENTATION, "orientation", 0, 1, + pdf_state_path | pdf_state_content | pdf_state_document) + +pdf_gen1(INHERITGSTATE, "inheritgstate",1, 1, pdf_state_all) /* dep6 */ + + +/* + * ---------------------------------------------------------------------- + * PDI + * ---------------------------------------------------------------------- + */ + +pdf_gen1(PDI, "pdi", 1, 1, pdf_state_all) +pdf_gen1(PDIWARNING, "pdiwarning", 1, 1, pdf_state_all) /* dep7 */ +pdf_gen1(PDIUSEBOX, "pdiusebox", 1, 1, pdf_state_all) /* dep6 */ +pdf_gen1(PDISTRICT, "pdistrict", 1, 1, pdf_state_all) /* unsupp */ + + +/* + * ---------------------------------------------------------------------- + * Hypertext + * ---------------------------------------------------------------------- + */ + +pdf_gen1(HYPERTEXTFORMAT, "hypertextformat", 1, 1, pdf_state_all) +pdf_gen1(HYPERTEXTENCODING, "hypertextencoding", 1, 1, pdf_state_all) +pdf_gen1(USERCOORDINATES, "usercoordinates", 1, 1, pdf_state_all) +pdf_gen1(USEHYPERTEXTENCODING, "usehypertextencoding", 1, 1, pdf_state_all) + /* unsupp */ + +pdf_gen1(HIDETOOLBAR, "hidetoolbar", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(HIDEMENUBAR, "hidemenubar", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(HIDEWINDOWUI, "hidewindowui", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(FITWINDOW, "fitwindow", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(CENTERWINDOW, "centerwindow", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(DISPLAYDOCTITLE, "displaydoctitle", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(NONFULLSCREENPAGEMODE, "nonfullscreenpagemode", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(DIRECTION, "direction", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ + +pdf_gen1(VIEWAREA, "viewarea", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(VIEWCLIP, "viewclip", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(PRINTAREA, "printarea", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(PRINTCLIP, "printclip", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ + +pdf_gen1(OPENACTION, "openaction", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(OPENMODE, "openmode", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(BOOKMARKDEST, "bookmarkdest", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ +pdf_gen1(TRANSITION, "transition", 1, 1, pdf_state_all) /* dep6 */ +pdf_gen1(DURATION, "duration", 1, 1, pdf_state_all) /* dep6 */ +pdf_gen1(BASE, "base", 1, 1, + pdf_state_content | pdf_state_document) /* dep6 */ + +pdf_gen1(LAUNCHLINK_PARAMETERS, "launchlink:parameters", 1, 1, + pdf_state_all) /* dep6 */ +pdf_gen1(LAUNCHLINK_OPERATION, "launchlink:operation", 1, 1, + pdf_state_all) /* dep6 */ +pdf_gen1(LAUNCHLINK_DEFAULTDIR, "launchlink:defaultdir", 1, 1, + pdf_state_all) /* dep6 */ + + +/* + * ---------------------------------------------------------------------- + * Security (all dep6) + * ---------------------------------------------------------------------- + */ + +pdf_gen1(USERPASSWORD, "userpassword", 1, 1, pdf_state_object) /* dep6 */ +pdf_gen1(MASTERPASSWORD,"masterpassword",1,1, pdf_state_object) /* dep6 */ +pdf_gen1(PERMISSIONS, "permissions", 1, 1, pdf_state_object) /* dep6 */ + + +/* + * ---------------------------------------------------------------------- + * Tagged PDF + * ---------------------------------------------------------------------- + */ + +pdf_gen1(AUTOSPACE, "autospace", 1, 1, pdf_state_all) + + +#undef pdf_gen1 +#undef pdf_gen2 diff --git a/src/pdflib/pdflib/p_pattern.c b/src/pdflib/pdflib/p_pattern.c new file mode 100644 index 0000000..73306f7 --- /dev/null +++ b/src/pdflib/pdflib/p_pattern.c @@ -0,0 +1,231 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_pattern.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib pattern routines + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +void +pdf_init_pattern(PDF *p) +{ + static const char fn[] = "pdf_init_pattern"; + int i; + + p->pattern_number = 0; + p->pattern_capacity = PATTERN_CHUNKSIZE; + + p->pattern = (pdf_pattern *) pdc_malloc(p->pdc, + sizeof(pdf_pattern) * p->pattern_capacity, fn); + + for (i = 0; i < p->pattern_capacity; i++) { + p->pattern[i].used_on_current_page = pdc_false; + p->pattern[i].obj_id = PDC_BAD_ID; + } +} + +void +pdf_grow_pattern(PDF *p) +{ + static const char fn[] = "pdf_grow_pattern"; + int i; + + p->pattern = (pdf_pattern *) pdc_realloc(p->pdc, p->pattern, + sizeof(pdf_pattern) * 2 * p->pattern_capacity, fn); + + for (i = p->pattern_capacity; i < 2 * p->pattern_capacity; i++) { + p->pattern[i].used_on_current_page = pdc_false; + p->pattern[i].obj_id = PDC_BAD_ID; + } + + p->pattern_capacity *= 2; +} + +void +pdf_write_page_pattern(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->pt_bias; + + for (i = 0; i < p->pattern_number; i++) + if (p->pattern[i].used_on_current_page) + total++; + + if (total > 0 || bias) + { + pdc_puts(p->out, "/Pattern"); + pdc_begin_dict(p->out); + } + + if (total > 0) + { + for (i = 0; i < p->pattern_number; i++) + { + if (p->pattern[i].used_on_current_page) + { + p->pattern[i].used_on_current_page = pdc_false; /* reset */ + pdc_printf(p->out, "/P%d", bias + i); + pdc_objref(p->out, "", p->pattern[i].obj_id); + } + } + + if (!bias) + pdc_end_dict(p->out); + } +} + +void +pdf_get_page_patterns(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->pattern_number; i++) { + if (p->pattern[i].used_on_current_page) { + p->pattern[i].used_on_current_page = pdc_false; /* reset */ + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_pattern(PDF *p, int n) +{ + p->pattern[n].used_on_current_page = pdc_true; +} + +void +pdf_cleanup_pattern(PDF *p) +{ + if (p->pattern) { + pdc_free(p->pdc, p->pattern); + p->pattern = NULL; + } +} + +/* Start a new pattern definition. */ +int +pdf__begin_pattern( + PDF *p, + pdc_scalar width, + pdc_scalar height, + pdc_scalar xstep, + pdc_scalar ystep, + int painttype) +{ + int slot = -1; + + pdc_check_number_limits(p->pdc, "width", width, + PDC_FLOAT_PREC, PDC_FLOAT_MAX); + pdc_check_number_limits(p->pdc, "height", height, + PDC_FLOAT_PREC, PDC_FLOAT_MAX); + + pdc_check_number_zero(p->pdc, "xstep", xstep); + pdc_check_number_zero(p->pdc, "ystep", ystep); + + if (painttype != 1 && painttype != 2) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "painttype", pdc_errprintf(p->pdc, "%d", painttype), 0, 0); + + if (p->pattern_number == p->pattern_capacity) + pdf_grow_pattern(p); + + pdf_pg_suspend(p); + PDF_SET_STATE(p, pdf_state_pattern); + + p->pattern[p->pattern_number].obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); + p->pattern[p->pattern_number].painttype = painttype; + + pdc_begin_dict(p->out); /* pattern dict*/ + + p->res_id = pdc_alloc_id(p->out); + + pdc_puts(p->out, "/PatternType 1\n"); /* tiling pattern */ + + /* colored or uncolored pattern */ + pdc_printf(p->out, "/PaintType %d\n", painttype); + pdc_puts(p->out, "/TilingType 1\n"); /* constant spacing */ + + pdc_printf(p->out, "/BBox[0 0 %f %f]\n", width, height); + + pdc_printf(p->out, "/XStep %f\n", xstep); + pdc_printf(p->out, "/YStep %f\n", ystep); + + pdc_objref(p->out, "/Resources", p->res_id); + + p->length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", p->length_id); + + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + + pdc_end_dict(p->out); /* pattern dict*/ + pdc_begin_pdfstream(p->out); + + slot = p->pattern_number; + p->pattern_number++; + + /* top-down y-coordinates */ + pdf_set_topdownsystem(p, height); + + /* set color differing from PDF default */ + pdf_set_default_color(p, pdc_false); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin pattern %d]\n", slot); + + return slot; +} + +/* Finish the pattern definition. */ +void +pdf__end_pattern(PDF *p) +{ + /* check whether pdf__save() and pdf__restore() calls are balanced */ + if (p->curr_ppt->sl > 0) + pdc_error(p->pdc, PDF_E_GSTATE_UNMATCHEDSAVE, 0, 0, 0, 0); + + pdf_end_text(p); + pdc_end_pdfstream(p->out); + pdc_end_obj(p->out); /* pattern */ + + pdc_put_pdfstreamlength(p->out, p->length_id); + + pdc_begin_obj(p->out, p->res_id); /* Resource object */ + pdc_begin_dict(p->out); /* Resource dict */ + + pdf_write_page_fonts(p); /* Font resources */ + + pdf_write_page_colorspaces(p); /* Color space resources */ + + pdf_write_page_pattern(p); /* Pattern resources */ + + pdf_write_xobjects(p); /* XObject resources */ + + pdf_write_page_extgstates(p); /* ExtGState resources */ + + pdc_end_dict(p->out); /* resource dict */ + pdc_end_obj(p->out); /* resource object */ + + pdf_pg_resume(p, -1); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End pattern %d]\n", + p->pattern_number -1); +} diff --git a/src/pdflib/pdflib/p_pdi.c b/src/pdflib/pdflib/p_pdi.c new file mode 100644 index 0000000..a138987 --- /dev/null +++ b/src/pdflib/pdflib/p_pdi.c @@ -0,0 +1,28 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_pdi.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDF import routines (require the PDI library) + * + */ + +#define P_PDI_C + +#include "p_intern.h" + + + + + + + diff --git a/src/pdflib/pdflib/p_pfm.c b/src/pdflib/pdflib/p_pfm.c new file mode 100644 index 0000000..cab291b --- /dev/null +++ b/src/pdflib/pdflib/p_pfm.c @@ -0,0 +1,406 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_pfm.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib routines for fast reading of PFM font metrics files + * + */ + +#include "p_intern.h" +#include "p_font.h" + +/* read data types from the PFM */ +#define PFM_BYTE(offset) pfm[offset] +#define PFM_WORD(offset) PDC_GET_WORD(&pfm[offset]) +#define PFM_SHORT(offset) PDC_GET_SHORT(&pfm[offset]) +#define PFM_DWORD(offset) PDC_GET_DWORD3(&pfm[offset]) + +/* Offsets in the buffer containing the various PFM structures */ +#define header_base 0 +#define header_dfVersion (PFM_WORD(header_base + 0)) +#define header_dfSize (PFM_DWORD(header_base + 2)) +#define header_dfAscent (PFM_WORD(header_base + 74)) +#define header_dfItalic (PFM_BYTE(header_base + 80)) +#define header_dfWeight (PFM_WORD(header_base + 83)) +#define header_dfCharSet (PFM_BYTE(header_base + 85)) +#define header_dfPitchAndFamily (PFM_BYTE(header_base + 90)) +#define header_dfMaxWidth (PFM_WORD(header_base + 93)) +#define header_dfFirstChar (PFM_BYTE(header_base + 95)) +#define header_dfLastChar (PFM_BYTE(header_base + 96)) +#define header_dfDefaultChar (PFM_BYTE(header_base + 97)) + +#define ext_base 117 +#define ext_dfExtentTable (PFM_DWORD(ext_base + 6)) +#define ext_dfKernPairs (PFM_DWORD(ext_base + 14)) +#define ext_dfKernTrack (PFM_DWORD(ext_base + 18)) +#define ext_dfDriverInfo (PFM_DWORD(ext_base + 22)) + +#define etm_base 147 +#define etmCapHeight (PFM_SHORT(etm_base + 14)) +#define etmXHeight (PFM_SHORT(etm_base + 16)) +#define etmLowerCaseAscent (PFM_SHORT(etm_base + 18)) +#define etmLowerCaseDescent (PFM_SHORT(etm_base + 20)) +#define etmSlant (PFM_SHORT(etm_base + 22)) +#define etmUnderlineOffset (PFM_SHORT(etm_base + 32)) +#define etmUnderlineWidth (PFM_SHORT(etm_base + 34)) + +#define dfDevice 199 + +/* Windows font descriptor flags */ +#define PDF_FIXED_PITCH 0x01 /* Fixed width font; rarely used flag */ + +#define PDF_DONTCARE 0x00 /* Don't care or don't know. */ +#define PDF_ROMAN 0x10 /* Variable stroke width, serifed */ +#define PDF_SWISS 0x20 /* Variable stroke width, sans-serifed */ +#define PDF_MODERN 0x30 /* fixed pitch */ +#define PDF_SCRIPT 0x40 /* Cursive, etc. */ +#define PDF_DECORATIVE 0x50 /* Old English, etc. */ + +/* Windows character set flags */ +#define PFM_ANSI_CHARSET 0 +#define PFM_SYMBOL_CHARSET 2 +#define PFM_GREEK_CHARSET 161 +#define PFM_TURKISH_CHARSET 162 +#define PFM_VIETNAMESE_CHARSET 163 +#define PFM_HEBREW_CHARSET 177 +#define PFM_ARABIC_CHARSET 178 +#define PFM_BALTIC_CHARSET 186 +#define PFM_RUSSIAN_CHARSET 204 +#define PFM_THAI_CHARSET 222 +#define PFM_EASTEUROPE_CHARSET 238 + +static const pdc_keyconn pdf_charset_keylist[] = +{ + {"winansi", PFM_ANSI_CHARSET }, + {"", PFM_SYMBOL_CHARSET }, + {"cp1253", PFM_GREEK_CHARSET }, + {"cp1254", PFM_TURKISH_CHARSET }, + {"cp1258", PFM_VIETNAMESE_CHARSET}, + {"cp1255", PFM_HEBREW_CHARSET }, + {"cp1256", PFM_ARABIC_CHARSET }, + {"cp1257", PFM_BALTIC_CHARSET }, + {"cp1251", PFM_RUSSIAN_CHARSET }, + {"cp874", PFM_THAI_CHARSET }, + {"cp1250", PFM_EASTEUROPE_CHARSET}, + {NULL, 0}, +}; + +#define PDF_STRING_PostScript \ + ((const char*) "\120\157\163\164\123\143\162\151\160\164") + +/* + * Kerning pairs + */ +typedef struct kern_ +{ + pdc_byte first; /* First character */ + pdc_byte second; /* Second character */ + pdc_byte kern[2]; /* Kern distance */ +} +KERN; + +pdc_bool +pdf_check_pfm_encoding(PDF *p, pdf_font *font, pdc_encoding enc) +{ + const char *encname = + pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, + pdf_get_encoding_name(p, enc, font)); + const char *newencname = NULL; + pdc_encoding newenc = pdc_invalidenc; + pdc_bool issymbfont = pdc_undef; + + pdc_logg_cond(p->pdc, 2, trc_font, + "\tFont internal charset (dfCharSet): %d\n", font->ft.enc); + + /* Font encoding */ + newencname = pdc_get_keyword(font->ft.enc, pdf_charset_keylist); + if (newencname == NULL) + { + pdc_set_errmsg(p->pdc, PDF_E_T1_BADCHARSET, + pdc_errprintf(p->pdc, "%d", font->ft.enc), 0, 0, 0); + return pdc_false; + } + + if (strlen(newencname)) + { + int codepage = 0; + + pdc_logg_cond(p->pdc, 2, trc_font, + "\tFont internal encoding \"%s\" found\n", newencname); + + newenc = pdc_find_encoding(p->pdc, newencname); + if (newenc == pdc_invalidenc) + newenc = pdc_insert_encoding(p->pdc, newencname, &codepage, + pdc_true); + + font->ft.issymbfont = pdc_false; + } + else + { + pdc_logg_cond(p->pdc, 2, trc_font, "\tSymbol font\n"); + + font->ft.issymbfont = pdc_true; + newenc = pdc_builtin; + + /* auto */ + if (!strcmp(font->encapiname, "auto")) + { + issymbfont = pdc_true; + enc = pdc_builtin; + } + } + + /* builtin */ + if (enc == pdc_builtin) + issymbfont = pdc_true; + + /* unicode */ + if (enc == pdc_unicode) + { + font->unibyte = pdc_true; + issymbfont = pdc_false; + enc = newenc; + } + + /* encoding is subset of 8-bit encoding */ + if (enc >= pdc_winansi && newenc >= pdc_winansi) + { + if (pdc_is_encoding_subset(p->pdc, pdc_get_encoding_vector(p->pdc, enc), + pdc_get_encoding_vector(p->pdc, newenc))) + { + if (enc != pdc_winansi && newenc == pdc_winansi && + strcmp(encname, "iso8859-1")) + font->towinansi = pdc_invalidenc; + + issymbfont = pdc_false; + enc = newenc; + } + } + + /* illegal encoding */ + if (issymbfont == pdc_undef || font->ft.issymbfont == pdc_undef) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + return pdc_false; + } + + font->ft.enc = enc; + if (issymbfont && !font->ft.issymbfont) + { + pdc_warning(p->pdc, PDF_E_FONT_FORCEENC, + pdf_get_encoding_name(p, newenc, NULL), + 0, 0, 0); + font->ft.enc = newenc; + } + if (!issymbfont && font->ft.issymbfont) + { + pdc_warning(p->pdc, PDF_E_FONT_FORCEENC, + pdf_get_encoding_name(p, pdc_builtin, NULL), + 0, 0, 0); + font->ft.enc = pdc_builtin; + font->towinansi = pdc_invalidenc; + } + + if (font->towinansi != pdc_invalidenc) + pdf_transform_fontwidths(p, font, + pdc_get_encoding_vector(p->pdc, font->ft.enc), + pdc_get_encoding_vector(p->pdc, font->towinansi)); + + return pdc_true; +} + + +/* + * Currently we do not populate the following fields correctly: + * - serif flag + */ + +static pdc_bool +pdf_parse_pfm(PDF *p, pdc_file *fp, pdf_font *font) +{ + static const char fn[] = "pdf_parse_pfm"; + fnt_font_metric *ftm = &font->ft.m; + size_t length; + pdc_byte *pfm; + pdc_bool ismem; + int i, dfFirstChar, dfLastChar, default_width; + unsigned long dfExtentTable; + + /* read whole file and close it */ + pfm = (pdc_byte *) pdc_freadall(fp, &length, &ismem); + pdc_fclose(fp); + + /* check whether this is really a valid PostScript PFM file */ + if (pfm == NULL || + (header_dfVersion != 0x100 && header_dfVersion != 0x200) || + dfDevice > length || + strncmp((const char *) pfm + dfDevice, PDF_STRING_PostScript, 10) || + ext_dfDriverInfo > length) + { + if (!ismem) + pdc_free(p->pdc, pfm); + return pdc_false; + } + + /* fetch relevant data from the PFM */ + ftm->type = fnt_Type1; + + font->ft.name = pdc_strdup(p->pdc, (const char *)pfm + ext_dfDriverInfo); + ftm->name = pdc_strdup(p->pdc, font->ft.name); + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPostScript font name: \"%s\"\n", ftm->name); + + switch (header_dfPitchAndFamily & 0xF0) + { + case PDF_ROMAN: + ftm->flags |= FNT_SERIF; + break; + case PDF_MODERN: + /* Has to be ignored, contrary to MS's specs */ + break; + case PDF_SCRIPT: + ftm->flags |= FNT_SCRIPT; + break; + case PDF_DECORATIVE: + /* the dfCharSet flag lies in this case... */ + header_dfCharSet = PFM_SYMBOL_CHARSET; + break; + case PDF_SWISS: + case PDF_DONTCARE: + default: + break; + } + + /* temporarily */ + font->ft.enc = (pdc_encoding) header_dfCharSet; + + dfFirstChar = header_dfFirstChar; + dfLastChar = header_dfLastChar; + dfExtentTable = ext_dfExtentTable; + + /* + * Some rare PFMs do not contain any ExtentTable if the fixed pitch flag + * is set. Use the dfMaxWidth entry for all glyphs in this case. + * If the user forced the font to be monospaced we use this value instead. + */ + if ((!(header_dfPitchAndFamily & PDF_FIXED_PITCH) && dfExtentTable == 0) || + font->opt.monospace) + { + ftm->isFixedPitch = pdc_true; + default_width = font->opt.monospace ? font->opt.monospace : + (int) header_dfMaxWidth; + } + else + { + /* default values -- don't take the width of the default character */ + default_width = FNT_DEFAULT_WIDTH; + } + + font->ft.numcodes = 256; + ftm->numwidths = font->ft.numcodes; + ftm->widths = (int *) pdc_calloc(p->pdc, ftm->numwidths * sizeof(int), fn); + for (i = 0; i < font->ft.numcodes; i++) + ftm->widths[i] = default_width; + + if (!ftm->isFixedPitch) + { + if (ext_dfExtentTable == 0 || + ext_dfExtentTable + 2 * (header_dfLastChar-header_dfFirstChar) + 1 > + length) + { + if (!ismem) + pdc_free(p->pdc, pfm); + return pdc_false; + } + + for (i = dfFirstChar; i <= dfLastChar; i++) + ftm->widths[i] = + (int) PFM_WORD(dfExtentTable + 2 * (i - dfFirstChar)); + /* + * Check whether the font is actually opt.monospaced + * (the fixed pitch flag is not necessarily set) + */ + default_width = ftm->widths[dfFirstChar]; + + for (i = dfFirstChar+1; i <= dfLastChar; i++) + if (default_width != ftm->widths[i]) + break; + + if (i == dfLastChar + 1) + ftm->isFixedPitch = pdc_true; + } + + font->ft.weight = fnt_check_weight(header_dfWeight); + ftm->defwidth = default_width; + ftm->italicAngle = (header_dfItalic ? etmSlant/(10.0) : 0.0); + ftm->capHeight = etmCapHeight; + ftm->xHeight = etmXHeight; + ftm->descender = -etmLowerCaseDescent; + ftm->ascender = (int) header_dfAscent; + + ftm->underlinePosition = -etmUnderlineOffset; + ftm->underlineThickness = etmUnderlineWidth; + + ftm->urx = header_dfMaxWidth; + + + if (!ismem) + pdc_free(p->pdc, pfm); + + return pdc_true; +} + +pdc_bool +pdf_get_metrics_pfm( + PDF *p, + pdf_font *font, + const char *fontname, + pdc_encoding enc, + const char *filename, + pdc_bool requested) +{ + static const char fn[] = "pdf_get_metrics_pfm"; + char fullname[PDC_FILENAMELEN]; + pdc_file *pfmfile; + + (void) fontname; + + /* open PFM file */ + pfmfile = pdc_fsearch_fopen(p->pdc, filename, fullname, "PFM ", + PDC_FILE_BINARY); + if (pfmfile == NULL) + return pdc_check_fopen_errmsg(p->pdc, requested); + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tLoading PFM metric fontfile \"%s\":\n", fullname); + + /* Read PFM metrics */ + if (!pdf_parse_pfm(p, pfmfile, font)) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_CORRUPT, "PFM", fullname, 0, 0); + return pdc_false; + } + + /* save full filename */ + font->metricfilename = pdc_strdup_ext(p->pdc, fullname, 0, fn); + + /* Check encoding */ + if (!pdf_check_pfm_encoding(p, font, enc)) + return pdc_false; + + if (!pdf_make_fontflag(p, font)) + return pdc_false; + + return pdc_true; +} diff --git a/src/pdflib/pdflib/p_photoshp.c b/src/pdflib/pdflib/p_photoshp.c new file mode 100644 index 0000000..354f547 --- /dev/null +++ b/src/pdflib/pdflib/p_photoshp.c @@ -0,0 +1,23 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_photoshp.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib Photoshop image resource data routines + * + */ + +#define P_PHOTOSHP_C + +#include "p_intern.h" +#include "p_image.h" + diff --git a/src/pdflib/pdflib/p_png.c b/src/pdflib/pdflib/p_png.c new file mode 100644 index 0000000..42359a3 --- /dev/null +++ b/src/pdflib/pdflib/p_png.c @@ -0,0 +1,855 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_png.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PNG processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#if defined(__ia64__) && defined (__linux__) +#define PDF_ALIGN16 +#endif + +/* SPNG - Simple PNG +** +** The items below, prefixed with spng_, or SPNG_, establish a replacement +** for LIBPNG that works very fast, but processes simple PNG images only: +** - bit_depth <= 8 (no 16-bit) +** - interlace_type 0 (no interlacing) +** - color_type 0, 2, or 3 (no alpha-channel); color type 3 requires +** libpng for palette processing +*/ +#define SPNG_SIGNATURE "\211\120\116\107\015\012\032\012" + +#define SPNG_CHUNK_IHDR 0x49484452 +#define SPNG_CHUNK_PLTE 0x504C5445 +#define SPNG_CHUNK_tRNS 0x74524E53 +#define SPNG_CHUNK_IDAT 0x49444154 +#define SPNG_CHUNK_IEND 0x49454E44 + +/* spng_init() return codes +*/ +#define SPNG_ERR_OK 0 /* no error */ +#define SPNG_ERR_NOPNG 1 /* bad PNG signature */ +#define SPNG_ERR_FMT 2 /* bad PNG file format */ + +typedef struct +{ + /* from IHDR: + */ + int width; + int height; + pdc_byte bit_depth; + pdc_byte color_type; + pdc_byte compr_type; + pdc_byte filter_type; + pdc_byte interlace_type; +} spng_info; + +static int +spng_getint(pdc_file *fp) +{ + unsigned char buf[4]; + + if (!PDC_OK_FREAD(fp, buf, 4)) + return -1; + + return (int) pdc_get_be_long(buf); +} /* spng_getint */ + +static int +spng_init(PDF *p, pdf_image *image, spng_info *spi) +{ + pdc_file *fp = image->fp; + char buf[8]; + + (void) p; + + /* check signature + */ + if (!PDC_OK_FREAD(fp, buf, 8) || + strncmp(buf, SPNG_SIGNATURE, 8) != 0) + return SPNG_ERR_NOPNG; + + /* read IHDR + */ + if (spng_getint(fp) != 13 || + spng_getint(fp) != SPNG_CHUNK_IHDR) + return SPNG_ERR_FMT; + + spi->width = spng_getint(fp); + spi->height = spng_getint(fp); + + if (!PDC_OK_FREAD(fp, buf, 5)) + return SPNG_ERR_FMT; + + spi->bit_depth = (pdc_byte) buf[0]; + spi->color_type = (pdc_byte) buf[1]; + spi->compr_type = (pdc_byte) buf[2]; + spi->filter_type = (pdc_byte) buf[3]; + spi->interlace_type = (pdc_byte) buf[4]; + + (void) spng_getint(fp); /* CRC */ + + /* decide whether this image is "simple". + */ +#ifdef HAVE_LIBPNG + if (spi->bit_depth > 8 || spi->color_type > 3 || spi->interlace_type != 0) +#else + if (spi->bit_depth > 8 || spi->color_type > 2 || spi->interlace_type != 0) +#endif /* !HAVE_LIBPNG */ + { + image->use_raw = pdc_false; + return SPNG_ERR_OK; + } + else + image->use_raw = pdc_true; + + /* read (or skip) all chunks up to the first IDAT. + */ + for (/* */ ; /* */ ; /* */) + { + int len = spng_getint(fp); + int type = spng_getint(fp); + + switch (type) + { + case SPNG_CHUNK_IDAT: /* prepare data xfer */ + image->info.png.nbytes = (size_t) len; + return SPNG_ERR_OK; + + case -1: + return SPNG_ERR_FMT; + + /* if we decide to live without LIBPNG, + ** we should handle these cases, too. + */ + case SPNG_CHUNK_tRNS: /* transparency chunk */ + case SPNG_CHUNK_PLTE: /* read in palette */ + + default: + pdc_fseek(fp, len + 4, SEEK_CUR); + /* skip data & CRC */ + break; + } /* switch */ + } + + return SPNG_ERR_OK; +} /* spng_init */ + +#define PDF_PNG_BUFFERSIZE 8192 + +static void +pdf_data_source_PNG_init(PDF *p, PDF_data_source *src) +{ + static const char fn[] = "pdf_data_source_PNG_init"; + pdf_image *image = (pdf_image *) src->private_data; + +#ifdef HAVE_LIBPNG + if (image->use_raw) + { +#endif + src->buffer_length = PDF_PNG_BUFFERSIZE; + src->buffer_start = (pdc_byte *) + pdc_malloc(p->pdc, src->buffer_length, fn); + src->bytes_available = 0; + src->next_byte = src->buffer_start; + +#ifdef HAVE_LIBPNG + } + else + { + image->info.png.cur_line = 0; + src->buffer_length = image->info.png.rowbytes; + } +#endif +} + +#undef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static void +spng_error(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "PNG", + pdf_get_image_filename(p, image), 0, 0); +} /* spng_error */ + +static pdc_bool +pdf_data_source_PNG_fill(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + + PDC_TRY(p->pdc) + { +#ifdef HAVE_LIBPNG + if (image->use_raw) + { +#endif + pdc_file * fp = image->fp; + size_t buf_avail = src->buffer_length; + pdc_byte *scan = src->buffer_start; + + src->bytes_available = 0; + + if (image->info.png.nbytes == 0) + { + PDC_EXIT_TRY(p->pdc); + return pdc_false; + } + + do + { + size_t nbytes = min(image->info.png.nbytes, buf_avail); + + if (!PDC_OK_FREAD(fp, scan, nbytes)) + spng_error(p, src); + + src->bytes_available += nbytes; + scan += nbytes; + buf_avail -= nbytes; + + if ((image->info.png.nbytes -= nbytes) == 0) + { + /* proceed to next IDAT chunk + */ + (void) spng_getint(fp); /* CRC */ + image->info.png.nbytes = + (size_t) spng_getint(fp); /* length */ + + if (spng_getint(fp) != SPNG_CHUNK_IDAT) + { + image->info.png.nbytes = 0; + PDC_EXIT_TRY(p->pdc); + return pdc_true; + } + } + } + while (buf_avail); + +#ifdef HAVE_LIBPNG + } + else + { + if (image->info.png.cur_line == image->height) + { + PDC_EXIT_TRY(p->pdc); + return pdc_false; + } + + src->next_byte = image->info.png.raster + + image->info.png.cur_line * image->info.png.rowbytes; + + src->bytes_available = src->buffer_length; + + image->info.png.cur_line++; + } +#endif /* HAVE_LIBPNG */ + } + PDC_CATCH(p->pdc) + { + image->corrupt = pdc_true; + } + + return !image->corrupt; +} + +static void +pdf_data_source_PNG_terminate(PDF *p, PDF_data_source *src) +{ + pdf_image *image = (pdf_image *) src->private_data; + +#ifdef HAVE_LIBPNG + if (image->use_raw) + { +#endif + pdc_free(p->pdc, (void *) src->buffer_start); + +#ifdef HAVE_LIBPNG + } +#endif +} + +#ifdef HAVE_LIBPNG +/* + * We suppress libpng's warning message by supplying + * our own error and warning handlers +*/ +static void +pdf_libpng_warning_handler(png_structp png_ptr, png_const_charp message) +{ + (void) png_ptr; /* avoid compiler warning "unreferenced parameter" */ + (void) message; /* avoid compiler warning "unreferenced parameter" */ + + /* do nothing */ + return; +} + +/* + * use the libpng portability aid in an attempt to overcome version differences + */ +#ifndef png_jmpbuf +#define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +static void +pdf_libpng_error_handler(png_structp png_ptr, png_const_charp message) +{ +#ifdef PDF_ALIGN16 + jmp_buf jbuf; +#endif + + (void) message; /* avoid compiler warning "unreferenced parameter" */ + +#ifdef PDF_ALIGN16 + memcpy(jbuf, png_jmpbuf(png_ptr), sizeof (jmp_buf)); + longjmp(jbuf, 1); +#else + longjmp(png_jmpbuf(png_ptr), 1); +#endif +} + +static void * +pdf_libpng_malloc(png_structp png_ptr, size_t size) +{ + PDF *p = (PDF *)png_ptr->mem_ptr; + + return pdc_malloc(p->pdc, size, "libpng"); +} + +static void +pdf_libpng_free(png_structp png_ptr, void *mem) +{ + PDF *p = (PDF *)png_ptr->mem_ptr; + + pdc_free(p->pdc, mem); +} + +pdc_bool +pdf_is_PNG_file(PDF *p, pdc_file *fp) +{ + pdc_byte sig[8]; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type PNG...\n"); + + if (!PDC_OK_FREAD(fp, sig, 8) || !png_check_sig(sig, 8)) { + pdc_fseek(fp, 0L, SEEK_SET); + return pdc_false; + } + return pdc_true; +} + +static void /* CDPDF - moved to inside the HAVE_LIBPNG definition */ +pdf_png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + pdc_file *fp = (pdc_file *) png_ptr->io_ptr; + char *filename = (char *) pdc_file_name(fp); + + if (!PDC_OK_FREAD(fp, data, length)) + { + pdc_core *pdc = pdc_file_getpdc(fp); + + pdc_error(pdc, PDF_E_IMAGE_CORRUPT, "PNG", filename, 0, 0); + } +} + +int +pdf_process_PNG_data( + PDF *p, + int imageslot) +{ + static const char *fn = "pdf_process_PNG_data"; + pdc_file *save_fp; + spng_info s_info; +#ifdef PDF_ALIGN16 + jmp_buf jbuf; +#endif + + png_uint_32 width, height, ui; + png_bytep *row_pointers = NULL, trans; + png_color_8p sig_bit; + png_color_16p trans_values; + int bit_depth, color_type, i, num_trans; + pdc_scalar dpi_x, dpi_y; + pdf_image *image; + volatile int errcode = 0; + pdf_colorspace cs; + pdf_colormap * volatile colormap = NULL; + volatile int slot; + + image = &p->images[imageslot]; + + /* + * We can install our own memory handlers in libpng since + * our PNG library is specially extended to support this. + * A custom version of libpng without support for + * png_create_read_struct_2() is no longer supported. + */ + + image->info.png.png_ptr = + png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, + (png_error_ptr)pdf_libpng_error_handler, (png_error_ptr)pdf_libpng_warning_handler, /* CDPDF - added type cast */ + p, (png_malloc_ptr) pdf_libpng_malloc, + (png_free_ptr) pdf_libpng_free); + + if (!image->info.png.png_ptr) + { + pdc_error(p->pdc, PDC_E_MEM_OUT, fn, 0, 0, 0); + } + + image->info.png.info_ptr = png_create_info_struct(image->info.png.png_ptr); + + if (image->info.png.info_ptr == NULL) + { + png_destroy_read_struct(&image->info.png.png_ptr, + (png_infopp) NULL, (png_infopp) NULL); + pdc_error(p->pdc, PDC_E_MEM_OUT, fn, 0, 0, 0); + } + + /* due to alignment bug on itanium machines: + ** use well aligned local jbuf instead of sometimes + ** bad aligned (allocated) jmp_buf. + */ +#ifdef PDF_ALIGN16 + if (setjmp(jbuf)) +#else + if (setjmp(png_jmpbuf(image->info.png.png_ptr))) +#endif + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_PNG_ERROR; + } +#ifdef PDF_ALIGN16 + memcpy(png_jmpbuf(image->info.png.png_ptr), jbuf, sizeof (jmp_buf)); +#endif + + if (pdf_is_PNG_file(p, image->fp) == pdc_false) + { + errcode = PDC_E_IO_BADFORMAT; + goto PDF_PNG_ERROR; + } + + /* from file or from memory */ + png_set_read_fn(image->info.png.png_ptr, image->fp, (png_rw_ptr)pdf_png_read_data); /* CDPDF - added type cast */ + + png_set_sig_bytes(image->info.png.png_ptr, 8); + png_read_info(image->info.png.png_ptr, image->info.png.info_ptr); + png_get_IHDR(image->info.png.png_ptr, image->info.png.info_ptr, + &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); + + image->width = (pdc_scalar) width; + image->height = (pdc_scalar) height; + + /* reduce 16-bit images to 8 bit since PDF < 1.5 stops at 8 bit */ + if (p->compatibility < PDC_1_5 && bit_depth == 16) + { + png_set_strip_16(image->info.png.png_ptr); + bit_depth = 8; + } + + image->bpc = bit_depth; + + /* + * We currently don't support a real alpha channel but only binary + * tranparency ("poor man's alpha"). For palette images we do our best and + * treat alpha values of up to 50% as transparent, and values above 50% + * as opaque. Gray and RGB images with an associated alpha channel will + * be pre-multiplied by libpng (against white background). + */ +#define ALPHA_THRESHOLD 128 + + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* LATER: construct mask from alpha channel */ + /* + png_set_IHDR(image->info.png.png_ptr, image->info.png.info_ptr, + width, height, bit_depth, PNG_COLOR_MASK_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + */ + /* + * We strip the alpha channel, and let libpng pre-multiply + * the opacity values to the image data. + */ + png_set_strip_alpha(image->info.png.png_ptr); + /* fall through */ + + case PNG_COLOR_TYPE_GRAY: + if (png_get_sBIT(image->info.png.png_ptr, + image->info.png.info_ptr, &sig_bit)) + { + png_set_shift(image->info.png.png_ptr, sig_bit); + } + + image->colorspace = DeviceGray; + + image->components = 1; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + /* LATER: construct mask from alpha channel */ + /* + * We strip the alpha channel, and let libpng pre-multiply + * the opacity values to the image data. + */ + png_set_strip_alpha(image->info.png.png_ptr); + /* fall through */ + + case PNG_COLOR_TYPE_RGB: + if (image->colorspace == pdc_undef) + image->colorspace = DeviceRGB; + image->components = 3; + + break; + + case PNG_COLOR_TYPE_PALETTE: + { + png_colorp pcm; + + png_get_PLTE(image->info.png.png_ptr, image->info.png.info_ptr, + &pcm, &cs.val.indexed.palette_size); + + colormap = + (pdf_colormap *) pdc_malloc(p->pdc, sizeof(pdf_colormap), fn); + + /* This seems redundant, but the png_colorp structure may not + * be packed on some platforms. + */ + for (i = 0; i < cs.val.indexed.palette_size; i++) + { + (*colormap)[i][0] = (pdc_byte) pcm[i].red; + (*colormap)[i][1] = (pdc_byte) pcm[i].green; + (*colormap)[i][2] = (pdc_byte) pcm[i].blue; + } + + image->components = 1; + + /* This case should arguably be prohibited. However, we allow + * it and take the palette indices 0 and 1 as the mask, + * disregarding any color values in the palette. + */ + if (image->imagemask) { + image->colorspace = DeviceGray; + break; + } + + cs.type = Indexed; + cs.val.indexed.base = DeviceRGB; + cs.val.indexed.colormap = colormap; + cs.val.indexed.colormap_id = PDC_BAD_ID; + slot = pdf_add_colorspace(p, &cs, pdc_false); + + image->colorspace = slot; + + } + break; + } + if (colormap) + pdc_free(p->pdc, colormap); + + if (image->imagemask) + { + if (image->components != 1) + { + errcode = PDF_E_IMAGE_BADMASK; + goto PDF_PNG_ERROR; + } + + if (p->compatibility <= PDC_1_3) { + if (image->components != 1 || image->bpc != 1) + { + errcode = PDF_E_IMAGE_MASK1BIT13; + goto PDF_PNG_ERROR; + } + } + else if (image->bpc > 1) + { + /* images with more than one bit will be written as /SMask, + * and don't require an /ImageMask entry. + */ + image->imagemask = pdc_false; + } + image->colorspace = DeviceGray; + } + + /* we invert this flag later */ + if (image->ignoremask) + image->transparent = pdc_true; + + /* let libpng expand interlaced images */ + (void) png_set_interlace_handling(image->info.png.png_ptr); + + /* read the physical dimensions chunk to find the resolution values */ + dpi_x = (pdc_scalar) png_get_x_pixels_per_meter(image->info.png.png_ptr, + image->info.png.info_ptr); + dpi_y = (pdc_scalar) png_get_y_pixels_per_meter(image->info.png.png_ptr, + image->info.png.info_ptr); + + if (dpi_x != 0 && dpi_y != 0) + { /* absolute values */ + image->dpi_x = dpi_x * PDC_INCH2METER; + image->dpi_y = dpi_y * PDC_INCH2METER; + + } + else + { /* aspect ratio */ + image->dpi_y = -png_get_pixel_aspect_ratio(image->info.png.png_ptr, + image->info.png.info_ptr); + + if (image->dpi_y == 0) /* unknown */ + image->dpi_x = 0; + else + image->dpi_x = -1.0; + } + + /* read the transparency chunk */ + if (png_get_valid(image->info.png.png_ptr, image->info.png.info_ptr, + PNG_INFO_tRNS)) + { + png_get_tRNS(image->info.png.png_ptr, image->info.png.info_ptr, + &trans, &num_trans, &trans_values); + if (num_trans > 0) + { + if (color_type == PNG_COLOR_TYPE_GRAY) + { + image->transparent = !image->transparent; + /* LATER: scale down 16-bit transparency values ? */ + image->transval[0] = (pdc_byte) trans_values[0].gray; + + } + else if (color_type == PNG_COLOR_TYPE_RGB) + { + image->transparent = !image->transparent; + /* LATER: scale down 16-bit transparency values ? */ + image->transval[0] = (pdc_byte) trans_values[0].red; + image->transval[1] = (pdc_byte) trans_values[0].green; + image->transval[2] = (pdc_byte) trans_values[0].blue; + + } + else if (color_type == PNG_COLOR_TYPE_PALETTE) + { + /* we use the first transparent entry in the tRNS palette */ + for (i = 0; i < num_trans; i++) + { + if ((pdc_byte) trans[i] < ALPHA_THRESHOLD) + { + image->transparent = !image->transparent; + image->transval[0] = (pdc_byte) i; + break; + } + } + } + } + } + + + + + png_read_update_info(image->info.png.png_ptr, image->info.png.info_ptr); + + image->info.png.rowbytes = + png_get_rowbytes(image->info.png.png_ptr, image->info.png.info_ptr); + + image->info.png.raster = (pdc_byte *) + pdc_calloc(p->pdc,image->info.png.rowbytes * height, fn); + + row_pointers = (png_bytep *) + pdc_malloc(p->pdc, height * sizeof(png_bytep), fn); + + for (ui = 0; ui < height; ui++) + { + row_pointers[ui] = + image->info.png.raster + ui * image->info.png.rowbytes; + } + + /* try the simple way: + */ + save_fp = image->fp; + + image->src.init = pdf_data_source_PNG_init; + image->src.fill = pdf_data_source_PNG_fill; + image->src.terminate = pdf_data_source_PNG_terminate; + image->src.private_data = (void *) image; + + + image->fp = pdc_fsearch_fopen(p->pdc, image->filename, NULL, NULL, + PDC_FILE_BINARY); + if (image->fp != NULL && + spng_init(p, image, &s_info) == SPNG_ERR_OK && image->use_raw) + { + pdc_fclose(save_fp); + image->predictor = pred_png; + image->compression = pdf_comp_flate; + } + else + { + if (image->fp != (pdc_file *) 0) + pdc_fclose(image->fp); + + image->fp = save_fp; + + /* Provide a suitable background for images with alpha channel */ + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_color_16p image_background; + + if (png_get_bKGD(image->info.png.png_ptr, image->info.png.info_ptr, + &image_background)) + { + png_set_background(image->info.png.png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + } + else + { + png_color_16 my_white; + + if (bit_depth == 8) + { + my_white.red = 0xFF; + my_white.green = 0xFF; + my_white.blue = 0xFF; + my_white.gray = 0xFF; + } + else + { + my_white.red = 0xFFFF; + my_white.green = 0xFFFF; + my_white.blue = 0xFFFF; + my_white.gray = 0xFFFF; + } + + png_set_background(image->info.png.png_ptr, &my_white, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + + /* fetch the actual image data */ + png_read_image(image->info.png.png_ptr, row_pointers); + } + + image->in_use = pdc_true; /* mark slot as used */ + + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + pdc_free(p->pdc, image->info.png.raster); + if (row_pointers != NULL) + pdc_free(p->pdc, row_pointers); + + png_destroy_read_struct(&image->info.png.png_ptr, + &image->info.png.info_ptr, NULL); + + if (!image->corrupt) + return imageslot; + + PDF_PNG_ERROR: + { + const char *stemp = NULL; + + if (errcode) + { + png_destroy_read_struct(&image->info.png.png_ptr, + &image->info.png.info_ptr, NULL); + stemp = pdf_get_image_filename(p, image); + } + + switch (errcode) + { + case PDF_E_IMAGE_ICC: + case PDF_E_IMAGE_ICC2: + case PDF_E_IMAGE_MASK1BIT13: + case PDF_E_IMAGE_BADMASK: + pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0); + break; + + case PDC_E_IO_BADFORMAT: + pdc_set_errmsg(p->pdc, errcode, stemp, "PNG", 0, 0); + break; + + case PDF_E_IMAGE_CORRUPT: + pdc_set_errmsg(p->pdc, errcode, "PNG", stemp, 0, 0); + break; + + case 0: /* error code and message already set */ + break; + } + } + + return -1; +} + +#else /* !HAVE_LIBPNG */ + +pdc_bool +pdf_is_PNG_file(PDF *p, pdc_file *fp) +{ + return pdc_false; +} + +/* simple built-in PNG reader without libpng */ + +int +pdf_process_PNG_data( + PDF *p, + int imageslot) +{ + static const char fn[] = "pdf_process_PNG_data"; + spng_info s_info; + pdf_image *image; + + image = &p->images[imageslot]; + + image->src.init = pdf_data_source_PNG_init; + image->src.fill = pdf_data_source_PNG_fill; + image->src.terminate = pdf_data_source_PNG_terminate; + image->src.private_data = (void *) image; + + if (spng_init(p, image, &s_info) == SPNG_ERR_OK && image->use_raw) + { + image->predictor = pred_png; + image->compression = pdf_comp_flate; /* CDPDF - fixed function name */ + + image->width = (pdc_scalar) s_info.width; + image->height = (pdc_scalar) s_info.height; + image->bpc = s_info.bit_depth; + + image->components = 3; + + /* other types are rejected in spng_init() */ + image->colorspace = + (s_info.color_type == 0 ? DeviceGray : DeviceRGB); + + + + } + else + { + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "PNG", 0, 0, 0); + return -1; + } + + image->in_use = pdc_true; /* mark slot as used */ + + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + return image->corrupt ? -1 : imageslot; +} + +#endif /* !HAVE_LIBPNG */ diff --git a/src/pdflib/pdflib/p_shading.c b/src/pdflib/pdflib/p_shading.c new file mode 100644 index 0000000..e027ce6 --- /dev/null +++ b/src/pdflib/pdflib/p_shading.c @@ -0,0 +1,381 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_shading.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib routines for smooth shading + * + */ + +#include "p_intern.h" +#include "p_color.h" + +typedef enum +{ + shnone = 0, + axial = 2, + radial = 3 +} pdf_shadingtype_e; + +struct pdf_shading_s { + pdc_id obj_id; /* object id of this shading */ + pdc_bool used_on_current_page; /* this shading used on current page */ +}; + +void +pdf_init_shadings(PDF *p) +{ + int i; + + p->shadings_number = 0; + p->shadings_capacity = SHADINGS_CHUNKSIZE; + + p->shadings = (pdf_shading *) pdc_malloc(p->pdc, + sizeof(pdf_shading) * p->shadings_capacity, "pdf_init_shadings"); + + for (i = 0; i < p->shadings_capacity; i++) { + p->shadings[i].used_on_current_page = pdc_false; + p->shadings[i].obj_id = PDC_BAD_ID; + } +} + +static void +pdf_grow_shadings(PDF *p) +{ + int i; + + p->shadings = (pdf_shading *) pdc_realloc(p->pdc, p->shadings, + sizeof(pdf_shading) * 2 * p->shadings_capacity, "pdf_grow_shadings"); + + for (i = p->shadings_capacity; i < 2 * p->shadings_capacity; i++) { + p->shadings[i].used_on_current_page = pdc_false; + p->shadings[i].obj_id = PDC_BAD_ID; + } + + p->shadings_capacity *= 2; +} + +void +pdf_write_page_shadings(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->sh_bias; + + for (i = 0; i < p->shadings_number; i++) + if (p->shadings[i].used_on_current_page) + total++; + + if (total > 0 || bias) + { + pdc_puts(p->out, "/Shading"); + pdc_begin_dict(p->out); + } + + if (total > 0) + { + for (i = 0; i < p->shadings_number; i++) + { + if (p->shadings[i].used_on_current_page) + { + p->shadings[i].used_on_current_page = pdc_false; /* reset */ + pdc_printf(p->out, "/Sh%d", bias + i); + pdc_objref(p->out, "", p->shadings[i].obj_id); + } + } + + if (!bias) + pdc_end_dict(p->out); + } +} + +void +pdf_get_page_shadings(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->shadings_number; i++) { + if (p->shadings[i].used_on_current_page) { + p->shadings[i].used_on_current_page = pdc_false; /* reset */ + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_shading(PDF *p, int n) +{ + p->shadings[n].used_on_current_page = pdc_true; +} + +void +pdf_cleanup_shadings(PDF *p) +{ + if (p->shadings) { + pdc_free(p->pdc, p->shadings); + p->shadings = NULL; + } +} + +int +pdf_get_shading_painttype(PDF *p) +{ + return p->pattern[p->pattern_number - 1].painttype; +} + + +static const pdc_defopt pdf_shading_pattern_options[] = +{ + {"gstate", pdc_gstatehandle, 0, 1, 1, 0, 0, NULL}, + PDC_OPT_TERMINATE +}; + +int +pdf__shading_pattern(PDF *p, int shading, const char *optlist) +{ + pdc_resopt *results; + pdc_clientdata data; + int gstate = -1; + int retval = -1; + + if (p->compatibility == PDC_1_3) + pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); + + pdf_check_handle(p, shading, pdc_shadinghandle); + + if (optlist && strlen(optlist)) { + pdf_set_clientdata(p, &data); + results = pdc_parse_optionlist(p->pdc, + optlist, pdf_shading_pattern_options, &data, pdc_true); + + (void) pdc_get_optvalues("gstate", results, &gstate, NULL); + + pdc_cleanup_optionlist(p->pdc, results); + } + + if (p->pattern_number == p->pattern_capacity) + pdf_grow_pattern(p); + + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_end_contents_section(p); + + /* Pattern object */ + p->pattern[p->pattern_number].obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); + + /* Shadings don't have a painttype, but this signals to the + * code which writes the pattern usage that no color values + * will be required when setting the pattern color space. + */ + p->pattern[p->pattern_number].painttype = 1; + + pdc_begin_dict(p->out); /* Pattern dict*/ + + pdc_puts(p->out, "/PatternType 2\n"); /* shading pattern */ + + pdc_objref(p->out, "/Shading", p->shadings[shading].obj_id); + + p->shadings[shading].used_on_current_page = pdc_true; + + if (gstate != -1) + pdc_objref(p->out, "/ExtGState", pdf_get_gstate_id(p, gstate)); + + pdc_end_dict(p->out); /* Pattern dict*/ + pdc_end_obj(p->out); /* Pattern object */ + + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + retval = p->pattern_number; + p->pattern_number++; + return retval; +} + +void +pdf__shfill(PDF *p, int shading) +{ + int bias = p->curr_ppt->sh_bias; + + if (p->compatibility == PDC_1_3) + pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); + + pdf_check_handle(p, shading, pdc_shadinghandle); + + pdf_end_text(p); + pdc_printf(p->out, "/Sh%d sh\n", bias + shading); + + p->shadings[shading].used_on_current_page = pdc_true; +} + +static const pdc_defopt pdf_shading_options[] = +{ + {"N", pdc_scalarlist, PDC_OPT_NOZERO, 1, 1, 0, PDC_FLOAT_MAX, NULL}, + {"r0", pdc_scalarlist, PDC_OPT_NONE, 1, 1, 0, PDC_FLOAT_MAX, NULL}, + {"r1", pdc_scalarlist, PDC_OPT_NONE, 1, 1, 0, PDC_FLOAT_MAX, NULL}, + {"extend0", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 1, NULL}, + {"extend1", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 0, NULL}, + {"antialias", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 0, NULL}, + PDC_OPT_TERMINATE +}; + +int +pdf__shading( + PDF *p, + const char *type, + pdc_scalar x_0, pdc_scalar y_0, + pdc_scalar x_1, pdc_scalar y_1, + pdc_scalar c_1, pdc_scalar c_2, pdc_scalar c_3, pdc_scalar c_4, + const char *optlist) +{ + pdf_shadingtype_e shtype = shnone; + pdf_color *color0, color1; + pdf_colorspace *cs; + pdc_resopt *results; + pdc_scalar N = 1.0; + pdc_scalar r_0, r_1; + pdc_bool extend0 = pdc_false, extend1 = pdc_false, antialias = pdc_false; + int retval = -1; + + if (p->compatibility == PDC_1_3) + pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); + + if (!pdc_stricmp(type, "axial")) { + shtype = axial; + + } else if (!pdc_stricmp(type, "radial")) { + shtype = radial; + + } else + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0); + + pdc_check_number(p->pdc, "x_0", x_0); + pdc_check_number(p->pdc, "y_0", y_0); + pdc_check_number(p->pdc, "x_1", x_1); + pdc_check_number(p->pdc, "y_1", y_1); + pdc_check_number(p->pdc, "c_1", c_1); + pdc_check_number(p->pdc, "c_2", c_2); + pdc_check_number(p->pdc, "c_3", c_3); + pdc_check_number(p->pdc, "c_4", c_4); + + color0 = pdf_get_cstate(p, pdf_fill); + + color1.cs = color0->cs; + + cs = &p->colorspaces[color0->cs]; + + switch (cs->type) { + case DeviceGray: + color1.val.gray = c_1; + break; + + case DeviceRGB: + color1.val.rgb.r = c_1; + color1.val.rgb.g = c_2; + color1.val.rgb.b = c_3; + break; + + case DeviceCMYK: + color1.val.cmyk.c = c_1; + color1.val.cmyk.m = c_2; + color1.val.cmyk.y = c_3; + color1.val.cmyk.k = c_4; + break; + + + + default: + pdc_error(p->pdc, PDF_E_INT_BADCS, + pdc_errprintf(p->pdc, "%d", color0->cs), 0, 0, 0); + } + + results = pdc_parse_optionlist(p->pdc, + optlist, pdf_shading_options, NULL, pdc_true); + + (void) pdc_get_optvalues("N", results, &N, NULL); + + (void) pdc_get_optvalues("antialias", results, &antialias,NULL); + + if (shtype == radial) { + if (pdc_get_optvalues("r0", results, &r_0, NULL) != 1) + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "r0", 0, 0, 0); + + if (pdc_get_optvalues("r1", results, &r_1, NULL) != 1) + pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "r1", 0, 0, 0); + } + + if (shtype == axial) { + if (pdc_get_optvalues("r0", results, &r_0, NULL) == 1) + pdc_warning(p->pdc, PDC_E_OPT_IGNORED, "r0", 0, 0, 0); + + if (pdc_get_optvalues("r1", results, &r_1, NULL) == 1) + pdc_warning(p->pdc, PDC_E_OPT_IGNORED, "r1", 0, 0, 0); + } + + if (shtype == radial || shtype == axial) { + pdc_get_optvalues("extend0", results, &extend0, NULL); + pdc_get_optvalues("extend1", results, &extend1, NULL); + } + + pdc_cleanup_optionlist(p->pdc, results); + + if (p->shadings_number == p->shadings_capacity) + pdf_grow_shadings(p); + + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_end_contents_section(p); + + /* Shading object */ + p->shadings[p->shadings_number].obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); + + pdc_begin_dict(p->out); /* Shading dict*/ + + pdc_printf(p->out, "/ShadingType %d\n", (int) shtype); + + pdc_printf(p->out, "/ColorSpace"); + pdf_write_colorspace(p, color1.cs, pdc_false); + pdc_puts(p->out, "\n"); + + if (antialias) + pdc_printf(p->out, "/AntiAlias true\n"); + + switch (shtype) { + case axial: /* Type 2 */ + pdc_printf(p->out, "/Coords[%f %f %f %f]\n", x_0, y_0, x_1, y_1); + if (extend0 || extend1) + pdc_printf(p->out, "/Extend[%s %s]\n", + extend0 ? "true" : "false", extend1 ? "true" : "false"); + pdc_puts(p->out, "/Function"); + pdf_write_function_dict(p, color0, &color1, N); + break; + + case radial: /* Type 3 */ + pdc_printf(p->out, "/Coords[%f %f %f %f %f %f]\n", + x_0, y_0, r_0, x_1, y_1, r_1); + if (extend0 || extend1) + pdc_printf(p->out, "/Extend[%s %s]\n", + extend0 ? "true" : "false", extend1 ? "true" : "false"); + pdc_puts(p->out, "/Function"); + pdf_write_function_dict(p, color0, &color1, N); + break; + + default: + break; + } + + pdc_end_dict(p->out); /* Shading dict */ + pdc_end_obj(p->out); /* Shading object */ + + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + retval = p->shadings_number; + p->shadings_number++; + return retval; +} diff --git a/src/pdflib/pdflib/p_subsett.c b/src/pdflib/pdflib/p_subsett.c new file mode 100644 index 0000000..47eece6 --- /dev/null +++ b/src/pdflib/pdflib/p_subsett.c @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_subsett.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib subsetting routines + * + */ + +#include <time.h> + +#include "p_intern.h" +#include "p_font.h" + +#include "ft_truetype.h" +#include "pc_md5.h" + diff --git a/src/pdflib/pdflib/p_table.c b/src/pdflib/pdflib/p_table.c new file mode 100644 index 0000000..dc45525 --- /dev/null +++ b/src/pdflib/pdflib/p_table.c @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_table.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib table function + * + */ + +#define P_TABLE_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_defopt.h" +#include "p_font.h" +#include "p_tagged.h" + diff --git a/src/pdflib/pdflib/p_tagged.c b/src/pdflib/pdflib/p_tagged.c new file mode 100644 index 0000000..339b848 --- /dev/null +++ b/src/pdflib/pdflib/p_tagged.c @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_tagged.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib marked content routines + * + */ + +#define P_TAGGED_C + +#include "p_intern.h" +#include "p_layer.h" +#include "p_tagged.h" + + + + +#undef PDF_FEATURE_TAGGED + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pdflib/pdflib/p_tagged.h b/src/pdflib/pdflib/p_tagged.h new file mode 100644 index 0000000..8dab696 --- /dev/null +++ b/src/pdflib/pdflib/p_tagged.h @@ -0,0 +1,25 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_tagged.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib marked content header + * + */ + +#ifndef P_TAGGED_H +#define P_TAGGED_H + + + +#endif /* P_TAGGED_H */ + diff --git a/src/pdflib/pdflib/p_template.c b/src/pdflib/pdflib/p_template.c new file mode 100644 index 0000000..b6a4f6d --- /dev/null +++ b/src/pdflib/pdflib/p_template.c @@ -0,0 +1,246 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_template.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib template routines + * + */ + +#define P_TEMPLATE_C + +#include "p_intern.h" +#include "p_image.h" + + +int +pdf_embed_image(PDF *p, int im) +{ + pdf_image *image = &p->images[im]; + char optlist[2048], *ol; + pdc_scalar width, height; + int templ; + + width = image->width; + height = fabs(image->height); + + /* create option list */ + optlist[0] = 0; + ol = optlist; + + + if (image->iconname) + sprintf(ol, "iconname {%s}", image->iconname); + + /* create template */ + templ = pdf__begin_template(p, width, height, optlist); + + /* fit image */ + sprintf(optlist, "boxsize {%g %g} fitmethod meet", width, height); + pdf__fit_image(p, im, 0, 0, optlist); + + /* end template */ + pdf__end_template(p); + + return templ; +} + +#define PDF_OPIOPT_FLAG PDC_OPT_UNSUPP + +#define PDF_METADATA_FLAG PDC_OPT_UNSUPP + +#define PDF_LAYER_FLAG PDC_OPT_UNSUPP + +/* definitions of begin template options */ +static const pdc_defopt pdf_begin_template_options[] = +{ + {"topdown", pdc_booleanlist, PDC_OPT_NONE, 1, 1, 0.0, 0.0, NULL}, + + {"OPI-1.3", pdc_stringlist, PDF_OPIOPT_FLAG, 1, 1, 0.0, 32000.0, NULL}, + + {"OPI-2.0", pdc_stringlist, PDF_OPIOPT_FLAG | PDC_OPT_IGNOREIF1, + 1, 1, 0.0, 32000.0, NULL}, + + {"iconname", pdc_stringlist, 0, 1, 1, 1.0, PDF_MAX_NAMESTRING, NULL}, + + {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, + 0.0, PDC_INT_MAX, NULL}, + + {"layer", pdc_layerhandle, PDF_LAYER_FLAG, 1, 1, + 0.0, 0.0, NULL}, + + PDF_ERRORPOLICY_OPTION + + PDC_OPT_TERMINATE +}; + +/* Start a new template definition. */ +int +pdf__begin_template(PDF *p, pdc_scalar width, pdc_scalar height, + const char *optlist) +{ + pdf_image *image; + pdc_resopt *resopts; + const char *keyword; + pdc_clientdata cdata; + pdc_bool topdown; + char *iconname = NULL; + pdc_bool verbose = pdc_true; + int im = -1; + + pdc_check_number_limits(p->pdc, "width", width, + PDC_FLOAT_PREC, PDC_FLOAT_MAX); + pdc_check_number_limits(p->pdc, "height", height, + PDC_FLOAT_PREC, PDC_FLOAT_MAX); + + for (im = 0; im < p->images_capacity; im++) + if (!p->images[im].in_use) /* found free slot */ + break; + + if (im == p->images_capacity) + pdf_grow_images(p); + + image = &p->images[im]; + image->verbose = pdf_get_errorpolicy(p, NULL, image->verbose); + image->topdown_save = (p->ydirection == -1) ? pdc_true : pdc_false; + topdown = image->topdown_save; + image->in_use = pdc_true; /* mark slot as used */ + + /* parsing optlist */ + pdf_set_clientdata(p, &cdata); + resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_begin_template_options, + &cdata, pdc_true); + + /* save and check options */ + if (optlist && *optlist) + { + image->verbose = pdf_get_errorpolicy(p, resopts, image->verbose); + + keyword = "topdown"; + pdc_get_optvalues(keyword, resopts, &topdown, NULL); + + keyword = "iconname"; + if (pdc_get_optvalues(keyword, resopts, NULL, NULL)) + iconname = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + + + + + pdc_cleanup_optionlist(p->pdc, resopts); + } + + verbose = image->verbose; + + + + + + p->ydirection = topdown ? -1 : 1; + pdf_pg_suspend(p); + PDF_SET_STATE(p, pdf_state_template); + + /* form xobject */ + image->no = pdf_new_xobject(p, form_xobject, PDC_NEW_ID); + image->width = width; + image->height = height; + + p->templ = im; /* remember the current template id */ + + pdc_begin_dict(p->out); /* form xobject dict*/ + pdc_puts(p->out, "/Type/XObject\n"); + pdc_puts(p->out, "/Subtype/Form\n"); + + /* contrary to the PDF reference /FormType and /Matrix are required! */ + pdc_printf(p->out, "/FormType 1\n"); + pdc_printf(p->out, "/Matrix[1 0 0 1 0 0]\n"); + + p->res_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Resources", p->res_id); + + pdc_printf(p->out, "/BBox[0 0 %f %f]\n", width, height); + + + + + p->length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", p->length_id); + + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + + pdc_end_dict(p->out); /* form xobject dict*/ + + pdc_begin_pdfstream(p->out); + + /* top-down y-coordinates */ + pdf_set_topdownsystem(p, height); + + /* set color differing from PDF default */ + pdf_set_default_color(p, pdc_false); + + /* insert icon name */ + if (iconname) + { + pdc_id obj_id = pdf_get_xobject(p, im); + pdf_insert_name(p, iconname, names_ap, obj_id); + } + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin template %d]\n", p->templ); + + return im; +} + +/* Finish the template definition. */ +void +pdf__end_template(PDF *p) +{ + pdf_image *image = &p->images[p->templ]; + + /* check whether pdf__save() and pdf__restore() calls are balanced */ + if (p->curr_ppt->sl > 0) + pdc_error(p->pdc, PDF_E_GSTATE_UNMATCHEDSAVE, 0, 0, 0, 0); + + pdf_end_text(p); + pdc_end_pdfstream(p->out); + pdc_end_obj(p->out); /* form xobject */ + + pdc_put_pdfstreamlength(p->out, p->length_id); + + pdc_begin_obj(p->out, p->res_id); /* Resource object */ + pdc_begin_dict(p->out); /* Resource dict */ + + pdf_write_page_fonts(p); /* Font resources */ + + pdf_write_page_colorspaces(p); /* Color space resources */ + + pdf_write_page_pattern(p); /* Pattern resources */ + + pdf_write_xobjects(p); /* XObject resources */ + + pdf_write_page_extgstates(p); /* ExtGState resources */ + + pdc_end_dict(p->out); /* resource dict */ + pdc_end_obj(p->out); /* resource object */ + + pdf_pg_resume(p, -1); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + p->ydirection = image->topdown_save ? -1 : 1; + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End template %d]\n", p->templ); +} + + diff --git a/src/pdflib/pdflib/p_text.c b/src/pdflib/pdflib/p_text.c new file mode 100644 index 0000000..105df11 --- /dev/null +++ b/src/pdflib/pdflib/p_text.c @@ -0,0 +1,3715 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_text.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib text routines + * + */ + +#define P_TEXT_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_defopt.h" +#include "p_font.h" +#include "p_layer.h" +#include "p_tagged.h" + + +/* --------------------- Text state and options functions ------------------- */ + +struct pdf_tstate_s +{ + pdc_bool glyphinit; /* glyph description initialized */ + pdc_bool hsinit; /* horizontal scaling initialized */ + int mask; /* bit mask for text options */ + int font; /* slot number of the current font */ + int trm; /* text rendering mode */ + pdc_scalar fs; /* font size */ + pdc_scalar ld; /* leading */ + pdc_scalar cs; /* character spacing */ + pdc_scalar ws; /* word spacing */ + pdc_scalar hs; /* horizontal scaling */ + pdc_scalar ia; /* italic angle */ + pdc_bool fb; /* fake bold */ + pdc_scalar rise; /* text rise */ + pdc_scalar ulw; /* underline width */ + pdc_scalar ulp; /* underline position */ + + pdc_bool newpos; /* new text position */ + pdc_scalar currtx; /* x coordinate of current text position */ + pdc_scalar currty; /* y coordinate of current text position */ + pdc_scalar prevtx; /* x coordinate of previous text position */ + pdc_scalar prevty; /* y coordinate of previous text position */ + pdc_scalar linetx; /* x coordinate of text line start position */ + pdc_scalar refptx; /* x and y coordinate of reference position */ + pdc_scalar refpty; /* for moving to next text line start position*/ +}; + +/* Initialize the text state at the beginning of each page */ +void +pdf_init_tstate(PDF *p) +{ + static const char fn[] = "pdf_init_tstate"; + + /* text state */ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts; + + if (!p->curr_ppt->tstate) + { + p->curr_ppt->tstate = (pdf_tstate *) pdc_malloc(p->pdc, + PDF_MAX_SAVE_LEVEL * sizeof(pdf_tstate), fn); + ppt->currto = (pdf_text_options *) pdc_malloc(p->pdc, + sizeof(pdf_text_options), fn); + } + + ts = &ppt->tstate[ppt->sl]; + + ts->glyphinit = pdc_undef; + ts->hsinit = (p->ydirection == -1) ? pdc_false : pdc_true; + + ts->mask = 0; + ts->font = -1; + ts->trm = 0; + ts->fs = PDC_FLOAT_MIN; + ts->ld = 0; + ts->cs = 0; + ts->ws = 0; + ts->hs = 1; + ts->ia = 0; + ts->fb = pdc_false; + ts->rise = 0; + ts->ulw = PDF_UNDERLINEWIDTH_AUTO; + ts->ulp = PDF_UNDERLINEPOSITION_AUTO; + + ts->newpos = pdc_false; + ts->currtx = 0; + ts->currty = 0; + ts->prevtx = 0; + ts->prevty = 0; + ts->linetx = 0; + ts->refptx = 0; + ts->refpty = 0; + + /* current text options */ + pdf_init_text_options(p, ppt->currto); +} + +void +pdf_cleanup_page_tstate(PDF *p, pdf_ppt *ppt) +{ + if (ppt->tstate != NULL) + { + pdc_free(p->pdc, ppt->tstate); + pdc_free(p->pdc, ppt->currto); + ppt->tstate = NULL; + ppt->currto = NULL; + } +} + +void +pdf_save_tstate(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + int sl = ppt->sl; + + memcpy(&ppt->tstate[sl + 1], &ppt->tstate[sl], sizeof(pdf_tstate)); +} + +void +pdf_restore_currto(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_text_options *currto = ppt->currto; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + + currto->mask = ts->mask; + currto->font = ts->font; + currto->textrendering = ts->trm; + currto->fontsize = ts->fs; + currto->leading = ts->ld; + currto->charspacing = ts->cs; + currto->wordspacing = ts->ws; + currto->horizscaling = ts->hs; + currto->italicangle = ts->ia; + currto->fakebold = ts->fb; + currto->textrise = ts->rise; + currto->underlinewidth = ts->ulw; + currto->underlineposition = ts->ulp; +} + +void +pdf_set_tstate(PDF *p, pdc_scalar value, pdf_text_optflags tflag) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + pdf_text_options *currto = ppt->currto; + int ivalue = (int) value; + pdc_scalar prevvalue; + + /* text state parameter values can never be percentages */ + + switch (tflag) + { + case to_font: + pdf_check_handle(p, ivalue, pdc_fonthandle); + prevvalue = ts->font; + ts->font = currto->font = ivalue; + if (prevvalue != -1 && + (p->fonts[(int) prevvalue].metricflags & font_italic) != + (p->fonts[currto->font].metricflags & font_italic)) + currto->mask |= (1 << to_italicangle); + break; + + case to_textrendering: + if (ivalue < 0 || ivalue > PDF_LAST_TRMODE) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "textrendering", pdc_errprintf(p->pdc, "%d", ivalue), + 0, 0); + prevvalue = ts->trm; + ts->trm = currto->textrendering = ivalue; + break; + + case to_fontsize: + pdc_check_number_zero(p->pdc, "fontsize", value); + prevvalue = ts->ld; + ts->ld = currto->leading = value; + if (!PDC_FLOAT_ISNULL(value - prevvalue)) + currto->mask |= (1 << to_leading); + prevvalue = ts->fs; + ts->fs = currto->fontsize = value; + break; + + case to_leading: + prevvalue = ts->ld; + ts->ld = currto->leading = value; + break; + + case to_charspacing: + prevvalue = ts->cs; + ts->cs = currto->charspacing = value; + break; + + case to_wordspacing: + prevvalue = ts->ws; + ts->ws = currto->wordspacing = value; + break; + + case to_underlinewidth: + prevvalue = ts->ulw; + ts->ulw = currto->underlinewidth = value; + break; + + case to_underlineposition: + prevvalue = ts->ulp; + ts->ulp = currto->underlineposition = value; + break; + + case to_horizscaling: + pdc_check_number_zero(p->pdc, "horizscaling", value); + prevvalue = ts->hs; + ts->hs = currto->horizscaling = value; + break; + + case to_italicangle: + pdc_check_number_limits(p->pdc, "italicangle", value, + -90 + PDC_FLOAT_PREC, 90 + PDC_FLOAT_MAX); + prevvalue = ts->ia; + ts->ia = currto->italicangle = value; + break; + + case to_fakebold: + prevvalue = ts->fb; + ts->fb = currto->fakebold = (pdc_bool) ivalue; + return; + + case to_textrise: + prevvalue = ts->rise; + ts->rise = currto->textrise = value; + break; + + + case to_overline: + currto->overline = (pdc_bool) ivalue; + return; + + case to_strikeout: + currto->strikeout = (pdc_bool) ivalue; + return; + + case to_underline: + currto->underline = (pdc_bool) ivalue; + return; + + case to_textformat: + currto->textformat = (pdc_text_format) ivalue; + return; + + case to_charref: + currto->charref = (pdc_bool) ivalue; + return; + + case to_escapesequence: + currto->escapesequence = (pdc_bool) ivalue; + return; + + case to_glyphcheck: + currto->glyphcheck = (pdc_glyphcheck) ivalue; + return; + + case to_glyphwarning: + currto->glyphwarning = (pdc_bool) ivalue; + return; + + default: + return; + } + + if (!PDC_FLOAT_ISNULL(value - prevvalue)) + currto->mask |= (1 << tflag); + ts->mask = currto->mask; +} + +void +pdf__setfont(PDF *p, int font, pdc_scalar fontsize) +{ + pdf_set_tstate(p, (pdc_scalar) font, to_font); + pdf_set_tstate(p, fontsize, to_fontsize); +} + +void +pdf__set_text_pos(PDF *p, pdc_scalar x, pdc_scalar y) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + ts->newpos = pdc_true; + ts->currtx = x; + ts->currty = y; + ts->prevtx = ts->refptx; + ts->prevty = ts->refpty; + ts->linetx = x; +} + +double +pdf_get_tstate(PDF *p, pdf_text_optflags tflag) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_text_options *currto = ppt->currto; + + switch (tflag) + { + case to_font: + return (double) currto->font; + + case to_textrendering: + return (double) currto->textrendering; + + case to_fontsize: + return (double) currto->fontsize; + + case to_leading: + return (double) currto->leading; + + case to_charspacing: + return (double) currto->charspacing; + + case to_wordspacing: + return (double) currto->wordspacing; + + case to_horizscaling: + return (double) currto->horizscaling; + + case to_italicangle: + return (double) currto->italicangle; + + case to_fakebold: + return (double) currto->fakebold; + + case to_textrise: + return (double) currto->textrise; + + case to_underlinewidth: + return (double) currto->underlinewidth; + + case to_underlineposition: + return (double) currto->underlineposition; + + + case to_overline: + return (double) currto->overline; + + case to_strikeout: + return (double) currto->strikeout; + + case to_underline: + return (double) currto->underline; + + case to_textx: + return (double) ppt->tstate[ppt->sl].currtx; + + case to_texty: + return (double) ppt->tstate[ppt->sl].currty; + + default: + break; + } + + return 0; +} + +int +pdf_get_font(PDF *p) +{ + if (p->curr_ppt) + return (int) pdf_get_tstate(p, to_font); + return -1; +} + +void +pdf_init_text_options(PDF *p, pdf_text_options *to) +{ + to->mask = 0; + to->pcmask = 0; + to->font = -1; + to->fontsize = PDC_FLOAT_MIN; + to->fontsize_pc = 0; + to->fontsize_st = (int) text_fontsize; + to->fontset = 0; + to->leading = 0; + to->leading_pc = 0; + to->textrendering = 0; + to->charspacing = 0; + to->charspacing_pc = 0; + to->horizscaling = 1; + to->italicangle = 0; + to->fakebold = pdc_false; + to->textrise = 0; + to->textrise_pc = 0; + to->wordspacing = 0; + to->wordspacing_pc = 0; + to->underlinewidth = PDF_UNDERLINEWIDTH_AUTO; + to->underlineposition = PDF_UNDERLINEPOSITION_AUTO; + to->overline = pdc_false; + to->strikeout = pdc_false; + to->underline = pdc_false; + to->text = NULL; + to->textlen = 0; + to->textformat = p->textformat; + to->charref = p->pdc->charref; + to->escapesequence = p->pdc->escapesequ; + to->glyphcheck = p->glyphcheck; + to->glyphwarning = p->debug[(int) 'g']; + to->glyphwarning = pdf_get_errorpolicy(p, NULL, to->glyphwarning); + pdf_init_coloropt(p, &to->fillcolor); + pdf_init_coloropt(p, &to->strokecolor); + to->strokewidth = PDF_UNDERLINEWIDTH_AUTO; + to->dasharray[0] = 0; + to->dasharray[1] = 0; + to->xadvancelist = NULL; + to->nglyphs = 0; + to->link = NULL; +} + +static pdf_text_optflags pdf_toptflags[] = +{ + to_font, to_fontsize, to_textrendering, to_charspacing, + to_horizscaling, to_italicangle, to_wordspacing, to_textrise +}; + +void +pdf_set_text_options(PDF *p, pdf_text_options *to) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_text_options *currto = p->curr_ppt->currto; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + pdf_text_optflags tflag; + int i, n; + + /* we synchronize both text state and text options */ + + n = sizeof(pdf_toptflags) / sizeof(pdf_text_optflags); + for (i = 0; i < n; i++) + { + tflag = pdf_toptflags[i]; + if (to->mask & (1 << tflag)) + { + switch (tflag) + { + case to_font: + if (!(currto->mask & (1 << tflag)) && + to->font == currto->font) + break; + ts->font = currto->font = to->font; + continue; + + case to_fontsize: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->fontsize - currto->fontsize)) + break; + ts->fs = currto->fontsize = to->fontsize; + continue; + + case to_textrendering: + if (!(currto->mask & (1 << tflag)) && + to->textrendering == currto->textrendering) + break; + ts->trm = currto->textrendering = to->textrendering; + continue; + + /* to->leading is never used */ + + case to_charspacing: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->charspacing - currto->charspacing)) + break; + ts->cs = currto->charspacing = to->charspacing; + continue; + + case to_horizscaling: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->horizscaling - currto->horizscaling)) + break; + ts->hs = currto->horizscaling = to->horizscaling; + continue; + + case to_italicangle: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->italicangle - currto->italicangle)) + break; + ts->ia = currto->italicangle = to->italicangle; + continue; + + case to_fakebold: + ts->fb = currto->fakebold = to->fakebold; + continue; + + case to_wordspacing: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->wordspacing - currto->wordspacing)) + break; + ts->ws = currto->wordspacing = to->wordspacing; + continue; + + case to_textrise: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->textrise - currto->textrise)) + break; + ts->rise = currto->textrise = to->textrise; + continue; + + case to_underlinewidth: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->underlinewidth - + currto->underlinewidth)) + break; + ts->ulw = currto->underlinewidth = to->underlinewidth; + continue; + + case to_underlineposition: + if (!(currto->mask & (1 << tflag)) && + PDC_FLOAT_ISNULL(to->underlineposition - + currto->underlineposition)) + break; + ts->ulp = currto->underlineposition = to->underlineposition; + continue; + + default: + continue; + } + + to->mask &= ~(1 << tflag); + } + } + + ts->mask = currto->mask = to->mask; +} + +int +pdf_get_fontsize_option(PDF *p, int font, pdc_resopt *resopts, + pdc_scalar *fontsize) +{ + pdc_scalar fs[2], fm ; + int ns; + + /* *fontsize is initialized from outside */ + + fs[0] = 0; /* see "auto" */ + fs[1] = 0; + ns = pdc_get_optvalues("fontsize", resopts, (pdc_scalar *) fs, NULL); + if (ns == 1) + { + *fontsize = fs[0]; + } + else if (ns == 2) + { + int kind = (int) fs[0]; + + pdf_check_handle(p, font, pdc_fonthandle); + + switch(kind) + { + case text_xheight: + fm = (pdc_scalar) p->fonts[font].ft.m.xHeight; + break; + + case text_capheight: + fm = (pdc_scalar) p->fonts[font].ft.m.capHeight; + break; + + case text_ascender: + fm = (pdc_scalar) p->fonts[font].ft.m.ascender; + break; + + default: + fm = 1000.0; + break; + } + + *fontsize = fs[1] * 1000.0 / fm; + } + + return ns; +} + +pdc_bool +pdf_calculate_text_options(PDF *p, pdf_text_options *to, pdc_bool force, + pdc_scalar fontscale, pdc_scalar minfontsize, + pdc_scalar fontsizeref) +{ + pdc_bool kminfs = pdc_false; + + if (to->mask & (1 << to_fontsize) || force) + { + pdc_scalar fontsize; + + if (fontsizeref == 0) + fontsizeref = to->fontsize; + + if (to->pcmask & (1 << to_fontsize)) + fontsize = to->fontsize_pc * fontsizeref; + else + fontsize = fontscale * to->fontsize; + + if (to->fontsize_st != (int) text_fontsize) + { + pdf_font *currfont = &p->fonts[to->font]; + pdc_scalar fm; + + switch(to->fontsize_st) + { + case text_xheight: + fm = (pdc_scalar) currfont->ft.m.xHeight; + break; + + case text_capheight: + fm = (pdc_scalar) currfont->ft.m.capHeight; + break; + + case text_ascender: + fm = (pdc_scalar) currfont->ft.m.ascender; + break; + + default: + fm = 1000.0; + break; + } + + fontsize *= 1000.0 / fm; + } + + if (fontscale < 1.0 && fabs(fontsize) < minfontsize) + { + if (fontsize > 0) + fontsize = minfontsize; + else + fontsize = -minfontsize; + kminfs = pdc_true; + } + to->fontsize = fontsize; + + /* we reset relative fontsize specifications */ + if (to->mask & (1L << to_fontsize)) + { + to->pcmask &= ~(1 << to_fontsize); + to->fontsize_st = (int) text_fontsize; + } + } + + if ((to->mask & (1 << to_charspacing) || force) && + (to->pcmask & (1 << to_charspacing))) + { + to->charspacing = to->charspacing_pc * to->fontsize; + } + + if ((to->mask & (1 << to_wordspacing) || force) && + (to->pcmask & (1 << to_wordspacing))) + { + to->wordspacing = to->wordspacing_pc * to->fontsize; + } + + if ((to->mask & (1 << to_textrise) || force) && + (to->pcmask & (1 << to_textrise))) + { + to->textrise = to->textrise_pc * to->fontsize; + } + + /* maybe used in a future version */ + if ((to->mask & (1 << to_leading) || force) && + (to->pcmask & (1 << to_leading))) + { + to->leading = to->leading_pc * to->fontsize; + } + + return kminfs; +} + +void +pdf_get_text_options(PDF *p, pdf_text_options *to, pdc_resopt *resopts) +{ + char **strlist; + int i, inum; + pdc_scalar fs[2]; + + if (pdc_get_optvalues("glyphwarning", resopts, &to->glyphwarning, NULL)) + to->mask |= (1L << to_glyphwarning); + to->glyphwarning = pdf_get_errorpolicy(p, resopts, to->glyphwarning); + + if (pdc_get_optvalues("font", resopts, &to->font, NULL)) + { + pdf_check_handle(p, to->font, pdc_fonthandle); + to->mask |= (1L << to_font); + to->fontset |= (1L << to_font); + } + + fs[0] = 0; /* see "auto" */ + fs[1] = 0; + inum = pdc_get_optvalues("fontsize", resopts, (pdc_scalar *) fs, NULL); + if (inum) + { + i = inum - 1; + to->fontsize = fs[i]; + if (inum == 2) + to->fontsize_st = (int) fs[0]; + else + to->fontsize_st = (int) text_fontsize; + to->mask |= (1L << to_fontsize); + to->mask |= (1L << to_fontsize_st); + + if (pdc_is_lastopt_percent(resopts, i)) + { + to->pcmask |= (1 << to_fontsize); + to->fontsize_pc = to->fontsize; + } + else + to->pcmask &= ~(1 << to_fontsize); + + to->fontset |= (1L << to_fontsize); + } + + if (pdc_get_optvalues("charref", resopts, &to->charref, NULL)) + to->mask |= (1L << to_charref); + + if (pdc_get_optvalues("escapesequence", resopts, &to->escapesequence, NULL)) + to->mask |= (1L << to_escapesequence); + + if (pdc_get_optvalues("glyphcheck", resopts, &inum, NULL)) + { + to->glyphcheck = (pdc_glyphcheck) inum; + to->mask |= (1L << to_glyphcheck); + } + + if (pdc_get_optvalues("charspacing", resopts, &to->charspacing, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_charspacing); + to->charspacing_pc = to->charspacing; + } + else + to->pcmask &= ~(1 << to_charspacing); + to->mask |= (1L << to_charspacing); + } + + if (pdc_get_optvalues("horizscaling", resopts, &to->horizscaling, NULL)) + { + if (!pdc_is_lastopt_percent(resopts, 0)) + to->horizscaling /= 100.0; + to->mask |= (1L << to_horizscaling); + } + + if (pdc_get_optvalues("italicangle", resopts, &to->italicangle, NULL)) + to->mask |= (1L << to_italicangle); + + if (pdc_get_optvalues("fakebold", resopts, &to->fakebold, NULL)) + to->mask |= (1L << to_fakebold); + + + if (pdc_get_optvalues("overline", resopts, &to->overline, NULL)) + to->mask |= (1L << to_overline); + + if (pdc_get_optvalues("strikeout", resopts, &to->strikeout, NULL)) + to->mask |= (1L << to_strikeout); + + if (pdc_get_optvalues("textformat", resopts, &inum, NULL)) + { + to->textformat = (pdc_text_format) inum; + to->mask |= (1L << to_textformat); + pdf_check_textformat(p, to->textformat); + } + + if (pdc_get_optvalues("textrendering", resopts, &to->textrendering, NULL)) + to->mask |= (1L << to_textrendering); + + if (pdc_get_optvalues("textrise", resopts, &to->textrise, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_textrise); + to->textrise_pc = to->textrise; + } + else + to->pcmask &= ~(1 << to_textrise); + to->mask |= (1L << to_textrise); + } + + if (pdc_get_optvalues("underline", resopts, &to->underline, NULL)) + to->mask |= (1L << to_underline); + + if (pdc_get_optvalues("wordspacing", resopts, &to->wordspacing, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_wordspacing); + to->wordspacing_pc = to->wordspacing; + } + else + to->pcmask &= ~(1 << to_wordspacing); + to->mask |= (1L << to_wordspacing); + } + + if (pdc_get_optvalues("underlinewidth", resopts, &to->underlinewidth, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_underlinewidth); + } + else + to->pcmask &= ~(1 << to_underlinewidth); + to->mask |= (1L << to_underlinewidth); + } + + if (pdc_get_optvalues("underlineposition", resopts, + &to->underlineposition, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_underlineposition); + } + else + to->pcmask &= ~(1 << to_underlineposition); + to->mask |= (1L << to_underlineposition); + } + + inum = pdc_get_optvalues("fillcolor", resopts, NULL, &strlist); + if (inum) + { + pdf_parse_coloropt(p, "fillcolor", strlist, inum, (int) color_max, + &to->fillcolor); + to->mask |= (1L << to_fillcolor); + } + + inum = pdc_get_optvalues("strokecolor", resopts, NULL, &strlist); + if (inum) + { + pdf_parse_coloropt(p, "strokecolor", strlist, inum, (int) color_max, + &to->strokecolor); + to->mask |= (1L << to_strokecolor); + } + + if (pdc_get_optvalues("strokewidth", resopts, &to->strokewidth, NULL)) + { + if (pdc_is_lastopt_percent(resopts, 0)) + { + to->pcmask |= (1 << to_strokewidth); + } + else + to->pcmask &= ~(1 << to_strokewidth); + to->mask |= (1L << to_strokewidth); + } + + inum = pdc_get_optvalues("dasharray", resopts, to->dasharray, NULL); + if (inum) + { + if (inum == 1) + to->dasharray[1] = to->dasharray[0]; + to->mask |= (1L << to_dasharray); + } + + inum = pdc_get_optvalues("xadvancelist", resopts, NULL, &strlist); + if (inum) + { + to->xadvancelist = (pdc_scalar *) strlist; + to->nglyphs = inum; + } + + /* + * deprecated + */ + if (pdc_get_optvalues("weblink", resopts, NULL, &strlist)) + { + to->link = strlist[0]; + to->linktype = "URI"; + } + else if (pdc_get_optvalues("locallink", resopts, NULL, &strlist)) + { + to->link = strlist[0]; + to->linktype = "GoTo"; + } + else if (pdc_get_optvalues("pdflink", resopts, NULL, &strlist)) + { + to->link = strlist[0]; + to->linktype = "GoToR"; + } +} + +/* ------------------------ Text object functions -------------------------- */ + +static void +pdf_begin_text(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + pdf_text_options *currto = ppt->currto; + pdf_font *currfont = NULL; + + if (currto->font > -1) + currfont = &p->fonts[currto->font]; + + /* end text object if italicangle changed */ + if (currto->mask & (1L << to_italicangle)) + pdf_end_text(p); + + /* begin text object */ + if (!p->in_text) + { + p->in_text = pdc_true; + pdc_puts(p->out, "BT\n"); + } + + if (PDF_FORCE_OUTPUT() && ts->glyphinit == pdc_undef) + ts->glyphinit = pdc_false; + + if (currfont && + ((currto->mask & (1L << to_font)) || + (currto->mask & (1L << to_fontsize)) || !ts->glyphinit)) + { + pdc_printf(p->out, "/F%d %f Tf\n", + ppt->fn_bias + currto->font, p->ydirection * currto->fontsize); + + currfont->used_in_current_doc = pdc_true; + currfont->used_on_current_page = pdc_true; + } + + if (currto->mask & (1L << to_textrendering) || !ts->glyphinit) + pdc_printf(p->out, "%d Tr\n", currto->textrendering); + + if (currto->mask & (1L << to_leading) || !ts->glyphinit) + pdc_printf(p->out, "%f TL\n", p->ydirection * currto->leading); + + if (currto->mask & (1L << to_charspacing) || !ts->glyphinit) + pdc_printf(p->out, "%f Tc\n", p->ydirection * currto->charspacing); + + if (!ts->hsinit || currto->mask & (1L << to_horizscaling) || !ts->glyphinit) + pdc_printf(p->out, "%f Tz\n", + 100 * p->ydirection * currto->horizscaling); + + if (currto->mask & (1L << to_textrise) || !ts->glyphinit) + pdc_printf(p->out, "%f Ts\n", p->ydirection * currto->textrise); + + /* initialize */ + if (!ts->glyphinit) + ts->glyphinit = pdc_true; + ts->hsinit = pdc_true; + ts->mask = currto->mask = 0; +} + +void +pdf_end_text(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + + if (p->in_text) + { + p->in_text = pdc_false; + pdc_puts(p->out, "ET\n"); + + ts->newpos = pdc_false; + ts->prevtx = 0; + ts->prevty = 0; + ts->refptx = 0; + ts->refpty = 0; + } +} + +void +pdf_reset_tstate(PDF *p) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts = &ppt->tstate[ppt->sl]; + + pdf_set_tstate(p, 0, to_textrendering); + pdf_set_tstate(p, 0, to_leading); + pdf_set_tstate(p, 0, to_charspacing); + pdf_set_tstate(p, 0, to_wordspacing); + pdf_set_tstate(p, 1, to_horizscaling); + pdf_set_tstate(p, 0, to_italicangle); + pdf_set_tstate(p, 0, to_fakebold); + pdf_set_tstate(p, 0, to_textrise); + pdf_set_tstate(p, PDF_UNDERLINEWIDTH_AUTO, to_underlinewidth); + pdf_set_tstate(p, PDF_UNDERLINEPOSITION_AUTO, to_underlineposition); + + ts->hsinit = (p->ydirection == -1) ? pdc_false : pdc_true; + if (ts->mask || !ts->hsinit) + { + pdc_scalar ydirection = p->ydirection; + p->ydirection = 1; + pdf_begin_text(p); + pdf_end_text(p); + p->ydirection = ydirection; + } +} + + +/* ------------------- Text string checking function ---------------------- */ + +typedef struct pdf_ligat_s pdf_ligat; + +struct pdf_ligat_s +{ + pdf_ligat *next; + int icp; /* text position */ + int nb; /* number of parts */ + pdc_byte culist[2 * PDC_MAX_UVLIST]; + /* ligature parts */ +}; + +static pdf_ligat * +pdf_register_ligat(PDF *p, pdf_ligat *ligatlist, int icp, int nv, + pdc_ushort *culist, int charlen) +{ + static const char fn[] = "pdf_hook_ligat"; + int i; + + pdf_ligat *ligat = + (pdf_ligat *) pdc_malloc_tmp(p->pdc, sizeof(pdf_ligat), fn, NULL, NULL); + + if (ligatlist == NULL) + { + ligatlist = ligat; + } + else + { + pdf_ligat *next = ligatlist; + + while (next->next != NULL) + next = next->next; + next->next = ligat; + } + + ligat->next = NULL; + ligat->icp = charlen * icp; + nv--; + ligat->nb = charlen * nv; + + if (charlen == 1) + { + for (i = 0; i < nv; i++) + ligat->culist[i] = (pdc_byte) culist[i+1]; + } + else + { + memcpy(ligat->culist, &culist[1], (size_t) ligat->nb); + } + return ligatlist; +} + +static void +pdf_cleanup_ligat(PDF *p, pdf_ligat *list) +{ + pdf_ligat *next; + + while (list != NULL) + { + next = list->next; + pdc_free_tmp(p->pdc, list); + list = next; + } +} + + +#define PDF_MAX_GLYPHCHECKS 8 + +int +pdf_get_approximate_uvlist(PDF *p, pdf_font *currfont, pdc_encodingvector *ev, + int usv, pdc_bool replace, + pdc_ushort *uvlist, pdc_ushort *cglist) +{ + int cg = 0, nv = 1; + + (void) p; + (void) ev; + (void) usv; + + + if (cg <= 0) + { + if (replace) + { + cglist[0] = (pdc_ushort) currfont->replacementcode; + uvlist[0] = (pdc_ushort) currfont->replacementchar; + } + else + { + cglist[0] = 0; + uvlist[0] = 0; + } + nv = 1; + } + + return nv; +} + +static void +pdf_logg_glyph_replacement(PDF *p, int ic, int code, + pdc_encoding enc, int charlen, + pdc_ushort *uvlist, pdc_ushort *cglist, int nv) +{ + const char *glyphname; + int i; + + pdc_logg(p->pdc, "\t\tat text position %d: ", ic); + + if (charlen == 1) + pdc_logg(p->pdc, "code x%02X ", code); + else + pdc_logg(p->pdc, "U+%04X ", code); + + pdc_logg(p->pdc, "was replaced by: "); + if (nv > 1) + pdc_logg(p->pdc, "\n"); + + for (i = 0; i < nv; i++) + { + if (nv > 1) + pdc_logg(p->pdc, "\t\t\t"); + + if (charlen == 1) + pdc_logg(p->pdc, "code x%02X ", cglist[i]); + else + pdc_logg(p->pdc, "U+%04X ", uvlist[i]); + + if (enc >= 0) + { + if (charlen == 1) + pdc_logg(p->pdc, "U+%04X ", uvlist[i]); + else + pdc_logg(p->pdc, "code x%02X ", cglist[i]); + } + + glyphname = pdc_unicode2glyphname(p->pdc, uvlist[i]); + if (glyphname && strlen(glyphname)) + pdc_logg(p->pdc, "\"%s\"", glyphname); + + pdc_logg(p->pdc, "\n"); + } +} + +void +pdf_get_input_textformat(pdf_font *currfont, + pdc_text_format *intextformat, int *convflags) +{ + /* input text format */ + if (currfont->unibyte) + { + /* encoding=unicode, but 8-bit encoding ev is available */ + *convflags |= PDC_CONV_FORCEUTF16; + } + else if (currfont->codesize <= 1) + { + /* we must force bytes[2] source input format + * for 8-bit encodings because of "pass through mode". + */ + if (*intextformat == pdc_auto) + *intextformat = pdc_bytes; + else if (*intextformat == pdc_auto2) + *intextformat = pdc_bytes2; + } +} + +/* Converts and checks input text string. + * + * The function returns a pointer to an allocated temporary memory + * (pdc_malloc_tmp, pdc_free_tmp) containing the converted string + * if flag PDF_USE_TMPALLOC is set. + * + * If return value is -1 an error was occurred, otherwise >= 0. + * glyphcheck = none: the number of unmapped glyphs will be returned. + * + */ + +int +pdf_check_textstring(PDF *p, const char *text, int len, int flags, + pdf_text_options *to, pdc_byte **outtext_p, int *outlen, + int *outcharlen, pdc_bool verbose) +{ + static const char fn[] = "pdf_check_textstring"; + + pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_text); + pdc_bool logg2 = pdc_false; + pdf_font *currfont = &p->fonts[to->font]; + pdc_encoding enc = currfont->ft.enc; + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + pdc_encodingvector *inev = NULL; + pdc_encodingvector *outev = NULL; + + pdc_text_format intextformat = to->textformat; + pdc_text_format outtextformat = pdc_utf16; + + int charlen = 1, newcharlen = 1; + int convflags = PDC_CONV_NOBOM; + int unmapgids = 0; + + pdf_ligat *ligat, *ligatlist = NULL; + pdc_byte *intext = (pdc_byte *) text, *outtext = NULL; + int newlen = -1, maxlen, replchar; + + if (logg1) + { + logg2 = pdc_logg_is_enabled(p->pdc, 2, trc_text); + + if (logg2) + pdc_logg_hexdump(p->pdc, "input text", "\t\t", (char *) text, len); + else + pdc_logg(p->pdc, + "\tText will be checked and converted: \"%T\"\n", text, len); + + if (logg2) + { + pdc_logg(p->pdc, + "\t\tfont: \"%s\"\n" + "\t\tencoding: \"%s\"\n" + "\t\ttextformat: %s\n" + "\t\tcharref: %s\n" + "\t\tescapesequence: %s\n" + "\t\tglyphwarning: %s\n" + "\t\tglyphcheck: %s\n", + currfont->ft.name, + pdf_get_encoding_name(p, enc, currfont), + pdc_get_keyword(intextformat, pdf_textformat_keylist), + PDC_BOOLSTR(to->charref), + PDC_BOOLSTR(to->escapesequence), + PDC_BOOLSTR(to->glyphwarning), + pdc_get_keyword(to->glyphcheck, pdf_glyphcheck_keylist)); + + convflags |= PDC_CONV_LOGGING; + } + } + + /* text is passed through for CID fonts with non Unicode CMap */ + if (currfont->passthrough) + { + if (logg2) + pdc_logg(p->pdc, "\t\ttext is passed through as is\n"); + + outtext = (pdc_byte *) ((flags & PDF_USE_TMPALLOC) ? + pdc_malloc_tmp(p->pdc, (size_t) len + 2, fn, NULL, NULL) : + pdc_malloc(p->pdc, (size_t) len + 2, fn)); + memcpy(outtext, text, (size_t) len); + outtext[len] = 0; + outtext[len + 1] = 0; + *outlen = len; + + outtextformat = pdc_bytes; + } + else + { + + if (flags & PDF_FORCE_NEWALLOC) + convflags |= PDC_CONV_NEWALLOC; + + if (flags & PDF_USE_TMPALLOC) + convflags |= PDC_CONV_TMPALLOC; + + if (to->glyphcheck == (int) text_replace) + { + replchar = currfont->replacementchar; + } + else + { + replchar = (int) to->glyphcheck; + if (to->glyphcheck == text_error) + { + convflags |= PDC_CONV_ENCERROR; + if (flags & PDF_KEEP_CONTROL) + convflags |= PDC_CONV_KEEPLBCHAR; + } + } + + if (flags & PDF_KEEP_UNICODE || to->glyphcheck != text_nocheck) + inev = ev; + + + /* "Pass through mode" for 8-bit text. + * The encoding vector must be specified, because + * the text could emerge as a Unicode text due to a BOM. + */ + if ((enc >= 0 && inev == NULL) || + (enc == pdc_builtin && !(flags & PDF_KEEP_UNICODE))) + { + inev = ev; + outev = ev; + outtextformat = pdc_bytes; + } + + /* input text format */ + pdf_get_input_textformat(currfont, &intextformat, &convflags); + + /* convert to 8-bit or UTF-16 text string */ + if (pdc_convert_textstring(p->pdc, intextformat, currfont->codepage, + inev, + NULL, 0, + replchar, intext, len, + &outtextformat, outev, &outtext, outlen, + convflags, pdc_false)) + { + if (newlen > -1) + pdc_free_tmp(p->pdc, intext); + goto PDF_CHECK_TEXT_ERROR; + } + } + + if (newlen > -1) + pdc_free_tmp(p->pdc, intext); + + /* check text string */ + if (outtext != NULL && *outlen) + { + pdc_ushort *usouttext = (pdc_ushort *) outtext; + pdc_ushort uvlist[PDC_MAX_UVLIST]; + pdc_ushort cglist[PDC_MAX_UVLIST]; + pdc_bool kcheck = pdc_true; + int i = 0, nv = 1, icp = 0, usvp; + int code, gid, usv, ic; + + (void) i; + + /* storage length of a character */ + if (outtextformat == pdc_utf16) + { + charlen = 2; + newcharlen = 2; + } + + /* maximal text string length - found out emprirically! */ + maxlen = (currfont->codesize == 1) ? PDF_MAXARRAYSIZE : PDF_MAXDICTSIZE; + if (!(flags & PDF_KEEP_TEXTLEN) && *outlen > maxlen) + { + pdc_set_errmsg(p->pdc, PDF_E_TEXT_TOOLONG, + pdc_errprintf(p->pdc, "%d", maxlen), 0, 0, 0); + goto PDF_CHECK_TEXT_ERROR; + } + + len = *outlen / charlen; + switch (enc) + { + + + /* + * builtin + */ + case pdc_builtin: + if (charlen == 1 || !(flags & PDF_KEEP_UNICODE)) + newcharlen = 1; + for (ic = 0; ic < len; ic++) + { + if (charlen == 1) + code = (int) outtext[ic]; + else + code = (int) usouttext[ic]; + + if (code) + { + gid = fnt_get_glyphid(code, &currfont->ft); + + /* glyph id for code value not available */ + if (gid <= 0) + { + unmapgids++; + if (to->glyphcheck == text_error) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_CODENOTFOUND1, + pdc_errprintf(p->pdc, "x%02X", code), + currfont->ft.name, 0, 0); + goto PDF_CHECK_TEXT_ERROR; + } + else if (to->glyphcheck == text_replace) + { + pdc_warning(p->pdc, PDF_E_FONT_CODENOTFOUNDREP1, + pdc_errprintf(p->pdc, "x%02X", code), + currfont->ft.name, 0, 0); + code = currfont->replacementcode; + } + } + } + + if (newcharlen == 1) + outtext[icp] = (pdc_byte) code; + else + usouttext[icp] = (pdc_ushort) code; + icp++; + } + + break; + + + /* + * cid + */ + case pdc_cid: + /* + * pass through. check and temporary conversion in + * pdf_calculate_textsize(), because we want to keep native code. + */ + break; + + + /* + * encoding vector + */ + default: + if (charlen == 1 || !(flags & PDF_KEEP_UNICODE)) + newcharlen = 1; + for (ic = 0; ic < len; ic++) + { + if (charlen == 1) + { + code = (int) outtext[ic]; + usv = ev->codes[code]; + kcheck = code > 0; + } + else + { + usv = (int) usouttext[ic]; + code = pdc_get_encoding_bytecode(p->pdc, ev, + (pdc_ushort) usv); + if (code < 0) + code = 0; + kcheck = usv > 0; + } + + if ((flags & PDF_KEEP_CONTROL) && + pdc_is_linebreaking_relchar((pdc_ushort) usv)) + { + kcheck = pdc_false; + } + + /* glyph check */ + if (kcheck) + { + /* encoding vector hasn't defined [Uni]code */ + if (usv <= 0 || code <= 0) + { + unmapgids++; + if (to->glyphcheck == text_error) + { + if (usv <= 0) + { + pdc_set_errmsg(p->pdc, PDC_E_ENC_NOTDEF_CODE, + pdc_errprintf(p->pdc, "x%02X", code), + ev->apiname, 0, 0); + goto PDF_CHECK_TEXT_ERROR; + } + else if (code <= 0) + { + pdc_set_errmsg(p->pdc, PDC_E_ENC_NOTDEF_UNICODE, + pdc_errprintf(p->pdc, "%04X", usv), + ev->apiname, 0, 0); + goto PDF_CHECK_TEXT_ERROR; + } + } + else if (to->glyphcheck == text_replace) + { + usvp = (usv <= 0) ? code : usv; + nv = pdf_get_approximate_uvlist(p, currfont, ev, + usv, pdc_true, + uvlist, cglist); + usv = (int) uvlist[0]; + code = (int) cglist[0]; + + if (logg2) + { + pdf_logg_glyph_replacement(p, ic, usvp, + enc, charlen, uvlist, cglist, nv); + } + } + } + else + { + gid = fnt_get_glyphid(code, &currfont->ft); + + /* glyph id for code not available */ + if (gid <= 0 && currfont->gid0code != code) + { + unmapgids++; + if (to->glyphcheck == text_error) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_CODENOTFOUND2, + pdc_errprintf(p->pdc, "x%02X", code), + pdc_errprintf(p->pdc, "%04X", usv), + currfont->ft.name, 0); + goto PDF_CHECK_TEXT_ERROR; + } + else if (to->glyphcheck == text_replace) + { + pdc_warning(p->pdc, PDF_E_FONT_CODENOTFOUNDREP2, + pdc_errprintf(p->pdc, "x%02X", code), + pdc_errprintf(p->pdc, "%04X", usv), + currfont->ft.name, 0); + + usvp = (usv <= 0) ? code : usv; + nv = pdf_get_approximate_uvlist(p, currfont, ev, + usv, pdc_true, + uvlist, cglist); + usv = (int) uvlist[0]; + code = (int) cglist[0]; + + if (logg2) + { + pdf_logg_glyph_replacement(p, ic, usvp, + enc, charlen, uvlist, cglist, nv); + } + } + } + } + } + + if (newcharlen == 1) + { + outtext[icp] = (pdc_byte) code; + } + else + { + usouttext[icp] = (pdc_ushort) usv; + } + if (nv > 1) + { + if (newcharlen == 1) + ligatlist = pdf_register_ligat(p, ligatlist, icp, nv, + cglist, newcharlen); + else + ligatlist = pdf_register_ligat(p, ligatlist, + icp, nv, uvlist, newcharlen); + nv = 1; + } + icp++; + } + + break; + } + + if (icp) + { + /* calculate complete text length */ + len = newcharlen * icp; + if (ligatlist != NULL) + { + ligat = ligatlist; + while (ligat != NULL) + { + len += ligat->nb; + ligat = ligat->next; + } + } + + if (len != *outlen) + { + *outlen = len; + if (flags & PDF_USE_TMPALLOC) + outtext = (pdc_byte *) pdc_realloc_tmp(p->pdc, outtext, + (size_t) (*outlen + newcharlen), fn); + else + outtext = (pdc_byte *) pdc_realloc(p->pdc, outtext, + (size_t) (*outlen + newcharlen), fn); + outtext[*outlen] = 0; + if (newcharlen == 2) + outtext[*outlen + 1] = 0; + } + + /* insert ligature parts */ + if (ligatlist != NULL) + { + int nbrest, nbgap, nbmove = 0; + + len = newcharlen * icp; + ligat = ligatlist; + while (ligat != NULL) + { + nbgap = ligat->nb; + icp = ligat->icp + nbmove; + nbrest = len - icp; + icp += newcharlen; + ic = icp + nbgap; + + memmove(&outtext[ic], &outtext[icp], (size_t) nbrest); + memcpy(&outtext[icp], ligat->culist, (size_t) nbgap); + + nbmove += nbgap; + len += nbgap; + + ligat = ligat->next; + } + + pdf_cleanup_ligat(p, ligatlist); + } + } + } + + *outtext_p = outtext; + *outcharlen = newcharlen; + + if (logg1) + { + if (logg2) + pdc_logg_hexdump(p->pdc, "converted text", "\t\t", + (char *) outtext, *outlen); + else + pdc_logg(p->pdc, + "\tChecked and converted text of length %d: \"%T\"\n", + *outlen, outtext, *outlen); + } + return unmapgids; + + PDF_CHECK_TEXT_ERROR: + + if (outtext != NULL) + { + if (flags & PDF_USE_TMPALLOC) + pdc_free_tmp(p->pdc, outtext); + else + pdc_free(p->pdc, outtext); + } + + pdf_cleanup_ligat(p, ligatlist); + + if (verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + + *outtext_p = NULL; + *outlen = 0; + + return -1; +} + + +/* ------------------------ Text width functions ------------------------ */ + +/* Calculates the geometrical width and height of input text string + * depending on + * + * to->font, to->fontsize, to->kerning, + * to->charspacing, to->horizscaling, to->wordspacing, + * to->xadvancelist + * + * In the case of vertical writing mode the width is the maximum + * of all glyph widths and height the height of the text string. + * + */ + +pdc_scalar +pdf_calculate_textsize(PDF *p, const pdc_byte *text, int len, int charlen, + pdf_text_options *to, int breakchar, pdc_scalar *height, + pdc_bool verbose) +{ + pdf_font *currfont = &p->fonts[to->font]; + pdc_encoding enc = currfont->ft.enc; + pdc_byte *tmpstring = (pdc_byte *) text; + pdc_ushort *ustext = (pdc_ushort *) text; + pdc_scalar glwidth = 0, width = 0; + pdc_scalar font2user = to->fontsize / 1000.0; + pdc_bool kbreak = pdc_false; + int usv, ic, icc, numglyphs = 0, numspaces = 0; + + /* We cannot handle empty strings or fonts without widths info */ + if (!len || currfont->widthsmissing) + { + if (height) + *height = 0.0; + return width; + } + + if (enc != pdc_cid) + len /= charlen; + + for (ic = 0; ic < len; ) + { + icc = ic; + + { + if (charlen == 1) + { + usv = (int) text[ic]; + } + else if (enc == pdc_unicode) + { + usv = pdc_char16_to_char32(p->pdc, ustext, &ic, len, verbose); + } + else + { + usv = (int) ustext[ic]; + } + + /* count spaces */ + if (usv == (int) currfont->ft.spacechar) + numspaces++; + + /* break character */ + if (breakchar > 0) + kbreak = (usv == breakchar); + + ic++; + } + + /* start by adding in the width of the character */ + if (currfont->opt.monospace) + { + glwidth = (pdc_scalar) currfont->opt.monospace; + } + else + { + glwidth = (pdc_scalar) fnt_get_glyphwidth(usv, &currfont->ft); + if (glwidth == FNT_MISSING_WIDTH) + glwidth = currfont->ft.m.defwidth; + } + + /* count glyphs */ + numglyphs++; + + /* horizontal or vertical writing mode */ + if (!currfont->ft.vertical) + { + width += glwidth; + + + /* supplied glyph widths */ + if (icc < to->nglyphs) + { + pdc_scalar shift = to->xadvancelist[icc] / font2user - glwidth; + width += shift; + if (p->pdc->ptfrun) + shift = PDC_ROUND(1e10 * shift) / 1e10; + shift = PDC_ROUND(1e1 * shift) / 1e1; + to->xadvancelist[icc] = shift; + } + } + else + { + /* maximum of width */ + if (glwidth > width) + width = glwidth; + } + + /* length of text part ranging to decimal character */ + if (kbreak) + break; + } + + if (breakchar > 0 && !kbreak) + return 0; + + /* charspacing and wordspacing */ + if (!currfont->ft.vertical) + { + if (to->charspacing) + width += numglyphs * to->charspacing / font2user; + if (to->wordspacing) + width += numspaces * to->wordspacing / font2user; + if (height) + *height = 0.0; + } + else + { + /* height for positive y direction. + * Acrobat calculates with negative direction (see pdf_place_text). + */ + *height = numglyphs * (to->fontsize + -to->charspacing) + + numspaces * (-to->wordspacing); + } + + /* take horizontal scaling factor and font scaling factor into account */ + width *= font2user * to->horizscaling; + + if (tmpstring != text) + pdc_free_tmp(p->pdc, tmpstring); + + return width; + +} + +pdc_scalar +pdf_trim_textwidth(pdc_scalar width, pdf_text_options *to) +{ + if (!PDC_FLOAT_ISNULL(width)) + width -= to->horizscaling * to->charspacing; + + return width; +} + + +pdc_scalar +pdf__stringwidth(PDF *p, const char *text, int len, int font, + pdc_scalar fontsize) +{ + pdc_byte *utext; + int charlen; + pdc_scalar width = 0, height = 0; + pdf_text_options to = *p->curr_ppt->currto; + + if (text && len == 0) + len = (int) strlen(text); + if (text == NULL || len <= 0) + return width; + + pdf_check_handle(p, font, pdc_fonthandle); + + pdc_check_number_zero(p->pdc, "fontsize", fontsize); + + /* convert text string */ + to.font = font; + to.fontsize = fontsize; + pdf_check_textstring(p, text, len, PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC, + &to, &utext, &len, &charlen, pdc_true); + if (utext && len) + width = pdf_calculate_textsize(p, utext, len, charlen, + &to, -1, &height, pdc_true); + + return width; +} + + +/* ------------------------ Text output functions ------------------------ */ + +static void +pdf_convert_text_towinansi(PDF *p, const pdc_byte *fromtext, int len, + pdc_byte *totext, pdf_font *currfont) +{ + pdc_encodingvector *evfrom = + pdc_get_encoding_vector(p->pdc, currfont->ft.enc); + pdc_encodingvector *evto = + pdc_get_encoding_vector(p->pdc, currfont->towinansi); + int i; + + for (i = 0; i < len; i++) + totext[i] = pdc_transform_bytecode(p->pdc, evto, evfrom, fromtext[i]); +} + +void +pdf_put_fieldtext(PDF *p, const char *text, int font) +{ + if (pdc_is_utf8_bytecode(text)) + { + pdf_put_hypertext(p, text); + } + else + { + static const char fn[] = "pdf_put_fieldtext"; + pdf_font *currfont = &p->fonts[font]; + char *tmpstring = (char *) text; + int len = (int) pdc_strlen(text); + + if (len && currfont->towinansi != pdc_invalidenc && + !pdc_is_utf16be_unicode(text)) + { + /* Convert 8-bit code string to winansi */ + tmpstring = (char *) pdc_malloc_tmp(p->pdc, + (size_t) len, fn, NULL, NULL); + pdf_convert_text_towinansi(p, (pdc_byte *) text, len, + (pdc_byte *) tmpstring, currfont); + } + + pdc_put_pdfstring(p->out, tmpstring, len); + if (tmpstring != text) + pdc_free_tmp(p->pdc, tmpstring); + } +} + +static void +pdf_put_textstring(PDF *p, const pdc_byte *text, int len, int charlen, + pdf_font *currfont) +{ + static const char fn[] = "pdf_put_textstring"; + pdc_byte *tmpstring = (pdc_byte *) text; + + (void) charlen; + + if (len) + { + + /* Convert 8-bit code string to winansi */ + if (currfont->towinansi != pdc_invalidenc) + { + tmpstring = (pdc_byte *) pdc_malloc_tmp(p->pdc, + (size_t) len, fn, NULL, NULL); + pdf_convert_text_towinansi(p, text, len, tmpstring, currfont); + } + + } + + pdc_put_pdfstring(p->out, (char *) tmpstring, len); + if (tmpstring != text) + pdc_free_tmp(p->pdc, tmpstring); +} + +static void +pdf_put_textstring_shift(PDF *p, pdc_byte *text, int len, int charlen, + pdf_text_options *to, pdc_scalar spaceshift) +{ + pdf_font *currfont = &p->fonts[to->font]; + pdc_ushort *ustext = (pdc_ushort *) text; + pdc_byte *currtext; + pdc_scalar shift; + pdc_bool isutf16; + int currlen, nchars; + int leftchar = 0, rightchar; + int ic, icp, incr = charlen; + + currlen = 0; + currtext = text; + nchars = len/charlen; + isutf16 = charlen == 2 && + currfont->codesize == 2 && + currfont->ft.enc == pdc_unicode; + for (ic = 0; ic < nchars; ic++) + { + if (charlen == 1) + { + rightchar = (int) text[ic]; + } + else if(!isutf16) + { + rightchar = (int) ustext[ic]; + } + else + { + icp = ic; + rightchar = + pdc_char16_to_char32(p->pdc, ustext, &ic, nchars, pdc_true); + incr = (1 + ic - icp) * charlen; + } + + if (ic) + { + /* PDF wants the inverse shift amount + * (positive numbers move left, negative move right!) */ + + if (spaceshift != 0 && leftchar == (int) currfont->ft.spacechar) + shift = -spaceshift; + else + shift = 0; + + + if (ic <= to->nglyphs) + shift -= to->xadvancelist[ic-1]; + + if (shift) + { + pdf_put_textstring(p, currtext, currlen, charlen, currfont); + pdc_printf(p->out, "%f", shift); + currtext = &text[charlen * ic]; + currlen = 0; + } + } + leftchar = rightchar; + currlen += incr; + } + + pdf_put_textstring(p, currtext, currlen, charlen, currfont); + + if (to->nglyphs && to->nglyphs >= nchars) + pdc_printf(p->out, "%f", -to->xadvancelist[nchars - 1]); + +} + + +/* --------------------- General text placing function --------------------- */ + + +#define PDF_RENDERMODE_FILLCLIP 4 +#define PDF_ITALICANGLE_DEFAULT -12 + +static void +pdf_place_singletext(PDF *p, pdc_byte *text, int len, int charlen, + pdf_text_options *to, pdc_scalar tx, pdc_scalar ty, + pdc_scalar width, pdc_scalar height, pdc_scalar leading, + pdc_bool cont) +{ + pdf_tstate *ts = &p->curr_ppt->tstate[p->curr_ppt->sl]; + pdf_font *currfont = &p->fonts[to->font]; + pdc_scalar dx, dy, spaceshift = 0; + pdc_scalar font2user = to->fontsize / 1000.0; + pdc_scalar linewidth = 0; + pdc_scalar deflinewidth = 0; + pdc_bool hasdeco = to->underline || to->overline || to->strikeout; + pdc_bool takeTJ = pdc_false; + + /* default linewidth for underlinewidth and strokewidth */ + if (hasdeco || (to->mask & (1 << to_strokewidth))) + { + if (currfont->ft.m.underlineThickness == 0) + currfont->ft.m.underlineThickness = 50; + deflinewidth = fabs(to->horizscaling * font2user * + currfont->ft.m.underlineThickness); + } + + /* fill and stroke color */ + if (to->mask & (1 << to_fillcolor)) + pdf_set_coloropt(p, (int) pdf_fill, &to->fillcolor); + if (to->mask & (1 << to_strokecolor)) + pdf_set_coloropt(p, (int) pdf_stroke, &to->strokecolor); + + + /* stroke width and dasharray for stroked text */ + if (to->mask & (1 << to_strokewidth)) + { + if (to->strokewidth == PDF_UNDERLINEWIDTH_AUTO) + { + linewidth = deflinewidth; + } + else + { + linewidth = to->strokewidth; + if ((to->pcmask & (1 << to_strokewidth))) + linewidth *= fabs(to->fontsize); + } + pdf__setlinewidth(p, linewidth); + } + if (to->mask & (1 << to_dasharray)) + pdf__setdash(p, to->dasharray[0], to->dasharray[1]); + + /* text decoration */ + if (width && hasdeco) + { + pdc_scalar scale = fabs(to->horizscaling); + pdc_scalar delta, fs, trise, lineheight; + pdc_scalar txe = 0, tye = 0; + pdc_scalar lineposition = 0; + + fs = p->ydirection * font2user; + trise = p->ydirection * to->textrise; + lineheight = fs * currfont->ft.m.ascender; + delta = scale * (fs * currfont->ft.m.underlinePosition + trise); + + pdf__save(p); + + if (to->underlinewidth == PDF_UNDERLINEWIDTH_AUTO) + { + linewidth = deflinewidth; + } + else + { + linewidth = to->underlinewidth; + if ((to->pcmask & (1 << to_underlinewidth))) + linewidth *= fabs(to->fontsize); + } + + if (to->underlineposition == PDF_UNDERLINEPOSITION_AUTO) + { + lineposition = delta; + } + else + { + lineposition = p->ydirection * to->underlineposition; + if ((to->pcmask & (1 << to_underlineposition))) + lineposition *= to->fontsize; + } + + if (!currfont->ft.vertical) + { + txe = tx + width; + } + else + { + txe = tx - width / 2.0; + tye = ty - p->ydirection * height; + lineposition *= p->ydirection; + delta = fabs(delta); + } + + pdf__setlinecap(p, 0); + if (!(to->mask & (1 << to_dasharray))) + pdf__setdash(p, 0, 0); + + if (to->underline) + { + pdf__setlinewidth(p, linewidth); + if (!currfont->ft.vertical) + { + pdf__moveto(p, tx, ty + lineposition); + pdf__lineto(p, txe, ty + lineposition); + } + else + { + pdf__moveto(p, txe + lineposition, ty); + pdf__lineto(p, txe + lineposition, tye); + } + pdf__stroke(p); + } + + if (to->strikeout) + { + pdf__setlinewidth(p, deflinewidth); + if (!currfont->ft.vertical) + { + pdf__moveto(p, tx, ty + lineheight/2 + delta); + pdf__lineto(p, txe, ty + lineheight/2 + delta); + } + else + { + pdf__moveto(p, tx, ty); + pdf__lineto(p, tx, tye); + } + pdf__stroke(p); + } + + if (to->overline) + { + pdf__setlinewidth(p, deflinewidth); + if (!currfont->ft.vertical) + { + delta = scale * (fs * currfont->ft.m.underlinePosition - trise); + pdf__moveto(p, tx, ty + lineheight - delta); + pdf__lineto(p, txe, ty + lineheight - delta); + } + else + { + pdf__moveto(p, txe + width + delta, ty); + pdf__lineto(p, txe + width + delta, tye); + } + pdf__stroke(p); + } + + pdf__restore(p); + } + + + + /* wordspacing */ + if (!PDC_FLOAT_ISNULL(to->wordspacing)) + { + spaceshift = to->wordspacing / font2user; + if (p->pdc->ptfrun) + spaceshift = PDC_ROUND(1e10 * spaceshift) / 1e10; + spaceshift = PDC_ROUND(1e1 * spaceshift) / 1e1; + takeTJ = PDC_FLOAT_ISNULL(spaceshift) ? pdc_false : pdc_true; + } + + + /* supplied glyph widths */ + if (!takeTJ) + takeTJ = to->nglyphs; + + /* begin text object */ + pdf_begin_text(p); + + /* italic angle - realized by Tm operator */ + if (!PDC_FLOAT_ISNULL(to->italicangle) || + currfont->metricflags & font_italic) + { + if (!currfont->ft.vertical) + { + pdc_scalar italicangle = -p->ydirection * to->italicangle; + + if (currfont->metricflags & font_italic && italicangle == 0) + italicangle = -p->ydirection * PDF_ITALICANGLE_DEFAULT; + + if (ts->hs < 0) + italicangle = -italicangle; + + pdc_printf(p->out, "1 0 %f 1 %f %f Tm\n", + tan(italicangle * PDC_DEG2RAD), tx, ty); + + cont = pdc_false; + ts->newpos = pdc_false; + ts->refptx = tx; + ts->refpty = ty; + } + else + { + pdc_error(p->pdc, PDF_E_TEXT_ITALUNSUPP, 0, 0, 0, 0); + } + } + else + { + /* components of text displacement vector */ + if (!cont) + { + dx = tx - ts->prevtx; + dy = ty - ts->prevty; + } + else + { + dx = tx - ts->refptx; + dy = ty - ts->refpty + leading; + } + + /* condition for text displacement operator Td */ + if (!PDC_FLOAT_ISNULL(dx) || !PDC_FLOAT_ISNULL(dy) || + ts->newpos || (cont && takeTJ)) + { + if (cont) + { + dy -= leading; + cont = pdc_false; + } + pdc_printf(p->out, "%f %f Td\n", dx, dy); + + /* new reference position for next line */ + ts->newpos = pdc_false; + ts->refptx = tx; + ts->refpty = ty; + } + else + { + ts->refpty -= leading; + } + } + + /* show text */ + if (!takeTJ) + { + pdf_put_textstring(p, text, len, charlen, currfont); + if (!cont) + pdc_puts(p->out, "Tj\n"); + else + pdc_puts(p->out, "'\n"); + } + else + { + pdc_puts(p->out, "["); + pdf_put_textstring_shift(p, text, len, charlen, to, spaceshift); + pdc_puts(p->out, "]TJ\n"); + } + + /* new text position */ + if (!currfont->ft.vertical) + { + ts->currtx = tx + width; + ts->currty = ty; + } + else + { + ts->currtx = tx; + ts->currty = ty - p->ydirection * height; + } + ts->prevtx = ts->currtx; + ts->prevty = ts->currty; + + if (to->textrendering >= PDF_RENDERMODE_FILLCLIP) + pdf_end_text(p); +} + +#define PDF_FAKEBOLD_OFFSET 0.03 /* 3% of font size */ + +void +pdf_place_text(PDF *p, pdc_byte *text, int len, int charlen, + pdf_text_options *to, pdc_scalar width, pdc_scalar height, + pdc_bool cont) +{ + pdf_tstate *ts = &p->curr_ppt->tstate[p->curr_ppt->sl]; + pdf_font *currfont = &p->fonts[to->font]; + pdc_scalar tx, ty, leading = 0; + + /* text position */ + if (!cont) + { + tx = ts->currtx; + ty = ts->currty; + } + else + { + leading = p->ydirection * to->leading; + tx = ts->linetx; + ty = ts->currty - leading; + } + + pdf_place_singletext(p, text, len, charlen, to, tx, ty, + width, height, leading, cont); + + /* text bolding */ + if (to->fakebold || currfont->metricflags & font_bold) + { + static const pdc_scalar fx[] = {0, 0.70711, 1}; + static const pdc_scalar fy[] = {1, 0.70711, 0}; + pdc_scalar offset, currtx, currty, linetx; + int it, nt = 3; + + offset = PDF_FAKEBOLD_OFFSET * to->fontsize; + + linetx = ts->linetx; + currtx = ts->currtx; + currty = ts->currty; + for (it = 0; it < nt; it++) + { + pdf__set_text_pos(p, tx + fx[it] * offset, + ty + p->ydirection * fy[it] * offset); + pdf_place_singletext(p, text, len, charlen, to, + ts->currtx, ts->currty, + width, height, leading, pdc_false); + } + pdf__set_text_pos(p, currtx, currty); + ts->linetx = linetx; + } +} + +/* --------------------- Simple text showing functions --------------------- */ + +void +pdf__show_text( + PDF *p, + const char *text, + int len, + pdc_bool cont) +{ + static const char *fn = "pdf__show_text"; + pdf_text_options *currto = p->curr_ppt->currto; + pdc_byte *utext = NULL; + int charlen = 1; + pdc_scalar width = 0, height = 0; + + if (text && len == 0) + len = (int) strlen(text); + if (text == NULL || len <= 0) + { + if (cont) + len = 0; + else + return; + } + + /* no font set */ + if (currto->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); + + if (len) + { + /* convert text string */ + pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC, + currto, &utext, &len, &charlen, pdc_true); + if (utext == NULL || (!cont && !len)) + return; + + /* width and height of text string */ + width = pdf_calculate_textsize(p, utext, len, charlen, + currto, -1, &height, pdc_true); + } + else + { + utext = (pdc_byte *) pdc_calloc_tmp(p->pdc, 2, fn, NULL, NULL); + } + + + /* place text */ + pdf_place_text(p, utext, len, charlen, currto, width, height, cont); +} + + +/* ---------- Text showing function with explicit glyph widths ---------- */ + +void +pdf__xshow(PDF *p, const char *text, int len, const pdc_scalar *xadvancelist) +{ + static const char *fn = "pdf__xshow"; + pdf_text_options *currto = p->curr_ppt->currto; + pdc_byte *utext = NULL; + int charlen = 1; + size_t nbytes = 0; + pdc_scalar width, height; + + if (text && len == 0) + len = (int) strlen(text); + if (text == NULL || !len) + return; + + /* no font set */ + if (currto->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); + + /* convert text string */ + pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC, + currto, &utext, &len, &charlen, pdc_true); + if (utext == NULL || !len) + return; + + /* allocating glyph widths arrays */ + nbytes = (size_t) (len / charlen) * sizeof(pdc_scalar); + currto->xadvancelist = (pdc_scalar *) pdc_malloc_tmp(p->pdc, + nbytes, fn, NULL, NULL); + memcpy(currto->xadvancelist, xadvancelist, nbytes); + currto->nglyphs = len / charlen; + + /* length of text */ + width = pdf_calculate_textsize(p, utext, len, charlen, + currto, -1, &height, pdc_true); + + + /* place text */ + pdf_place_text(p, utext, len, charlen, currto, width, height, pdc_false); + + currto->xadvancelist = NULL; + currto->nglyphs = 0; +} + + +/* --------------------------- Leader functions ---------------------------- */ + + + +/* ----------------------- Text fitting function ------------------------ */ + +struct pdf_fittext_s +{ + pdc_vector start; /* text start position */ + pdc_vector end; /* text end position */ + pdc_vector writingdir; /* unit vector of text writing direction */ + pdc_vector perpendiculardir;/* unit vector perpendicular to writing dir. */ + pdc_vector scale; /* x/y scaling */ + pdc_scalar angle; /* rotation angle of writingdir in degree */ + pdc_scalar width; /* textline width */ + pdc_scalar height; /* textline height */ + pdc_scalar mwidth; /* textline width with margins */ + pdc_scalar mheight; /* textline height with margins */ + pdc_scalar ascender; /* textline ascender */ + pdc_scalar capheight; /* textline capheight */ + pdc_scalar xheight; /* textline xheight */ + pdc_scalar descender; /* textline descender */ +}; + + +/* definitions of fit text options */ +static const pdc_defopt pdf_fit_textline_options[] = +{ + PDF_TEXT_OPTIONS + + {"xadvancelist", pdc_scalarlist, PDC_OPT_NOZERO, 0, PDC_USHRT_MAX, + PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, + + PDF_FIT_OPTIONS1 + PDF_FIT_OPTIONS2 + PDF_FIT_OPTIONS6 + + PDF_FONT_OPTIONS1 + PDF_FONT_OPTIONS2 + + PDF_ERRORPOLICY_OPTION + PDC_OPT_TERMINATE +}; + +pdc_resopt * +pdf_parse_fittextline_optlist(PDF *p, pdf_text_options *to, + pdf_fit_options *fit, const char *optlist) +{ + pdc_resopt *resopts = NULL; + pdf_font_options fo; + + /* *to must be initialized */ + + /* initialize fit options */ + pdf_init_fit_options(p, pdc_false, fit); + fit->flags |= is_textline; + + /* initialize font options */ + pdf_init_font_options(p, &fo); + fo.flags |= is_textline; + + /* parsing option list */ + if (optlist && strlen(optlist)) + { + pdc_clientdata data; + + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_fit_textline_options, &data, pdc_true); + + pdf_get_font_options(p, &fo, resopts); + pdf_get_text_options(p, to, resopts); + pdf_get_fit_options(p, pdc_false, fit, resopts); + } + + /* font options specified */ + if (fo.mask & (1 << fo_fontname) && fo.mask & (1 << fo_encoding)) + { + to->font = pdf_load_font_internal(p, &fo); + to->mask |= (1L << to_font); + to->fontset |= (1L << to_font); + } + else + { + pdf_cleanup_font_options(p, &fo); + } + + return resopts; +} + +static pdc_bool +pdf_parse_textline_options(PDF *p, const char *text, int len, + pdf_text_options *to, pdf_fit_options *fit, + const char *optlist) +{ + pdf_ppt *ppt = p->curr_ppt; + + if (text && len == 0) + len = (int) strlen(text); + if (text == NULL || len <= 0) + return pdc_false; + + /* initialize text options */ + *to = *ppt->currto; + to->text = (char *) text; + to->textlen = len; + + /* parsing option list */ + pdf_parse_fittextline_optlist(p, to, fit, optlist); + + /* no font set */ + if (to->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); + + /* no font size set */ + if (to->fontsize == PDC_FLOAT_MIN) + { + pdc_error(p->pdc, PDF_E_TEXT_NOFONTSIZESET, 0, 0, 0, 0); + } + + return pdc_true; +} + +int +pdf_fit_textline_internal(PDF *p, pdf_fittext *fitres, + pdf_text_options *to, pdf_fit_options *fit, + pdc_matrix *matrix) +{ + pdc_bool logg5 = pdc_logg_is_enabled(p->pdc, 5, trc_text); + pdf_ppt *ppt = p->curr_ppt; + pdf_font *currfont = &p->fonts[to->font]; + pdc_byte *utext = (pdc_byte *) ""; + int len, charlen; + pdc_bool blind = (fitres != NULL) ? pdc_true : pdc_false; + pdc_bool vertical = currfont->ft.vertical; + + pdc_matrix ctm = ppt->gstate[ppt->sl].ctm; + pdc_matrix m, mm; + pdc_vector elemsize, elemscale, elemmargin, textrelpos, fitrelpos; + pdc_vector polyline[5]; + pdc_scalar textyextent[2]; + pdc_box fitbox, elembox; + pdc_scalar ss, width, height, boxwidth, boxheight, fontsizeref; + pdc_scalar ascender, capheight, xheight, descender; + pdc_scalar x, y, tx = 0, ty = 0, basey = 0; + pdc_bool hasfitbox = pdc_false; + pdc_scalar font2user; + int indangle = fit->orientate / 90; + int unmapgids = 0, i; + + (void) ppt; + + /* box size */ + boxwidth = fit->boxsize[0]; + boxheight = fit->boxsize[1]; + + /* reference for font size as percentage */ + if (indangle % 2) + fontsizeref = boxwidth; + else + fontsizeref = boxheight; + + /* calculate and set text options */ + pdf_calculate_text_options(p, to, pdc_false, 1.0, PDC_FLOAT_PREC, + fontsizeref); + if (!blind) + pdf_set_text_options(p, to); + + /* convert text string */ + unmapgids = pdf_check_textstring(p, to->text, to->textlen, PDF_USE_TMPALLOC, + to, &utext, &len, &charlen, pdc_true); + if (utext == NULL || !len) + return -1; + + if (to->nglyphs && len/charlen != to->nglyphs) + pdc_warning(p->pdc, PDF_E_TEXT_SIZENOMATCH, + pdc_errprintf(p->pdc, "%d", to->nglyphs), + pdc_errprintf(p->pdc, "%d", len/charlen), 0, 0); + + /* width and height of text */ + width = pdf_calculate_textsize(p, utext, len, charlen, + to, -1, &height, pdc_true); + width = pdf_trim_textwidth(width, to); + if (PDC_FLOAT_ISNULL(width)) + return -1; + + /* font specifics */ + font2user = to->fontsize / 1000.0; + ascender = font2user * currfont->ft.m.ascender; + capheight = font2user * currfont->ft.m.capHeight; + xheight = font2user * currfont->ft.m.xHeight; + descender = font2user * currfont->ft.m.descender; + + /* margin lower left corner */ + elemmargin.x = fit->margin[0]; + elemmargin.y = fit->margin[1]; + + /* new box size */ + boxwidth -= 2 * elemmargin.x; + if (boxwidth < 0) + boxwidth = 0; + boxheight -= 2 * elemmargin.y; + if (boxheight < 0) + boxheight = 0; + hasfitbox = boxwidth > PDC_FLOAT_PREC && boxheight > PDC_FLOAT_PREC; + + /* kind of text box */ + pdf_get_mbox_boxheight(p, fit->matchbox, textyextent); + + /* text x size */ + elemsize.x = width; + + /* TODO: for vertical text */ + /* text y size */ + if (!vertical) + { + height = 0; + for (i = 0; i < 2; i++) + { + basey = 0; + if (textyextent[i] <= 0) + { + switch ((int) textyextent[i]) + { + case text_none: + break; + + case text_ascender: + basey = ascender; + break; + + case text_capheight: + basey = capheight; + break; + + case text_xheight: + basey = xheight; + break; + + case text_descender: + basey = -descender; + break; + + case text_textrise: + basey = to->textrise; + break; + + case text_fontsize: + basey = to->fontsize; + break; + + case text_leading: + basey = to->leading; + break; + } + } + else + { + basey = textyextent[i]; + } + height += basey; + } + } + elemsize.y = height; + + /* orientation */ + if (indangle % 2) + { + ss = elemsize.x; + elemsize.x = elemsize.y; + elemsize.y = ss; + } + + /* box for fitting */ + fitbox.ll.x = 0; + fitbox.ll.y = 0; + fitbox.ur.x = boxwidth; + fitbox.ur.y = boxheight; + + /* relativ position in fit and text box */ + fitrelpos.x = fit->position[0] / 100.0; + fitrelpos.y = fit->position[1] / 100.0; + textrelpos = fitrelpos; + + /* decimal character and position */ + if (fit->alignchar) + { + pdc_encoding enc = currfont->ft.enc; + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + pdc_scalar decwidth, decheight, pos1, pos2; + int poschar = (int) fit->alignchar; + + switch(enc) + { + case pdc_cid: + if (currfont->codesize != 2) + poschar = -1; + break; + + case pdc_glyphid: + poschar = fnt_get_glyphid(poschar, &currfont->ft); + break; + + case pdc_builtin: + poschar = -1; + break; + + default: + if (ev != NULL && charlen == 1) + { + poschar = pdc_get_encoding_bytecode(p->pdc, ev, + (pdc_ushort) poschar); + } + break; + } + + /* width and height of text part ranging to decimal character */ + decwidth = pdf_calculate_textsize(p, utext, len, charlen, + to, poschar, &decheight, pdc_true); + + /* position found */ + if (decwidth > 0) + { + /* relative position of position character */ + pos1 = decwidth / width; + pos2 = 1 - pos1; + i = vertical ? ((indangle + 3) % 4) : indangle; + switch (i) + { + case 0: + textrelpos.x = pos1; + break; + + case 1: + textrelpos.y = pos1; + break; + + case 2: + textrelpos.x = pos2; + break; + + case 3: + textrelpos.y = pos2; + break; + } + } + } + + /* calculate image box */ + pdc_place_element(fit->fitmethod, fit->shrinklimit, &fitbox, &fitrelpos, + &elemsize, &textrelpos, &elembox, &elemscale); + + if (logg5) + pdc_logg(p->pdc, + "\t\tFitting input parameter:\n" + "\t\t\tfitmethod = %s\n" + "\t\t\tshrinklimit = %f\n" + "\t\t\trefpoint = %f, %f\n" + "\t\t\tboxsize = %f, %f\n" + "\t\t\tfitrelpos = %f, %f\n" + "\t\t\telemsize = %f, %f\n" + "\t\t\ttextrelpos = %f, %f\n" + "\t\tFitting output parameter:\n" + "\t\t\telembox = %f, %f, %f, %f\n" + "\t\t\telemscale = %f, %f\n", + pdc_get_keyword(fit->fitmethod, pdf_fitmethod_keylist), + fit->shrinklimit, fit->refpoint[0], fit->refpoint[1], + fitbox.ur.x, fitbox.ur.y, fitrelpos.x, fitrelpos.y, + elemsize.x, elemsize.y, textrelpos.x, textrelpos.y, + elembox.ll.x, elembox.ll.y, elembox.ur.x, elembox.ur.y, + elemscale.x, elemscale.y); + + /* reference point */ + pdc_translation_matrix(fit->refpoint[0], fit->refpoint[1], &mm); + if (matrix == NULL) + { + if (blind) + { + m = ctm; + pdc_multiply_matrix(&mm, &m); + } + else + m = mm; + } + else + { + m = *matrix; + pdc_multiply_matrix(&mm, &m); + } + + /* optional rotation */ + if (fabs(fit->rotate) > PDC_FLOAT_PREC) + { + pdc_rotation_matrix(p->ydirection * fit->rotate, &mm); + pdc_multiply_matrix(&mm, &m); + } + + /* output after translation and rotation */ + if (!blind) + { + /* new CTM */ + if (fit->showborder || + fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice) + { + pdf_concat_raw(p, &m); + pdc_identity_matrix(&m); + } + + /* show border */ + if (fit->showborder) + { + pdf__rect(p, elemmargin.x, p->ydirection * elemmargin.y, + boxwidth, boxheight); + pdf__rect(p, 0, 0, fit->boxsize[0], fit->boxsize[1]); + pdf__stroke(p); + } + + /* clipping */ + if ( + (fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice)) + { + pdc_scalar cw = fit->boxsize[0]; + pdc_scalar ch = fit->boxsize[1]; + + if (cw < PDC_FLOAT_PREC) + cw = PDF_ACRO_MAXPAGE; + if (ch < PDC_FLOAT_PREC) + ch = PDF_ACRO_MAXPAGE; + pdf__rect(p, 0, 0, cw, ch); + pdf__clip(p); + } + } + + /* reference point for elembox */ + if (elemmargin.x > PDC_FLOAT_PREC || elemmargin.y > PDC_FLOAT_PREC) + { + tx = elemmargin.x; + if (boxwidth < PDC_FLOAT_PREC) + tx *= 1.0 - 2 * fitrelpos.x; + ty = elemmargin.y; + if (boxheight < PDC_FLOAT_PREC) + ty *= 1.0 - 2 * fitrelpos.y; + + pdc_translation_matrix(tx, p->ydirection * ty, &mm); + pdc_multiply_matrix(&mm, &m); + } + + + /* translation of element box */ + elembox.ll.y *= p->ydirection; + elembox.ur.y *= p->ydirection; + pdc_box2polyline(NULL, &elembox, polyline); + tx = polyline[indangle].x; + ty = polyline[indangle].y; + pdc_translation_matrix(tx, ty, &mm); + pdc_multiply_matrix(&mm, &m); + boxwidth = elembox.ur.x - elembox.ll.x; + boxheight = elembox.ur.y - elembox.ll.y; + + /* orientation of text */ + if (fit->orientate != 0) + { + pdc_rotation_matrix(p->ydirection * fit->orientate, &mm); + pdc_multiply_matrix(&mm, &m); + if (indangle % 2) + { + ss = elemscale.x; + elemscale.x = elemscale.y; + elemscale.y = ss; + + ss = boxwidth; + boxwidth = p->ydirection * boxheight; + boxheight = p->ydirection * ss; + + ss = elemmargin.x; + elemmargin.x = p->ydirection * elemmargin.y; + elemmargin.y = p->ydirection * ss; + } + } + + /* matchbox */ + if (!blind && fit->matchbox) + { + pdc_rectangle matchrect; + + pdf_concat_raw(p, &m); + pdc_identity_matrix(&m); + + matchrect.llx = 0; + matchrect.lly = 0; + matchrect.urx = boxwidth; + matchrect.ury = boxheight; + + pdf_set_mbox_rectangle(p, fit->matchbox, &matchrect, 0); + pdf_draw_mbox_rectangle(p, fit->matchbox, + mbox_saverestore | mbox_area | mbox_border); + + pdf_add_page_mbox(p, fit->matchbox); + } + + /* scaling */ + if (elemscale.x != 1 || elemscale.y != 1) + { + pdc_scale_matrix(elemscale.x, elemscale.y, &mm); + pdc_multiply_matrix(&mm, &m); + } + + /* relative text position */ + if (!vertical) + { + x = 0; + y = p->ydirection * basey; + } + else + { + x = width / 2.0; + y = p->ydirection * height; + } + + if (logg5) + pdc_logg(p->pdc, + "\t\tReference point:\n" + "\t\t\tx = %f\n" + "\t\t\ty = %f\n" + "\t\tEmbedding matrix components of textline fitting:\n" + "\t\t\ta = %f\n" + "\t\t\tb = %f\n" + "\t\t\tc = %f\n" + "\t\t\td = %f\n" + "\t\t\te = %f\n" + "\t\t\tf = %f\n", + x, y, m.a, m.b, m.c, m.d, m.e, m.f); + + /* + * blind mode: pdf__info_textline + */ + if (blind) + { + pdc_scalar mwidth = 2 * fabs(elemmargin.x); + pdc_scalar mheight = 2 * fabs(elemmargin.y); + pdc_scalar vlen; + + /* start position */ + pdc_transform_point(&m, x, y, &tx, &ty); + fitres->start.x = tx; + fitres->start.y = ty; + + /* end position */ + if (!vertical) + { + tx = x + width; + ty = y; + } + else + { + tx = x; + ty = y - p->ydirection * height; + } + pdc_transform_point(&m, tx, ty, &tx, &ty); + fitres->end.x = tx; + fitres->end.y = ty; + + /* relative vector from start to end */ + tx = fitres->end.x - fitres->start.x; + ty = fitres->end.y - fitres->start.y; + vlen = sqrt(tx * tx + ty * ty); + if (!vertical) + { + /* width and x scaling */ + fitres->width = vlen; + fitres->mwidth = vlen + mwidth; + fitres->scale.x = fitres->width / width; + + /* unit vector of base line */ + fitres->writingdir.x = tx / vlen; + fitres->writingdir.y = ty / vlen; + + /* relative vector of fontsize */ + tx = x; + ty = y + p->ydirection * height; + pdc_transform_point(&m, tx, ty, &tx, &ty); + tx -= fitres->start.x; + ty -= fitres->start.y; + vlen = sqrt(tx * tx + ty * ty); + + /* height and y scaling */ + fitres->height = vlen; + fitres->mheight = vlen + mheight; + fitres->scale.y = fitres->height / height; + } + else + { + /* height and y scaling */ + fitres->height = vlen; + fitres->mheight = vlen + mheight; + fitres->scale.y = fitres->height / height; + + /* unit vector of perpendiculardir line */ + fitres->writingdir.x = tx / vlen; + fitres->writingdir.y = ty / vlen; + + /* relative vector of width */ + tx = x + width; + ty = y; + pdc_transform_point(&m, tx, ty, &tx, &ty); + tx -= fitres->start.x; + ty -= fitres->start.y; + vlen = sqrt(tx * tx + ty * ty); + + /* width ans x scaling */ + fitres->width = vlen; + fitres->mwidth = vlen + mwidth; + fitres->scale.x = fitres->width / width; + } + + /* unit vector of perpendiculardir line */ + fitres->perpendiculardir.x = tx / vlen; + fitres->perpendiculardir.y = ty / vlen; + + /* rotation angle of base line */ + fitres->angle = atan2(fitres->writingdir.y, fitres->writingdir.x) / + PDC_DEG2RAD; + + /* font specifics */ + fitres->ascender = pdc_transform_scalar(&m, ascender); + fitres->capheight = pdc_transform_scalar(&m, capheight); + fitres->xheight = pdc_transform_scalar(&m, xheight); + fitres->descender = pdc_transform_scalar(&m, descender); + } + else + { + /* CTM */ + pdf_concat_raw(p, &m); + + /* set text position */ + pdf__set_text_pos(p, x, y); + + + /* place text */ + pdf_place_text(p, utext, len, charlen, to, width, height, pdc_false); + + + /* create a link - deprecated - */ + if (to->link) + { + pdf_check_textstring(p, to->text, to->textlen, + PDF_USE_TMPALLOC | PDF_KEEP_UNICODE, + to, &utext, &len, &charlen, pdc_true); + pdf_create_link(p, to->linktype, x, y + p->ydirection * descender, + x + width, y + p->ydirection * to->fontsize, + to->link, (char *) utext, len); + pdc_free_tmp(p->pdc, utext); + } + } + + return unmapgids; +} + +void +pdf_calculate_textline_size(PDF *p, pdf_text_options *to, pdf_fit_options *fit, + pdc_scalar *width, pdc_scalar *height) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_fittext fitres; + pdc_matrix ctminv; + + /* calculate textline size for table cells */ + fitres.width = 0.0; + fitres.height = 0.0; + pdf_fit_textline_internal(p, &fitres, to, fit, NULL); + + pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm); + if (width) + *width = pdc_transform_scalar(&ctminv, fitres.mwidth); + if (height) + *height = pdc_transform_scalar(&ctminv, fitres.mheight); +} + +void +pdf__fit_textline(PDF *p, const char *text, int len, pdc_scalar x, pdc_scalar y, + const char *optlist) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_tstate *ts; + pdf_text_options to; + pdf_fit_options fit; + pdc_matrix ctminv; + pdc_scalar currtx, currty; + + pdc_check_number(p->pdc, "x", x); + pdc_check_number(p->pdc, "y", y); + + /* parse options */ + if (!pdf_parse_textline_options(p, text, len, &to, &fit, optlist)) + return; + + fit.refpoint[0] = x; + fit.refpoint[1] = y; + + pdf__save(p); + + /* output text line */ + pdf_fit_textline_internal(p, NULL, &to, &fit, NULL); + pdf_cleanup_fit_options(p, &fit); + + ts = &ppt->tstate[ppt->sl]; + pdc_transform_point(&ppt->gstate[ppt->sl].ctm, + ts->currtx, ts->currty, &currtx, &currty); + + pdf__restore(p); + + /* calculate current text position*/ + pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm); + pdc_transform_point(&ctminv, currtx, currty, &currtx, &currty); + pdf__set_text_pos(p, currtx, currty); +} + +static const pdc_keyconn pdf_info_keylist[] = +{ + {"startx", 1}, + {"starty", 2}, + {"endx", 3}, + {"endy", 4}, + {"writingdirx", 5}, + {"writingdiry", 6}, + {"perpendiculardirx", 7}, + {"perpendiculardiry", 8}, + {"scalex", 9}, + {"scaley", 10}, + {"width", 11}, + {"height", 12}, + {"ascender", 13}, + {"capheight", 14}, + {"xheight", 15}, + {"descender", 16}, + {"unmappedglyphs", 17}, + {"angle", 18}, + {NULL, 0} +}; + +double +pdf__info_textline(PDF *p, const char *text, int len, const char *keyword, + const char *optlist) +{ + pdf_ppt *ppt = p->curr_ppt; + pdf_text_options to; + pdf_fit_options fit; + pdf_fittext fitres; + double tinfo = 0; + int retval, infokey; + + if (!keyword || !*keyword) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "keyword", 0, 0, 0); + + infokey = pdc_get_keycode_ci(keyword, pdf_info_keylist); + if (infokey == PDC_KEY_NOTFOUND) + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "keyword", keyword, 0, 0); + + /* parse options */ + retval = pdf_parse_textline_options(p, text, len, &to, &fit, optlist); + + if (retval) + { + /* calculate textline */ + retval = pdf_fit_textline_internal(p, &fitres, &to, &fit, NULL); + pdf_cleanup_fit_options(p, &fit); + + if (retval > -1) + { + pdf_font *currfont = &p->fonts[to.font]; + pdc_matrix ctminv; + + pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm); + + switch(infokey) + { + case 1: + case 2: + pdc_transform_vector(&ctminv, &fitres.start, NULL); + break; + + case 3: + case 4: + pdc_transform_vector(&ctminv, &fitres.end, NULL); + break; + + case 5: + case 6: + pdc_transform_rvector(&ctminv, &fitres.writingdir, NULL); + break; + + case 7: + case 8: + pdc_transform_rvector(&ctminv, &fitres.perpendiculardir, NULL); + break; + } + + pdc_logg_cond(p->pdc, 1, trc_text, + "\tInfo textline%s:\n" + "\tstartx = %f\n" + "\tstarty = %f\n" + "\tendx = %f\n" + "\tendy = %f\n" + "\twritingdirx = %f\n" + "\twritingdiry = %f\n" + "\tperpendiculardirx = %f\n" + "\tperpendiculardiry = %f\n" + "\tscalex = %f\n" + "\tscaley = %f\n" + "\twidth = %f\n" + "\theight = %f\n" + "\tascender = %f\n" + "\tcapheight = %f\n" + "\txheight = %f\n" + "\tdescender = %f\n", + currfont->ft.vertical ? " (vertical writing mode)" : "", + fitres.start.x, fitres.start.y, + fitres.end.x, fitres.end.y, + fitres.writingdir.x, fitres.writingdir.y, + fitres.perpendiculardir.x, fitres.perpendiculardir.y, + fitres.scale.x, fitres.scale.y, + fitres.width, fitres.height, + fitres.ascender, fitres.capheight, + fitres.xheight,fitres.descender); + + switch(infokey) + { + case 1: + tinfo = (double) fitres.start.x; + break; + + case 2: + tinfo = (double) fitres.start.y; + break; + + case 3: + tinfo = (double) fitres.end.x; + break; + + case 4: + tinfo = (double) fitres.end.y; + break; + + case 5: + tinfo = (double) fitres.writingdir.x; + break; + + case 6: + tinfo = (double) fitres.writingdir.y; + break; + + case 7: + tinfo = (double) fitres.perpendiculardir.x; + break; + + case 8: + tinfo = (double) fitres.perpendiculardir.y; + break; + + case 9: + tinfo = (double) fitres.scale.x; + break; + + case 10: + tinfo = (double) fitres.scale.y; + break; + + case 11: + tinfo = (double) fitres.width; + break; + + case 12: + tinfo = (double) fitres.height; + break; + + case 13: + tinfo = (double) fitres.ascender; + break; + + case 14: + tinfo = (double) fitres.capheight; + break; + + case 15: + tinfo = (double) fitres.xheight; + break; + + case 16: + tinfo = (double) fitres.descender; + break; + + case 17: + tinfo = (double) retval; + break; + + case 18: + tinfo = (double) fitres.angle; + break; + } + } + } + + return tinfo; +} + + + +/*****************************************************************************/ +/** deprecated historical text formatting function **/ +/*****************************************************************************/ + +/* this helper function returns the width of the null-terminated string +** 'text' for the current font and size EXCLUDING the last character's +** additional charspacing. +*/ +static pdc_scalar +pdf_swidth(PDF *p, const char *text) +{ + pdf_text_options *currto = p->curr_ppt->currto; + + pdc_scalar width = pdf_calculate_textsize(p, + (pdc_byte *) text, (int)strlen(text), 1, + currto, -1, NULL, pdc_true); + return (width - currto->horizscaling * currto->charspacing); +} + +static void +pdf_show_aligned(PDF *p, const char *text, pdc_scalar x, pdc_scalar y, + pdc_scalar wordspacing, pdf_alignment mode) +{ + if (!text) + return; + + switch (mode) { + default: + case text_left: + case text_justify: + case text_fulljustify: + /* nothing extra here... */ + break; + + case text_right: + x -= pdf_swidth(p, text); + break; + + case text_center: + x -= pdf_swidth(p, text) / 2; + break; + } + + pdf__set_text_pos(p, x, y); + pdf_set_tstate(p, wordspacing, to_wordspacing); + pdf__show_text(p, text, (int) strlen(text), pdc_false); +} + +int +pdf__show_boxed( + PDF *p, + const char *text, int len, + pdc_scalar left, + pdc_scalar bottom, + pdc_scalar width, + pdc_scalar height, + const char *hmode, + const char *feature) +{ + pdc_scalar old_wordspacing, wordspacing, textwidth, curx, cury; + pdc_bool prematureexit; /* return because box is too small */ + int curTextPos; /* character currently processed */ + int lastdone; /* last input character processed */ + int toconv = len; + pdf_text_options *currto = p->curr_ppt->currto; + pdf_font *currfont; + pdc_byte *utext = NULL; + pdc_text_format old_textformat; + pdf_alignment mode = text_left; + pdc_bool blind = pdc_false; + + /* text length */ + if (text == NULL) + return 0; + if (!len) + len = (int) strlen(text); + if (!len) + return 0; + + pdc_check_number(p->pdc, "left", left); + pdc_check_number(p->pdc, "bottom", bottom); + pdc_check_number(p->pdc, "width", width); + pdc_check_number(p->pdc, "height", height); + + if (hmode == NULL || *hmode == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "hmode", 0, 0, 0); + + if (!strcmp(hmode, "left")) + mode = text_left; + else if (!strcmp(hmode, "right")) + mode = text_right; + else if (!strcmp(hmode, "center")) + mode = text_center; + else if (!strcmp(hmode, "justify")) + mode = text_justify; + else if (!strcmp(hmode, "fulljustify")) + mode = text_fulljustify; + else + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "hmode", hmode, 0, 0); + + if (feature != NULL && *feature != '\0') + { + if (!strcmp(feature, "blind")) + blind = pdc_true; + else + pdc_error(p->pdc, PDC_E_ILLARG_STRING, "feature", feature, 0, 0); + } + + /* no font set */ + if (currto->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); + currfont = &p->fonts[currto->font]; + + if (width == 0 && height != 0) + pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, + "width", pdc_errprintf(p->pdc, "%f", width), 0, 0); + + if (width != 0 && height == 0) + pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, + "height", pdc_errprintf(p->pdc, "%f", height), 0, 0); + + if (currfont->ft.vertical) + { + pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "vertical writing mode", + 0, 0, 0); + } + + /* we cannot handle several encodings */ + if (currfont->ft.enc == pdc_unicode) + { + pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "Unicode", 0, 0, 0); + } + + if (currfont->ft.enc == pdc_glyphid) + { + pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "glyphid", 0, 0, 0); + } + + if (currfont->ft.enc == pdc_cid) + { + pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "CID", 0, 0, 0); + } + + if (currfont->ft.enc == pdc_ebcdic || + currfont->ft.enc == pdc_ebcdic_37 || + currfont->ft.enc == pdc_ebcdic_winansi) + { + pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "EBCDIC", 0, 0, 0); + } + + /* old wordspacing */ + old_textformat = currto->textformat; + + /* convert text string */ + if (toconv) + { + int charlen; + + /* convert text string */ + pdf_check_textstring(p, text, len, + PDF_KEEP_CONTROL | PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC, + currto, &utext, &len, &charlen, pdc_true); + if (utext == NULL || !len) + return 0; + + utext[len] = 0; + text = (const char *) utext; + currto->textformat = pdc_bytes; + } + + /* old wordspacing */ + old_wordspacing = currto->wordspacing; + + /* special case for a single aligned line */ + if (width == 0 && height == 0) + { + if (!blind) + pdf_show_aligned(p, text, left, bottom, old_wordspacing, mode); + + if (toconv) + currto->textformat = old_textformat; + return 0; + } + + curx = left; + cury = bottom + p->ydirection * height; + prematureexit = pdc_false; + curTextPos = 0; + lastdone = 0; + + /* switch curx for right and center justification */ + if (mode == text_right) + curx += width; + else if (mode == text_center) + curx += (width / 2); + +#define MAX_CHARS_IN_LINE 2048 + + /* loop until all characters processed, or box full */ + + while ((curTextPos < len) && !prematureexit) + { + /* buffer for constructing the line */ + char linebuf[MAX_CHARS_IN_LINE]; + int curCharsInLine = 0; /* # of chars in constructed line */ + int lastWordBreak = 0; /* the last seen space char */ + int wordBreakCount = 0; /* # of blanks in this line */ + + /* loop over the input string */ + while (curTextPos < len) + { + if (curCharsInLine >= MAX_CHARS_IN_LINE) + pdc_error(p->pdc, PDC_E_ILLARG_TOOLONG, "(text line)", + pdc_errprintf(p->pdc, "%d", MAX_CHARS_IN_LINE-1), 0, 0); + + /* abandon DOS line-ends */ + if (text[curTextPos] == PDF_RETURN && + text[curTextPos+1] == PDF_NEWLINE) + curTextPos++; + + /* if it's a forced line break draw the line */ + if (text[curTextPos] == PDF_NEWLINE || + text[curTextPos] == PDF_RETURN) + { + cury -= p->ydirection * currto->leading; + + if (p->ydirection * (cury - bottom) < 0) { + prematureexit = pdc_true; /* box full */ + break; + } + + linebuf[curCharsInLine] = 0; /* terminate the line */ + + /* check whether the line is too long */ + wordspacing = 0; + pdf_set_tstate(p, wordspacing, to_wordspacing); + textwidth = pdf_swidth(p, linebuf); + + /* the forced break occurs too late for this line */ + if (textwidth > width) + { + if (wordBreakCount == 0) { /* no blank found */ + prematureexit = pdc_true; + break; + } + linebuf[lastWordBreak] = 0; /* terminate at last blank */ + if (curTextPos > 0 && text[curTextPos-1] == PDF_RETURN) + --curTextPos; + curTextPos -= (curCharsInLine - lastWordBreak); + + if (!blind) + { + textwidth = pdf_swidth(p, linebuf); + if (wordBreakCount != 1 && + (mode == text_justify || + mode == text_fulljustify)) + { + wordspacing = (width - textwidth) / + ((wordBreakCount - 1) * currto->horizscaling); + } + pdf_show_aligned(p, linebuf, curx, cury, wordspacing, + mode); + } + } + else if (!blind) + { + if (mode == text_fulljustify && wordBreakCount > 0) + { + wordspacing = (width - textwidth) / + (wordBreakCount * currto->horizscaling); + } + pdf_show_aligned(p, linebuf, curx, cury, wordspacing, mode); + } + + lastdone = curTextPos; + curCharsInLine = lastWordBreak = wordBreakCount = 0; + curTextPos++; + + } + else if (text[curTextPos] == PDF_SPACE) + { + linebuf[curCharsInLine] = 0; /* terminate the line */ + + /* line too long ==> break at last blank */ + wordspacing = 0; + pdf_set_tstate(p, wordspacing, to_wordspacing); + if (pdf_swidth(p, linebuf) > width) + { + cury -= p->ydirection * currto->leading; + + if (p->ydirection * (cury - bottom) < 0) + { + prematureexit = pdc_true; /* box full */ + break; + } + + linebuf[lastWordBreak] = 0; /* terminate at last blank */ + curTextPos -= (curCharsInLine - lastWordBreak - 1); + + if (lastWordBreak == 0) + curTextPos--; + + /* LATER: * force break if wordBreakCount == 1, + * i.e., no blank + */ + if (wordBreakCount == 0) + { + prematureexit = pdc_true; + break; + } + + /* adjust word spacing for full justify */ + if (wordBreakCount != 1 && (mode == text_justify || + mode == text_fulljustify)) + { + textwidth = pdf_swidth(p, linebuf); + wordspacing = (width - textwidth) / + ((wordBreakCount - 1) * currto->horizscaling); + } + + lastdone = curTextPos; + if (!blind) + { + pdf_show_aligned(p, linebuf, curx, cury, wordspacing, + mode); + } + curCharsInLine = lastWordBreak = wordBreakCount = 0; + } + else + { + /* blank found, and line still fits */ + wordBreakCount++; + lastWordBreak = curCharsInLine; + linebuf[curCharsInLine++] = text[curTextPos++]; + } + } + else + { + /* regular character ==> store in buffer */ + linebuf[curCharsInLine++] = text[curTextPos++]; + } + } + + if (prematureexit) { + break; /* box full */ + } + + /* if there is anything left in the buffer, draw it */ + if (curTextPos >= len && curCharsInLine != 0) + { + cury -= p->ydirection * currto->leading; + + if (p->ydirection * (cury - bottom) < 0) + { + prematureexit = pdc_true; /* box full */ + break; + } + + linebuf[curCharsInLine] = 0; /* terminate the line */ + + /* check if the last line is too long */ + wordspacing = 0; + pdf_set_tstate(p, wordspacing, to_wordspacing); + textwidth = pdf_swidth(p, linebuf); + + if (textwidth > width) + { + if (wordBreakCount == 0) + { + prematureexit = pdc_true; + break; + } + + linebuf[lastWordBreak] = 0; /* terminate at last blank */ + curTextPos -= (curCharsInLine - lastWordBreak - 1); + + /* recalculate the width */ + textwidth = pdf_swidth(p, linebuf); + + /* adjust word spacing for full justify */ + if (wordBreakCount != 1 && (mode == text_justify || + mode == text_fulljustify)) + { + wordspacing = (width - textwidth) / + ((wordBreakCount - 1) * currto->horizscaling); + } + } + else if (!blind) + { + if (mode == text_fulljustify && wordBreakCount) + { + wordspacing = (width - textwidth) / + (wordBreakCount * currto->horizscaling); + } + } + + lastdone = curTextPos; + if (!blind) + { + pdf_show_aligned(p, linebuf, curx, cury, wordspacing, mode); + } + curCharsInLine = lastWordBreak = wordBreakCount = 0; + } + } + + pdf_set_tstate(p, old_wordspacing, to_wordspacing); + + /* return number of remaining characters */ + + while (text[lastdone] == PDF_SPACE) + ++lastdone; + + if ((text[lastdone] == PDF_RETURN || + text[lastdone] == PDF_NEWLINE) && text[lastdone+1] == 0) + ++lastdone; + + if (toconv) + currto->textformat = old_textformat; + + return (int) (len - lastdone); +} diff --git a/src/pdflib/pdflib/p_textflow.c b/src/pdflib/pdflib/p_textflow.c new file mode 100644 index 0000000..006facb --- /dev/null +++ b/src/pdflib/pdflib/p_textflow.c @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_textflow.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib textflow function + * + */ + +#define P_TEXTFLOW_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_font.h" +#include "p_defopt.h" +#include "p_tagged.h" + + diff --git a/src/pdflib/pdflib/p_tiff.c b/src/pdflib/pdflib/p_tiff.c new file mode 100644 index 0000000..5ed382f --- /dev/null +++ b/src/pdflib/pdflib/p_tiff.c @@ -0,0 +1,1169 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_tiff.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * TIFF processing for PDFlib + * + */ + +#include "p_intern.h" +#include "p_color.h" +#include "p_image.h" + +#ifndef HAVE_LIBTIFF + +pdc_bool /* CDPDF fixed last parameter declaration */ +pdf_is_TIFF_file(PDF *p, pdc_file *fp, pdf_tiff_info *tiff, pdc_bool check) +{ + (void) p; + (void) fp; + (void) tiff; + (void) check; + + return pdc_false; +} + +int +pdf_process_TIFF_data( + PDF *p, + int imageslot) +{ + pdf_image *image = &p->images[imageslot]; + + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "TIFF", 0, 0, 0); + + return -1; +} + +#else + +#include "tiffiop.h" +static tsize_t +pdf_libtiff_read(void* fd, tdata_t buf, tsize_t size) +{ + pdc_file *fp = (pdc_file *) fd; + + return ((tsize_t) pdc_fread(buf, 1, (size_t) size, fp)); +} + +static toff_t +pdf_libtiff_seek(void* fd, toff_t off, int whence) +{ + pdc_file *fp = (pdc_file *) fd; + + return ((toff_t) pdc_fseek(fp, (long) off, whence)); +} + +static int +pdf_libtiff_close(void* fd) +{ + (void) fd; + + /* pdc_fclose(fp); this happens in caller function */ + + return 0; +} + +static toff_t +pdf_libtiff_size(void* fd) +{ + pdc_file *fp = (pdc_file *) fd; + + return (toff_t) pdc_file_size(fp); +} + +static void * +pdf_libtiff_malloc(TIFF *t, tsize_t size) +{ + PDF *p = (PDF*) t->pdflib_opaque; + return pdc_calloc(p->pdc, (size_t)size, "libtiff"); +} + +static void * +pdf_libtiff_realloc(TIFF *t, tdata_t mem, tsize_t size) +{ + PDF *p = (PDF*) t->pdflib_opaque; + return(pdc_realloc(p->pdc, (void*)mem, (size_t)size, "libtiff")); +} + +static void +pdf_libtiff_free(TIFF *t, tdata_t mem) +{ + PDF *p = (PDF*) t->pdflib_opaque; + pdc_free(p->pdc, (void*)mem); +} + +#define PDF_TIFF_LENGTH_MAX 512 +static void +pdf_libtiff_error(TIFF *t, const char* module, const char* fmt, va_list ap) +{ + PDF *p = (PDF*) t->pdflib_opaque; + + if (pdc_logg_is_enabled(p->pdc, 5, trc_image)) + { + char buffer[PDF_TIFF_LENGTH_MAX]; + + /* Create the message */ + pdc_vsnprintf(buffer, PDF_TIFF_LENGTH_MAX, fmt, ap); + pdc_logg(p->pdc, "\tlibtiff(%s): %s\n", module, buffer); + } +} + +static void +pdf_data_source_TIFF_init(PDF *p, PDF_data_source *src) +{ + static const char *fn = "pdf_data_source_TIFF_init"; + pdf_image *image; + + image = (pdf_image *) src->private_data; + + if (image->strips == 1) + image->info.tiff.cur_line = 0; + + if (image->use_raw) + { + /* malloc is done in the fill function */ + src->buffer_length = (size_t) 0; + src->buffer_start = (pdc_byte *) NULL; + } + else + { + if (image->bpc == 1) + src->buffer_length = + (size_t) (image->components * ((int) image->width+7)/8); + else + src->buffer_length = + (size_t) (image->components * image->width); + + src->buffer_start = (pdc_byte *) + pdc_malloc(p->pdc, src->buffer_length, fn); + } +} + +/* Convert the a and b samples of Lab data from signed to unsigned. */ + +static void +pdf_signed_to_unsigned(pdc_byte *buf, size_t count) +{ + size_t i; + + for(i=0; i < count; i+=3) + { + buf[i+1] ^= 0x80; + buf[i+2] ^= 0x80; + } +} + +#define MYTIFF image->info.tiff.tif + +static pdc_bool +pdf_data_source_TIFF_fill(PDF *p, PDF_data_source *src) +{ + static const char *fn = "pdf_data_source_TIFF_fill"; + pdf_image *image; + int col; + pdc_byte *dest; + uint16 fillorder; + uint32 *s, *bc; + + image = (pdf_image *) src->private_data; + + PDC_TRY(p->pdc) + { + if (image->use_raw) + { + if (image->info.tiff.cur_line == image->strips) + { + PDC_EXIT_TRY(p->pdc); + return pdc_false; + } + + TIFFGetField(MYTIFF, TIFFTAG_STRIPBYTECOUNTS, &bc); + + if (bc[image->info.tiff.cur_line] > src->buffer_length) + { + src->buffer_length = bc[image->info.tiff.cur_line]; + src->buffer_start = (pdc_byte *) + pdc_realloc(p->pdc, src->buffer_start, + src->buffer_length, fn); + } + + if (TIFFReadRawStrip(MYTIFF, (tstrip_t) image->info.tiff.cur_line, + (tdata_t) src->buffer_start, + (tsize_t) bc[image->info.tiff.cur_line]) == -1) + { + pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "TIFF", + pdf_get_image_filename(p, image), 0, 0); + } + + src->next_byte = src->buffer_start; + src->bytes_available = bc[image->info.tiff.cur_line]; + + /* special handling for uncompressed 16-bit images */ + if (MYTIFF->tif_header.tiff_magic == TIFF_LITTLEENDIAN && + image->compression == pdf_comp_none && image->bpc == 16) + { + TIFFSwabArrayOfShort((uint16 *) src->buffer_start, + (unsigned long) src->bytes_available/2); + } + + if (TIFFGetField(MYTIFF, TIFFTAG_FILLORDER, &fillorder) + && (fillorder == FILLORDER_LSB2MSB)) + { + TIFFReverseBits((unsigned char *) src->buffer_start, + (unsigned long) src->bytes_available); + } + + /* The a and b values of (uncompressed) Lab must be adjusted */ + if (p->colorspaces[image->colorspace].type == Lab) + { + pdf_signed_to_unsigned(src->buffer_start, src->bytes_available); + } + + if (image->strips > 1) + { + /* only a single strip of a multi-strip image */ + image->info.tiff.cur_line = image->strips; + } + else + image->info.tiff.cur_line++; + } + else + { + if (image->info.tiff.cur_line++ == image->height) + { + PDC_EXIT_TRY(p->pdc); + return pdc_false; + } + + src->next_byte = src->buffer_start; + src->bytes_available = src->buffer_length; + + dest = src->buffer_start; + s = image->info.tiff.raster + + ((int)image->height - image->info.tiff.cur_line) * + (int) image->width; + + switch (image->components) + { + case 1: + if (image->bpc == 1) + { + unsigned char mask; + + memset((void*) dest, 0, src->buffer_length); + + for (mask=0x80, col = 0; col < image->width; col++) + { + if (TIFFGetR(*s++) != 0) + *dest |= mask; + + if ((mask>>=1) == 0) + { + mask = 0x80; + ++dest; + } + } + } + else /* bpc == 8 */ + { + for (col = 0; col < image->width; col++, s++) + { + *dest++ = (pdc_byte) TIFFGetR(*s); + } + } + break; + + case 3: + for (col = 0; col < image->width; col++, s++) + { + *dest++ = (pdc_byte) TIFFGetR(*s); + *dest++ = (pdc_byte) TIFFGetG(*s); + *dest++ = (pdc_byte) TIFFGetB(*s); + } + break; + + case 4: + for (col = 0; col < image->width; col++, s++) + { + unsigned char* t = (unsigned char*)&(*s); + *dest++ = (pdc_byte) t[0]; + *dest++ = (pdc_byte) t[1]; + *dest++ = (pdc_byte) t[2]; + *dest++ = (pdc_byte) t[3]; + } + break; + + default: + pdc_error(p->pdc, PDF_E_IMAGE_BADCOMP, + pdc_errprintf(p->pdc, "%d", image->components), + pdf_get_image_filename(p, image), 0, 0); + } + } + } + PDC_CATCH(p->pdc) + { + image->corrupt = pdc_true; + } + + return !image->corrupt; +} + +static void +pdf_data_source_TIFF_terminate(PDF *p, PDF_data_source *src) +{ + pdc_free(p->pdc, (void *) src->buffer_start); +} + +static int +pdf_check_colormap(int n, uint16* r, uint16* g, uint16* b) +{ + while (n-- > 0) + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) + return(16); + return(8); +} + +pdc_bool +pdf_is_TIFF_file(PDF *p, pdc_file *fp, pdf_tiff_info *tiff_info, pdc_bool check) +{ + const char *filename; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type TIFF...\n"); + + filename = pdc_file_name(fp); + tiff_info->tif = TIFFClientOpen(filename, "rc", + (void *)fp, + pdf_libtiff_read, NULL, + pdf_libtiff_seek, pdf_libtiff_close, pdf_libtiff_size, + NULL, NULL, (void *)p, + pdf_libtiff_malloc, pdf_libtiff_realloc, pdf_libtiff_free, + pdf_libtiff_error, pdf_libtiff_error); + if (tiff_info->tif == NULL) + { + pdc_fseek(fp, 0L, SEEK_SET); + return pdc_false; + } + if (check) + TIFFClose(tiff_info->tif); + return pdc_true; +} + +int +pdf_process_TIFF_data( + PDF *p, + int imageslot) +{ + static const char *fn = "pdf_process_TIFF_data"; + uint32 w, h; + uint16 unit, bpc, compression, photometric, extra, *sinfo; + uint16 orientation, planarconfig; + uint16 *rmap, *gmap, *bmap; + tsample_t components; + pdf_image *image; + float res_x, res_y; /* sic! */ + pdf_colorspace cs; + int slot; + int errint = 0; + int errcode = 0; + pdc_bool isopen = pdc_false; + int strips; + + image = &p->images[imageslot]; + + image->info.tiff.raster = (uint32 *) NULL; + + if (!pdf_is_TIFF_file(p, image->fp, &image->info.tiff, pdc_false)) + { + errcode = PDF_E_IMAGE_CORRUPT; + goto PDF_TIFF_ERROR; + } + + MYTIFF->tif_fd = (FILE*) image->fp; + isopen = pdc_true; + + if (image->page != 1) + { + if (TIFFSetDirectory(MYTIFF, (tdir_t) (image->page - 1)) != 1 ) + { + errint = image->page; + errcode = PDF_E_IMAGE_NOPAGE; + goto PDF_TIFF_ERROR; + } + } + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_ORIENTATION, &orientation); + image->orientation = orientation; + + TIFFGetField(MYTIFF, TIFFTAG_COMPRESSION, &compression); + + TIFFGetField(MYTIFF, TIFFTAG_IMAGEWIDTH, &w); + image->width = (pdc_scalar) w; + + TIFFGetField(MYTIFF, TIFFTAG_IMAGELENGTH, &h); + image->height = (pdc_scalar) h; + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_BITSPERSAMPLE, &bpc); + image->bpc = bpc; + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_SAMPLESPERPIXEL, &components); + image->components = components; + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_EXTRASAMPLES, &extra, &sinfo); + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_PLANARCONFIG, &planarconfig); + + photometric = 255; /* dummy value */ + TIFFGetField(MYTIFF, TIFFTAG_PHOTOMETRIC, &photometric); + + /* fetch the resolution values if found in the file */ + if (TIFFGetField(MYTIFF, TIFFTAG_XRESOLUTION, &res_x) && + TIFFGetField(MYTIFF, TIFFTAG_YRESOLUTION, &res_y) && + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_RESOLUTIONUNIT, &unit) && + res_x > 0 && res_y > 0) { + + if (unit == RESUNIT_INCH) { + image->dpi_x = res_x; + image->dpi_y = res_y; + + } else if (unit == RESUNIT_CENTIMETER) { + image->dpi_x = res_x * 2.54; + image->dpi_y = res_y * 2.54; + + } else if (unit == RESUNIT_NONE) { + image->dpi_x = -res_x; + image->dpi_y = -res_y; + } + +#define PDF_REALLY_BIG_DPI 10000 + + /* Guard against obviously wrong values */ + if (unit != RESUNIT_NONE && + (image->dpi_x <= 1 || + image->dpi_y <= 1 || + image->dpi_x > PDF_REALLY_BIG_DPI || + image->dpi_y > PDF_REALLY_BIG_DPI)) + + image->dpi_x = image->dpi_y = 0; /* unknown */ + } + + + + /* ------------------------------------------------------------ + * Reject unsupported flavors. + * ---------------------------------------------------------- */ + + /* Catch some rare properties related to compression, photometric, + * and bpc which are definitely not supported (neither in pass-through + * mode nor libtiff) in order to provide a better error message than + * the generic "Error reading data". + */ + + /* Unsupported compression types */ + switch ((int) compression) + { + case /* 34661 */ COMPRESSION_JBIG: + case /* 34712 */ COMPRESSION_JP2000: + case 9 /* JBIG T85 */: + case 10 /* TIFF-FX JBIG (T.82) MRC (T.43) */: + case 34715 /* TFX */: + errint = (int) compression; + errcode = PDF_E_TIFF_UNSUPP_COMPRESSION; + goto PDF_TIFF_ERROR; + break; + + default: + break; + } + + /* Unsupported photometric values */ + switch ((int) photometric) + { + case PHOTOMETRIC_ICCLAB /* 9 */: + case PHOTOMETRIC_ITULAB /* 10 */: + errint = (int) photometric; + errcode = PDF_E_TIFF_UNSUPP_COLORSPACE; + goto PDF_TIFF_ERROR; + break; + + default: + break; + } + + /* 32-bit images are not supported */ + if (image->bpc > 16) + { + errcode = PDF_E_TIFF_16BIT_UNSUPP; + goto PDF_TIFF_ERROR; + } + + /* We don't support 16-bit CMYK unless it's uncompressed */ + if (image->bpc == 16 && components == 4 && compression != COMPRESSION_NONE) + { + errcode = PDF_E_TIFF_16BITCMYK_UNSUPP; + goto PDF_TIFF_ERROR; + } + + + /* ------------------------------------------------------------ + * We assume pass-through mode in the beginning, and disable it + * for image types where it doesn't work. + * ---------------------------------------------------------- */ + + image->use_raw = image->passthrough; + + /* Pass-through is not implemented for tiled images */ + if (TIFFIsTiled(MYTIFF)) + image->use_raw = pdc_false; + + + + /* Can't handle these colorspaces in raw mode (except with OJPEG) */ + if (compression != COMPRESSION_OJPEG && + (photometric == PHOTOMETRIC_YCBCR || + photometric == PHOTOMETRIC_CIELAB || + photometric == PHOTOMETRIC_MASK)) + { + image->use_raw = pdc_false; + } + + /* Can't pass through extra bits or use multiple data sources in raw mode + * (except with OJPEG). + */ + if (extra != 0 || + (compression != COMPRESSION_OJPEG && + planarconfig == PLANARCONFIG_SEPARATE && components > 1)) + { + image->components -= extra; /* ignore the extra channels */ + image->use_raw = pdc_false; + } + + /* PDF doesn't support other values of the color depth */ + if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16) + image->use_raw = pdc_false; + + /* Disable pass-through for a large number of strips to avoid + * file size bloat (due to many small Image XObjects) and + * ugly display in Acrobat (because of banding artifacts). + * The threshold for the number of strips has been determined empirically + * as a good compromise between file size and performance. + * + * We must still maintain pass-through mode for those cases where it + * is functionally more advanced, and benefit from its better performance + * for small numbers of strips. + * + * Also, we maintain pass-through mode for very large images since + * pass-through mode - especially with pixel mode (RGBA retrieval) - + * may run out of memory. + */ + +/* ca. 10K x 10K pixels (nopassthrough requires up to 4 times as many bytes!) */ +#define PDF_TIFF_THRESHOLD 0x6000000 + + strips = (int) TIFFNumberOfStrips(MYTIFF); + + if (strips > 25 && + compression != COMPRESSION_OJPEG && compression != COMPRESSION_JPEG && + photometric != PHOTOMETRIC_PALETTE && + image->width * image->width < PDF_TIFF_THRESHOLD) + { + image->use_raw = pdc_false; + } + + if (image->bpc == 16) + { + /* PDF < 1.5 doesn't support 16-bit images, so we cannot pass through */ + if (p->compatibility < PDC_1_5) + { + image->use_raw = pdc_false; + } + + /* + * PDF requires big-endian 16-bit data. We therefore use passthrough + * mode only for big-endian input or uncompressed data. + * + * It's not nice to pull the endianness directly from the TIFF + * structure, but there doesn't seem to be a public interface for it. + */ + if (MYTIFF->tif_header.tiff_magic == TIFF_LITTLEENDIAN && + (compression == COMPRESSION_DEFLATE || + compression == COMPRESSION_ADOBE_DEFLATE)) + { + image->use_raw = pdc_false; + } + + /* We don't support 16-bit CMYK unless in passthrough mode. + * Compressed images have already been rejected earlier. + */ + if (components == 4 && image->use_raw == pdc_false) + { + errcode = PDF_E_TIFF_16BITCMYK_UNSUPP; + goto PDF_TIFF_ERROR; + } + } + + /* + * Disable pass-through for unknown compression schemes, + * and collect the necessary parameters for well-known schemes. + */ + + if (image->use_raw == pdc_true) + { + uint32 group3opts; + uint16 predictor; + toff_t jpegifoffset, jpegifbytecount; + + switch ((int) compression) + { + case COMPRESSION_CCITTRLE: + case COMPRESSION_CCITTRLEW: + image->params = (char *) pdc_malloc(p->pdc, PDF_MAX_PARAMSTRING, + fn); + + strcpy(image->params, "/EndOfBlock false"); + strcat(image->params, "/EncodedByteAlign true"); + + if (photometric == PHOTOMETRIC_MINISBLACK) + strcat(image->params, "/BlackIs1 true"); + + image->compression = pdf_comp_ccitt; + break; + + case COMPRESSION_CCITTFAX3: + image->params = (char*) pdc_malloc(p->pdc, PDF_MAX_PARAMSTRING, + fn); + + strcpy(image->params, "/EndOfBlock false"); + + /* The following contains disabled code segments. + * Apparently, and contrary to my reading of the specs, + * the following can not be deduced from the respective + * TIFF entry or option: + * - /EncodedByteAlign can not reliably be deduced from + * GROUP3OPT_FILLBITS; + * + * From practical experience, the respective lines are + * disabled, but I don't have any clear explanation for this. + * A few TIFF images still don't work with this setting, + * unfortunately. + */ + + /* SEE ABOVE! + strcat(image->params, "/DamagedRowsBeforeError 1"); + */ + + if (TIFFGetField(MYTIFF, TIFFTAG_GROUP3OPTIONS, &group3opts)) + { + /* /K = 0 (= G3,1D) is default */ + if (group3opts & GROUP3OPT_2DENCODING) + strcat(image->params, "/K 1"); + + /* SEE ABOVE! + if (group3opts & GROUP3OPT_FILLBITS) + strcat(image->params, "/EncodedByteAlign true"); + */ + } + + if (photometric == PHOTOMETRIC_MINISBLACK) + strcat(image->params, "/BlackIs1 true"); + + image->compression = pdf_comp_ccitt; + break; + + case COMPRESSION_CCITTFAX4: + image->params = (char*) pdc_malloc(p->pdc, PDF_MAX_PARAMSTRING, + fn); + + strcpy(image->params, "/K -1"); + /* Required for bug #511 */ + strcat(image->params, "/EndOfBlock false"); + + if (photometric == PHOTOMETRIC_MINISBLACK) + strcat(image->params, "/BlackIs1 true"); + + image->compression = pdf_comp_ccitt; + break; + + case COMPRESSION_OJPEG: + /* + * Check whether a full-blown JPEG can be found inside the TIFF + * + * Heuristic: + * If we find a positive JPEGIFOFFSET there should be valid + * JFIF data; however, sometimes there isn't and we must not + *call the JPEG module. Strangely enough, various creators which + * do not emit valid JFIF do emit the JPEGIFBYTECOUNT tag. + * Therefore we use the absence of JPEGIFBYTECOUNT as a hint + * that JFIF processing might work. + * + * Known trouble-makers which include JPEGIFBYTECOUNT: + * "Oi/GFS, writer v00.06.02" + */ + if (TIFFGetField(MYTIFF, TIFFTAG_JPEGIFOFFSET, &jpegifoffset) && + jpegifoffset != 0 && + !TIFFGetField(MYTIFF, TIFFTAG_JPEGIFBYTECOUNT, + &jpegifbytecount)) + { + /* stop TIFF processing */ + TIFFClose(MYTIFF); + + /* store data offset for the JPEG module (after TIFFClose() + * the image->info union is no longer used by the TIFF + * module) + */ + image->info.jpeg.jpegifoffset = jpegifoffset; + + /* ...and process the data at the offset as JPEG */ + pdc_logg_cond(p->pdc, 1, trc_image, + "\tTIFF with OJPEG: switching to JPEG processing...\n"); + return pdf_process_JPEG_data(p, imageslot); + } + else + { + /* We must repeat the check here since we omitted the OJPEG + * case when we applied the test for the first time. + */ + if (extra != 0 || + (planarconfig == PLANARCONFIG_SEPARATE && components > 1)) + { + /* ignore the extra channels */ + image->components -= extra; + } + image->use_raw = pdc_false; + } + break; + + case COMPRESSION_NONE: + if (photometric == PHOTOMETRIC_MINISWHITE) + image->invert = !image->invert; + + image->compression = pdf_comp_none; + break; + + case COMPRESSION_LZW: + if (TIFFGetField(MYTIFF, TIFFTAG_PREDICTOR, &predictor)) { + if (predictor != pred_default && predictor != pred_tiff) { + image->use_raw = pdc_false; + break; + } else + image->predictor = (pdf_predictor) predictor; + } + + if (photometric == PHOTOMETRIC_MINISWHITE) + image->invert = !image->invert; + + image->compression = pdf_comp_lzw; + break; + + case COMPRESSION_PACKBITS: + if (photometric == PHOTOMETRIC_MINISWHITE) + image->invert = !image->invert; + + image->compression = pdf_comp_runlength; + break; + + case COMPRESSION_DEFLATE: + case COMPRESSION_ADOBE_DEFLATE: + if (TIFFGetField(MYTIFF, TIFFTAG_PREDICTOR, &predictor)) { + if (predictor != pred_default && predictor != pred_tiff) { + image->use_raw = pdc_false; + break; + } else + image->predictor = (pdf_predictor) predictor; + } + + if (photometric == PHOTOMETRIC_MINISWHITE) + image->invert = !image->invert; + + image->compression = pdf_comp_flate; + break; + + default: + image->use_raw = pdc_false; + } + } + + if (image->use_raw) + { + /* pass-through mode: directly copy chunks of strip data */ + image->strips = strips; + + pdc_logg_cond(p->pdc, 1, trc_image, "\tpassthrough mode...\n"); + } + else + { + /* libtiff cannot handle JPEG-compressed TIFFs with separate image + * planes + */ + if (planarconfig == PLANARCONFIG_SEPARATE && + (compression == COMPRESSION_OJPEG || compression==COMPRESSION_JPEG)) + { + errcode = PDF_E_TIFF_UNSUPP_JPEG_SEPARATE; + goto PDF_TIFF_ERROR; + } + + /* Fallback: use TIFFlib to retrieve pixel data */ + + /* We have special handling for preserving bpc=1 if components=1, + * and therefore don't change bpc in this case. + */ + if (!(image->components == 1 && image->bpc == 1)) + { + /* Retrieve pixel data with libtiff, which converts to 8 bits. */ + image->bpc = 8; + } + + image->strips = 1; + image->compression = pdf_comp_none; + + /* Palette images are automatically converted to RGB by TIFFlib. + * Since there are actually 1-bit images (photometric=min-is-white) + * with a palette out there (which are invalid TIFF, and are not + * converted to RGB by TIFFlib) we must also check photometric. + */ + if (image->components == 1 && photometric == PHOTOMETRIC_PALETTE && + TIFFGetField(MYTIFF, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) + { + image->components = 3; + } + pdc_logg_cond(p->pdc, 1, trc_image, "\tno passthrough mode...\n"); + } + + if (image->imagemask) + { + if (image->components != 1) + { + errcode = PDF_E_IMAGE_BADMASK; + goto PDF_TIFF_ERROR; + } + + if (p->compatibility == PDC_1_3) + { + if (image->components != 1 || image->bpc != 1) + { + errcode = PDF_E_IMAGE_MASK1BIT13; + goto PDF_TIFF_ERROR; + } + } + else if (image->bpc > 1) + { + /* images with more than one bit will be written as /SMask, + * and don't require an /ImageMask entry. + */ + image->imagemask = pdc_false; + } + } + + if (image->mask != pdc_undef) + { + if (image->strips != 1) + { + errcode = PDF_E_TIFF_MASK_MULTISTRIP; + goto PDF_TIFF_ERROR; + } + } + + if (image->colorspace == pdc_undef) + { + uint16 inkset; + + switch (image->components) + { + case 1: + image->colorspace = DeviceGray; + break; + + case 3: + image->colorspace = DeviceRGB; + break; + + case 4: + if (photometric == PHOTOMETRIC_SEPARATED) + { + /* Can't handle CMYK with mask */ + if (extra != 0) + { + errint = image->components; + errcode = PDF_E_TIFF_CMYK_MASK; + goto PDF_TIFF_ERROR; + } + + TIFFGetFieldDefaulted(MYTIFF, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) + { + errint = inkset; + errcode = PDF_E_TIFF_UNSUPP_SEP_NONCMYK; + goto PDF_TIFF_ERROR; + } + image->colorspace = DeviceCMYK; + } + else + { + /* if it's not separated it must be RGB with alpha */ + image->components = 3; + image->colorspace = DeviceRGB; + image->compression = pdf_comp_none; + } + break; + + default: + errint = image->components; + errcode = PDF_E_IMAGE_BADCOMP; + goto PDF_TIFF_ERROR; + } + } + + + image->src.private_data = (void *) image; + image->src.init = pdf_data_source_TIFF_init; + image->src.fill = pdf_data_source_TIFF_fill; + image->src.terminate = pdf_data_source_TIFF_terminate; + + if (image->use_raw) { + uint32 row, rowsperstrip; + int strip; + + /* must handle colormap ourselves */ + if (photometric == PHOTOMETRIC_PALETTE) + { + int i; + pdf_colormap colormap; + + if (!TIFFGetField(MYTIFF, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) + { + errcode = PDF_E_IMAGE_COLORMAP; + goto PDF_TIFF_ERROR; + } + + cs.type = Indexed; + cs.val.indexed.palette_size = 1 << bpc; + cs.val.indexed.colormap = &colormap; + cs.val.indexed.colormap_id = PDC_BAD_ID; + + cs.val.indexed.base = DeviceRGB; + +#define CVT(x) (uint16) (((x) * 255) / ((1L<<16)-1)) + /* TODO: properly deal with 16-bit palette entries in PDF 1.5 */ + if (pdf_check_colormap(cs.val.indexed.palette_size, + rmap, gmap, bmap) == 16) + { + /* convert colormap to 8 bit values */ + for (i = 0; i < cs.val.indexed.palette_size; i++) + { + rmap[i] = CVT(rmap[i]); + gmap[i] = CVT(gmap[i]); + bmap[i] = CVT(bmap[i]); + } + } +#undef CVT + + for (i = 0; i < cs.val.indexed.palette_size; i++) + { + colormap[i][0] = (pdc_byte) rmap[i]; + colormap[i][1] = (pdc_byte) gmap[i]; + colormap[i][2] = (pdc_byte) bmap[i]; + } + + image->components = 1; + + slot = pdf_add_colorspace(p, &cs, pdc_false); + image->colorspace = slot; + + + } + + + + if (image->strips > image->height) + image->strips = (int) image->height; + + if (TIFFGetFieldDefaulted(MYTIFF, + TIFFTAG_ROWSPERSTRIP, &rowsperstrip) == 1 && (int)rowsperstrip!= -1) + image->rowsperstrip = (int) rowsperstrip; + else + image->rowsperstrip = (int) image->height; + + /* + * The first strip must be handled separately because it carries the + * colormap for indexed images. Other strips reuse this colormap. + */ + image->info.tiff.cur_line = 0; + image->height = (pdc_scalar) + (image->rowsperstrip > (int) h ? (int) h : image->rowsperstrip); + + /* + * Images may also be written to the output before the first page + * We do this ourselves (instead of in pdf_put_image() to avoid + * many empty contents sections for multi-strip images. + */ + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_end_contents_section(p); + + pdf_put_image(p, imageslot, pdc_true, pdc_false); + + for (row = (uint32) image->rowsperstrip, strip = 1; + row < h; row += (uint32) image->rowsperstrip, strip++) { + + image->height = (pdc_scalar) (row+image->rowsperstrip > h ? + (int) (h - row) : image->rowsperstrip); + + /* + * tell pdf_data_source_TIFF_fill() to read only data of the + * current strip + */ + image->info.tiff.cur_line = strip; + pdf_put_image(p, imageslot, pdc_false, pdc_false); + } + + image->height = (pdc_scalar) h; + image->no -= (image->strips - 1); /* number of first strip */ + + /* Special handling for multi-strip images (see comment above) */ + if (PDF_GET_STATE(p) == pdf_state_page) + pdf_begin_contents_section(p); + + } else { /* !use_raw */ + size_t npixels; + + + + /* + * Retrieve full scan lines from TIFFlib for these color spaces, + * and Gray, RGB, or CMYK pixel data otherwise. + */ + if (p->colorspaces[image->colorspace].type == DeviceCMYK || + (p->colorspaces[image->colorspace].type == ICCBased && + image->components == 4)) + { + pdc_logg_cond(p->pdc, 1, trc_image, + "\tRetrieving full scan lines in native color space...\n"); + image->pixelmode = pdc_false; + } + else + { + pdc_logg_cond(p->pdc, 1, trc_image, + "\tRetrieving converted pixel data (pixel mode)...\n"); + image->pixelmode = pdc_true; + } + + if (image->pixelmode) + { + npixels = (size_t) (w * h); + + image->info.tiff.raster = (uint32 *) pdc_malloc(p->pdc, + (size_t) (npixels * sizeof (uint32)), fn); + + if (!TIFFReadRGBAImageOriented(MYTIFF, + w, h, image->info.tiff.raster, orientation, 1)) + { + errcode = PDC_E_IO_READ; + goto PDF_TIFF_ERROR; + } + } + else + { + int linecounter = 0; + + npixels = (size_t) (TIFFScanlineSize(MYTIFF) * h); + image->info.tiff.raster = (uint32 *) + pdc_malloc(p->pdc, (size_t) npixels, fn); + + while (linecounter < image->height) + { + if (TIFFReadScanline(MYTIFF, + (tdata_t) (image->info.tiff.raster + + ((int)image->height - linecounter - 1) * (int)image->width), + (uint32) linecounter, (tsample_t) 0) == -1) + { + errcode = PDC_E_IO_READ; + goto PDF_TIFF_ERROR; + } + linecounter++; + } + } + + pdf_put_image(p, imageslot, pdc_true, pdc_true); + + if (image->info.tiff.raster != NULL) + pdc_free(p->pdc, (void *) image->info.tiff.raster); + } + + image->in_use = pdc_true; /* mark slot as used */ + + if (!image->corrupt) + { + TIFFClose(MYTIFF); + return imageslot; + } + + PDF_TIFF_ERROR: + { + const char *stemp = NULL; + + if (errcode) + stemp = pdf_get_image_filename(p, image); + + if (image->info.tiff.raster != NULL) + pdc_free(p->pdc, (void *) image->info.tiff.raster); + + if (isopen) + TIFFClose(MYTIFF); + + switch (errcode) + { + case PDC_E_IO_READ: + case PDF_E_IMAGE_ICC: + case PDF_E_IMAGE_ICC2: + case PDF_E_IMAGE_MASK1BIT13: + case PDF_E_IMAGE_COLORIZE: + case PDF_E_TIFF_MASK_MULTISTRIP: + case PDF_E_IMAGE_COLORMAP: + case PDF_E_IMAGE_BADMASK: + case PDF_E_TIFF_CMYK_MASK: + case PDF_E_TIFF_UNSUPP_JPEG_SEPARATE: + case PDF_E_TIFF_16BITCMYK_UNSUPP: + case PDF_E_TIFF_16BIT_UNSUPP: + pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0); + break; + + case PDF_E_IMAGE_CORRUPT: + pdc_set_errmsg(p->pdc, errcode, "TIFF", stemp, 0, 0); + break; + + case PDF_E_TIFF_UNSUPP_COLORSPACE: + case PDF_E_TIFF_UNSUPP_COMPRESSION: + case PDF_E_IMAGE_BADCOMP: + pdc_set_errmsg(p->pdc, errcode, + pdc_errprintf(p->pdc, "%d", errint), stemp, 0, 0); + break; + + case PDF_E_IMAGE_NOPAGE: + pdc_set_errmsg(p->pdc, errcode, + pdc_errprintf(p->pdc, "%d", errint), "TIFF", stemp, 0); + break; + + case PDF_E_TIFF_UNSUPP_SEP_NONCMYK: + pdc_set_errmsg(p->pdc, errcode, + stemp, pdc_errprintf(p->pdc, "%d", errint), 0, 0); + break; + + case 0: /* error code and message already set */ + break; + } + } + + return -1; +} + +#undef MYTIFF +#endif /* HAVE_LIBTIFF */ diff --git a/src/pdflib/pdflib/p_truetype.c b/src/pdflib/pdflib/p_truetype.c new file mode 100644 index 0000000..80f2f10 --- /dev/null +++ b/src/pdflib/pdflib/p_truetype.c @@ -0,0 +1,301 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_truetype.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib TrueType handling routines + * + */ + +#include "p_intern.h" +#include "p_font.h" + +#include "ft_truetype.h" + +#ifdef PDF_TRUETYPE_SUPPORTED + + +pdc_bool +pdf_get_metrics_tt(PDF *p, pdf_font *font, const char *fontname, + pdc_encoding enc, const char *filename) +{ + pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_font); + pdc_bool logg2 = pdc_logg_is_enabled(p->pdc, 2, trc_font); + int filesize = 0; + double kbfilesize = 0; + int foundglyphs, flags = 0; + tt_file *ttf; + pdc_bool retval; + pdc_encoding enc_req; + pdc_encodingvector *ev = NULL; + pdc_bool isotf; + int errcode = 0; + + (void) logg2; + + /* + * Initialisation + */ + ttf = fnt_new_tt(p->pdc, &font->ft); + ttf->filename = filename; + ttf->fontname = fontname; + ttf->verbose = font->verbose; + ttf->incore = pdc_true; + ttf->monospace = font->opt.monospace; + filesize = font->ft.filelen; + kbfilesize = filesize / 1024.0; + + /* + * Read font file + */ + retval = fnt_read_tt(ttf); + if (retval == pdc_false) + goto PDF_TRUETYPE_ERROR2; + + /* + * Font type + */ + if (ttf->tab_CFF_) + { + isotf = pdc_true; + font->ft.m.type = fnt_Type1C; + font->cff_offset = (long) ttf->tab_CFF_->offset; + font->cff_length = ttf->tab_CFF_->length; + } + else + { + isotf = pdc_false; + font->ft.m.type = fnt_TrueType; + TT_IOCHECK(ttf, tt_tag2idx(ttf, fnt_str_glyf) != -1); + TT_IOCHECK(ttf, tt_tag2idx(ttf, fnt_str_loca) != -1); + } + + /* Number of Glyphs */ + if (ttf->numGlyphs <= 1) + { + errcode = FNT_E_TT_NOGLYFDESC; + goto PDF_TRUETYPE_ERROR1; + } + + + /* + * Encoding + */ + if (isotf) + { + /* OpenType font with CFF table */ + if (ttf->charcoll != cc_none) + { + /* CID font */ + if (font->ft.m.charcoll != cc_none) + { + if (!ttf->regisadobe) + { + errcode = PDF_E_CJK_UNSUPP_REGISTRY; + goto PDF_TRUETYPE_ERROR1; + } + + if (font->ft.m.charcoll != ttf->charcoll) + { + errcode = PDF_E_CJK_UNSUPP_CHARCOLL; + goto PDF_TRUETYPE_ERROR1; + } + + + if (font->outcmapname != NULL) + enc = pdc_cid; + + if (logg1) + pdc_logg(p->pdc, "\tCID font ordering: \"%s\"\n", + fnt_get_ordering_cid(ttf->charcoll)); + } + else if (enc == pdc_unicode || enc == pdc_glyphid) + { + font->ft.m.charcoll = ttf->charcoll; + font->supplement = ttf->supplement; + } + else + { + errcode = PDF_E_FONT_ONLY_CMAP; + goto PDF_TRUETYPE_ERROR1; + } + } + else if (font->ft.m.charcoll != cc_none) + { + /* SID font */ + errcode = PDF_E_FONT_UNSUPP_CMAP; + goto PDF_TRUETYPE_ERROR1; + } + } + else + { + if (font->ft.m.charcoll != cc_none) + { + int i; + pdc_bool iscjk = pdc_false; + + for (i = 0; i < PDC_NUMCHARCOLL; i++) + { + if (ttf->tab_OS_2->charcolls[i]) + iscjk = pdc_true; + + if (ttf->tab_OS_2->charcolls[i] == font->ft.m.charcoll) + break; + } + if (i == PDC_NUMCHARCOLL) + { + if (iscjk) + { + /* CJK font */ + errcode = PDF_E_CJK_UNSUPP_CHARCOLL; + goto PDF_TRUETYPE_ERROR1; + } + else + { + /* no CJK font */ + errcode = PDF_E_FONT_UNSUPP_CMAP; + goto PDF_TRUETYPE_ERROR1; + } + } + else + { + if (font->outcmapname != NULL) + { + ttf->charcoll = font->ft.m.charcoll; + enc = pdc_cid; + } + } + } + } + + /* encoding vector */ + enc_req = fnt_get_tt_encoding_key(ttf, enc); + if (enc_req == pdc_invalidenc) + { + errcode = FNT_E_TT_BADCMAP; + goto PDF_TRUETYPE_ERROR1; + } + else if (enc_req != enc) + { + if (strcmp(font->encapiname, "auto")) + { + pdc_warning(p->pdc, PDF_E_FONT_FORCEENC, + pdf_get_encoding_name(p, enc_req, NULL), + 0, 0, 0); + } + enc = enc_req; + } + if (enc >= 0) + ev = pdc_get_encoding_vector(p->pdc, enc); + font->ft.enc = enc; + font->ft.issymbfont = ttf->issymbol; + font->hasnomac = !ttf->tab_cmap || !ttf->tab_cmap->mac; + + + /* builtin encoding */ + if (enc == pdc_builtin) + { + if (font->ft.issymbfont == pdc_false) + { + errcode = PDF_E_FONT_BADENC; + goto PDF_TRUETYPE_ERROR1; + } + else + { + /* encoding vector for builtin */ + ev = pdf_create_font_encoding(p, enc, font, fontname, pdc_true); + font->symenc = font->ft.enc; + } + } + + { + /* optimizing PDF output */ + if (enc == pdc_ebcdic || + enc == pdc_ebcdic_37 || + enc == pdc_ebcdic_winansi) + font->towinansi = pdc_winansi; + + } + + /* /FontName in FontDescriptor */ + font->ft.m.name = pdc_strdup(p->pdc, ttf->tab_name->englishname4); + + /* /BaseFont name */ + font->ft.name = pdc_strdup(p->pdc, ttf->tab_name->englishname6); + + +#define PDF_RESTRICTED_TT_EMBEDDING 0x02 + /* check embedding flags */ + if ((font->opt.embedding) && ttf->tab_OS_2 && + ttf->tab_OS_2->fsType == PDF_RESTRICTED_TT_EMBEDDING) + { + errcode = FNT_E_TT_EMBED; + goto PDF_TRUETYPE_ERROR1; + } + + + if (logg1) + { + pdc_logg(p->pdc, + "\tFull font name: \"%s\"\n" + "\tPostScript font name: \"%s\"\n" + "\tFont embedding: %s\n", + font->ft.name, font->ft.m.name, + PDC_BOOLSTR(font->opt.embedding)); + + if (ttf->tab_name->producer != NULL) + pdc_logg(p->pdc, "\tFont producer: \"%s\"\n", + ttf->tab_name->producer); + + pdc_logg(p->pdc, "\tNumber of Glyphs: %d\n", ttf->numGlyphs); + } + + /* Save font values */ + fnt_set_tt_fontvalues(ttf); + + /* Flags for creating font arrays */ + flags = TT_FONT_code2gid | TT_FONT_m_widths; + + + /* Create font mapping and width arrays */ + foundglyphs = fnt_set_tt_fontarrays(ttf, flags); + + /***********************************/ + if (font->symenc != pdc_invalidenc) + font->ft.enc = pdc_builtin; + /***********************************/ + + if (!foundglyphs) + { + errcode = PDF_E_FONT_BADENC; + goto PDF_TRUETYPE_ERROR1; + } + + + fnt_delete_tt(ttf); + + if (!pdf_make_fontflag(p, font)) + return pdc_false; + + return pdc_true; + + PDF_TRUETYPE_ERROR1: + pdc_set_errmsg(p->pdc, errcode, 0, 0, 0, 0); + + PDF_TRUETYPE_ERROR2: + fnt_delete_tt(ttf); + + return pdc_false; +} + + +#endif /* PDF_TRUETYPE_SUPPORTED */ diff --git a/src/pdflib/pdflib/p_type1.c b/src/pdflib/pdflib/p_type1.c new file mode 100644 index 0000000..8483710 --- /dev/null +++ b/src/pdflib/pdflib/p_type1.c @@ -0,0 +1,427 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_type1.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib Type1 font handling routines + * + */ + +#include "pc_ctype.h" + +#include "p_intern.h" +#include "p_font.h" + + +/* Type 1 font portions: ASCII, encrypted, zeros */ +typedef enum { t1_ascii, t1_encrypted, t1_zeros } pdf_t1portion; + +typedef struct { + pdf_t1portion portion; + size_t length[4]; + pdc_file *fontfile; + pdc_byte *img; /* in-core Type1 font file image */ + pdc_byte *end; /* first byte above image buf */ + pdc_byte *pos; /* current "file" position */ +} t1_private_data; + +#define PFA_TESTBYTE 4 + +#define PDF_CURRENTFILE "currentfile eexec" + + +/* ---------------------------- General platforms --------------------------- */ + +#define LINEBUFLEN 256 + +/* + * PFA files are assumed to be encoded in host format. Therefore + * we must use literal strings and characters for interpreting the + * font file. + */ + +static int +PFA_data_fill(PDF *p, PDF_data_source *src) +{ + static const char *fn = "PFA_data_fill"; +#ifndef PDFLIB_EBCDIC + static const char HexToBin['F' - '0' + 1] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15 + }; +#else +#endif + char *s, *c; + int i; + int len; + t1_private_data *t1_private; + pdf_t1portion t1portion; + + t1_private = (t1_private_data *) src->private_data; + + if (src->buffer_start == NULL) + { + src->buffer_start = (pdc_byte *) pdc_malloc(p->pdc, LINEBUFLEN + 1, fn); + src->buffer_length = LINEBUFLEN; + } + + s = pdc_fgetline((char *) src->buffer_start, LINEBUFLEN, + t1_private->fontfile); + if (s == NULL) + return pdc_false; + + /* set unix line end */ + len = (int) strlen(s); + s[len] = '\n'; + len++; + s[len] = 0; + + /* check for line of zeros: set t1_zero flag if found */ + if (*s == '0') + { + for (i = 0; s[i] == '0'; i++) + { + /* */ ; + } + if (s[i] == '\n') + t1_private->portion = t1_zeros; + } + + /* check whether font data portion follows: set t1_encrypted flag later */ + t1portion = t1_private->portion; + if (t1_private->portion != t1_encrypted && + !strncmp((const char *)s, PDF_CURRENTFILE, strlen(PDF_CURRENTFILE))) + t1portion = t1_encrypted; + + src->next_byte = src->buffer_start; + + switch (t1_private->portion) + { + case t1_ascii: + { + t1_private->length[1] += (size_t) len; + src->bytes_available = (size_t) len; + } + break; + + case t1_encrypted: + { + src->bytes_available = 0; + + /* Convert to upper case for safe binary conversion */ + for (c = s; *c != '\n'; c++) + { + *c = (char) pdc_toupper(*c); + } + + /* convert ASCII to binary in-place */ + for (i = 0; s[i] != '\n'; i += 2) + { + if ((!pdc_isxdigit(s[i]) && !pdc_isspace(s[i])) || + (!pdc_isxdigit(s[i+1]) && !pdc_isspace(s[i+1]))) + { + pdc_fclose(t1_private->fontfile); + pdc_error(p->pdc, PDF_E_FONT_CORRUPT, "PFA", "?", 0, 0); + } +#ifndef PDFLIB_EBCDIC + s[i/2] = (char) (16*HexToBin[s[i]-'0'] + HexToBin[s[i+1]-'0']); +#else +#endif + src->bytes_available++; + } + t1_private->length[2] += src->bytes_available; + } + break; + + case t1_zeros: + { + t1_private->length[3] += (size_t) len; + src->bytes_available = (size_t) len; + } + break; + } + + t1_private->portion = t1portion; + + return pdc_true; +} + +#define PFB_MARKER 0x80 +#define PFB_ASCII 1 +#define PFB_BINARY 2 +#define PFB_EOF 3 + +static int +pdf_t1getc(t1_private_data *t1) +{ + int val; + + if (t1->fontfile) + { + return pdc_fgetc(t1->fontfile); + } + val = (int) *t1->pos; + t1->pos++; + + return val; +} + +static pdc_bool +pdf_read_pfb_segment(PDF *p, PDF_data_source *src, t1_private_data *t1, int i) +{ + static const char *fn = "pdf_read_pfb_segment"; + size_t length, len; + + length = (size_t) (pdf_t1getc(t1) & 0xff); + length |= (size_t) (pdf_t1getc(t1) & 0xff) << 8; + length |= (size_t) (pdf_t1getc(t1) & 0xff) << 16; + length |= (size_t) (pdf_t1getc(t1) & 0xff) << 24; + + if (src->buffer_start) + pdc_free(p->pdc, (void *) src->buffer_start); + src->buffer_start = (pdc_byte *) pdc_malloc(p->pdc, length, fn); + + if (t1->fontfile) { + len = pdc_fread(src->buffer_start, 1, length, t1->fontfile); + } else { + len = length; + if (t1->pos + len > t1->end) + len = (unsigned int)(t1->end - t1->pos); + memcpy(src->buffer_start, t1->pos, len); + t1->pos += len; + } + + t1->length[i] = len; + src->next_byte = src->buffer_start; + src->bytes_available = len; + + return (len != length) ? pdc_true : pdc_false;; +} + +static int +PFB_data_fill(PDF *p, PDF_data_source *src) +{ + t1_private_data *t1; + unsigned char c, type; + pdc_bool err = pdc_false; + + t1 = (t1_private_data *) src->private_data; + + c = (unsigned char) pdf_t1getc(t1); + type = (unsigned char) pdf_t1getc(t1); + + if (t1->length[1] == (size_t) 0) { + if (c != PFB_MARKER || type != PFB_ASCII) { + err = pdc_true; + } else { + err = pdf_read_pfb_segment(p, src, t1, 1); + } + + } else if (t1->length[2] == (size_t) 0) { + if (c != PFB_MARKER || type != PFB_BINARY) { + err = pdc_true; + } else { + err = pdf_read_pfb_segment(p, src, t1, 2); + } + + } else if (t1->length[3] == 0) { + if (c != PFB_MARKER || type != PFB_ASCII) { + err = pdc_true; + } else { + err = pdf_read_pfb_segment(p, src, t1, 3); + } + } else if (c != PFB_MARKER || type != PFB_EOF) { + err = pdc_true; + } else { + return pdc_false; + } + + if (err) { + if (t1->fontfile) + pdc_fclose(t1->fontfile); + pdc_error(p->pdc, PDF_E_FONT_CORRUPT, "PFB", "?", 0, 0); + } + + return pdc_true; +} + +static void +t1data_terminate(PDF *p, PDF_data_source *src) +{ + pdc_free(p->pdc, (void *) src->buffer_start); +} + +static void +t1data_init(PDF *p, PDF_data_source *src) +{ + t1_private_data *t1_private; + + (void) p; + + t1_private = (t1_private_data *) src->private_data; + + t1_private->portion = t1_ascii; + t1_private->length[1] = (size_t) 0; + t1_private->length[2] = (size_t) 0; + t1_private->length[3] = (size_t) 0; + + src->buffer_start = NULL; +} + + +pdc_bool +pdf_t1open_fontfile(PDF *p, pdf_font *font, const char *filename, + PDF_data_source *t1src, pdc_bool requested) +{ + static const char *fn = "pdf_t1open_fontfile"; + t1_private_data *t1_private = NULL; + pdc_file *fp = NULL; + const char *stemp = NULL; + unsigned char magic[PFA_TESTBYTE]; + char fullname[PDC_FILENAMELEN]; + int fflags = PDC_FILE_BINARY; + int ispfb = pdc_true; + + if (filename) + { + + fp = pdc_fsearch_fopen(p->pdc, filename, fullname, "PostScript Type1 ", + fflags); + if (fp == NULL) + { + if (t1src) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + return pdc_check_fopen_errmsg(p->pdc, requested); + } + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tLoading PostScript Type1 fontfile \"%s\":\n", fullname); + + } + + if (fp) + { + pdc_fread(magic, 1, PFA_TESTBYTE, fp); + stemp = filename; + } + else if (font->ft.img) + { + strncpy((char *) magic, (const char *)font->ft.img, PFA_TESTBYTE); + stemp = font->ft.name; + } + + /* try to identify PFA files */ + if (magic[0] != PFB_MARKER) + { + char startsequ[PFA_TESTBYTE + 1]; + + strcpy(startsequ, FNT_PFA_STARTSEQU); + + if (strncmp((const char *) magic, startsequ, PFA_TESTBYTE)) + { + if (fp) + pdc_fclose(fp); + pdc_set_errmsg(p->pdc, PDF_E_T1_NOFONT, stemp, 0, 0, 0); + if (t1src) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + return pdc_false; + } + ispfb = pdc_false; + } + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPostScript Type1 font of format \"%s\" detected\n", + ispfb ? "PFB" : "PFA"); + + if (t1src) + { + t1src->private_data = (unsigned char *) + pdc_malloc(p->pdc, sizeof(t1_private_data), fn); + t1_private = (t1_private_data *) t1src->private_data; + + if (filename) + { + pdc_fclose(fp); + if (ispfb) + { + t1_private->fontfile = + pdc_fsearch_fopen(p->pdc, fullname, NULL, "PFB ", fflags); + } + else + { + t1_private->fontfile = + pdc_fsearch_fopen(p->pdc, fullname, NULL, "PFA ", + PDC_FILE_TEXT); + } + + if (t1_private->fontfile == NULL) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + else if (font->ft.img) + { + t1_private->fontfile = NULL; + t1_private->img = font->ft.img; + t1_private->pos = font->ft.img; + t1_private->end = font->ft.img + font->ft.filelen; + } + + t1src->init = t1data_init; + t1src->fill = ispfb ? PFB_data_fill : PFA_data_fill; + t1src->terminate = t1data_terminate; + } + else if (fp != NULL) + { + if (pdc_file_isvirtual(fp) == pdc_true) + { + if (ispfb) + font->ft.img = + (pdc_byte *) pdc_freadall(fp, &font->ft.filelen, NULL); + font->ft.imgname = pdc_strdup(p->pdc, fullname); + pdc_lock_pvf(p->pdc, font->ft.imgname); + } + font->ft.filename = pdc_strdup(p->pdc, fullname); + pdc_fclose(fp); + } + + return pdc_true; +} + +pdc_bool +pdf_make_t1src (PDF *p, pdf_font *font, PDF_data_source *t1src) +{ + return pdf_t1open_fontfile(p, font, font->filename, t1src, pdc_true); +} + +void +pdf_put_length_objs(PDF *p, PDF_data_source *t1src, + pdc_id length1_id, pdc_id length2_id, pdc_id length3_id) +{ + pdc_begin_obj(p->out, length1_id); /* Length1 object */ + pdc_printf(p->out, "%ld\n", + (long) ((t1_private_data *) t1src->private_data)->length[1]); + pdc_end_obj(p->out); + + pdc_begin_obj(p->out, length2_id); /* Length2 object */ + pdc_printf(p->out, "%ld\n", + (long) ((t1_private_data *) t1src->private_data)->length[2]); + pdc_end_obj(p->out); + + pdc_begin_obj(p->out, length3_id); /* Length3 object */ + pdc_printf(p->out, "%ld\n", + (long) ((t1_private_data *) t1src->private_data)->length[3]); + pdc_end_obj(p->out); + + if (((t1_private_data *) t1src->private_data)->fontfile) + pdc_fclose(((t1_private_data *) t1src->private_data)->fontfile); + + pdc_free(p->pdc, (void *) t1src->private_data); +} diff --git a/src/pdflib/pdflib/p_type3.c b/src/pdflib/pdflib/p_type3.c new file mode 100644 index 0000000..411bd0d --- /dev/null +++ b/src/pdflib/pdflib/p_type3.c @@ -0,0 +1,740 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_type3.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Routines for Type 3 (user-defined) fonts + * + */ + +#include "p_intern.h" +#include "p_font.h" +#include "p_image.h" + +int +pdf_get_t3colorized(PDF *p) +{ + return p->fonts[p->t3slot].t3font->colorized; +} + +static void +pdf_init_t3font(PDF *p, pdf_t3font *t3font, int glyph_capacity) +{ + static char fn[] = "pdf_init_t3font"; + int i; + + /* statement order is critical for cleanup! + */ + t3font->curr_glyph = 0; + t3font->next_glyph = 0; + t3font->capacity = glyph_capacity; + t3font->glyphs = (pdf_t3glyph *) + pdc_malloc(p->pdc, t3font->capacity * sizeof (pdf_t3glyph), fn); + + for (i = 0; i < t3font->capacity; i++) + t3font->glyphs[i].name = NULL; + + t3font->charprocs_id = PDC_BAD_ID; + t3font->pass = 0; + +} + +void +pdf_cleanup_t3font(PDF *p, pdf_t3font *t3font) +{ + int i; + + for (i = 0; i < t3font->next_glyph; i++) + { + if (t3font->glyphs[i].name) + { + pdc_free(p->pdc, t3font->glyphs[i].name); + t3font->glyphs[i].name = NULL; + } + } + + pdc_free(p->pdc, t3font->glyphs); + t3font->glyphs = NULL; +} + +static void +pdf_type3_protocol(PDF *p, pdf_font *font, pdc_encodingvector *ev) +{ + /* logging protocol */ + if (pdc_logg_is_enabled(p->pdc, 2, trc_font)) + { + char *glyphname; + pdc_ushort uv = 0; + int gid, code, width = 0; + + for (gid = 0; gid < font->t3font->next_glyph; gid++) + { + glyphname = NULL; + + pdc_logg(p->pdc, "\t\tGlyph%4d: ", gid); + + if (ev != NULL) + { + code = font->ft.gid2code[gid]; + uv = ev->codes[code]; + if (glyphname == NULL) + glyphname = ev->chars[code]; + width = fnt_get_glyphwidth(code, &font->ft); + + pdc_logg(p->pdc, "code=%3d ", code); + } + + if (width == FNT_MISSING_WIDTH) + width = 0; + + pdc_logg(p->pdc, "U+%04X width=%4d \"%s\"\n", + uv, width, glyphname); + } + } +} + +/* + * We found a Type 3 font in the cache, but its encoding doesn't match. + * Make a copy of the font in a new slot, and attach the new encoding. + */ + +pdc_bool +pdf_handle_t3font(PDF *p, const char *fontname, pdc_encoding enc, + pdf_font *font, int *slot) +{ + static const char fn[] = "pdf_handle_t3font"; + const char *encname; + char *fname; + size_t namlen; + pdf_font *deffont = &p->fonts[*slot]; + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + fnt_font_metric *ftm = &font->ft.m; + size_t nalloc; + int code, gid; + pdc_bool newinst = pdc_false; + + /* font name incl. encoding name */ + encname = pdc_get_user_encoding(p->pdc, enc); + namlen = strlen(fontname) + strlen(encname) + 2; + fname = (char *) pdc_malloc(p->pdc, namlen, fn); + pdc_sprintf(p->pdc, pdc_false, fname, "%s.%s", fontname, encname); + + /* we have to copy the available font. + * otherwise the original font will be changed + */ + newinst = deffont->ft.enc != pdc_invalidenc; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\n\tType3 font \"%s\" with %d glyphs found\n", + fontname, deffont->t3font->next_glyph); + + if (newinst) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tInstance with specified encoding will be created\n"); + + } + + /* copy data from available font (see pdf__begin_font()) */ + font->ft.m.type = fnt_Type3; + font->ft.matrix = deffont->ft.matrix; + font->t3font = deffont->t3font; + font->ft.numglyphs = deffont->t3font->next_glyph; + nalloc = (size_t) font->ft.numglyphs; + + ftm->name = fname; + font->ft.name = pdc_strdup(p->pdc, fname); + font->ft.enc = enc; + font->ft.issymbfont = pdc_false; + font->opt.embedding = pdc_true; + + if (enc >= pdc_winansi) + { + font->codesize = 1; + font->ft.numcodes = 256; + font->lastcode = -1; + + ftm->widths = (int *) pdc_calloc(p->pdc, + (size_t) font->ft.numcodes * sizeof(int), fn); + ftm->numwidths = font->ft.numcodes; + } + + font->ft.code2gid = (pdc_ushort *) pdc_calloc(p->pdc, + (size_t) font->ft.numcodes * sizeof(pdc_ushort), fn); + + font->ft.gid2code = (pdc_ushort *) pdc_calloc(p->pdc, + nalloc * sizeof (pdc_ushort), fn); + + /* fill up font arrays */ + for (gid = 0; gid < font->ft.numglyphs; gid++) + { + const char *str = NULL, *glyphname = font->t3font->glyphs[gid].name; + + if (enc >= pdc_winansi) + { + /* search for code */ + for (code = 0; code < font->ft.numcodes; code++) + { + if (ev->chars[code] != NULL) + str = ev->chars[code]; + else if (ev->codes[code]) + str = pdc_unicode2glyphname(p->pdc, ev->codes[code]); + + if (str != NULL && !pdc_strcmp(glyphname, str)) + break; + } + + /* code found */ + if (code < font->ft.numcodes) + { + font->ft.code2gid[code] = gid; + font->ft.gid2code[gid] = code; + + if (!gid) + font->gid0code = code; + + if (font->opt.monospace) + ftm->widths[code] = font->opt.monospace; + else + ftm->widths[code] = + (int) (font->t3font->glyphs[gid].width + 0.5); + } + } + } + + + pdf_type3_protocol(p, font, ev); + + /* font flags */ + if (!pdf_make_fontflag(p, font)) + return pdc_false; + + if (newinst) + { + *slot = -1; + } + else + { + if (deffont->apiname != NULL) + pdc_free(p->pdc, deffont->apiname); + *deffont = *font; + deffont->hasoriginal = pdc_true; + } + + return pdc_true; +} + +pdc_bool +pdf_isvalid_font(PDF *p, int slot) +{ + if (slot > -1 && slot < p->fonts_number) + { + pdf_font *font = &p->fonts[slot]; + if (!font->opt.auxiliary && + (font->t3font == NULL || font->t3font->pass != 2)) + return pdc_true; + } + + return pdc_false; +} + +#define PDF_FAMILYNAME_FLAG PDC_OPT_UNSUPP +#define PDF_STRETCH_FLAG PDC_OPT_UNSUPP +#define PDF_WEIGHT_FLAG PDC_OPT_UNSUPP + +/* + * internal font stretch values + */ +#define PDF_FS_ULTRACONDENSED 1 +#define PDF_FS_EXTRACONDENSED 2 +#define PDF_FS_CONDENSED 3 +#define PDF_FS_SEMICONDENSED 4 +#define PDF_FS_NORMAL 5 +#define PDF_FS_SEMIEXPANDED 6 +#define PDF_FS_EXPANDED 7 +#define PDF_FS_EXTRAEXPANDED 8 +#define PDF_FS_ULTRAEXPANDED 9 + +static const pdc_keyconn pdf_fontstretch_keylist[] = +{ + {"UltraCondensed", PDF_FS_ULTRACONDENSED}, + {"ExtraCondensed", PDF_FS_EXTRACONDENSED}, + {"Condensed", PDF_FS_CONDENSED}, + {"SemiCondensed", PDF_FS_SEMICONDENSED}, + {"Normal", PDF_FS_NORMAL}, + {"SemiExpanded", PDF_FS_SEMIEXPANDED}, + {"Expanded", PDF_FS_EXPANDED}, + {"ExtraExpanded", PDF_FS_EXTRAEXPANDED}, + {"UltraExpanded", PDF_FS_ULTRAEXPANDED}, + {NULL, 0} +}; + +/* conf. with fnt_fontweight_keylist[] in ft_font.c */ +static const pdc_keyconn pdf_fontweight_keylist[] = +{ + {"thin", FNT_FW_THIN}, + {"extralight", FNT_FW_EXTRALIGHT}, + {"light", FNT_FW_LIGHT}, + {"normal", FNT_FW_NORMAL}, + {"medium", FNT_FW_MEDIUM}, + {"semibold", FNT_FW_SEMIBOLD}, + {"bold", FNT_FW_BOLD}, + {"extrabold", FNT_FW_EXTRABOLD}, + {"black", FNT_FW_BLACK}, + {NULL, 0} +}; + +/* definitions of begin font options */ +static const pdc_defopt pdf_begin_font_options[] = +{ + {"colorized", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"widthsonly", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL}, + + {"familyname", pdc_stringlist, PDF_FAMILYNAME_FLAG, 1, 1, + 1.0, PDF_MAX_FONTNAME, NULL}, + + {"stretch", pdc_keywordlist, PDF_STRETCH_FLAG, 1, 1, + 0.0, 0.0, pdf_fontstretch_keylist}, + + {"weight", pdc_keywordlist, PDF_WEIGHT_FLAG, 1, 1, + 0.0, 0.0, pdf_fontweight_keylist}, + + PDC_OPT_TERMINATE +}; + +void +pdf__begin_font( + PDF *p, + const char *fontname, int len, + pdc_scalar a, pdc_scalar b, pdc_scalar c, pdc_scalar d, + pdc_scalar e, pdc_scalar f, + const char *optlist) +{ + static const char fn[] = "pdf__begin_font"; + char *fname; + pdc_resopt *results; + pdf_font tmpfont, *font; + pdf_font_options fo; + pdc_scalar det; + pdc_clientdata cdata; + int colorized = pdc_false; + int metricsonly = pdc_false; + int slot; + + if (fontname == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + + /* Converting fontname */ + fname = pdf_convert_name(p, fontname, len, PDC_CONV_WITHBOM); + if (fname == NULL || *fname == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + fontname = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, fname); + pdc_free(p->pdc, fname); + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tBegin of Type3 font \"%s\"\n", fontname); + + /* error message prefix */ + pdc_push_errmsg(p->pdc, PDF_E_T3_FONT_PREFIX, fontname, 0, 0, 0); + + /* look for an already existing font */ + for (slot = 0; slot < p->fonts_number; slot++) + { + if (!pdc_strcmp(p->fonts[slot].apiname, fontname)) + { + if (p->fonts[slot].t3font->pass == 1) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tType3 font [%d] with metric definition found\n", slot); + + PDF_CHECK_STATE(p, pdf_state_document); + + p->fonts[slot].t3font->pass = 2; + p->t3slot = slot; + + pdc_pop_errmsg(p->pdc); + + pdf_pg_suspend(p); + PDF_SET_STATE(p, pdf_state_font); + return; + } + + pdc_error(p->pdc, PDF_E_T3_FONTEXISTS, 0, 0, 0, 0); + } + } + + pdc_check_number(p->pdc, "a", a); + pdc_check_number(p->pdc, "b", b); + pdc_check_number(p->pdc, "c", c); + pdc_check_number(p->pdc, "d", d); + pdc_check_number(p->pdc, "e", e); + pdc_check_number(p->pdc, "f", f); + + det = a*d - b*c; + + if (det == 0) + pdc_error(p->pdc, PDC_E_ILLARG_MATRIX, + pdc_errprintf(p->pdc, "%f %f %f %f %f %f", a, b, c, d, e, f), + 0, 0, 0); + + /* parsing optlist */ + pdf_set_clientdata(p, &cdata); + results = pdc_parse_optionlist(p->pdc, optlist, pdf_begin_font_options, + &cdata, pdc_true); + + pdc_get_optvalues("colorized", results, &colorized, NULL); + pdc_get_optvalues("widthsonly", results, &metricsonly, NULL); + + + pdc_cleanup_optionlist(p->pdc, results); + + /* initialize font struct */ + font = &tmpfont; + pdf_init_font_options(p, &fo); + pdf_init_font(p, font, &fo); + + /* + * We store the new font in a font slot marked with "invalidenc" encoding. + * When the font is used for the first time we modify the encoding. + * Later uses will make a copy if the encoding is different. + */ + + /* API font name */ + font->apiname = pdc_strdup(p->pdc, fontname); + + font->ft.m.type = fnt_Type3; + font->hasoriginal = pdc_true; + + font->ft.matrix.a = a; + font->ft.matrix.b = b; + font->ft.matrix.c = c; + font->ft.matrix.d = d; + font->ft.matrix.e = e; + font->ft.matrix.f = f; + + font->t3font = (pdf_t3font*) pdc_malloc(p->pdc, sizeof(pdf_t3font), fn); + pdf_init_t3font(p, font->t3font, T3GLYPHS_CHUNKSIZE); + + font->t3font->colorized = colorized; + + + /* the resource id is needed until the font dict is written */ + font->t3font->res_id = pdc_alloc_id(p->out); + + /* Now everything is fine, insert Type3 font with invalid encoding */ + slot = pdf_insert_font(p, font); + + /* + * We must store a pointer to the current font because its glyph + * definitions may use other fonts and we would be unable to find + * "our" current font again. This pointer lives throughout the + * font definition, and will be reset in PDF_end_font() below. + */ + p->t3slot = slot; + + if (metricsonly) + { + font->t3font->pass = 1; + pdc_logg_cond(p->pdc, 2, trc_font, + "\t\tonly for metric definition\n"); + } + else + { + pdf_pg_suspend(p); + } + + pdc_pop_errmsg(p->pdc); + + PDF_SET_STATE(p, pdf_state_font); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin font %d]\n", p->t3slot); +} + +void +pdf__end_font(PDF *p) +{ + int ig; + pdf_font *font; + pdf_t3font *t3font; + + PDF_SET_STATE(p, pdf_state_document); + + font = &p->fonts[p->t3slot]; + t3font = font->t3font; + + /* error message prefix */ + pdc_push_errmsg(p->pdc, PDF_E_T3_FONT_PREFIX, font->apiname, 0, 0, 0); + + if (t3font->pass == 0) + { + pdf_t3glyph glyph0 = t3font->glyphs[0]; + + /* search for .notdef glyph */ + if (pdc_strcmp(glyph0.name, (char *) pdc_get_notdef_glyphname())) + { + for (ig = 0; ig < t3font->next_glyph; ig++) + { + if (!pdc_strcmp(t3font->glyphs[ig].name, + (char *) pdc_get_notdef_glyphname())) + break; + } + + if (ig < t3font->next_glyph) + { + pdc_logg_cond(p->pdc, 2, trc_font, + "\tGlyph id %d: \"%s\" will be exchanged " + "with glyph id 0: \"%s\"\n", + ig, t3font->glyphs[ig].name, glyph0.name); + + t3font->glyphs[0] = t3font->glyphs[ig]; + t3font->glyphs[ig] = glyph0; + } + else + { + pdc_warning(p->pdc, PDF_E_T3_MISSNOTDEF, 0, 0, 0, 0); + } + } + } + + if (t3font->pass != 1) + { + t3font->charprocs_id = pdc_alloc_id(p->out); + pdc_begin_obj(p->out, t3font->charprocs_id); /* CharProcs dict */ + pdc_begin_dict(p->out); + + for (ig = 0; ig < t3font->next_glyph; ig++) + { + pdf_t3glyph *glyph = &t3font->glyphs[ig]; + + if (glyph->charproc_id != PDC_BAD_ID) + { + pdf_put_pdfname(p, glyph->name); + pdc_objref(p->out, "", glyph->charproc_id); + } + } + + pdc_end_dict(p->out); + pdc_end_obj(p->out); /* CharProcs dict */ + + pdc_begin_obj(p->out, t3font->res_id); + pdc_begin_dict(p->out); /* Resource dict */ + + pdf_write_page_fonts(p); /* Font resources */ + + pdf_write_page_colorspaces(p); /* Color space resources */ + + pdf_write_page_pattern(p); /* Pattern resources */ + + pdf_write_xobjects(p); /* XObject resources */ + + pdc_end_dict(p->out); /* Resource dict */ + pdc_end_obj(p->out); /* Resource object */ + + pdf_pg_resume(p, -1); + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + /* see pdf__begin_glyph */ + pdf_init_tstate(p); + pdf_init_gstate(p); + pdf_init_cstate(p); + } + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tEnd of Type3 font \"%s\"\n", font->apiname); + + pdc_pop_errmsg(p->pdc); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End font %d]\n", p->t3slot); + + p->t3slot = -1; +} + +void +pdf__begin_glyph( + PDF *p, + const char *glyphname, + pdc_scalar wx, + pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury) +{ + static const char fn[] = "pdf__begin_glyph"; + pdf_font *font; + pdf_t3font *t3font; + pdf_t3glyph *glyph = NULL; + int ig; + + if (glyphname == NULL || *glyphname == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "glyphname", 0, 0, 0); + + font = &p->fonts[p->t3slot]; + t3font = font->t3font; + + /* error message prefix */ + pdc_push_errmsg(p->pdc, PDF_E_T3_FONT_PREFIX, font->apiname, 0, 0, 0); + + for (ig = 0; ig < t3font->next_glyph; ig++) + { + glyph = &t3font->glyphs[ig]; + if (!pdc_strcmp(glyph->name, glyphname)) + { + if (t3font->pass == glyph->pass) + pdc_error(p->pdc, PDF_E_T3_GLYPH, glyphname, 0, 0, 0); + else + break; + } + } + + /* new glyph */ + if (ig == t3font->next_glyph) + { + if (t3font->pass == 2) + pdc_error(p->pdc, PDF_E_T3_UNKOWNGLYPH, glyphname, 0, 0, 0); + + pdc_check_number(p->pdc, "wx", wx); + pdc_check_number(p->pdc, "llx", llx); + pdc_check_number(p->pdc, "lly", lly); + pdc_check_number(p->pdc, "urx", urx); + pdc_check_number(p->pdc, "ury", ury); + + if (t3font->colorized == pdc_true && + (llx != 0 || lly != 0 || + urx != 0 || ury != 0)) + pdc_error(p->pdc, PDF_E_T3_BADBBOX, 0, 0, 0, 0); + + if (ig == t3font->capacity) + { + t3font->capacity *= 2; + t3font->glyphs = (pdf_t3glyph *) pdc_realloc(p->pdc, t3font->glyphs, + t3font->capacity * sizeof (pdf_t3glyph), fn); + } + + glyph = &t3font->glyphs[ig]; + glyph->charproc_id = PDC_BAD_ID; + glyph->name = pdc_strdup(p->pdc, glyphname); + glyph->wx = wx; + glyph->llx = llx; + glyph->lly = lly; + glyph->urx = urx; + glyph->ury = ury; + + /* see comment in p_font.c for explanation */ + glyph->width = 1000 * wx * font->ft.matrix.a; + + /* if the strdup above fails, cleanup won't touch this slot. */ + t3font->next_glyph++; + } + glyph->pass = t3font->pass; + t3font->curr_glyph = ig; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tBegin of Type3 font glyph \"%s\"\n", glyphname); + + if (t3font->pass != 1) + { + if (t3font->pass == 2) + pdc_logg_cond(p->pdc, 2, trc_font, + "\t\tglyph [%d] was used in text\n", ig); + + glyph->charproc_id = pdc_begin_obj(p->out, PDC_NEW_ID); + pdc_begin_dict(p->out); + + p->length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", p->length_id); + + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + + pdc_end_dict(p->out); + + pdc_begin_pdfstream(p->out); + + if (t3font->colorized == pdc_true) + pdc_printf(p->out, "%f 0 d0\n", glyph->wx); + else + { + pdc_printf(p->out, "%f 0 %f %f %f %f d1\n", + glyph->wx, glyph->llx, glyph->lly, glyph->urx, glyph->ury); + + /* adjust the font's bounding box */ + if (glyph->llx < font->ft.bbox.llx) + font->ft.bbox.llx = glyph->llx; + if (glyph->lly < font->ft.bbox.lly) + font->ft.bbox.lly = glyph->lly; + if (glyph->urx > font->ft.bbox.urx) + font->ft.bbox.urx = glyph->urx; + if (glyph->ury > font->ft.bbox.ury) + font->ft.bbox.ury = glyph->ury; + } + + /* we must initialize the text, graphics and color state + * otherwise the user get unpredictable appearance of a + * glyph because of optimizing outputting graphics properties. + * Following statements were inserted due to bug #719 + */ + pdf_init_tstate(p); + pdf_init_gstate(p); + pdf_init_cstate(p); + + PDF_SET_STATE(p, pdf_state_glyph); + } + else + { + PDF_SET_STATE(p, pdf_state_glyphmetric); + } + + pdc_pop_errmsg(p->pdc); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[Begin glyph %d]\n", ig); +} + +void +pdf__end_glyph(PDF *p) +{ + pdf_t3font *t3font = p->fonts[p->t3slot].t3font; + pdf_t3glyph *glyph = &t3font->glyphs[t3font->curr_glyph]; + int ig = t3font->curr_glyph; + + if (t3font->pass != 1 && glyph->charproc_id != PDC_BAD_ID) + { + /* check whether pdf__save() and pdf__restore() calls are balanced */ + if (p->curr_ppt->sl > 0) + pdc_error(p->pdc, PDF_E_GSTATE_UNMATCHEDSAVE, 0, 0, 0, 0); + + pdf_end_text(p); + pdc_end_pdfstream(p->out); /* glyph description stream */ + pdc_end_obj(p->out); /* glyph description */ + + pdc_put_pdfstreamlength(p->out, p->length_id); + } + + PDF_SET_STATE(p, pdf_state_font); + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tEnd of Type3 font glyph \"%s\"\n", + t3font->glyphs[ig].name); + + if (!p->pdc->smokerun) + pdc_logg_cond(p->pdc, 1, trc_api, "[End glyph %d]\n", ig); +} + + +void +pdf_init_type3(PDF *p) +{ + p->t3slot = -1; +} + diff --git a/src/pdflib/pdflib/p_util.c b/src/pdflib/pdflib/p_util.c new file mode 100644 index 0000000..2728236 --- /dev/null +++ b/src/pdflib/pdflib/p_util.c @@ -0,0 +1,733 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_util.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib utility functions + * + */ + +#define P_UTIL_C + +#include "p_intern.h" +#include "p_font.h" +#include "p_image.h" +#include "p_layer.h" + + +/* ------------------------- [hyper]textformat -----------------------------*/ + +void +pdf_check_textformat(PDF *p, pdc_text_format textformat) +{ + if (!p->pdc->ptfrun && p->pdc->unicaplang && textformat != pdc_auto2) + pdc_error(p->pdc, PDF_E_ENC_UNSUPPENCFORMAT, "textformat", 0, 0, 0); + + pdc_logg_cond(p->pdc, 1, trc_encoding, "\tTextformat: \"%s\"\n", + pdc_get_keyword(textformat, pdf_textformat_keylist)); +} + +void +pdf_check_hypertextformat(PDF *p, pdc_text_format hypertextformat) +{ + if (!p->pdc->ptfrun && p->pdc->unicaplang && hypertextformat != pdc_auto2) + pdc_error(p->pdc, PDF_E_ENC_UNSUPPENCFORMAT, "hypertextformat", + 0, 0, 0); + + pdc_logg_cond(p->pdc, 1, trc_encoding, "\tHypertextformat: \"%s\"\n", + pdc_get_keyword(hypertextformat, pdf_textformat_keylist)); +} + + +/* ------------------------- hypertextencoding -----------------------------*/ + +void +pdf_check_hypertextencoding(PDF *p, pdc_encoding hypertextencoding) +{ + if (!p->pdc->ptfrun && p->pdc->unicaplang && + hypertextencoding != pdc_unicode) + pdc_error(p->pdc, PDF_E_ENC_UNSUPPENCFORMAT, "hypertextencoding", + 0, 0, 0); + + pdc_logg_cond(p->pdc, 1, trc_encoding, "\tHypertextencoding: \"%s\"\n", + pdc_get_user_encoding(p->pdc, hypertextencoding)); +} + + +/* ----------------------- string utility functions -----------------------*/ + +static void +pdf_set_convertflags(PDF *p, int *convflags) +{ + (void) p; + (void) convflags; + +} + +const char * +pdf__utf16_to_utf8(PDF *p, const char *utf16string, int len, int *size) +{ + char *utf8string; + int convflags = PDC_CONV_WITHBOM | PDC_CONV_EBCDIC | PDC_CONV_TRY7BYTES; + + pdf_set_convertflags(p, &convflags); + utf8string = pdc_utf16_to_utf8(p->pdc, utf16string, len, convflags, size); + + pdf_insert_utilstring(p, utf8string, pdc_false); + + return utf8string; +} + +const char * +pdf__utf32_to_utf16(PDF *p, const char *utf32string, int len, + const char *ordering, int *outlen) +{ + char *utf16string = pdc_utf32_to_utf16(p->pdc, utf32string, len, + ordering, 0, outlen); + + pdf_insert_utilstring(p, utf16string, pdc_false); + + return utf16string; +} + +const char * +pdf__utf8_to_utf16(PDF *p, const char *utf8string, const char *ordering, + int *outlen) +{ + char *utf16string; + int convflags = PDC_CONV_EBCDIC; + + pdf_set_convertflags(p, &convflags); + utf16string = pdc_utf8_to_utf16(p->pdc, utf8string, ordering, + convflags, outlen); + + pdf_insert_utilstring(p, utf16string, pdc_false); + + return utf16string; +} + +void +pdf_init_stringlists(PDF *p) +{ + p->stringlists_number = 0; + p->stringlists_capacity = 0; + p->stringlists = NULL; + p->stringlistsizes = NULL; + p->utilstrlist_index = -1; + p->utilstring_number = 0; +} + +int +pdf_insert_stringlist(PDF *p, char **stringlist, int ns) +{ + static const char fn[] = "pdf_insert_stringlist"; + int i; + + if (p->stringlists_number == p->stringlists_capacity) + { + int j = p->stringlists_capacity; + + if (!p->stringlists_capacity) + { + p->stringlists_capacity = STRINGLISTS_CHUNKSIZE; + + p->stringlists = (char ***) pdc_malloc(p->pdc, + sizeof(char **) * p->stringlists_capacity, fn); + + p->stringlistsizes = (int *) pdc_malloc(p->pdc, + sizeof(int) * p->stringlists_capacity, fn); + } + else + { + p->stringlists_capacity *= 2; + p->stringlists = (char ***) pdc_realloc(p->pdc, p->stringlists, + sizeof(char **) * p->stringlists_capacity, fn); + + p->stringlistsizes = (int *) pdc_realloc(p->pdc, p->stringlistsizes, + sizeof(int) * p->stringlists_capacity, fn); + } + for (i = j; i < p->stringlists_capacity; i++) + { + p->stringlists[i] = NULL; + p->stringlistsizes[i] = 0; + } + } + + i = p->stringlists_number; + p->stringlists[i] = stringlist; + p->stringlistsizes[i] = ns; + p->stringlists_number++; + + return i; +} + +void +pdf_cleanup_stringlists(PDF *p) +{ + int i; + + if (p->stringlists) + { + for (i = 0; i < p->stringlists_number; i++) + { + if (p->stringlists[i]) + pdc_cleanup_optstringlist(p->pdc, + p->stringlists[i], p->stringlistsizes[i]); + } + pdc_free(p->pdc, p->stringlists); + pdc_free(p->pdc, p->stringlistsizes); + } + + pdf_init_stringlists(p); +} + +#define PDF_MAX_UTILSTRLISTS 10 + +int +pdf_insert_utilstring(PDF *p, const char *utilstring, pdc_bool kdup) +{ + static const char fn[] = "pdf_insert_utilstring"; + char **utilstrlist; + int i = 0; + + if (p->utilstrlist_index == -1) + { + utilstrlist = (char **) pdc_calloc(p->pdc, + PDF_MAX_UTILSTRLISTS * sizeof (char *), fn); + p->utilstrlist_index = + pdf_insert_stringlist(p, utilstrlist, PDF_MAX_UTILSTRLISTS); + } + utilstrlist = p->stringlists[p->utilstrlist_index]; + + if (p->utilstring_number >= PDF_MAX_UTILSTRLISTS) + p->utilstring_number = 0; + i = p->utilstring_number; + if (utilstrlist[i] != NULL) + pdc_free(p->pdc, utilstrlist[i]); + if (kdup) + utilstrlist[i] = pdc_strdup_ext(p->pdc, utilstring, 0, fn); + else + utilstrlist[i] = (char *) utilstring; + p->utilstring_number++; + + return i; +} + +const char * +pdf_get_utilstring(PDF *p, int i) +{ + if (p->utilstrlist_index > -1 && i > -1 && i < p->utilstring_number) + { + char **utilstrlist = p->stringlists[p->utilstrlist_index]; + return utilstrlist[i]; + } + + return NULL; +} + +/* ------------------------ name treatment -------------------------------*/ + +void +pdf_put_pdfname(PDF *p, const char *name) +{ + char *ascname = (char *) name; + int len = (int) strlen(ascname); + + + pdc_put_pdfname(p->out, ascname, len); + +} + + +/* ---------------------- hyper text treatment -------------------------------*/ + +pdc_encoding +pdf_get_hypertextencoding_opt(PDF *p, pdc_resopt *resopts, int *codepage, + pdc_bool verbose) +{ + char **strlist; + pdc_encoding htenc; + + if (pdc_get_optvalues("hypertextencoding", resopts, NULL, &strlist)) + { + int cp; + + htenc = pdf_get_hypertextencoding(p, strlist[0], &cp, verbose); + pdf_check_hypertextencoding(p, htenc); + + if (codepage) + *codepage = cp; + } + else + { + htenc = pdf_get_hypertextencoding_param(p, codepage); + } + + return htenc; +} + +/* hypertext conversion for deprecated functions */ +char * +pdf_convert_hypertext_depr(PDF *p, const char *text, int len) +{ + int outlen; + + pdf_get_hypertextencoding_param(p, NULL); + + return pdf_convert_hypertext(p, text, len, p->hypertextformat, + p->hypertextencoding, p->hypertextcodepage, &outlen, + PDC_UTF8_FLAG, pdc_true); +} + +/* + * Conversion to PDFDoc/EBCDIC or UTF-16/[EBCDIC-]UTF-8 + */ +char * +pdf_convert_hypertext(PDF *p, const char *text, int len, + pdc_text_format hypertextformat, pdc_encoding hypertextencoding, + int codepage, int *outlen, pdc_bool oututf8, pdc_bool verbose) +{ + pdc_encodingvector *inev = NULL, *outev = NULL; + pdc_byte *intext = (pdc_byte *) text, *outtext = NULL; + pdc_text_format textformat = pdc_utf16be; + int convflags = PDC_CONV_WITHBOM | PDC_CONV_TRYBYTES; + + *outlen = 0; + + if (text == NULL) + return NULL; + + if (len == 0) + len = (int) strlen(text); + + /* incoming encoding */ + if (hypertextencoding >= 0) + { + inev = pdc_get_encoding_vector(p->pdc, hypertextencoding); + } + + /* PDFDocEncoding */ + outev = pdc_get_encoding_vector(p->pdc, pdc_pdfdoc); + + /* conversion to UTF-16-BE or PDFDocEncoding / EBCDIC */ + pdf_set_convertflags(p, &convflags); + pdc_convert_string(p->pdc, hypertextformat, codepage, inev, + intext, len, + &textformat, outev, &outtext, outlen, + convflags, verbose); + + + /* conversion to UTF-8 if Unicode */ + if (oututf8 && textformat == pdc_utf16be) + { + pdc_text_format outtextformat = PDC_UTF8; + pdc_byte *newtext = NULL; + + pdc_convert_string(p->pdc, textformat, 0, NULL, outtext, *outlen, + &outtextformat, NULL, &newtext, outlen, + PDC_CONV_WITHBOM, verbose); + pdc_free(p->pdc, outtext); + outtext = newtext; + } + + return (char *) outtext; +} + + +/* + * Conversion from [EBCDIC-]UTF-8 to UTF-16 and from EBCDIC to PDFDoc + */ +static void +pdf_put_hypertext_ext(PDF *p, const char *text, pdc_bool isfilename) +{ + pdc_byte *newtext = NULL; + pdc_encodingvector *outev = pdc_get_encoding_vector(p->pdc, pdc_pdfdoc); + int len = (int) pdc_strlen(text); + int convflags = PDC_CONV_WITHBOM | PDC_CONV_TRYBYTES; + + if (pdc_is_utf8_bytecode(text)) + { + pdc_text_format textformat = PDC_UTF8; + pdc_text_format outtextformat = pdc_utf16be; + + pdf_set_convertflags(p, &convflags); + pdc_convert_string(p->pdc, textformat, 0, NULL, (pdc_byte *) text, len, + &outtextformat, outev, &newtext, &len, + convflags, pdc_true); + text = (const char *) newtext; + } + + if (isfilename) + { + if (pdc_is_utf16be_unicode(text)) + pdc_error(p->pdc, PDC_E_IO_UNSUPP_UNINAME, 0, 0, 0, 0); + pdc_put_pdffilename(p->out, text, len); + } + else + { + pdc_put_pdfstring(p->out, text, len); + } + + if (newtext != NULL) + pdc_free(p->pdc, newtext); +} + +void +pdf_put_hypertext(PDF *p, const char *text) +{ + pdf_put_hypertext_ext(p, text, pdc_false); +} + +void +pdf_put_pdffilename(PDF *p, const char *text) +{ + pdf_put_hypertext_ext(p, text, pdc_true); +} + + +/* ------------------------ name strings -------------------------------*/ + +static void +pdf_prepare_name_string(PDF *p, const char *name, int len, + char **newname, int *newlen, + pdc_encoding *htenc, int *htcp) +{ + *newname = (char *) name; + *newlen = len; + *htenc = pdc_invalidenc; + *htcp = 0; + + if (p->usehyptxtenc && !len && !pdc_is_utf8_bytecode(name)) + { + *htenc = pdf_get_hypertextencoding_param(p, htcp); + + } +} + +char * +pdf_convert_name(PDF *p, const char *name, int len, int flags) +{ + char *resname; + char *newname; + int newlen; + pdc_encoding htenc; + int htcp; + + pdf_prepare_name_string(p, name, len, &newname, &newlen, &htenc, &htcp); + + flags |= PDC_CONV_EBCDIC; + resname = pdc_convert_name_ext(p->pdc, newname, newlen, htenc, htcp, flags); + if (newname != name) + pdc_free(p->pdc, newname); + + return resname; +} + +const char * +pdf_convert_filename(PDF *p, const char *filename, int len, + const char *paramname, int flags) +{ + const char *resfilename; + char *newfilename; + int newlen; + pdc_encoding htenc; + int htcp; + + pdf_prepare_name_string(p, filename, len, &newfilename, &newlen, + &htenc, &htcp); + + flags |= PDC_CONV_EBCDIC; + resfilename = pdc_convert_filename_ext(p->pdc, newfilename, len, + paramname, htenc, htcp, flags); + if (newfilename != filename) + pdc_free(p->pdc, newfilename); + + return resfilename; +} + +void +pdf_add_resource(PDF *p, const char *category, const char *resname) +{ + char *newresname; + int newlen; + pdc_encoding htenc; + int htcp; + + pdf_prepare_name_string(p, resname, 0, &newresname, &newlen, + &htenc, &htcp); + if (newlen) + { + char *tmpresname = pdc_utf16_to_utf8(p->pdc, newresname, newlen, + PDC_CONV_EBCDIC | PDC_CONV_WITHBOM, + &newlen); + pdc_free(p->pdc, newresname); + newresname = tmpresname; + newlen = 0; + } + + pdc_add_resource_ext(p->pdc, category, newresname, NULL, htenc, htcp); + + if (newresname != resname) + pdc_free(p->pdc, newresname); +} + +/* ------------------------ option text list -------------------------------*/ + +int +pdf_get_opt_textlist(PDF *p, const char *keyword, pdc_resopt *resopts, + pdc_encoding enc, int codepage, pdc_bool ishypertext, + const char *fieldname, char **text, char ***textlist) +{ + pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_optlist); + int ns; + char **strlist; + + ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist); + if (ns) + { + pdc_byte *string = NULL; + pdc_encodingvector *inev = NULL, *outev = NULL; + pdc_text_format intextformat = pdc_bytes, outtextformat = pdc_utf16be; + int convflags = PDC_CONV_WITHBOM | PDC_CONV_TRYBYTES; + pdc_bool isutf8; + int i, outlen; + + /* whole option list or string list is in UTF-8 */ + isutf8 = pdc_is_lastopt_utf8(resopts); + + /* Encoding */ + if (ishypertext) + { + /* Initialize */ + if (!isutf8) + { + if (enc < 0 && enc != pdc_unicode && enc != pdc_cid) + enc = pdf_get_hypertextencoding(p, "auto", &codepage, + pdc_true); + if (enc >= 0) + inev = pdc_get_encoding_vector(p->pdc, enc); + } + + /* PDFDocEncoding */ + outev = pdc_get_encoding_vector(p->pdc, pdc_pdfdoc); + } + else + { + if (enc == pdc_invalidenc) + { + if (fieldname) + { + pdc_cleanup_optionlist(p->pdc, resopts); + pdc_error(p->pdc, PDF_E_FF_FONTMISSING, fieldname, 0, 0, 0); + } + return 0; + } + else if (enc >= 0) + { + outev = pdc_get_encoding_vector(p->pdc, enc); + } + } + + if (logg1) + { + if (isutf8) + { + pdc_logg(p->pdc, "\tOption \"%s\" is "PDC_UTF8_STRG" encoded\n", + keyword); + } + else + { + pdc_logg(p->pdc, "\tOption \"%s\" is %s encoded\n", + keyword, pdc_get_user_encoding(p->pdc, enc)); + } + } + + for (i = 0; i < ns; i++) + { + string = (pdc_byte *) strlist[i]; + + { + if (ishypertext || isutf8) + { + intextformat = isutf8 ? PDC_UTF8 : pdc_bytes; + + if (pdc_logg_is_enabled(p->pdc, 2, trc_optlist)) + convflags |= PDC_CONV_LOGGING; + pdf_set_convertflags(p, &convflags); + pdc_convert_string(p->pdc, intextformat, codepage, inev, + string, (int) strlen((char *) string), + &outtextformat, outev, &string, &outlen, + convflags, pdc_true); + pdc_free(p->pdc, strlist[i]); + strlist[i] = (char *) string; + } + } + } + + if (text) + *text = strlist[0]; + else + *textlist = strlist; + + if (fieldname) + { + strlist = (char **) pdc_save_lastopt(resopts, PDC_OPT_SAVEALL); + pdf_insert_stringlist(p, strlist, ns); + } + } + + return ns; +} + +char * +pdf_get_opt_utf8name(PDF *p, const char *keyword, pdc_resopt *resopts) +{ + char **strlist = NULL; + char *utf8name = NULL; + + if (pdc_get_opt_utf8strings(p->pdc, keyword, resopts, PDC_OPT_SAVE1ELEM, + &strlist)) + { + utf8name = strlist[0]; + } + + return utf8name; +} + + +/* -------------------------- errorpolicy -------------------------------*/ + +pdc_bool +pdf_get_errorpolicy(PDF *p, pdc_resopt *resopts, pdc_bool verbose) +{ + int errpol = (int) p->errorpolicy; + + if (resopts != NULL) + pdc_get_optvalues("errorpolicy", resopts, &errpol, NULL); + + if (errpol != (int) errpol_legacy) + verbose = errpol; + + return verbose; +} + + +/* -------------------------- handle check -------------------------------*/ + +void +pdf_check_handle(PDF *p, int handle, pdc_opttype type) +{ + int minval = 0, maxval = 0; + pdc_bool empty = pdc_false; + + switch (type) + { + + case pdc_actionhandle: + maxval = pdf_get_max_action(p); + break; + + case pdc_bookmarkhandle: + maxval = p->outline_count; + break; + + case pdc_colorhandle: + maxval = p->colorspaces_number - 1; + break; + + + case pdc_fonthandle: + maxval = p->fonts_number - 1; + empty = !pdf_isvalid_font(p, handle); + break; + + case pdc_gstatehandle: + maxval = p->extgstates_number - 1; + break; + + + case pdc_imagehandle: + maxval = p->images_capacity - 1; + if (handle >= minval && handle <= maxval && + (!p->images[handle].in_use || + p->xobjects[p->images[handle].no].type == pdi_xobject)) + empty = pdc_true; + break; + + + case pdc_pagehandle: + maxval = p->images_capacity - 1; + if (handle >= minval && handle <= maxval && + (!p->images[handle].in_use || + p->xobjects[p->images[handle].no].type != pdi_xobject)) + empty = pdc_true; + break; + + case pdc_patternhandle: + maxval = p->pattern_number - 1; + break; + + case pdc_shadinghandle: + maxval = p->shadings_number - 1; + break; + + + case pdc_templatehandle: + maxval = p->images_capacity - 1; + if (handle >= minval && handle <= maxval && + (!p->images[handle].in_use || + p->xobjects[p->images[handle].no].type != form_xobject)) + empty = pdc_true; + break; + + + case pdc_stringhandle: + if (p->utilstrlist_index == -1) + empty = pdc_true; + maxval = p->utilstring_number - 1; + break; + + default: + break; + } + + if (handle < minval || handle > maxval || empty) + { + const char *stemp1 = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, + pdc_get_handletype(type)); + const char *stemp2 = pdc_errprintf(p->pdc, "%d", + (p->pdc->hastobepos && type != pdc_stringhandle) ? + handle + 1 : handle); + pdc_error(p->pdc, PDC_E_ILLARG_HANDLE, stemp1, stemp2, 0, 0); + } +} + +void +pdf_set_clientdata(PDF *p, pdc_clientdata *cdata) +{ + memset(cdata, 0, sizeof(pdc_clientdata)); + + cdata->maxaction = pdf_get_max_action(p); + cdata->maxbookmark = p->outline_count; + cdata->maxcolor = p->colorspaces_number - 1; + cdata->maxdocument = p->pdi_capacity - 1; + cdata->maxfont = p->fonts_number - 1; + cdata->maxgstate = p->extgstates_number - 1; + cdata->maximage = p->images_capacity - 1; + cdata->maxpage = p->images_capacity - 1; + cdata->maxpattern = p->pattern_number - 1; + cdata->maxshading = p->shadings_number - 1; + cdata->maxtemplate = p->images_capacity - 1; + cdata->maxstring = p->utilstring_number - 1; + + cdata->compatibility = p->compatibility; +} diff --git a/src/pdflib/pdflib/p_xgstate.c b/src/pdflib/pdflib/p_xgstate.c new file mode 100644 index 0000000..0e62df9 --- /dev/null +++ b/src/pdflib/pdflib/p_xgstate.c @@ -0,0 +1,514 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_xgstate.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Extended graphics state handling + * + */ + +#define P_XGSTATE_C + +#include "p_intern.h" +#include "p_font.h" + +static const pdc_keyconn pdf_blendmode_pdfkeylist[] = +{ + {"Normal", BM_Normal}, + {"Multiply", BM_Multiply}, + {"Screen", BM_Screen}, + {"Overlay", BM_Overlay}, + {"Darken", BM_Darken}, + {"Lighten", BM_Lighten}, + {"ColorDodge", BM_ColorDodge}, + {"ColorBurn", BM_ColorBurn}, + {"HardLight", BM_HardLight}, + {"SoftLight", BM_SoftLight}, + {"Difference", BM_Difference}, + {"Exclusion", BM_Exclusion}, + {"Hue", BM_Hue}, + {"Saturation", BM_Saturation}, + {"Color", BM_Color}, + {"Luminosity", BM_Luminosity}, + {NULL, 0} +}; + +/* external graphic state */ +struct pdf_extgstateresource_s +{ + pdc_id obj_id; /* object id of this resource */ + pdc_bool used_on_current_page; /* this resource used on current page */ + + pdc_id font_obj; /* font to use */ + pdc_scalar font_size; /* at what size */ + + pdc_scalar line_width; + int line_cap; + int line_join; + pdc_scalar miter_limit; + pdc_scalar* dash_array; + int dash_count; + pdc_scalar dash_phase; + + pdf_renderingintent ri; + pdc_bool stroke_adjust; + pdc_bool overprint_stroke; + pdc_bool overprint_fill; + int overprint_mode; + + /* + The following entries which take functions are not implemented + since PDFlib has no concept of a function at this time. + + BG - black generation + BG2 - black generation + UCR - undercolor-removal + UCR2 - undercolor-removal + TR - transfer + TR2 - transfer + HT - halftone + */ + + pdc_scalar flatness; + pdc_scalar smoothness; + + /* PDF 1.4 additions */ + pdf_blendmode blendmode; /* blend mode */ + pdc_scalar opacity_fill; /* fill opacity level */ + pdc_scalar opacity_stroke; /* stroke opacity level */ + pdc_bool alpha_is_shape; + pdc_bool text_knockout; +}; + +pdc_id +pdf_get_gstate_id(PDF *p, int gstate) +{ + /* TODO: is this required for ExtGStates used in Shadings? */ + p->extgstates[gstate].used_on_current_page = pdc_true; + + return (p->extgstates[gstate].obj_id); +} + +/* Definitions of Explicit Graphics State options */ +static const pdc_defopt pdf_create_gstate_options[] = +{ + {"alphaisshape", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1, 0.0, 0.0, NULL}, + + {"blendmode", pdc_keywordlist, PDC_OPT_BUILDOR | PDC_OPT_PDC_1_4, 1, 20, + 0.0, 0.0, pdf_blendmode_pdfkeylist}, + +/* These features do not work in Acrobat (5.0.1) + {"dasharray", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 8, + PDF_SMALLREAL, PDC_FLOAT_MAX, NULL}, + + {"dashphase", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 1, + 0.0, PDC_FLOAT_MAX, NULL}, + + {"fontsize", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 1, + PDF_SMALLREAL, PDC_FLOAT_MAX, NULL}, + + {"font", pdc_fonthandle, PDC_OPT_PDC_1_3 | PDC_OPT_REQUIRIF1, 1, 1, + 0, 0, NULL}, +*/ + + {"flatness", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 1, + PDF_SMALLREAL, PDC_FLOAT_MAX, NULL}, + + {"linecap", pdc_integerlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 2.0, + pdf_linecap_keylist}, + + {"linejoin", pdc_integerlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 2.0, + pdf_linejoin_keylist}, + + {"linewidth", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 1, + PDF_SMALLREAL, PDC_FLOAT_MAX, NULL}, + + {"miterlimit", pdc_scalarlist, PDC_OPT_PDC_1_3, 1, 1, 1.0, PDC_FLOAT_MAX, + NULL}, + + {"opacityfill", pdc_scalarlist, PDC_OPT_PDC_1_4 | PDC_OPT_PERCENT, + 1, 1, 0.0, 1.0, NULL}, + + {"opacitystroke", pdc_scalarlist, PDC_OPT_PDC_1_4 | PDC_OPT_PERCENT, + 1, 1, 0.0, 1.0, NULL}, + + {"overprintfill", pdc_booleanlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 0.0, NULL}, + + {"overprintmode", pdc_integerlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 1.0, NULL}, + + {"overprintstroke", pdc_booleanlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 0.0, NULL}, + + {"renderingintent", pdc_keywordlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 0.0, + pdf_renderingintent_pdfkeylist}, + + {"smoothness", pdc_scalarlist, PDC_OPT_PDC_1_3 | PDC_OPT_PERCENT, + 1, 1, 0.0, 1.0, NULL}, + + {"strokeadjust", pdc_booleanlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 0.0, NULL}, + + {"textknockout", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1, 0.0, 0.0, NULL}, + + PDC_OPT_TERMINATE +}; + +static void +pdf_init_extgstateresource(pdf_extgstateresource *egsr) +{ + egsr->used_on_current_page = pdc_false; + + /* we need to tell which parms have been set and which haven't, + ** so we initialize to invalid values. even boolean parms are + ** declared as integers, so we can set them to -1 here. + */ + egsr->font_obj = PDC_NEW_ID; + egsr->font_size = pdc_undef; + + egsr->line_width = pdc_undef; + egsr->line_cap = pdc_undef; + egsr->line_join = pdc_undef; + egsr->miter_limit = pdc_undef; + + egsr->dash_array = NULL; + egsr->dash_count = 0; + egsr->dash_phase = 0.0; + + egsr->ri = AutoIntent; + egsr->stroke_adjust = pdc_undef; + egsr->overprint_stroke = pdc_undef; + egsr->overprint_fill = pdc_undef; + egsr->overprint_mode = pdc_undef; + egsr->flatness = pdc_undef; + egsr->smoothness = pdc_undef; + + egsr->blendmode = BM_None; + egsr->opacity_stroke = pdc_undef; + egsr->opacity_fill = pdc_undef; + egsr->alpha_is_shape = pdc_undef; + egsr->text_knockout = pdc_undef; +} + +static void +pdf_grow_extgstates(PDF *p) +{ + int i; + + p->extgstates = (pdf_extgstateresource *) pdc_realloc(p->pdc, p->extgstates, + sizeof(pdf_extgstateresource) * 2 * p->extgstates_capacity, + "pdf_grow_extgstates"); + + for (i = p->extgstates_capacity; i < 2 * p->extgstates_capacity; i++) { + pdf_init_extgstateresource( &p->extgstates[i] ); + } + + p->extgstates_capacity *= 2; +} + +void +pdf_init_extgstates(PDF *p) +{ + static const char fn[] = "pdf_init_extgstates"; + int i; + + p->extgstates_number = 0; + p->extgstates_capacity = EXTGSTATE_CHUNKSIZE; + + p->extgstates = (pdf_extgstateresource *) + pdc_malloc(p->pdc, + sizeof(pdf_extgstateresource) * p->extgstates_capacity, fn); + + for (i = 0; i < p->extgstates_capacity; i++) { + pdf_init_extgstateresource( &p->extgstates[i] ); + } +} + +void +pdf_write_page_extgstates(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->eg_bias; + + for (i = 0; i < p->extgstates_number; i++) + if (p->extgstates[i].used_on_current_page) + total++; + + if (total > 0 || bias) + { + pdc_puts(p->out, "/ExtGState"); + pdc_begin_dict(p->out); + } + + if (total > 0) + { + for (i = 0; i < p->extgstates_number; i++) + { + if (p->extgstates[i].used_on_current_page) + { + p->extgstates[i].used_on_current_page = pdc_false; /* reset */ + pdc_printf(p->out, "/GS%d", bias + i); + pdc_objref(p->out, "", p->extgstates[i].obj_id); + } + } + + if (!bias) + pdc_end_dict(p->out); + } +} + +void +pdf_get_page_extgstates(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->extgstates_number; i++) { + if (p->extgstates[i].used_on_current_page) { + p->extgstates[i].used_on_current_page = pdc_false; /* reset */ + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_extgstate(PDF *p, int n) +{ + p->extgstates[n].used_on_current_page = pdc_true; +} + +void +pdf_write_doc_extgstates(PDF *p) +{ + int i, j; + + pdf_extgstateresource *gs; + + for (i = 0; i < p->extgstates_number; i++) + { + gs = &p->extgstates[i]; + + pdc_begin_obj(p->out, gs->obj_id); /* ExtGState resource */ + pdc_begin_dict(p->out); + + pdc_puts(p->out, "/Type/ExtGState\n"); + + if (gs->font_obj != PDC_NEW_ID) + { + pdc_puts(p->out, "/Font"); + pdc_begin_array(p->out); + pdc_objref(p->out, "", gs->font_obj); + pdc_printf(p->out, "%f", gs->font_size); + pdc_end_array(p->out); + } + + if (gs->line_width != pdc_undef) + pdc_printf(p->out, "/LW %f\n", gs->line_width); + + if (gs->line_cap != pdc_undef) + pdc_printf(p->out, "/LC %d\n", gs->line_cap); + + if (gs->line_join != pdc_undef) + pdc_printf(p->out, "/LJ %d\n", gs->line_join); + + if (gs->miter_limit != pdc_undef) + pdc_printf(p->out, "/ML %f\n", gs->miter_limit); + + if (gs->dash_count > 0) + { + pdc_printf(p->out, "/D"); + pdc_begin_array(p->out); + pdc_begin_array(p->out); + + for (j = 0; j < gs->dash_count; ++j) + pdc_printf(p->out, "%f ", gs->dash_array[j]); + + pdc_end_array_c(p->out); + pdc_printf(p->out, "%f", gs->dash_phase); + pdc_end_array(p->out); + /* but see page 157 of PDF Reference: integer */ + } + + if (gs->ri != AutoIntent) + pdc_printf(p->out, "/RI/%s\n", + pdc_get_keyword((long) gs->ri, pdf_renderingintent_pdfkeylist)); + + if (gs->stroke_adjust != pdc_undef) + pdc_printf(p->out, "/SA %s\n", PDC_BOOLSTR(gs->stroke_adjust)); + + if (gs->overprint_stroke != pdc_undef) + pdc_printf(p->out, "/OP %s\n", PDC_BOOLSTR(gs->overprint_stroke)); + + if (gs->overprint_fill != pdc_undef) + pdc_printf(p->out, "/op %s\n", PDC_BOOLSTR(gs->overprint_fill)); + else if (gs->overprint_stroke == pdc_true) + pdc_puts(p->out, "/op false\n"); + + if (gs->overprint_mode != pdc_undef) + pdc_printf(p->out, "/OPM %d\n", gs->overprint_mode); + + if (gs->flatness != pdc_undef) + pdc_printf(p->out, "/FL %f\n", gs->flatness); + + if (gs->smoothness != pdc_undef) + pdc_printf(p->out, "/SM %f\n", gs->smoothness); + + if (gs->opacity_fill != pdc_undef) + pdc_printf(p->out, "/ca %f\n", gs->opacity_fill); + + if (gs->blendmode != BM_None) { + const char *modename; + int modecount=0; + + for (j = 0; ; j++) { + if (!pdf_blendmode_pdfkeylist[j].word) + break; + if (gs->blendmode & pdf_blendmode_pdfkeylist[j].code) + modecount++; + } + + pdc_printf(p->out, "/BM"); + + /* + * ACROBUG: Acrobat 7 doesn't like Blend mode arrays with a + * singly entry under some circumstances (many entries? images + * involved?) so we avoid the array if we have only one entry. + */ + if (modecount > 1) + pdc_begin_array(p->out); + + for (j = 0; ; j++) { + modename = pdf_blendmode_pdfkeylist[j].word; + if (!modename) break; + if (gs->blendmode & pdf_blendmode_pdfkeylist[j].code) + pdc_printf(p->out, "/%s", modename); + } + + if (modecount > 1) + pdc_end_array(p->out); + } + + if (gs->opacity_stroke != pdc_undef) + pdc_printf(p->out, "/CA %f\n", gs->opacity_stroke); + + if (gs->alpha_is_shape != pdc_undef) + pdc_printf(p->out, "/AIS %s\n", PDC_BOOLSTR(gs->alpha_is_shape)); + + if (gs->text_knockout != pdc_undef) + pdc_printf(p->out, "/TK %s\n", PDC_BOOLSTR(gs->text_knockout)); + + pdc_end_dict(p->out); + pdc_end_obj(p->out); /* ExtGState resource */ + } +} + +void +pdf_cleanup_extgstates(PDF *p) +{ + int i; + + if (!p->extgstates) + return; + + for (i = 0; i < p->extgstates_number; i++) { + if (p->extgstates[i].dash_array) + pdc_free(p->pdc, p->extgstates[i].dash_array); + } + + pdc_free(p->pdc, p->extgstates); + p->extgstates = NULL; +} + +int +pdf__create_gstate(PDF *p, const char *optlist) +{ + pdf_extgstateresource *gs; + int slot = -1; + int font = pdc_undef; + int inum; + pdc_clientdata data; + pdc_resopt *results; + + if (optlist == NULL || !*optlist) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "optlist", 0, 0, 0); + + slot = p->extgstates_number; + if (slot == p->extgstates_capacity) + pdf_grow_extgstates(p); + + p->extgstates_number++; + gs = &p->extgstates[slot]; + gs->obj_id = pdc_alloc_id(p->out); + + /* parsing optlist */ + pdf_set_clientdata(p, &data); + results = pdc_parse_optionlist(p->pdc, optlist, pdf_create_gstate_options, + &data, pdc_true); + + pdc_get_optvalues("alphaisshape", results, &gs->alpha_is_shape, NULL); + + if (pdc_get_optvalues("blendmode", results, &inum, NULL)) + gs->blendmode = (pdf_blendmode) inum; + + gs->dash_count = pdc_get_optvalues("dasharray", results, NULL, NULL); + gs->dash_array = (pdc_scalar *) pdc_save_lastopt(results, PDC_OPT_SAVEALL); + + pdc_get_optvalues("dashphase", results, &gs->dash_phase, NULL); + + pdc_get_optvalues("flatness", results, &gs->flatness, NULL); + + pdc_get_optvalues("font", results, &font, NULL); + if (font != pdc_undef) + gs->font_obj = p->fonts[font].obj_id; + + pdc_get_optvalues("fontsize", results, &gs->font_size, NULL); + + pdc_get_optvalues("linecap", results, &gs->line_cap, NULL); + + pdc_get_optvalues("linejoin", results, &gs->line_join, NULL); + + pdc_get_optvalues("linewidth", results, &gs->line_width, NULL); + + pdc_get_optvalues("miterlimit", results, &gs->miter_limit, NULL); + + pdc_get_optvalues("opacityfill", results, &gs->opacity_fill, NULL); + + pdc_get_optvalues("opacitystroke", results, &gs->opacity_stroke, NULL); + + pdc_get_optvalues("overprintfill", results, &gs->overprint_fill, NULL); + + pdc_get_optvalues("overprintmode", results, &gs->overprint_mode, NULL); + + pdc_get_optvalues("overprintstroke", results, &gs->overprint_stroke, NULL); + + if (pdc_get_optvalues("renderingintent", results, &inum, NULL)) + gs->ri = (pdf_renderingintent) inum; + + pdc_get_optvalues("smoothness", results, &gs->smoothness, NULL); + + pdc_get_optvalues("strokeadjust", results, &gs->stroke_adjust, NULL); + + pdc_get_optvalues("textknockout", results, &gs->text_knockout, NULL); + + pdc_cleanup_optionlist(p->pdc, results); + + + + return slot; +} + +void +pdf__set_gstate(PDF *p, int gstate) +{ + int bias = p->curr_ppt->eg_bias; + + pdf_check_handle(p, gstate, pdc_gstatehandle); + + pdc_printf(p->out, "/GS%d gs\n", bias + gstate); + p->extgstates[gstate].used_on_current_page = pdc_true; +} diff --git a/src/pdflib/pdflib/p_xmp.c b/src/pdflib/pdflib/p_xmp.c new file mode 100644 index 0000000..eec4002 --- /dev/null +++ b/src/pdflib/pdflib/p_xmp.c @@ -0,0 +1,25 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_xmp.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib Metadata (XMP) related routines + * + */ + +#define P_XMP_C + +#include "p_intern.h" + + + + diff --git a/src/pdflib/pdflib/pdflib.c b/src/pdflib/pdflib/pdflib.c new file mode 100644 index 0000000..7ecd1f3 --- /dev/null +++ b/src/pdflib/pdflib/pdflib.c @@ -0,0 +1,4052 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pdflib.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib API functions + * + */ + +#define PDFLIB_C + +#include "p_intern.h" + + +#if (defined(WIN32) || defined(__CYGWIN)) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winbase.h> +#undef WIN32_LEAN_AND_MEAN +#endif /* WIN32 || __CYGWIN */ + +#if _MSC_VER >= 1310 /* VS .NET 2003 and later */ +/* pdflib.h declares some functions as deprecated, but we don't want to see + * these warnings here */ +#pragma warning(disable: 4995) +#endif + +static const PDFlib_api PDFlib = { + /* version numbers for checking the DLL against client code */ + sizeof(PDFlib_api), /* size of this structure */ + + PDFLIB_MAJORVERSION, /* PDFlib major version number */ + PDFLIB_MINORVERSION, /* PDFlib minor version number */ + PDFLIB_REVISION, /* PDFlib revision number */ + + 0, /* reserved */ + + PDF_activate_item, + PDF_add_bookmark, + PDF_add_bookmark2, + PDF_add_launchlink, + PDF_add_locallink, + PDF_add_nameddest, + PDF_add_note, + PDF_add_note2, + PDF_add_pdflink, + PDF_add_table_cell, + PDF_add_textflow, + PDF_add_thumbnail, + PDF_add_weblink, + PDF_arc, + PDF_arcn, + PDF_attach_file, + PDF_attach_file2, + PDF_begin_document, + PDF_begin_document_callback, + PDF_begin_font, + PDF_begin_glyph, + PDF_begin_item, + PDF_begin_layer, + PDF_begin_mc, + PDF_begin_page, + PDF_begin_page_ext, + PDF_begin_pattern, + PDF_begin_template, + PDF_begin_template_ext, + PDF_boot, + PDF_check_context, + PDF_circle, + PDF_clip, + PDF_close, + PDF_close_image, + PDF_close_pdi, + PDF_close_pdi_document, + PDF_close_pdi_page, + PDF_closepath, + PDF_closepath_fill_stroke, + PDF_closepath_stroke, + PDF_concat, + PDF_continue_text, + PDF_continue_text2, + PDF_create_3dview, + PDF_create_action, + PDF_create_annotation, + PDF_create_bookmark, + PDF_create_field, + PDF_create_fieldgroup, + PDF_create_gstate, + PDF_create_pvf, + PDF_create_textflow, + PDF_curveto, + PDF_define_layer, + PDF_delete, + PDF_delete_pvf, + PDF_delete_table, + PDF_delete_textflow, + PDF_encoding_set_char, + PDF_end_document, + PDF_end_font, + PDF_end_glyph, + PDF_end_item, + PDF_end_layer, + PDF_end_mc, + PDF_end_page, + PDF_end_page_ext, + PDF_end_pattern, + PDF_end_template, + PDF_endpath, + PDF_fill, + PDF_fill_imageblock, + PDF_fill_pdfblock, + PDF_fill_stroke, + PDF_fill_textblock, + PDF_findfont, + PDF_fit_image, + PDF_fit_pdi_page, + PDF_fit_table, + PDF_fit_textflow, + PDF_fit_textline, + PDF_get_api, + PDF_get_apiname, + PDF_get_buffer, + PDF_get_errmsg, + PDF_get_errnum, + PDF_get_majorversion, + PDF_get_minorversion, + PDF_get_opaque, + PDF_get_parameter, + PDF_get_pdi_parameter, + PDF_get_pdi_value, + PDF_get_value, + PDF_info_font, + PDF_info_matchbox, + PDF_info_table, + PDF_info_textflow, + PDF_info_textline, + PDF_initgraphics, + PDF_lineto, + PDF_load_3ddata, + PDF_load_font, + PDF_load_iccprofile, + PDF_load_image, + PDF_makespotcolor, + PDF_mc_point, + PDF_moveto, + PDF_new, + PDF_new2, + PDF_open_CCITT, + PDF_open_file, + PDF_open_image, + PDF_open_image_file, + PDF_open_mem, + PDF_open_pdi, + PDF_open_pdi_callback, + PDF_open_pdi_document, + PDF_open_pdi_page, + PDF_pcos_get_number, + PDF_pcos_get_string, + PDF_pcos_get_stream, + PDF_place_image, + PDF_place_pdi_page, + PDF_process_pdi, + PDF_rect, + PDF_restore, + PDF_resume_page, + PDF_rotate, + PDF_save, + PDF_scale, + PDF_set_border_color, + PDF_set_border_dash, + PDF_set_border_style, + PDF_set_gstate, + PDF_set_info, + PDF_set_info2, + PDF_set_layer_dependency, + PDF_set_parameter, + PDF_set_text_pos, + PDF_set_value, + PDF_setcolor, + PDF_setdash, + PDF_setdashpattern, + PDF_setflat, + PDF_setfont, + PDF_setgray, + PDF_setgray_fill, + PDF_setgray_stroke, + PDF_setlinecap, + PDF_setlinejoin, + PDF_setlinewidth, + PDF_setmatrix, + PDF_setmiterlimit, + PDF_setpolydash, + PDF_setrgbcolor, + PDF_setrgbcolor_fill, + PDF_setrgbcolor_stroke, + PDF_shading, + PDF_shading_pattern, + PDF_shfill, + PDF_show, + PDF_show2, + PDF_show_boxed, + PDF_show_boxed2, + PDF_show_xy, + PDF_show_xy2, + PDF_shutdown, + PDF_skew, + PDF_stringwidth, + PDF_stringwidth2, + PDF_stroke, + PDF_suspend_page, + PDF_translate, + PDF_utf16_to_utf8, + PDF_utf32_to_utf16, + PDF_utf8_to_utf16, + PDF_xshow, + pdf_catch, + pdf_exit_try, + pdf_jbuf, + pdf_rethrow +}; + +static pdc_bool +pdf__check_context(PDF *p) +{ + if (p == NULL || p->magic != PDC_MAGIC) + { + fprintf(stderr, "*** PDFlib context pointer %p is invalid ***\n", p); + return pdc_false; + } + + return pdc_true; +} + +static pdc_bool +pdf_enter_api(PDF *p, const char *funame, pdf_state s, const char *fmt, ...) +{ + /* check whether the client completely screwed up */ + if (pdf__check_context(p)) + { + pdc_bool retval; + va_list args; + + va_start(args, fmt); + retval = pdc_enter_api_logg(p->pdc, funame, pdc_true, fmt, args); + va_end(args); + + if (retval) + { + /* check whether we are in a valid scope */ + if ((p->state_stack[p->state_sp] & s) != 0) + { + return pdc_true; + } + + /* check glyphignore scope */ + if ((p->state_stack[p->state_sp] & pdf_state_glyphignore) == 0) + { + /* pdc_error() will NOT throw an exception + ** (and simply return instead) if the core + ** is already in error state. + */ + pdc_error(p->pdc, PDF_E_DOC_SCOPE, pdf_current_scope(p), + 0, 0, 0); + } + } + + pdc_logg_exit_api(p->pdc, pdc_true, "\n"); + } + + /* invalid PDFlib context or + ** core is in the error state or + ** glyphignore scope + */ + return pdc_false; +} + +static pdc_bool +pdf_enter_api_simple(PDF *p, const char *funame, const char *fmt, ...) +{ + /* check whether the client completely screwed up */ + if (pdf__check_context(p)) + { + pdc_bool retval; + va_list args; + + va_start(args, fmt); + retval = pdc_enter_api_logg(p->pdc, funame, pdc_false, fmt, args); + va_end(args); + + return retval; + } + + return pdc_false; +} + +static int +pdf_exit_boolean_api(PDF *p, int retval) +{ + /* check whether the client completely screwed up */ + if (pdf__check_context(p)) + { + if (p->pdc->hastobepos && retval == -1) + retval += 1; + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + +static int +pdf_exit_handle_api(PDF *p, int retval) +{ + /* check whether the client completely screwed up */ + if (pdf__check_context(p)) + { + if (p->pdc->hastobepos) + retval += 1; + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + + +/*************************** + * + * external API functions + * + ***************************/ + +PDFLIB_API void PDFLIB_CALL +PDF_boot(void) +{ + /* nothing yet */ +} + +PDFLIB_API void PDFLIB_CALL +PDF_shutdown(void) +{ + /* nothing yet */ +} + +PDFLIB_API const PDFlib_api * PDFLIB_CALL +PDF_get_api(void) +{ + return &PDFlib; +} + +PDFLIB_API int PDFLIB_CALL +PDF_get_majorversion(void) +{ + return PDFLIB_MAJORVERSION; +} + +PDFLIB_API int PDFLIB_CALL +PDF_get_minorversion(void) +{ + return PDFLIB_MINORVERSION; +} + + +#if (defined(WIN32) || defined(__CYGWIN)) && defined(PDFLIB_EXPORTS) + +/* + * DLL entry function as required by Visual C++. + * It is currently not necessary on Windows, but will eventually + * be used to boot thread-global resources for PDFlib + * (mainly font-related stuff). + */ +BOOL WINAPI +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved); + +BOOL WINAPI +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + (void) hModule; + (void) lpReserved; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + PDF_boot(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + PDF_shutdown(); + break; + } + + return TRUE; +} +#endif /* WIN32 && PDFLIB_EXPORT */ + + +/************************* + * + * general API functions + * + *************************/ + +PDFLIB_API int PDFLIB_CALL +PDF_check_context(PDF *p) +{ + return pdf__check_context(p); +} + +PDFLIB_API int PDFLIB_CALL +PDF_get_errnum(PDF *p) +{ + static const char fn[] = "PDF_get_errnum"; + int retval = -1; + + if (pdf_enter_api_simple(p, fn, "(p_%p)\n", (void *) p)) + { + retval = pdc_get_errnum(p->pdc); + pdc_logg_exit_api(p->pdc, pdc_false, "[%d]\n", retval); + } + + return retval; +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_get_errmsg(PDF *p) +{ + static const char fn[] = "PDF_get_errmsg"; + const char *retval = ""; + + if (pdf_enter_api_simple(p, fn, "(p_%p)\n", (void *) p)) + { + retval = pdc_get_errmsg(p->pdc); + pdc_logg_exit_api(p->pdc, pdc_false, "[\"%T\"]\n", retval, 0); + } + + return retval; +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_get_apiname(PDF *p) +{ + static const char fn[] = "PDF_get_apiname"; + const char *retval = ""; + + if (pdf_enter_api_simple(p, fn, "(p_%p)\n", (void *) p)) + { + retval = pdc_get_apiname(p->pdc); + pdc_logg_exit_api(p->pdc, pdc_false, "[\"%T\"]\n", retval, 0); + } + + return retval; +} + +PDFLIB_API void * PDFLIB_CALL +PDF_get_opaque(PDF *p) +{ + static const char fn[] = "PDF_get_opaque"; + void *retval = NULL; + + if (pdf__check_context(p)) + { + pdc_logg_cond(p->pdc, 1, trc_api, "/* "); + pdf_enter_api_simple(p, fn, "(p_%p) */\n", (void *) p); + retval = p->opaque; + pdc_logg_exit_api(p->pdc, pdc_false, "/* [%p] */\n", retval); + } + + return retval; +} + +PDFLIB_API pdf_jmpbuf * PDFLIB_CALL +pdf_jbuf(PDF *p) +{ + if (pdf__check_context(p)) + return (pdf_jmpbuf *) pdc_jbuf(p->pdc); + + return ((pdf_jmpbuf *) NULL); +} + +PDFLIB_API void PDFLIB_CALL +pdf_exit_try(PDF *p) +{ + if (pdf__check_context(p)) + pdc_exit_try(p->pdc); +} + +PDFLIB_API int PDFLIB_CALL +pdf_catch(PDF *p) +{ + if (pdf__check_context(p)) + return pdc_catch_extern(p->pdc); + + return pdc_false; +} + +PDFLIB_API void PDFLIB_CALL +pdf_rethrow(PDF *p) +{ + static const char fn[] = "pdf_rethrow"; + + if (pdf_enter_api_simple(p, fn, "(p_%p)\n", (void *) p)) + pdc_rethrow(p->pdc); +} + +PDFLIB_API void PDFLIB_CALL +pdf_throw(PDF *p, const char *parm1, const char *parm2, const char *parm3) +{ + if (pdf__check_context(p)) + { + pdc_enter_api(p->pdc, "pdf_throw"); + pdc_error(p->pdc, PDF_E_INT_WRAPPER, parm1, parm2, parm3, NULL); + } +} + + +/********************** + * + * p_3d.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_create_3dview( + PDF *p, + const char *username, + int len, + const char *optlist) +{ + static const char fn[] = "PDF_create_3dview"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, username, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_3DANNOT, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_load_3ddata( + PDF *p, + const char *filename, + int len, + const char *optlist) +{ + static const char fn[] = "PDF_load_3ddata"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, filename, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_3DANNOT, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + + +/********************** + * + * p_actions.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_create_action( + PDF *p, + const char *type, + const char *optlist) +{ + static const char fn[] = "PDF_create_action"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%s\", \"%T\")\n", + (void *) p, type, optlist, 0)) + { + retval = pdf__create_action(p, type, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + + +/********************** + * + * p_annots.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_attach_file( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *filename, + const char *description, + const char *author, + const char *mimetype, + const char *icon) +{ + static const char fn[] = "PDF_attach_file"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%T\", \"%T\", \"%T\", \"%s\", \"%s\")\n", + (void *) p, llx, lly, urx, ury, filename, 0, description, 0, + author, 0, mimetype, icon)) + { + int len_descr = description ? (int) pdc_strlen(description) : 0; + int len_auth = author ? (int) pdc_strlen(author) : 0; + + pdf__attach_file(p, llx, lly, urx, ury, filename, 0, + description, len_descr, author, len_auth, mimetype, icon); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_attach_file2( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *filename, int len_filename, + const char *description, int len_descr, + const char *author, int len_auth, + const char *mimetype, + const char *icon) +{ + static const char fn[] = "PDF_attach_file2"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%T\", /*c*/%d, \"%T\", /*c*/%d, " + "\"%T\", /*c*/%d, \"%s\", \"%s\")\n", + (void *) p, llx, lly, urx, ury, + filename, len_filename, len_filename, + description, len_descr, len_descr, + author, len_auth, len_auth, + mimetype, icon)) + { + pdf__attach_file(p, llx, lly, urx, ury, filename, len_filename, + description, len_descr, author, len_auth, mimetype, icon); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_note( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *contents, + const char *title, + const char *icon, + int open) +{ + static const char fn[] = "PDF_add_note"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%T\", \"%T\", \"%s\", %d)\n", + (void *) p, llx, lly, urx, ury, contents, 0, title, 0, + icon, open)) + { + int len_cont = contents ? (int) pdc_strlen(contents) : 0; + int len_title = title ? (int) pdc_strlen(title) : 0; + + pdf__add_note(p, llx, lly, urx, ury, contents, len_cont, + title, len_title, icon, open); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_note2( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *contents, int len_cont, + const char *title, int len_title, + const char *icon, + int open) +{ + static const char fn[] = "PDF_add_note2"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%T\", /*c*/%d, \"%T\", " + "/*c*/%d, \"%s\", %d)\n", + (void *) p, llx, lly, urx, ury, contents, len_cont, len_cont, + title, len_title, len_title, icon, open)) + { + pdf__add_note(p, llx, lly, urx, ury, contents, len_cont, + title, len_title, icon, open); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_pdflink( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *filename, + int page, + const char *optlist) +{ + static const char fn[] = "PDF_add_pdflink"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%s\", %d, \"%T\")\n", + (void *) p, llx, lly, urx, ury, filename, page, + optlist, 0)) + { + pdf__add_pdflink(p, llx, lly, urx, ury, filename, page, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_launchlink( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *filename) +{ + static const char fn[] = "PDF_add_launchlink"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%s\")\n", + (void *)p, llx, lly, urx, ury, filename)) + { + pdf__add_launchlink(p, llx, lly, urx, ury, filename); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_locallink( + PDF *p, + double llx, + double lly, + double urx, + double ury, + int page, + const char *optlist) +{ + static const char fn[] = "PDF_add_locallink"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, %d, \"%T\")\n", + (void *) p, llx, lly, urx, ury, page, optlist, 0)) + { + pdf__add_locallink(p, llx, lly, urx, ury, page, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_weblink( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *url) +{ + static const char fn[] = "PDF_add_weblink"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%s\")\n", + (void *) p, llx, lly, urx, ury, url)) + { + pdf__add_weblink(p, llx, lly, urx, ury, url); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_create_annotation( + PDF *p, + double llx, + double lly, + double urx, + double ury, + const char *type, + const char *optlist) +{ + static const char fn[] = "PDF_create_annotation"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%s\", \"%T\")\n", + (void *) p, llx, lly, urx, ury, type, optlist, 0)) + { + pdf__create_annotation(p, llx, lly, urx, ury, type, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_border_color( + PDF *p, + double red, + double green, + double blue) +{ + static const char fn[] = "PDF_set_border_color"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %f, %f, %f)\n", (void *) p, red, green, blue)) + { + pdf__set_border_color(p, red, green, blue); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_border_dash( + PDF *p, + double b, + double w) +{ + static const char fn[] = "PDF_set_border_dash"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %f, %f)\n", (void *) p, b, w)) + { + pdf__set_border_dash(p, b, w); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_border_style( + PDF *p, + const char *style, + double width) +{ + static const char fn[] = "PDF_set_border_style"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, \"%s\", %f)\n", (void *) p, style, width)) + { + pdf__set_border_style(p, style, width); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_block.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_fill_imageblock( + PDF *p, + int page, + const char *blockname, + int image, + const char *optlist) +{ + static const char fn[] = "PDF_fill_imageblock"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) pdf_state_content, + "(p_%p, %d, \"%T\", %d, \"%T\")\n", + (void *) p, page, blockname, 0, image, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, + PDF_E_UNSUPP_BLOCK_CONFIG, PDF_E_UNSUPP_BLOCK, pdc_false); + } + + return pdf_exit_boolean_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_fill_pdfblock( + PDF *p, + int page, + const char *blockname, + int contents, + const char *optlist) +{ + static const char fn[] = "PDF_fill_pdfblock"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) pdf_state_content, + "(p_%p, %d, \"%T\", %d, \"%T\")\n", + (void *) p, page, blockname, 0, contents, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, + PDF_E_UNSUPP_BLOCK_CONFIG, PDF_E_UNSUPP_BLOCK, pdc_false); + } + + return pdf_exit_boolean_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_fill_textblock( + PDF *p, + int page, + const char *blockname, + const char *text, int len, + const char *optlist) +{ + static const char fn[] = "PDF_fill_textblock"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) pdf_state_content, + "(p_%p, %d, \"%T\", \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, page, blockname, 0, text, len, len, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, + PDF_E_UNSUPP_BLOCK_CONFIG, PDF_E_UNSUPP_BLOCK, pdc_false); + } + + return pdf_exit_boolean_api(p, retval); +} + + +/********************** + * + * p_color.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_makespotcolor(PDF *p, const char *spotname, int len) +{ + static const char fn[] = "PDF_makespotcolor"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d)\n", + (void *) p, spotname, len, len)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_SPOTCOLOR, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_setcolor( + PDF *p, + const char *fstype, + const char *colorspace, + double c1, double c2, double c3, double c4) +{ + static const char fn[] = "PDF_setcolor"; + int legal_states; + + if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p)) + legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template; + else + legal_states = pdf_state_content | pdf_state_document; + + if (pdf_enter_api(p, fn, (pdf_state) legal_states, + "(p_%p, \"%s\", \"%s\", %f, %f, %f, %f)\n", + (void *) p, fstype, colorspace, c1, c2, c3, c4)) + { + pdf__setcolor(p, fstype, colorspace, c1, c2, c3, c4); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setgray(PDF *p, double g) +{ + static const char fn[] = "PDF_setgray"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, g)) + { + pdf__setcolor(p, "fillstroke", "gray", g, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setgray_fill(PDF *p, double gray) +{ + static const char fn[] = "PDF_setgray_fill"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, gray)) + { + pdf__setcolor(p, "fill", "gray", gray, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setgray_stroke(PDF *p, double gray) +{ + static const char fn[] = "PDF_setgray_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, gray)) + { + pdf__setcolor(p, "stroke", "gray", gray, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor(PDF *p, double r, double g, double b) +{ + static const char fn[] = "PDF_setrgbcolor"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f, %f)\n", + (void *) p, r, g, b)) + { + pdf__setcolor(p, "fillstroke", "rgb", r, g, b, 0); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_fill(PDF *p, double r, double g, double b) +{ + static const char fn[] = "PDF_setrgbcolor_fill"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f, %f)\n", + (void *) p, r, g, b)) + { + pdf__setcolor(p, "fill", "rgb", r, g, b, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_stroke(PDF *p, double r, double g, double b) +{ + static const char fn[] = "PDF_setrgbcolor_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f, %f)\n", + (void *) p, r, g, b)) + { + pdf__setcolor(p, "stroke", "rgb", r, g, b, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_document.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_begin_document( + PDF *p, + const char *filename, int len, + const char *optlist) +{ + static const char fn[] = "\nPDF_begin_document"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_object, + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, filename, len, len, optlist, 0)) + { + if (filename && *filename && len < 0) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "len", pdc_errprintf(p->pdc, "%d", len), 0, 0); + retval = pdf__begin_document(p, filename, len, optlist); + } + + return pdf_exit_boolean_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_begin_document_callback( + PDF *p, + size_t (*i_writeproc)(PDF *p, void *data, size_t size), + const char *optlist) +{ + static const char fn[] = "\nPDF_begin_document_callback"; + size_t (*writeproc)(PDF *, void *, size_t) = i_writeproc; + + if (pdf_enter_api(p, fn, pdf_state_object, + "(p_%p, wp_%p), \"%T\"", (void *) p, (void *) writeproc, optlist, 0)) + { + pdf__begin_document_callback(p, writeproc, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_close(PDF *p) +{ + static const char fn[] = "\nPDF_close"; + + if (pdf_enter_api(p, fn, pdf_state_document, + "(p_%p)\n", (void *) p)) + { + pdf__end_document(p, ""); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_document(PDF *p, const char *optlist) +{ + static const char fn[] = "\nPDF_end_document"; + + if (pdf_enter_api(p, fn, pdf_state_document, + "(p_%p, \"%T\")\n", (void *) p, optlist, 0)) + { + pdf__end_document(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_get_buffer(PDF *p, long *size) +{ + static const char fn[] = "PDF_get_buffer"; + const char *retval = NULL; + + if (!size) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "size", 0, 0, 0); + + *size = (long) 0; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document), + "(p_%p, &size_%p)\n", (void *) p, (void *) size)) + { + retval = pdf__get_buffer(p, size); + + pdc_logg_exit_api(p->pdc, pdc_false, "[%p, size=%ld]\n", + (void *) (retval), *size); + } + + return retval; +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_file(PDF *p, const char *filename) +{ + static const char fn[] = "\nPDF_open_file"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_object, "(p_%p, \"%s\")\n", + (void *) p, filename)) + { + retval = pdf__begin_document(p, filename, 0, ""); + } + + return pdf_exit_boolean_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_open_mem( + PDF *p, + size_t (*i_writeproc)(PDF *p, void *data, size_t size)) +{ + static const char fn[] = "\nPDF_open_mem"; + size_t (*writeproc)(PDF *, void *, size_t) = i_writeproc; + + if (pdf_enter_api(p, fn, pdf_state_object, + "(p_%p, wp_%p)\n", (void *) p, (void *) writeproc)) + { + pdf__begin_document_callback(p, writeproc, ""); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_draw.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_arc(PDF *p, double x, double y, double r, double alpha, double beta) +{ + static const char fn[] = "PDF_arc"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f, %f, %f, %f)\n", (void *) p, x, y, r, alpha, beta)) + { + pdf__arc(p, x, y, r, alpha, beta); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_arcn(PDF *p, double x, double y, double r, double alpha, double beta) +{ + static const char fn[] = "PDF_arcn"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f, %f, %f, %f)\n", (void *) p, x, y, r, alpha, beta)) + { + pdf__arcn(p, x, y, r, alpha, beta); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_circle(PDF *p, double x, double y, double r) +{ + static const char fn[] = "PDF_circle"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f, %f)\n", (void *) p, x, y, r)) + { + pdf__circle(p, x, y, r); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_clip(PDF *p) +{ + static const char fn[] = "PDF_clip"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__clip(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_closepath(PDF *p) +{ + static const char fn[] = "PDF_closepath"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__closepath(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_closepath_fill_stroke(PDF *p) +{ + static const char fn[] = "PDF_closepath_fill_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__closepath_fill_stroke(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_closepath_stroke(PDF *p) +{ + static const char fn[] = "PDF_closepath_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__closepath_stroke(p); + } + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); +} + +PDFLIB_API void PDFLIB_CALL +PDF_curveto(PDF *p, + double x_1, double y_1, double x_2, double y_2, double x_3, double y_3) +{ + static const char fn[] = "PDF_curveto"; + + if (pdf_enter_api(p, fn, pdf_state_path, + "(p_%p, %f, %f, %f, %f, %f, %f)\n", + (void *) p, x_1, y_1, x_2, y_2, x_3, y_3)) + { + pdf__curveto(p, x_1, y_1, x_2, y_2, x_3, y_3); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_endpath(PDF *p) +{ + static const char fn[] = "PDF_endpath"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__endpath(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_fill(PDF *p) +{ + static const char fn[] = "PDF_fill"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__fill(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_fill_stroke(PDF *p) +{ + static const char fn[] = "PDF_fill_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__fill_stroke(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_lineto(PDF *p, double x, double y) +{ + static const char fn[] = "PDF_lineto"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p, %f, %f)\n", + (void *) p, x, y)) + { + pdf__lineto(p, x, y); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_moveto(PDF *p, double x, double y) +{ + static const char fn[] = "PDF_moveto"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f)\n", (void *) p, x, y)) + { + pdf__moveto(p, x, y); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_rcurveto(PDF *p, + double x_1, double y_1, double x_2, double y_2, double x_3, double y_3) +{ + static const char fn[] = "PDF_rcurveto"; + + if (pdf_enter_api(p, fn, pdf_state_path, + "(p_%p, %f, %f, %f, %f, %f, %f)\n", + (void *) p, x_1, y_1, x_2, y_2, x_3, y_3)) + { + pdf__rcurveto(p, x_1, y_1, x_2, y_2, x_3, y_3); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_rect(PDF *p, double x, double y, double width, double height) +{ + static const char fn[] = "PDF_rect"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f, %f, %f)\n", (void *) p, x, y, width, height)) + { + pdf__rect(p, x, y, width, height); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_rlineto(PDF *p, double x, double y) +{ + static const char fn[] = "PDF_rlineto"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p, %f, %f)\n", + (void *) p, x, y)) + { + pdf__rlineto(p, x, y); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_rmoveto(PDF *p, double x, double y) +{ + static const char fn[] = "PDF_rmoveto"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path), + "(p_%p, %f, %f)\n", (void *) p, x, y)) + { + pdf__rmoveto(p, x, y); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_stroke(PDF *p) +{ + static const char fn[] = "PDF_stroke"; + + if (pdf_enter_api(p, fn, pdf_state_path, "(p_%p)\n", (void *) p)) + { + pdf__stroke(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + + +/********************** + * + * p_encoding.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_encoding_set_char( + PDF *p, + const char *encoding, + int slot, + const char *glyphname, + int uv) +{ + static const char fn[] = "PDF_encoding_set_char"; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%s\", %d, \"%s\", %d/*0x%04X*/)\n", + (void *) p, encoding, slot, glyphname, uv, uv)) + { + pdf__encoding_set_char(p, encoding, slot, glyphname, uv); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_fields.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_create_field( + PDF *p, + double llx, double lly, double urx, double ury, + const char *name, int len, + const char *type, + const char *optlist) +{ + static const char fn[] = "PDF_create_field"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %f, %f, %f, %f, \"%T\", /*c*/%d, \"%s\", \"%T\")\n", + (void *) p, llx, lly, urx, ury, name, len, len, + type, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_FORMFIELDS, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +PDFLIB_API void PDFLIB_CALL +PDF_create_fieldgroup( + PDF *p, + const char *name, int len, + const char *optlist) +{ + static const char fn[] = "PDF_create_fieldgroup"; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, name, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_FORMFIELDS, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_font.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_findfont( + PDF *p, + const char *fontname, + const char *encoding, + int embed) +{ + static const char fn[] = "PDF_findfont"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | + pdf_state_path | pdf_state_font), + "(p_%p, \"%s\", \"%s\", %d)\n", + (void *) p, fontname, encoding, embed)) + { + if (embed < 0 || embed > 1) + pdc_error(p->pdc, PDC_E_ILLARG_INT, + "embed", pdc_errprintf(p->pdc, "%d", embed), 0, 0); + + retval = pdf__load_font(p, fontname, 0, encoding, + (embed > 0) ? "embedding" : ""); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API double PDFLIB_CALL +PDF_info_font(PDF *p, int font, const char *keyword, const char *optlist) +{ + static const char fn[] = "PDF_info_font"; + double retval = 0; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\", \"%s\")\n", + (void *) p, font, keyword, optlist)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_FONTINFO, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API int PDFLIB_CALL +PDF_load_font( + PDF *p, + const char *fontname, int len, + const char *encoding, + const char *optlist) +{ + static const char fn[] = "PDF_load_font"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | + pdf_state_path | pdf_state_font), + "(p_%p, \"%T\", /*c*/%d, \"%s\", \"%T\")\n", + (void *) p, fontname, len, len, encoding, optlist, 0)) + { + retval = pdf__load_font(p, fontname, len, encoding, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + + +/********************** + * + * p_gstate.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_concat(PDF *p, double a, double b, double c, double d, double e, double f) +{ + static const char fn[] = "PDF_concat"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %f, %f, %f, %f, %f, %f)\n", (void *) p, a, b, c, d, e, f)) + { + pdf__concat(p, a, b, c, d, e, f); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_initgraphics(PDF *p) +{ + static const char fn[] = "PDF_initgraphics"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p)\n", (void *) p)) + { + pdf__initgraphics(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_restore(PDF *p) +{ + static const char fn[] = "PDF_restore"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p)\n", (void *) p)) + { + pdf__restore(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_rotate(PDF *p, double phi) +{ + static const char fn[] = "PDF_rotate"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, phi)) + { + pdf__rotate(p, phi); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_save(PDF *p) +{ + static const char fn[] = "PDF_save"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p)\n", (void *) p)) + { + pdf__save(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_scale(PDF *p, double sx, double sy) +{ + static const char fn[] = "PDF_scale"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f)\n", + (void *) p, sx, sy)) + { + pdf__scale(p, sx, sy); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setdash(PDF *p, double b, double w) +{ + static const char fn[] = "PDF_setdash"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f)\n", + (void *) p, b, w)) + { + pdf__setdash(p, b, w); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setdashpattern(PDF *p, const char *optlist) +{ + static const char fn[] = "PDF_setdashpattern"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\")\n", (void *) p, optlist, 0)) + { + pdf__setdashpattern(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setflat(PDF *p, double flat) +{ + static const char fn[] = "PDF_setflat"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, flat)) + { + pdf__setflat(p, flat); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setlinecap(PDF *p, int cap) +{ + static const char fn[] = "PDF_setlinecap"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %d)\n", + (void *) p, cap)) + { + pdf__setlinecap(p, cap); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setlinejoin(PDF *p, int join) +{ + static const char fn[] = "PDF_setlinejoin"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %d)\n", + (void *) p, join)) + { + pdf__setlinejoin(p, join); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setlinewidth(PDF *p, double width) +{ + static const char fn[] = "PDF_setlinewidth"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, width)) + { + pdf__setlinewidth(p, width); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setmatrix(PDF *p, double a, double b, double c, double d, + double e, double f) +{ + static const char fn[] = "PDF_setmatrix"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %f, %f, %f, %f, %f, %f)\n", (void *) p, a, b, c, d, e, f)) + { + pdf__setmatrix(p, a, b, c, d, e, f); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setmiterlimit(PDF *p, double miter) +{ + static const char fn[] = "PDF_setmiterlimit"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f)\n", + (void *) p, miter)) + { + pdf__setmiterlimit(p, miter); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_setpolydash(PDF *p, float *darray, int length) +{ + static const char fn[] = "PDF_setpolydash"; + int i; + + if (!darray) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "darray", 0, 0, 0); + + for (i = 0; i < length; i++) + pdc_logg_cond(p->pdc, 1, trc_api, + "/* *(darray+%d) = %f; */\n", i, darray[i]); + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, darray_%p, /*c*/%d)\n", (void *) p, (void *) darray, length)) + { + char optlist[1024], *sopt; + + sopt = optlist; + sopt += pdc_sprintf(p->pdc, pdc_false, optlist, "dasharray {"); + for (i = 0; i < length; i++) + { + pdc_check_number_limits(p->pdc, "darray", darray[i], + 0.0, PDC_FLOAT_MAX); + sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "%f ", darray[i]); + } + pdc_sprintf(p->pdc, pdc_false, sopt, "}"); + + pdf__setdashpattern(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_skew(PDF *p, double alpha, double beta) +{ + static const char fn[] = "PDF_skew"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f)\n", + (void *) p, alpha, beta)) + { + pdf__skew(p, alpha, beta); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_translate(PDF *p, double tx, double ty) +{ + static const char fn[] = "PDF_translate"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f)\n", + (void *) p, tx, ty)) + { + pdf__translate(p, tx, ty); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + + +/********************** + * + * p_hyper.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_add_bookmark( + PDF *p, + const char *text, + int parent, + int open) +{ + static const char fn[] = "PDF_add_bookmark"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", %d, %d)\n", (void *) p, text, 0, parent, open)) + { + int len = text ? (int) pdc_strlen(text) : 0; + retval = pdf__add_bookmark(p, text, len, parent, open); + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + +PDFLIB_API int PDFLIB_CALL +PDF_add_bookmark2( + PDF *p, + const char *text, int len, + int parent, + int open) +{ + static const char fn[] = "PDF_add_bookmark2"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d, %d, %d)\n", + (void *) p, text, len, len, parent, open)) + { + retval = pdf__add_bookmark(p, text, len, parent, open); + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_add_nameddest( + PDF *p, + const char *name, int len, + const char *optlist) +{ + static const char fn[] = "PDF_add_nameddest"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, name, len, len, optlist, 0)) + { + pdf__add_nameddest(p, name, len, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_create_bookmark( + PDF *p, + const char *text, int len, + const char *optlist) +{ + static const char fn[] = "PDF_create_bookmark"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_page | pdf_state_document), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, text, len, len, optlist, 0)) + { + retval = pdf__create_bookmark(p, text, len, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_info(PDF *p, const char *key, const char *value) +{ + static const char fn[] = "PDF_set_info"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", \"%T\")\n", + (void *) p, key, 0, value, 0)) + { + int len = value ? (int) pdc_strlen(value) : 0; + pdf__set_info(p, key, value, len); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_info2(PDF *p, const char *key, const char *value, int len) +{ + static const char fn[] = "PDF_set_info2"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", \"%T\", /*c*/%d)\n", + (void *) p, key, 0, value, len, len)) + { + pdf__set_info(p, key, value, len); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_icc.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_load_iccprofile( + PDF *p, + const char *profilename, int len, + const char *optlist) +{ + static const char fn[] = "PDF_load_iccprofile"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, profilename, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_ICC, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + + +/********************** + * + * p_image.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_add_thumbnail(PDF *p, int image) +{ + static const char fn[] = "PDF_add_thumbnail"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %d)\n", (void *) p, image)) + { + if (p->pdc->hastobepos) image -= 1; + pdf__add_thumbnail(p, image); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_close_image(PDF *p, int image) +{ + static const char fn[] = "PDF_close_image"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font), + "(p_%p, %d)\n", (void *) p, image)) + { + if (p->pdc->hastobepos) image -= 1; + pdf__close_image(p, image); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_fit_image( + PDF *p, + int image, + double x, + double y, + const char *optlist) +{ + static const char fn[] = "PDF_fit_image"; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, %f, %f, \"%T\")\n", (void *) p, image, x, y, optlist, 0)) + { + if (p->pdc->hastobepos) image -= 1; + pdf__fit_image(p, image, x, y, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_load_image( + PDF *p, + const char *type, + const char *filename, + int len, + const char *optlist) +{ + static const char fn[] = "PDF_load_image"; + int retval = -1; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | + pdf_state_font | pdf_state_content), + "(p_%p, \"%s\", \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, type, filename, len, len, optlist, 0)) + { + filename = pdf_convert_filename(p, filename, len, + "filename", PDC_CONV_WITHBOM); + retval = pdf__load_image(p, type, filename, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_CCITT( + PDF *p, + const char *filename, + int width, + int height, + int BitReverse, int K, int BlackIs1) +{ + static const char fn[] = "PDF_open_CCITT"; + int retval = -1; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | + pdf_state_font | pdf_state_content), + "(p_%p, \"%s\", %d, %d, %d, %d, %d)\n", + (void *) p, filename, width, height, + BitReverse, K, BlackIs1)) + { + char optlist[128]; + + pdc_sprintf(p->pdc, pdc_false, optlist, + "width %d height %d bitreverse %s K %d invert %s", + width, height, PDC_BOOLSTR(BitReverse), K, PDC_BOOLSTR(BlackIs1)); + filename = pdf_convert_filename(p, filename, 0, + "filename", PDC_CONV_WITHBOM); + retval = pdf__load_image(p, "CCITT", filename, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_image( + PDF *p, + const char *type, + const char *source, + const char *data, + long length, + int width, + int height, + int components, + int bpc, + const char *params) +{ + static const char fn[] = "PDF_open_image"; + int retval = -1; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | + pdf_state_font | pdf_state_content), + "(p_%p, \"%s\", \"%s\", idata_%p, %ld, %d, %d, %d, %d, \"%s\")\n", + (void *) p, type, source, (void *) data, length, + width, height, components, bpc, params)) + { + const char *filename = data; + char optlist[512]; + pdc_bool memory = pdc_false; + + if (type == NULL || *type == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0); + + if (source == NULL || *source == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "source", 0, 0, 0); + + if (!strcmp(type, "raw") && data == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "data", 0, 0, 0); + + /* create optlist */ + optlist[0] = 0; + if (!strcmp(type, "raw") || !strcmp(type, "ccitt")) + pdc_sprintf(p->pdc, pdc_false, optlist, + "width %d height %d components %d bpc %d ", + width, height, components, bpc); + + if (length < 0L) + { + strcat(optlist, "bitreverse true "); + length = -length; + } + + strcat(optlist, "reftype "); + if (!strcmp(source, "fileref")) + strcat(optlist, "fileref "); + else if (!strcmp(source, "memory")) + { + memory = pdc_true; + strcat(optlist, "direct "); + } + else if (!strcmp(source, "url")) + strcat(optlist, "url "); + + if (params != NULL && *params != '\0') + { + char **items; + int i, nitems; + + /* separator characters because of compatibility */ + nitems = pdc_split_stringlist(p->pdc, params, "\t :", 0, &items); + for (i = 0; i < nitems; i++) + { + if (!strcmp(items[i], "invert")) + strcat(optlist, "invert true "); + else if (!strcmp(items[i], "ignoremask")) + strcat(optlist, "ignoremask true "); + else if (!strcmp(items[i], "inline")) + strcat(optlist, "inline true "); + else if (!strcmp(items[i], "interpolate")) + strcat(optlist, "interpolate true "); + else if (!strcmp(items[i], "mask")) + strcat(optlist, "mask true "); + else if (!strcmp(items[i], "/K")) + strcat(optlist, "K "); + else if (!strcmp(items[i], "/BlackIs1")) + strcat(optlist, "invert "); + else + strcat(optlist, items[i]); + } + pdc_cleanup_stringlist(p->pdc, items); + } + + /* create virtual file */ + if (memory) + { + filename = "__raw__image__data__"; + pdc__create_pvf(p->pdc, filename, data, (size_t) length, ""); + } + + filename = pdf_convert_filename(p, filename, 0, + "filename", PDC_CONV_WITHBOM); + retval = pdf__load_image(p, type, filename, (const char *) optlist); + + if (memory) + (void) pdc__delete_pvf(p->pdc, filename); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_image_file( + PDF *p, + const char *type, + const char *filename, + const char *stringparam, + int intparam) +{ + static const char fn[] = "PDF_open_image_file"; + int retval = -1; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | + pdf_state_font | pdf_state_content), + "(p_%p, \"%s\", \"%s\", \"%s\", %d)\n", + (void *) p, type, filename, stringparam, intparam)) + { + char optlist[128]; + + optlist[0] = 0; + if (stringparam != NULL && *stringparam != '\0') + { + if (!strcmp(stringparam, "invert")) + strcpy(optlist, "invert true "); + else if (!strcmp(stringparam, "inline")) + strcpy(optlist, "inline true "); + else if (!strcmp(stringparam, "ignoremask")) + strcpy(optlist, "ignoremask true "); + else if (!strcmp(stringparam, "mask")) + strcpy(optlist, "mask true "); + else if (!strcmp(stringparam, "masked")) + pdc_sprintf(p->pdc, pdc_false, optlist, "masked %d ", + intparam); + else if (!strcmp(stringparam, "colorize")) + pdc_sprintf(p->pdc, pdc_false, optlist, "colorize %d ", + intparam); + else if (!strcmp(stringparam, "page")) + pdc_sprintf(p->pdc, pdc_false, optlist, "page %d ", + intparam); + else if (!strcmp(stringparam, "iccprofile")) + pdc_sprintf(p->pdc, pdc_false, optlist, "iccprofile %d ", + intparam); + } + filename = pdf_convert_filename(p, filename, 0, + "filename", PDC_CONV_WITHBOM); + retval = pdf__load_image(p, type, filename, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_place_image( + PDF *p, + int image, + double x, + double y, + double scale) +{ + static const char fn[] = "PDF_place_image"; + + /* scope check dependent on image type in kernel function */ + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, %f, %f, %f)\n", (void *) p, image, x, y, scale)) + { + char optlist[128]; + + pdc_sprintf(p->pdc, pdc_false, optlist, "dpi none scale %f", scale); + if (p->pdc->hastobepos) image -= 1; + pdf__fit_image(p, image, x, y, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_kerning.c + * + **********************/ + +PDFLIB_API double PDFLIB_CALL +PDF_get_kern_amount( + PDF *p, + int font, + int firstchar, + int secondchar) +{ + static const char fn[] = "PDF_get_kern_amount"; + double retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | pdf_state_path), + "(p_%p, %d, %d, %d)\n", (void *) p, font, firstchar, secondchar)) + { + if (p->pdc->hastobepos) font -= 1; + pdc_error(p->pdc, PDF_E_UNSUPP_KERNING, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + + +/********************** + * + * p_layer.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_begin_layer(PDF *p, int layer) +{ + static const char fn[] = "PDF_begin_layer"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p, %d)\n", (void *) p, layer)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_define_layer( + PDF *p, + const char *name, int len, + const char *optlist) +{ + static const char fn[] = "PDF_define_layer"; + int retval = -1; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, name, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_layer(PDF *p) +{ + static const char fn[] = "PDF_end_layer"; + + if (pdf_enter_api(p, fn, pdf_state_page, + "(p_%p)\n", (void *) p)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_layer_dependency( + PDF *p, + const char *type, + const char *optlist) +{ + static const char fn[] = "PDF_set_layer_dependency"; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, \"%s\", \"%T\")\n", (void *) p, type, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_mbox.c + * + **********************/ + + PDFLIB_API double PDFLIB_CALL + PDF_info_matchbox(PDF *p, const char *boxname, int len, int num, + const char *keyword) + { + static const char fn[] = "PDF_info_matchbox"; + double retval = 0; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_content | pdf_state_path | pdf_state_font), + "(p_%p, \"%T\", /*c*/%d, %d, \"%s\")\n", + (void *) p, boxname, len, len, num, keyword)) + { + retval = pdf__info_matchbox(p, boxname, len, num, keyword); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + + +/********************** + * + * p_object.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_delete(PDF *p) +{ + static const char fn[] = "PDF_delete"; + + if (pdf_enter_api_simple(p, fn, "(p_%p)\n", (void *) p)) + { + pdf__delete(p); + } +} + +PDFLIB_API PDF * PDFLIB_CALL +PDF_new(void) +{ + return pdf__new(NULL, NULL, NULL, NULL, NULL); +} + +PDFLIB_API PDF * PDFLIB_CALL +PDF_new2( + void (*errorhandler)(PDF *p, int type, const char *msg), + void* (*allocproc)(PDF *p, size_t size, const char *caller), + void* (*reallocproc)(PDF *p, void *mem, size_t size, const char *caller), + void (*freeproc)(PDF *p, void *mem), + void *opaque) +{ + return pdf__new(errorhandler, allocproc, reallocproc, freeproc, opaque); +} + + +/********************** + * + * p_page.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_begin_page(PDF *p, double width, double height) +{ + static const char fn[] = "\nPDF_begin_page"; + + if (pdf_enter_api(p, fn, pdf_state_document, "(p_%p, %f, %f)\n", + (void *) p, width, height)) + { + pdf__begin_page(p, width, height); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_begin_page_ext(PDF *p, double width, double height, const char *optlist) +{ + static const char fn[] = "\nPDF_begin_page_ext"; + + if (pdf_enter_api(p, fn, pdf_state_document, "(p_%p, %f, %f, \"%T\")\n", + (void *) p, width, height, optlist, 0)) + { + pdf__begin_page_ext(p, width, height, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_page(PDF *p) +{ + static const char fn[] = "PDF_end_page"; + + if (pdf_enter_api(p, fn, pdf_state_page, "(p_%p)\n", (void *) p)) + { + pdf__end_page_ext(p, ""); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_page_ext(PDF *p, const char *optlist) +{ + static const char fn[] = "PDF_end_page_ext"; + + if (pdf_enter_api(p, fn, pdf_state_page, "(p_%p, \"%T\")\n", + (void *) p, optlist, 0)) + { + pdf__end_page_ext(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_resume_page(PDF *p, const char *optlist) +{ + static const char fn[] = "\nPDF_resume_page"; + + if (pdf_enter_api(p, fn, pdf_state_document, "(p_%p, \"%T\")\n", + (void *) p, optlist, 0)) + { + pdf__resume_page(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_suspend_page(PDF *p, const char *optlist) +{ + static const char fn[] = "PDF_suspend_page"; + + if (pdf_enter_api(p, fn, pdf_state_page, "(p_%p, \"%T\")\n", + (void *) p, optlist, 0)) + { + pdf__suspend_page(p, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_parameter.c + * + **********************/ + +PDFLIB_API const char * PDFLIB_CALL +PDF_get_parameter(PDF *p, const char *key, double modifier) +{ + static const char fn[] = "PDF_get_parameter"; + const char *retval = ""; + + if (!pdc_stricmp(key, "version")) + { + retval = PDFLIB_VERSIONSTRING; + } + else if (!pdc_stricmp(key, "pdi")) + { + retval = "false"; + } + else if (pdf_enter_api(p, fn, (pdf_state) pdf_state_all, + "(p_%p, \"%s\", %f)\n", (void *) p, key, modifier)) + { + retval = pdf__get_parameter(p, key, modifier); + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%T\"]\n", retval, 0); + } + + return retval; +} + +PDFLIB_API double PDFLIB_CALL +PDF_get_value(PDF *p, const char *key, double modifier) +{ + static const char fn[] = "PDF_get_value"; + double retval = -1; + + if (!pdc_stricmp(key, "major")) + { + retval = PDFLIB_MAJORVERSION; + } + else if (!pdc_stricmp(key, "minor")) + { + retval = PDFLIB_MINORVERSION; + } + else if (!pdc_stricmp(key, "revision")) + { + retval = PDFLIB_REVISION; + } + else if (pdf_enter_api(p, fn, (pdf_state) pdf_state_all, + "(p_%p, \"%s\", %f)\n", (void *) p, key, modifier)) + { + retval = pdf__get_value(p, key, modifier); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_parameter(PDF *p, const char *key, const char *value) +{ + static const char fn[] = "PDF_set_parameter"; + + if (pdf_enter_api(p, fn, (pdf_state) pdf_state_all, + "(p_%p, \"%s\", \"%T\")\n", + (void *) p, key, value, 0)) + { + pdf__set_parameter(p, key, value); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_value(PDF *p, const char *key, double value) +{ + static const char fn[] = "PDF_set_value"; + + if (pdf_enter_api(p, fn, (pdf_state) pdf_state_all, + "(p_%p, \"%s\", %f)\n", (void *) p, key, value)) + { + pdf__set_value(p, key, value); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + + +/********************** + * + * p_pattern.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_begin_pattern( + PDF *p, + double width, + double height, + double xstep, + double ystep, + int painttype) +{ + static const char fn[] = "\nPDF_begin_pattern"; + int retval = -1; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %f, %f, %f, %f, %d)\n", + (void *) p, width, height, xstep, ystep, painttype)) + { + retval = pdf__begin_pattern(p, width, height, xstep, ystep, painttype); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_pattern(PDF *p) +{ + static const char fn[] = "PDF_end_pattern"; + + if (pdf_enter_api(p, fn, pdf_state_pattern, "(p_%p)\n", (void *) p)) + { + pdf__end_pattern(p); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_pdi.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi(PDF *p, int doc) +{ + static const char fn[] = "PDF_close_pdi"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, %d)\n", (void *) p, doc)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi_document(PDF *p, int doc) +{ + static const char fn[] = "PDF_close_pdi_document"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, %d)\n", (void *) p, doc)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi_page(PDF *p, int page) +{ + static const char fn[] = "PDF_close_pdi_page"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %d)\n", (void *) p, page)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_fit_pdi_page(PDF *p, int page, double x, double y, const char *optlist) +{ + static const char fn[] = "PDF_fit_pdi_page"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %d, %f, %f, \"%T\")\n", (void *) p, page, x, y, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API const char *PDFLIB_CALL +PDF_get_pdi_parameter( + PDF *p, + const char *key, + int doc, + int page, + int reserved, + int *len) +{ + static const char fn[] = "PDF_get_pdi_parameter"; + const char *retval = ""; + + if (len) + *len = 0; + + if (pdf_enter_api(p, fn, pdf_state_all, + len ? "(p_%p, \"%s\", %d, %d, %d, /*c*/&len_%p)" : + "(p_%p, \"%s\", %d, %d, %d, /*c*/NULL)\n", + (void *) p, key, doc, page, reserved, len)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%T\"]\n", retval, 0); + } + + return retval; +} + +PDFLIB_API double PDFLIB_CALL +PDF_get_pdi_value( + PDF *p, + const char *key, + int doc, + int page, + int reserved) +{ + static const char fn[] = "PDF_get_pdi_value"; + double retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%s\", %d, %d, %d)\n", + (void *) p, key, doc, page, reserved)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi( + PDF *p, + const char *filename, + const char *optlist, + int len) +{ + static const char fn[] = "PDF_open_pdi"; + int retval = -1; + + /* state "object" doesn't make sense until PDFlib can handle this, + ** but is allowed here for version compatibility + */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", \"%T\", %d)\n", + (void *) p, filename, len, optlist, 0, len)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_document( + PDF *p, + const char *filename, + int len, + const char *optlist) +{ + static const char fn[] = "PDF_open_pdi_document"; + int retval = -1; + + /* state "object" doesn't make sense until PDFlib can handle this, + ** but is allowed here for version compatibility + */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, filename, len, len, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_callback( + PDF *p, + void *opaque, + size_t filesize, + size_t (*readproc)(void *opaque, void *buffer, size_t size), + int (*seekproc)(void *opaque, long offset), + const char *optlist) +{ + static const char fn[] = "PDF_open_pdi_callback"; + int retval = -1; + + /* state "object" doesn't make sense until PDFlib can handle this, + ** but is allowed here for version compatibility + */ + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_object | pdf_state_document | pdf_state_page), + "(p_%p, opaque_%p, %ld, readproc_%p, seekproc_%p \"%T\")\n", + (void *)p, opaque, filesize, readproc, seekproc, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + } + + return pdf_exit_handle_api(p, retval); +} + + +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_page(PDF *p, int doc, int pagenumber, const char* optlist) +{ + static const char fn[] = "PDF_open_pdi_page"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %d, %d, \"%T\")\n", (void *) p, doc, pagenumber, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + } + + return pdf_exit_handle_api(p, retval); +} + +/* pCOS "context free parameters" +*/ +typedef enum +{ + cfp_none, cfp_major, cfp_minor, cfp_revision, cfp_version +} pcos_cfp; + +static pcos_cfp +get_pcos_cfp(const char *fmt, va_list args) +{ + const char *cfp = fmt; + + if (strcmp(fmt, "%s") == 0) + cfp = va_arg(args, char *); + + if (strcmp(cfp, "major") == 0) + return cfp_major; + + if (strcmp(cfp, "minor") == 0) + return cfp_minor; + + if (strcmp(cfp, "revision") == 0) + return cfp_revision; + + if (strcmp(cfp, "version") == 0) + return cfp_version; + + return cfp_none; +} /* get_pcos_cfp */ + + +PDFLIB_API double PDFLIB_CALL +PDF_pcos_get_number(PDF *p, int doc, const char *path, ...) +{ + static const char fn[] = "PDF_pcos_get_number"; + + double result = 0; + pcos_cfp cfp; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\")\n", (void *) p, doc, path)) + { + va_list args; + + if (!path) + path = ""; + + va_start(args, path); + cfp = get_pcos_cfp(path, args); + va_end(args); + + switch (cfp) + { + case cfp_major: + result = PDFLIB_MAJORVERSION; + break; + + case cfp_minor: + result = PDFLIB_MINORVERSION; + break; + + case cfp_revision: + result = PDFLIB_REVISION; + break; + + default: + { + pdc_set_unsupp_error(p->pdc, + PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, pdc_false); + break; + } + } /* switch */ + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", result); + } + return result; +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_pcos_get_string(PDF *p, int doc, const char *path, ...) +{ + static const char fn[] = "PDF_pcos_get_string"; + + const char *result = ""; + pcos_cfp cfp; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\")\n", (void *) p, doc, path)) + { + va_list args; + + if (!path) + path = ""; + + va_start(args, path); + cfp = get_pcos_cfp(path, args); + va_end(args); + + switch (cfp) + { + case cfp_version: + result = PDFLIB_VERSIONSTRING; + break; + + default: + { + pdc_set_unsupp_error(p->pdc, + PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, pdc_false); + break; + } + } /* switch */ + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%T\"]\n", result, 0); + } + return result; +} + +PDFLIB_API const unsigned char * PDFLIB_CALL +PDF_pcos_get_stream( + PDF *p, int doc, int *len, const char *optlist, const char *path, ...) +{ + static const char fn[] = "PDF_pcos_get_stream"; + + const unsigned char *result = (const unsigned char *) ""; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\", \"%s\")\n", (void *) p, doc, optlist, path)) + { + int length = 0; + + *len = 0; + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%T\", len=%d]\n", + result, length, length); + } + + return result; +} + +PDFLIB_API void PDFLIB_CALL +PDF_place_pdi_page(PDF *p, int page, double x, double y, double sx, double sy) +{ + static const char fn[] = "PDF_place_pdi_page"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %d, %f, %f, %f, %f)\n", (void *) p, page, x, y, sx, sy)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_process_pdi(PDF *p, int doc, int page, const char *optlist) +{ + static const char fn[] = "PDF_process_pdi"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document), + "(p_%p, %d, %d, \"%T\")\n", (void *) p, doc, page, optlist, 0)) + { + pdc_set_unsupp_error(p->pdc, PDF_E_UNSUPP_PDI_CONFIG, PDF_E_UNSUPP_PDI, + pdc_false); + } + + return pdf_exit_boolean_api(p, retval); +} + + +/********************** + * + * p_resource.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_create_pvf( + PDF *p, const char *filename, int len, + const void *data, size_t size, + const char *optlist) +{ + static const char fn[] = "PDF_create_pvf"; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", /*c*/%d, data_%p, /*c*/%d, \"%T\")\n", + (void *) p, filename, len, len, data, size, optlist, 0)) + { + filename = pdf_convert_filename(p, filename, len, "filename", 0); + pdc__create_pvf(p->pdc, filename, data, size, optlist); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_delete_pvf(PDF *p, const char *filename, int len) +{ + static const char fn[] = "PDF_delete_pvf"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", /*c*/%d)\n", + (void *) p, filename, len, len)) + { + filename = pdf_convert_filename(p, filename, len, "filename", 0); + retval = pdc__delete_pvf(p->pdc, filename); + } + + return pdf_exit_boolean_api(p, retval); +} + + +/********************** + * + * p_shading.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_shading( + PDF *p, + const char *type, + double x_0, double y_0, + double x_1, double y_1, + double c_1, double c_2, double c_3, double c_4, + const char *optlist) +{ + static const char fn[] = "PDF_shading"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font), + "(p_%p, \"%s\", %f, %f, %f, %f, %f, %f, %f, %f, \"%T\")\n", + (void *) p, type, x_0, y_0, x_1, y_1, c_1, c_2, c_3, c_4, + optlist, 0)) + { + retval = pdf__shading(p, type, x_0, y_0, x_1, y_1, + c_1, c_2, c_3, c_4, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_shading_pattern(PDF *p, int shading, const char *optlist) +{ + static const char fn[] = "PDF_shading_pattern"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font), + "(p_%p, %d, \"%T\")\n", (void *) p, shading, optlist, 0)) + { + if (p->pdc->hastobepos) shading -= 1; + retval = pdf__shading_pattern(p, shading, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_shfill(PDF *p, int shading) +{ + static const char fn[] = "PDF_shfill"; + int legal_states; + + if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p)) + legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template; + + else if (PDF_GET_STATE(p) == pdf_state_pattern && + pdf_get_shading_painttype(p) == 2) + legal_states = pdf_state_page | pdf_state_glyph | pdf_state_template; + + else + legal_states = pdf_state_content; + + if (pdf_enter_api(p, fn, (pdf_state) legal_states, + "(p_%p, %d)\n", (void *) p, shading)) + { + if (p->pdc->hastobepos) shading -= 1; + pdf__shfill(p, shading); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_table.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_add_table_cell(PDF *p, int table, int column, int row, const char *text, + int len, const char *optlist) +{ + static const char fn[] = "PDF_add_table_cell"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, %d, %d, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, table, column, row, text, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TABLES, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_delete_table(PDF *p, int table, const char *optlist) +{ + static const char fn[] = "PDF_delete_table"; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%T\")\n", (void *) p, table, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TABLES, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_fit_table(PDF *p, int table, double llx, double lly, + double urx, double ury, const char *optlist) +{ + static const char fn[] = "PDF_fit_table"; + const char *retval = ""; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %d, %f, %f, %f, %f, \"%T\")\n", + (void *) p, table, llx, lly, urx, ury, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TABLES, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%s\"]\n", retval); + } + + return retval; +} + +PDFLIB_API double PDFLIB_CALL +PDF_info_table(PDF *p, int table, const char *keyword) +{ + static const char fn[] = "PDF_info_table"; + double retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\")\n", (void *) p, table, keyword)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TABLES, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + + +/********************** + * + * p_tagged.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_begin_mc(PDF *p, const char *tag, const char *optlist) +{ + static const char fn[] = "PDF_begin_mc"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%s\", \"%T\")\n", (void *) p, tag, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_MC, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_mc(PDF *p) +{ + static const char fn[] = "PDF_end_mc"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p", (void *) p)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_MC, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_mc_point(PDF *p, const char *tag, const char *optlist) +{ + static const char fn[] = "PDF_mc_point"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%s\", \"%T\")\n", (void *) p, tag, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_MC, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_activate_item(PDF *p, int id) +{ + static const char fn[] = "PDF_activate_item"; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %d)\n", (void *) p, id)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TAGGED, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_begin_item( + PDF *p, + const char *tag, + const char *optlist) +{ + static const char fn[] = "PDF_begin_item"; + int retval = -1; + + /* further check in kernel function */ + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, \"%s\", \"%T\")\n", (void *) p, tag, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TAGGED, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_item(PDF *p, int id) +{ + static const char fn[] = "PDF_end_item"; + + /* further check in kernel function */ + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %d)\n", (void *) p, id)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TAGGED, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_template.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_begin_template(PDF *p, double width, double height) +{ + static const char fn[] = "\nPDF_begin_template"; + int retval = -1; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, %f, %f)\n", (void *) p, width, height)) + { + retval = pdf__begin_template(p, width, height, ""); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_begin_template_ext(PDF *p, double width, double height, const char *optlist) +{ + static const char fn[] = "\nPDF_begin_template_ext"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_document, "(p_%p, %f, %f, \"%T\")\n", + (void *) p, width, height, optlist, 0)) + { + retval = pdf__begin_template(p, width, height, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_template(PDF *p) +{ + static const char fn[] = "PDF_end_template"; + + if (pdf_enter_api(p, fn, pdf_state_template, "(p_%p)\n", (void *) p)) + { + pdf__end_template(p); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + + +/********************** + * + * p_text.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_continue_text(PDF *p, const char *text) +{ + static const char fn[] = "PDF_continue_text"; + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, \"%T\")\n", + (void *) p, text, 0)) + { + int len = text ? (int) strlen(text) : 0; + pdf__show_text(p, text, len, pdc_true); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_continue_text2(PDF *p, const char *text, int len) +{ + static const char fn[] = "PDF_continue_text2"; + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", /*c*/%d)\n", (void *) p, text, len, len)) + { + pdf__show_text(p, text, len, pdc_true); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_fit_textline(PDF *p, const char *text, int len, double x, double y, + const char *optlist) +{ + static const char fn[] = "PDF_fit_textline"; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", /*c*/%d, %f, %f, \"%T\")\n", + (void *) p, text, len, len, x, y, optlist, 0)) + { + pdf__fit_textline(p, text, len, x, y, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API double PDFLIB_CALL +PDF_info_textline(PDF *p, const char *text, int len, const char *keyword, + const char *optlist) +{ + static const char fn[] = "PDF_info_textline"; + double retval = 0; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | + pdf_state_path | pdf_state_font), + "(p_%p, \"%T\", /*c*/%d, \"%s\", \"%T\")\n", + (void *) p, text, len, len, keyword, optlist, 0)) + { + retval = pdf__info_textline(p, text, len, keyword, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_setfont(PDF *p, int font, double fontsize) +{ + static const char fn[] = "PDF_setfont"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %d, %f)\n", + (void *) p, font, fontsize)) + { + if (p->pdc->hastobepos) font -= 1; + pdf__setfont(p, font, fontsize); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_text_pos(PDF *p, double x, double y) +{ + static const char fn[] = "PDF_set_text_pos"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %f, %f)\n", + (void *) p, x, y)) + { + pdf__set_text_pos(p, x, y); + + pdc_logg_exit_api(p->pdc, pdc_false, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_show(PDF *p, const char *text) +{ + static const char fn[] = "PDF_show"; + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, \"%T\")\n", + (void *) p, text, 0)) + { + int len = text ? (int) strlen(text) : 0; + + pdf__show_text(p, text, len, pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_show2(PDF *p, const char *text, int len) +{ + static const char fn[] = "PDF_show2"; + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", /*c*/%d)\n", (void *) p, text, len, len)) + { + pdf__show_text(p, text, len, pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API int PDFLIB_CALL +PDF_show_boxed( + PDF *p, + const char *text, + double left, + double bottom, + double width, + double height, + const char *hmode, + const char *feature) +{ + static const char fn[] = "PDF_show_boxed"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", %f, %f, %f, %f, \"%s\", \"%s\")\n", + (void *) p, text, 0, left, bottom, width, height, hmode, feature)) + { + retval = pdf__show_boxed(p, text, 0, left, bottom, width, height, + hmode, feature); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + +PDFLIB_API int PDFLIB_CALL +PDF_show_boxed2( + PDF *p, + const char *text, + int len, + double left, + double bottom, + double width, + double height, + const char *hmode, + const char *feature) +{ + static const char fn[] = "PDF_show_boxed2"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", /*c*/%d, %f, %f, %f, %f, \"%s\", \"%s\")\n", + (void *) p, text, len, len, left, bottom, width, height, + hmode, feature)) + { + retval = pdf__show_boxed(p, text, len, left, bottom, width, height, + hmode, feature); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%d]\n", retval); + } + + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_show_xy(PDF *p, const char *text, double x, double y) +{ + static const char fn[] = "PDF_show_xy"; + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, \"%T\", %f, %f)\n", + (void *) p, text, 0, x, y)) + { + int len = text ? (int) strlen(text) : 0; + pdf__set_text_pos(p, x, y); + pdf__show_text(p, text, len, pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_show_xy2(PDF *p, const char *text, int len, double x, double y) +{ + static const char fn[] = "PDF_show_xy2"; + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", /*c*/%d, %f, %f)\n", + (void *) p, text, len, len, x, y)) + { + pdf__set_text_pos(p, x, y); + pdf__show_text(p, text, len, pdc_false); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API double PDFLIB_CALL +PDF_stringwidth(PDF *p, const char *text, int font, double fontsize) +{ + static const char fn[] = "PDF_stringwidth"; + double retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | + pdf_state_path | pdf_state_font), + "(p_%p, \"%T\", %d, %f)\n", + (void *) p, text, 0, font, fontsize)) + { + int len = text ? (int) strlen(text) : 0; + if (p->pdc->hastobepos) font -= 1; + retval = pdf__stringwidth(p, text, len, font, fontsize); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API double PDFLIB_CALL +PDF_stringwidth2(PDF *p, const char *text, int len, int font, double fontsize) +{ + static const char fn[] = "PDF_stringwidth2"; + double retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content | + pdf_state_path | pdf_state_font), + "(p_%p, \"%T\", /*c*/%d, %d, %f)\n", + (void *) p, text, len, len, font, fontsize)) + { + if (p->pdc->hastobepos) font -= 1; + retval = pdf__stringwidth(p, text, len, font, fontsize); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + +PDFLIB_API void PDFLIB_CALL +PDF_xshow(PDF *p, const char *text, int len, const double *xadvancelist) +{ + static const char fn[] = "PDF_xshow"; + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, \"%T\", %d, %p)\n", (void *) p, text, len, len, xadvancelist)) + { + pdf__xshow(p, text, len, xadvancelist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_textflow.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_add_textflow(PDF *p, int textflow, const char *text, int len, + const char *optlist) +{ + static const char fn[] = "PDF_add_textflow"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, textflow, text, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TEXTFLOWS, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API int PDFLIB_CALL +PDF_create_textflow(PDF *p, const char *text, int len, const char *optlist) +{ + static const char fn[] = "PDF_create_textflow"; + int retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", /*c*/%d, \"%T\")\n", + (void *) p, text, len, len, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TEXTFLOWS, 0, 0, 0, 0); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_delete_textflow(PDF *p, int textflow) +{ + static const char fn[] = "PDF_delete_textflow"; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d)\n", (void *) p, textflow)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TEXTFLOWS, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_fit_textflow( + PDF *p, + int textflow, + double llx, + double lly, + double urx, + double ury, + const char *optlist) +{ + static const char fn[] = "PDF_fit_textflow"; + const char *retval = ""; + + if (pdf_enter_api(p, fn, pdf_state_content, + "(p_%p, %d, %f, %f, %f, %f, \"%T\")\n", + (void *) p, textflow, llx, lly, urx, ury, optlist, 0)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TEXTFLOWS, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[\"%s\"]\n", retval); + } + + return retval; +} + +PDFLIB_API double PDFLIB_CALL +PDF_info_textflow(PDF *p, int textflow, const char *keyword) +{ + static const char fn[] = "PDF_info_textflow"; + double retval = -1; + + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, %d, \"%s\")\n", (void *) p, textflow, keyword)) + { + pdc_error(p->pdc, PDF_E_UNSUPP_TEXTFLOWS, 0, 0, 0, 0); + + pdc_logg_exit_api(p->pdc, pdc_true, "[%f]\n", retval); + } + + return retval; +} + + +/********************** + * + * p_type3.c + * + **********************/ + +PDFLIB_API void PDFLIB_CALL +PDF_begin_font( + PDF *p, + const char *fontname, int len, + double a, double b, double c, double d, double e, double f, + const char *optlist) +{ + static const char fn[] = "\nPDF_begin_font"; + + if (pdf_enter_api(p, fn, (pdf_state) (pdf_state_document | pdf_state_page), + "(p_%p, \"%T\", /*c*/%d, %f, %f, %f, %f, %f, %f, \"%T\")\n", + (void *) p, fontname, len, len, a, b, c, d, e, f, optlist, 0)) + { + pdf__begin_font(p, fontname, len, a, b, c, d, e, f, optlist); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_begin_glyph( + PDF *p, + const char *glyphname, + double wx, double llx, double lly, double urx, double ury) +{ + static const char fn[] = "\nPDF_begin_glyph"; + + if (pdf_enter_api(p, fn, pdf_state_font, + "(p_%p, \"%s\", %f, %f, %f, %f, %f)\n", + (void *) p, glyphname, wx, llx, lly, urx, ury)) + { + pdf__begin_glyph(p, glyphname, wx, llx, lly, urx, ury); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + +PDFLIB_API void PDFLIB_CALL +PDF_end_font(PDF *p) +{ + static const char fn[] = "\nPDF_end_font"; + + if (pdf_enter_api(p, fn, pdf_state_font, "(p_%p)\n", (void *) p)) + { + pdf__end_font(p); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +PDFLIB_API void PDFLIB_CALL +PDF_end_glyph(PDF *p) +{ + static const char fn[] = "PDF_end_glyph"; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_glyph | pdf_state_glyphmetric | + pdf_state_glyphignore), + "(p_%p)\n", (void *) p)) + { + pdf__end_glyph(p); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} + + +/********************** + * + * p_util.c + * + **********************/ + +PDFLIB_API const char * PDFLIB_CALL +PDF_utf16_to_utf8(PDF *p, const char *utf16string, int len, int *size) +{ + static const char fn[] = "PDF_utf16_to_utf8"; + const char *retval = ""; + + if (pdf__check_context(p)) + { + if (p->pdc->unicaplang) + { + retval = pdf__utf16_to_utf8(p, utf16string, len, size); + } + else + { + pdc_logg_cond(p->pdc, 1, trc_api, "/* "); + if (pdf_enter_api(p, fn, pdf_state_all, + size ? "(p_%p, \"%T\", %d, &size_%p)" : + "(p_%p, \"%s\", %d, NULL) */\n", + (void *) p, utf16string, len, len, (void *) size)) + { + retval = pdf__utf16_to_utf8(p, utf16string, len, size); + } + + pdc_logg_exit_api(p->pdc, pdc_false, "/* [\"%T\", size=%d] */\n", + retval, 0, size ? *size : 0); + } + } + + return retval; +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_utf32_to_utf16(PDF *p, const char *utf32string, int len, + const char *ordering, int *size) +{ + static const char fn[] = "PDF_utf32_to_utf16"; + const char *retval = ""; + + if (pdf__check_context(p)) + { + if (p->pdc->unicaplang) + { + retval = pdf__utf32_to_utf16(p, utf32string, len, ordering, size); + } + else + { + if (size == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "size", 0, 0, 0); + + pdc_logg_cond(p->pdc, 1, trc_api, "/* "); + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", %d, \"%s\", &size_%p) */\n", + (void *) p, utf32string, len, len, ordering, (void *) size)) + { + retval = pdf__utf32_to_utf16(p, utf32string, + len, ordering, size); + } + + pdc_logg_exit_api(p->pdc, pdc_false, "/* [\"%T\", size=%d] */\n", + retval, *size, *size); + } + } + + return retval; +} + +PDFLIB_API const char * PDFLIB_CALL +PDF_utf8_to_utf16(PDF *p, const char *utf8string, const char *format, + int *size) +{ + static const char fn[] = "PDF_utf8_to_utf16"; + const char *retval = ""; + + if (pdf__check_context(p)) + { + if (p->pdc->unicaplang) + { + retval = pdf__utf8_to_utf16(p, utf8string, format, size); + } + else + { + if (size == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "size", 0, 0, 0); + + pdc_logg_cond(p->pdc, 1, trc_api, "/* "); + if (pdf_enter_api(p, fn, pdf_state_all, + "(p_%p, \"%T\", \"%s\", &size_%p) */\n", + (void *) p, utf8string, 0, format, (void *) size)) + { + retval = pdf__utf8_to_utf16(p, utf8string, format, size); + } + + pdc_logg_exit_api(p->pdc, pdc_false, "/* [\"%T\", size=%d] */\n", + retval, *size, *size); + } + } + + return retval; +} + + +/********************** + * + * p_xgstate.c + * + **********************/ + +PDFLIB_API int PDFLIB_CALL +PDF_create_gstate(PDF *p, const char *optlist) +{ + static const char fn[] = "PDF_create_gstate"; + int retval = -1; + + if (pdf_enter_api(p, fn, + (pdf_state) (pdf_state_document | pdf_state_content), + "(p_%p, \"%T\")\n", (void *) p, optlist, 0)) + { + retval = pdf__create_gstate(p, optlist); + } + + return pdf_exit_handle_api(p, retval); +} + +PDFLIB_API void PDFLIB_CALL +PDF_set_gstate(PDF *p, int gstate) +{ + static const char fn[] = "PDF_set_gstate"; + + if (pdf_enter_api(p, fn, pdf_state_content, "(p_%p, %d)\n", + (void *) p, gstate)) + { + if (p->pdc->hastobepos) gstate -= 1; + pdf__set_gstate(p, gstate); + + pdc_logg_exit_api(p->pdc, pdc_true, NULL); + } +} diff --git a/src/pdflib/pdflib/pdflib.h b/src/pdflib/pdflib/pdflib.h new file mode 100644 index 0000000..23468dd --- /dev/null +++ b/src/pdflib/pdflib/pdflib.h @@ -0,0 +1,1572 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: pdflib.h,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * Public function declarations for PDFlib Lite, PDFlib, PDFlib+PDI, and PPS; + * see PDFlib API reference for details. + * + */ + +#ifndef PDFLIB_H +#define PDFLIB_H + +/* Make our declarations C++ compatible */ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <setjmp.h> + +#define PDFLIB_PRODUCTNAME "PDFlib" + +/* + * The version defines below can be used to check the version of the + * include file against the library. + */ + +#define PDFLIB_MAJORVERSION 7 /* major version number */ +#define PDFLIB_MINORVERSION 0 /* minor version number */ +#define PDFLIB_REVISION 2 /* revision number */ +#define PDFLIB_VERSIONSTRING "7.0.2" /* The whole bunch */ + + +/* + * ---------------------------------------------------------------------- + * Setup, mostly Windows calling conventions and DLL stuff + * ---------------------------------------------------------------------- + */ + +#if defined(WIN32) && !defined(PDFLIB_CALL) + #define PDFLIB_CALL __cdecl +#endif + +#if defined(WIN32) + + #ifdef PDFLIB_EXPORTS + #define PDFLIB_API __declspec(dllexport) /* prepare a DLL (internal use) */ + + #elif defined(PDFLIB_DLL) + + #define PDFLIB_API __declspec(dllimport) /* PDFlib clients: import DLL */ + #endif /* PDFLIB_DLL */ + +#endif /* WIN32 */ + +#if !defined(WIN32) && \ + ((defined __IBMC__ || defined __IBMCPP__) && defined __DLL__ && defined OS2) + #define PDFLIB_CALL _Export + #define PDFLIB_API +#endif /* IBM VisualAge C++ DLL */ + +#ifndef PDFLIB_CALL + #define PDFLIB_CALL /* */ /* default: no special calling conventions */ +#endif + +#ifndef PDFLIB_API + #define PDFLIB_API /* */ /* default: generate or use static library */ +#endif + +/* Define the basic PDF type. This is used opaquely at the API level. */ +#if !defined(PDF) || defined(ACTIVEX) + typedef struct PDF_s PDF; +#endif /* !PDF */ + +/* Export the API functions when creating a shared library on the Mac with CW */ +#if defined(__MWERKS__) && defined(PDFLIB_EXPORTS) +#pragma export on +#endif + +/* The API structure with function pointers. */ +typedef struct PDFlib_api_s PDFlib_api; + + +/* + * ---------------------------------------------------------------------- + * Function prototypes for all supported API functions + * ---------------------------------------------------------------------- + */ + +/* Activate a previously created structure element or other content item. */ +PDFLIB_API void PDFLIB_CALL +PDF_activate_item(PDF *p, int id); + +/* Deprecated, use PDF_create_bookmark(). */ +PDFLIB_API int PDFLIB_CALL +PDF_add_bookmark(PDF *p, const char *text, int parent, int open); + +/* Deprecated, use PDF_create_bookmark(). */ +PDFLIB_API int PDFLIB_CALL +PDF_add_bookmark2(PDF *p, const char *text, int len, int parent, int open); + +/* Deprecated, use PDF_create_action() and PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_launchlink(PDF *p, double llx, double lly, double urx, double ury, + const char *filename); + +/* Deprecated, use PDF_create_action() and PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_locallink(PDF *p, double llx, double lly, double urx, double ury, + int page, const char *optlist); + +/* Create a named destination on an arbitrary page in the current document. */ +PDFLIB_API void PDFLIB_CALL +PDF_add_nameddest(PDF *p, const char *name, int len, const char *optlist); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_note(PDF *p, double llx, double lly, double urx, double ury, + const char *contents, const char *title, const char *icon, int open); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_note2(PDF *p, double llx, double lly, double urx, double ury, + const char *contents, int len_cont, const char *title, int len_title, + const char *icon, int open); + +/* Deprecated, use PDF_create_action() and PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_pdflink(PDF *p, double llx, double lly, double urx, double ury, + const char *filename, int page, const char *optlist); + +/* Add a cell to a new or existing table. + Returns: A table handle which can be used in subsequent table-related calls. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_add_table_cell(PDF *p, int table, int column, int row, const char *text, + int len, const char *optlist); + +/* Create a Textflow object, or add text and explicit options to an existing + Textflow. + Returns: A Textflow handle, or -1 (in PHP: 0) on error. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_add_textflow(PDF *p, int textflow, const char *text, int len, + const char *optlist); + +/* Add an existing image as thumbnail for the current page. */ +PDFLIB_API void PDFLIB_CALL +PDF_add_thumbnail(PDF *p, int image); + +/* Deprecated, use PDF_create_action() and PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_weblink(PDF *p, double llx, double lly, double urx, double ury, + const char *url); + +/* Draw a counterclockwise circular arc segment. */ +PDFLIB_API void PDFLIB_CALL +PDF_arc(PDF *p, double x, double y, double r, double alpha, double beta); + +/* Draw a clockwise circular arc segment. */ +PDFLIB_API void PDFLIB_CALL +PDF_arcn(PDF *p, double x, double y, double r, double alpha, double beta); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_attach_file(PDF *p, double llx, double lly, double urx, double ury, + const char *filename, const char *description, const char *author, + const char *mimetype, const char *icon); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_attach_file2(PDF *p, double llx, double lly, double urx, double ury, + const char *filename, int len_filename, const char *description, + int len_descr, const char *author, int len_auth, const char *mimetype, + const char *icon); + +/* Create a new PDF file subject to various options. + Returns: -1 (in PHP: 0) on error, and 1 otherwise. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_begin_document(PDF *p, const char *filename, int len, const char *optlist); + +/* Create a new PDF document subject to various options. */ +typedef size_t (*writeproc_t)(PDF *p1, void *data, size_t size); +PDFLIB_API void PDFLIB_CALL +PDF_begin_document_callback(PDF *p, writeproc_t writeproc, const char *optlist); + +/* Start a Type 3 font definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_font(PDF *p, const char *fontname, int len, + double a, double b, double c, double d, double e, double f, + const char *optlist); + +/* Start a glyph definition for a Type 3 font. */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_glyph(PDF *p, const char *glyphname, double wx, + double llx, double lly, double urx, double ury); + +/* Open a structure element or other content item with attributes supplied + as options. + Returns: An item handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_begin_item(PDF *p, const char *tag, const char *optlist); + +/* Start a layer for subsequent output on the page (requires PDF 1.5). */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_layer(PDF *p, int layer); + +/* Begin a marked content sequence with or without properties (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_mc(PDF *p, const char *tag, const char *optlist); + +/* Deprecated, use PDF_begin_page_ext(). */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_page(PDF *p, double width, double height); + +/* Add a new page to the document, and specify various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_page_ext(PDF *p, double width, double height, const char *optlist); + +/* Start a pattern definition. + Returns: A pattern handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_begin_pattern(PDF *p, + double width, double height, double xstep, double ystep, int painttype); + +/* Deprecated, use PDF_begin_template_ext(). */ +PDFLIB_API int PDFLIB_CALL +PDF_begin_template(PDF *p, double width, double height); + +/* Start a template definition. + Returns: A template handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_begin_template_ext(PDF *p, double width, double height, + const char *optlist); + +/* Deprecated, and not required. */ +PDFLIB_API void PDFLIB_CALL +PDF_boot(void); + +/* Check the validity of a PDFlib context (unsupported). */ +PDFLIB_API int PDFLIB_CALL +PDF_check_context(PDF *p); + +/* Draw a circle. */ +PDFLIB_API void PDFLIB_CALL +PDF_circle(PDF *p, double x, double y, double r); + +/* Use the current path as clipping path, and terminate the path. */ +PDFLIB_API void PDFLIB_CALL +PDF_clip(PDF *p); + +/* Deprecated, use PDF_end_document(). */ +PDFLIB_API void PDFLIB_CALL +PDF_close(PDF *p); + +/* Close an image. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_image(PDF *p, int image); + +/* Deprecated, use PDF_close_pdi_document(). */ +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi(PDF *p, int doc); + +/* Close all open PDI page handles, and close the input PDF document. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi_document(PDF *p, int doc); + +/* Close the page handle and free all page-related resources. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi_page(PDF *p, int page); + +/* Close the current path. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath(PDF *p); + +/* Close the path, fill, and stroke it. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath_fill_stroke(PDF *p); + +/* Close the path, and stroke it. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath_stroke(PDF *p); + +/* Apply a transformation matrix to the current coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_concat(PDF *p, double a, double b, double c, double d, double e, double f); + +/* Print text at the next line. */ +PDFLIB_API void PDFLIB_CALL +PDF_continue_text(PDF *p, const char *text); + +/* Same as PDF_continue_text(), but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_continue_text2(PDF *p, const char *text, int len); + +/* Create a 3D view (requires PDF 1.6). + Returns: A 3D view handle, or -1 (in PHP: 0) on error. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_create_3dview(PDF *p, const char *username, int len, const char *optlist); + +/* Create an action which can be applied to various objects and events. + Returns: An action handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_create_action(PDF *p, const char *type, const char *optlist); + +/* Create a rectangular annotation on the current page. */ +PDFLIB_API void PDFLIB_CALL +PDF_create_annotation(PDF *p, double llx, double lly, double urx, double ury, + const char *type, const char *optlist); + +/* Create a bookmark subject to various options. + Returns: A handle for the generated bookmark. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_create_bookmark(PDF *p, const char *text, int len, const char *optlist); + +/* Create a form field on the current page subject to various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_create_field(PDF *p, double llx, double lly, double urx, double ury, + const char *name, int len, const char *type, const char *optlist); + +/* Create a form field group subject to various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_create_fieldgroup(PDF *p, const char *name, int len, const char *optlist); + +/* Create a graphics state object subject to various options. + Returns: A graphics state handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_create_gstate(PDF *p, const char *optlist); + +/* Create a named virtual read-only file from data provided in memory. */ +PDFLIB_API void PDFLIB_CALL +PDF_create_pvf(PDF *p, const char *filename, int len, + const void *data, size_t size, const char *optlist); + +/* Create a Textflow object from text contents, inline options, and explicit + options. + Returns: A Textflow handle, or -1 (in PHP: 0) on error. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_create_textflow(PDF *p, const char *text, int len, const char *optlist); + +/* Draw a Bezier curve from the current point, using 3 more control points. */ +PDFLIB_API void PDFLIB_CALL +PDF_curveto(PDF *p, + double x_1, double y_1, double x_2, double y_2, double x_3, double y_3); + +/* Create a new layer definition (requires PDF 1.5). + Returns: A layer handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_define_layer(PDF *p, const char *name, int len, const char *optlist); + +/* Delete a PDFlib object and free all internal resources. */ +PDFLIB_API void PDFLIB_CALL +PDF_delete(PDF *p); + +/* Delete a named virtual file and free its data structures (but not the + contents). + Returns: -1 (in PHP: 0) if the virtual file exists but is locked, and + 1 otherwise. + */ +PDFLIB_API int PDFLIB_CALL +PDF_delete_pvf(PDF *p, const char *filename, int len); + +/* Delete a table and all associated data structures. */ +PDFLIB_API void PDFLIB_CALL +PDF_delete_table(PDF *p, int table, const char *optlist); + +/* Delete a Textflow and all associated data structures. */ +PDFLIB_API void PDFLIB_CALL +PDF_delete_textflow(PDF *p, int textflow); + +/* Add a glyph name and/or Unicode value to a custom encoding. */ +PDFLIB_API void PDFLIB_CALL +PDF_encoding_set_char(PDF *p, const char *encoding, int slot, + const char *glyphname, int uv); + +/* Close the generated PDF document and apply various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_document(PDF *p, const char *optlist); + +/* Terminate a Type 3 font definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_font(PDF *p); + +/* Terminate a glyph definition for a Type 3 font. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_glyph(PDF *p); + +/* Close a structure element or other content item. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_item(PDF *p, int id); + +/* Deactivate all active layers (requires PDF 1.5). */ +PDFLIB_API void PDFLIB_CALL +PDF_end_layer(PDF *p); + +/* End the least recently opened marked content sequence (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_end_mc(PDF *p); + +/* Deprecated, use PDF_end_page_ext(). */ +PDFLIB_API void PDFLIB_CALL +PDF_end_page(PDF *p); + +/* Finish a page, and apply various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_page_ext(PDF *p, const char *optlist); + +/* Finish a pattern definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_pattern(PDF *p); + +/* Finish a template definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_template(PDF *p); + +/* End the current path without filling or stroking it. */ +PDFLIB_API void PDFLIB_CALL +PDF_endpath(PDF *p); + +/* Fill the interior of the path with the current fill color. */ +PDFLIB_API void PDFLIB_CALL +PDF_fill(PDF *p); + +/* Fill an image block with variable data according to its properties. + Returns: -1 (in PHP: 0) on error, and 1 otherwise. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_fill_imageblock(PDF *p, int page, const char *blockname, + int image, const char *optlist); + +/* Fill a PDF block with variable data according to its properties. + Returns: -1 (in PHP: 0) on error, and 1 otherwise. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_fill_pdfblock(PDF *p, int page, const char *blockname, + int contents, const char *optlist); + +/* Fill and stroke the path with the current fill and stroke color. */ +PDFLIB_API void PDFLIB_CALL +PDF_fill_stroke(PDF *p); + +/* Fill a text block with variable data according to its properties. + Returns: -1 (in PHP: 0) on error, and 1 otherwise. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_fill_textblock(PDF *p, int page, const char *blockname, + const char *text, int len, const char *optlist); + +/* Deprecated, use PDF_load_font(). */ +PDFLIB_API int PDFLIB_CALL +PDF_findfont(PDF *p, const char *fontname, const char *encoding, int embed); + +/* Place an image or template on the page, subject to various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_fit_image(PDF *p, int image, double x, double y, const char *optlist); + +/* Place an imported PDF page on the page subject to various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_fit_pdi_page(PDF *p, int page, double x, double y, const char *optlist); + +/* Fully or partially place a table on the page. + Returns: A string which specifies the reason for returning. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_fit_table(PDF *p, int table, double llx, double lly, + double urx, double ury, const char *optlist); + +/* Format the next portion of a Textflow into a rectangular area. + Returns: A string which specifies the reason for returning. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_fit_textflow(PDF *p, int textflow, double llx, double lly, + double urx, double ury, const char *optlist); + +/* Place a single line of text at position (x, y) subject to various options. */ +PDFLIB_API void PDFLIB_CALL +PDF_fit_textline(PDF *p, const char *text, int len, double x, double y, + const char *optlist); + +/* + * Retrieve a structure with PDFlib API function pointers (mainly for DLLs). + * Although this function is published here, it is not supposed to be used + * directly by clients. Use PDF_new_dl() (in pdflibdl.c). + */ +PDFLIB_API const PDFlib_api * PDFLIB_CALL +PDF_get_api(void); + +/* Get the name of the API function which threw the last exception or failed. + Returns: Name of an API function. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_apiname(PDF *p); + +/* Get the contents of the PDF output buffer. + Returns: A buffer full of binary PDF data for consumption by the client. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_buffer(PDF *p, long *size); + +/* Get the text of the last thrown exception or the reason of a failed + function call. + Returns: Text containing the description of the most recent error condition. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_errmsg(PDF *p); + +/* Get the number of the last thrown exception or the reason of a failed + function call. + Returns: The error code of the most recent error condition. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_get_errnum(PDF *p); + +/* Request the amount of kerning between two characters (unsupported). */ +PDFLIB_API double PDFLIB_CALL +PDF_get_kern_amount(PDF *p, int font, int firstchar, int secondchar); + +/* Deprecated, use PDF_get_value(). */ +PDFLIB_API int PDFLIB_CALL +PDF_get_majorversion(void); + +/* Deprecated, use PDF_get_value(). */ +PDFLIB_API int PDFLIB_CALL +PDF_get_minorversion(void); + +/* Fetch the opaque application pointer stored in PDFlib. + Returns: The opaque application pointer stored in PDFlib. +*/ +PDFLIB_API void * PDFLIB_CALL +PDF_get_opaque(PDF *p); + +/* Get the contents of some PDFlib parameter with string type. + Returns: The string value of the parameter as a hypertext string. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_parameter(PDF *p, const char *key, double modifier); + +/* Deprecated, use PDF_pcos_get_string(). */ +PDFLIB_API const char *PDFLIB_CALL +PDF_get_pdi_parameter(PDF *p, const char *key, int doc, int page, + int reserved, int *len); + +/* Deprecated, use PDF_pcos_get_number. */ +PDFLIB_API double PDFLIB_CALL +PDF_get_pdi_value(PDF *p, const char *key, int doc, int page, int reserved); + +/* Get the value of some PDFlib parameter with numerical type. + Returns: The numerical value of the parameter. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_get_value(PDF *p, const char *key, double modifier); + +/* Query detailed information about a loaded font. + Returns: The value of some font property as requested by keyword. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_info_font(PDF *p, int font, const char *keyword, const char *optlist); + +/* Query information about a matchbox on the current page. + Returns: The value of some matchbox parameter as requested by keyword. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_info_matchbox(PDF *p, const char *boxname, int len, int num, + const char *keyword); + +/* Retrieve table information related to the most recently placed table + instance. + Returns: The value of some table parameter as requested by keyword. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_info_table(PDF *p, int table, const char *keyword); + +/* Query the current state of a Textflow. + Returns: The value of some Textflow parameter as requested by keyword. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_info_textflow(PDF *p, int textflow, const char *keyword); + +/* Perform textline formatting and query the resulting metrics. + Returns: The value of some text metric value as requested by keyword. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_info_textline(PDF *p, const char *text, int len, const char *keyword, + const char *optlist); + +/* Reset all color and graphics state parameters to their defaults. */ +PDFLIB_API void PDFLIB_CALL +PDF_initgraphics(PDF *p); + +/* Draw a line from the current point to another point. */ +PDFLIB_API void PDFLIB_CALL +PDF_lineto(PDF *p, double x, double y); + +/* Load a 3D model from a disk-based or virtual file (requires PDF 1.6). + Returns: A 3D handle, or -1 (in PHP: 0) on error. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_load_3ddata(PDF *p, const char *filename, int len, const char *optlist); + +/* Search for a font and prepare it for later use. + Returns: A font handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_load_font(PDF *p, const char *fontname, int len, + const char *encoding, const char *optlist); + +/* Search for an ICC profile and prepare it for later use. + Returns: A profile handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_load_iccprofile(PDF *p, const char *profilename, int len, + const char *optlist); + +/* Open a disk-based or virtual image file subject to various options. + Returns: An image handle, or -1 (in PHP: 0) on error. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_load_image(PDF *p, const char *imagetype, const char *filename, + int len, const char *optlist); + +/* Find a built-in spot color name, or make a named spot color from the + current fill color. + Returns: A color handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_makespotcolor(PDF *p, const char *spotname, int reserved); + +/* Add a marked content point with or without properties (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_mc_point(PDF *p, const char *tag, const char *optlist); + +/* Set the current point. */ +PDFLIB_API void PDFLIB_CALL +PDF_moveto(PDF *p, double x, double y); + +/* Create a new PDFlib object. + Returns: A handle to a PDFlib object. +*/ +PDFLIB_API PDF * PDFLIB_CALL +PDF_new(void); + +/* Create a new PDFlib object with client-supplied error handling and memory + allocation routines. + Returns: A handle to a PDFlib object. +*/ +typedef void (*errorproc_t)(PDF *p1, int errortype, const char *msg); +typedef void* (*allocproc_t)(PDF *p2, size_t size, const char *caller); +typedef void* (*reallocproc_t)(PDF *p3, + void *mem, size_t size, const char *caller); +typedef void (*freeproc_t)(PDF *p4, void *mem); + +PDFLIB_API PDF * PDFLIB_CALL +PDF_new2(errorproc_t errorhandler, allocproc_t allocproc, + reallocproc_t reallocproc, freeproc_t freeproc, void *opaque); + +/* Deprecated, use PDF_load_image(). */ +PDFLIB_API int PDFLIB_CALL +PDF_open_CCITT(PDF *p, const char *filename, int width, int height, + int BitReverse, int K, int BlackIs1); + +/* Deprecated, use PDF_begin_document(). */ +PDFLIB_API int PDFLIB_CALL +PDF_open_file(PDF *p, const char *filename); + +/* Deprecated, use PDF_load_image() with virtual files. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_image(PDF *p, const char *imagetype, const char *source, + const char *data, long length, int width, int height, int components, + int bpc, const char *params); + +/* Deprecated, use PDF_load_image(). */ +PDFLIB_API int PDFLIB_CALL +PDF_open_image_file(PDF *p, const char *imagetype, const char *filename, + const char *stringparam, int intparam); + +/* Deprecated, use PDF_begin_document_callback(). */ +PDFLIB_API void PDFLIB_CALL +PDF_open_mem(PDF *p, writeproc_t writeproc); + +/* Deprecated, use PDF_open_pdi_document(). */ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi(PDF *p, const char *filename, const char *optlist, int len); + +/* Open a disk-based or virtual PDF document and prepare it for later use. + Returns: A PDI document handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_document(PDF *p, const char *filename, int len, + const char *optlist); + +/* Open a PDF document from a custom data source and prepare it for + later use. + Returns: A PDI document handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_callback(PDF *p, void *opaque, size_t filesize, + size_t (*readproc)(void *opaque, void *buffer, size_t size), + int (*seekproc)(void *opaque, long offset), + const char *optlist); + +/* Prepare a page for later use with PDF_fit_pdi_page(). + Returns: A page handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_page(PDF *p, int doc, int pagenumber, const char *optlist); + +/* Get the value of a pCOS path with type number or boolean. + Returns: The numerical value of the object identified by the pCOS path. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_pcos_get_number(PDF *p, int doc, const char *path, ...); + +/* Get the value of a pCOS path with type name, string or boolean. + Returns: A string with the value of the object identified by the pCOS path. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_pcos_get_string(PDF *p, int doc, const char *path, ...); + +/* Get the contents of a pCOS path with type stream, fstream, or string. + Returns: The unencrypted data contained in the stream or string. +*/ +PDFLIB_API const unsigned char * PDFLIB_CALL +PDF_pcos_get_stream(PDF *p, int doc, int *length, const char *optlist, + const char *path, ...); + +/* Deprecated, use PDF_fit_image(). */ +PDFLIB_API void PDFLIB_CALL +PDF_place_image(PDF *p, int image, double x, double y, double scale); + +/* Deprecated, use PDF_fit_pdi_page(). */ +PDFLIB_API void PDFLIB_CALL +PDF_place_pdi_page(PDF *p, int page, double x, double y, double sx, double sy); + +/* Process certain elements of an imported PDF document. + Returns: -1 (in PHP: 0) on error, and 1 otherwise. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_process_pdi(PDF *p, int doc, int page, const char *optlist); + +/* Draw a Bezier curve using relative coordinates (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_rcurveto(PDF *p, + double x_1, double y_1, double x_2, double y_2, double x_3, double y_3); + +/* Draw a rectangle. */ +PDFLIB_API void PDFLIB_CALL +PDF_rect(PDF *p, double x, double y, double width, double height); + +/* Restore the most recently saved graphics state from the stack. */ +PDFLIB_API void PDFLIB_CALL +PDF_restore(PDF *p); + +/* Resume a page to add more content to it. */ +PDFLIB_API void PDFLIB_CALL +PDF_resume_page(PDF *p, const char *optlist); + +/* Draw a line from the current point to (cp + (x, y)) (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_rlineto(PDF *p, double x, double y); + +/* Set the new current point relative the old current point (unsupported). */ +PDFLIB_API void PDFLIB_CALL +PDF_rmoveto(PDF *p, double x, double y); + +/* Rotate the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_rotate(PDF *p, double phi); + +/* Save the current graphics state to a stack. */ +PDFLIB_API void PDFLIB_CALL +PDF_save(PDF *p); + +/* Scale the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_scale(PDF *p, double sx, double sy); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_color(PDF *p, double red, double green, double blue); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_dash(PDF *p, double b, double w); + +/* Deprecated, use PDF_create_annotation(). */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_style(PDF *p, const char *style, double width); + +/* Activate a graphics state object. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_gstate(PDF *p, int gstate); + +/* Fill document information field key with value. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_info(PDF *p, const char *key, const char *value); + +/* Like PDF_set_info(), but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_info2(PDF *p, const char *key, const char *value, int len); + +/* Define hierarchical, group, and lock conditions among layers (requires + PDF 1.5). +*/ +PDFLIB_API void PDFLIB_CALL +PDF_set_layer_dependency(PDF *p, const char *type, const char *optlist); + +/* Set some PDFlib parameter with string type. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_parameter(PDF *p, const char *key, const char *value); + +/* Set the position for text output on the page. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_text_pos(PDF *p, double x, double y); + +/* Set the value of some PDFlib parameter with numerical type. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_value(PDF *p, const char *key, double value); + +/* Set the current color space and color. */ +PDFLIB_API void PDFLIB_CALL +PDF_setcolor(PDF *p, const char *fstype, const char *colorspace, + double c1, double c2, double c3, double c4); + +/* Set the current dash pattern. */ +PDFLIB_API void PDFLIB_CALL +PDF_setdash(PDF *p, double b, double w); + +/* Set a dash pattern defined by an option list. */ +PDFLIB_API void PDFLIB_CALL +PDF_setdashpattern(PDF *p, const char *optlist); + +/* Set the flatness parameter. */ +PDFLIB_API void PDFLIB_CALL +PDF_setflat(PDF *p, double flatness); + +/* Set the current font in the specified size. */ +PDFLIB_API void PDFLIB_CALL +PDF_setfont(PDF *p, int font, double fontsize); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray(PDF *p, double gray); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray_fill(PDF *p, double gray); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray_stroke(PDF *p, double gray); + +/* Set the linecap parameter. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinecap(PDF *p, int linecap); + +/* Set the linejoin parameter. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinejoin(PDF *p, int linejoin); + +/* Set the current linewidth. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinewidth(PDF *p, double width); + +/* Explicitly set the current transformation matrix. */ +PDFLIB_API void PDFLIB_CALL +PDF_setmatrix(PDF *p, double a, double b, double c, double d, + double e, double f); + +/* Set the miter limit. */ +PDFLIB_API void PDFLIB_CALL +PDF_setmiterlimit(PDF *p, double miter); + +/* Deprecated, use PDF_setdashpattern(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setpolydash(PDF *p, float *dasharray, int length); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor(PDF *p, double red, double green, double blue); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_fill(PDF *p, double red, double green, double blue); + +/* Deprecated, use PDF_setcolor(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_stroke(PDF *p, double red, double green, double blue); + +/* Define a blend from the current fill color to another color (requires + PDF 1.4). + Returns: A shading handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_shading(PDF *p, const char *shtype, double x_0, double y_0, double x_1, + double y_1, double c_1, double c_2, double c_3, double c_4, + const char *optlist); + +/* Define a shading pattern using a shading object (requires PDF 1.4). + Returns: A pattern handle. +*/ +PDFLIB_API int PDFLIB_CALL +PDF_shading_pattern(PDF *p, int shading, const char *optlist); + +/* Fill an area with a shading, based on a shading object (requires PDF 1.4) */ +PDFLIB_API void PDFLIB_CALL +PDF_shfill(PDF *p, int shading); + +/* Print text in the current font and size at the current position. */ +PDFLIB_API void PDFLIB_CALL +PDF_show(PDF *p, const char *text); + +/* Same as PDF_show() but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_show2(PDF *p, const char *text, int len); + +/* Deprecated, use PDF_fit_textline() or PDF_fit_textflow(). */ +PDFLIB_API int PDFLIB_CALL +PDF_show_boxed(PDF *p, const char *text, double left, double top, + double width, double height, const char *hmode, const char *feature); + +/* Deprecated, use PDF_fit_textline() or PDF_fit_textflow(). */ +PDFLIB_API int PDFLIB_CALL +PDF_show_boxed2(PDF *p, const char *text, int len, double left, double top, + double width, double height, const char *hmode, const char *feature); + +/* Print text in the current font. */ +PDFLIB_API void PDFLIB_CALL +PDF_show_xy(PDF *p, const char *text, double x, double y); + +/* Same as PDF_show_xy(), but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_show_xy2(PDF *p, const char *text, int len, double x, double y); + +/* Deprecated, and not required. */ +PDFLIB_API void PDFLIB_CALL +PDF_shutdown(void); + +/* Skew the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_skew(PDF *p, double alpha, double beta); + +/* Calculate the width of text in an arbitrary font. + Returns: The width of text. +*/ +PDFLIB_API double PDFLIB_CALL +PDF_stringwidth(PDF *p, const char *text, int font, double fontsize); + +/* Same as PDF_stringwidth(), but with explicit string length. */ +PDFLIB_API double PDFLIB_CALL +PDF_stringwidth2(PDF *p, const char *text, int len, int font, double fontsize); + +/* Stroke the path with the current color and line width, and clear it. */ +PDFLIB_API void PDFLIB_CALL +PDF_stroke(PDF *p); + +/* Suspend the current page so that it can later be resumed. */ +PDFLIB_API void PDFLIB_CALL +PDF_suspend_page(PDF *p, const char *optlist); + +/* Translate the origin of the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_translate(PDF *p, double tx, double ty); + +/* Convert a string from UTF-16 format to UTF-8. + Returns: The converted UTF-8 string, starting with the UTF-8 BOM. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_utf16_to_utf8(PDF *p, const char *utf16string, int len, int *size); + +/* Convert a string from UTF-32 format to UTF-16. + Returns: The converted UTF-16 string. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_utf32_to_utf16(PDF *p, const char *utf32string, int len, + const char *ordering, int *size); + +/* Convert a string from UTF-8 format to UTF-16. + Returns: The converted UTF-16 string. +*/ +PDFLIB_API const char * PDFLIB_CALL +PDF_utf8_to_utf16(PDF *p, const char *utf8string, const char *ordering, + int *size); + +/* Print text in the current font and size, using individual horizontal + positions (unsupported). +*/ +PDFLIB_API void PDFLIB_CALL +PDF_xshow(PDF *p, const char *text, int len, const double *xadvancelist); + + +/* + * ---------------------------------------------------------------------- + * PDFlib API structure with function pointers to all API functions + * ---------------------------------------------------------------------- + */ + +/* Auxiliary structure for try/catch */ +typedef struct +{ + jmp_buf jbuf; +} pdf_jmpbuf; + + +/* The API structure with pointers to all PDFlib API functions */ +struct PDFlib_api_s { + /* version numbers for checking the DLL against client code */ + size_t sizeof_PDFlib_api; /* size of this structure */ + + int major; /* PDFlib major version number */ + int minor; /* PDFlib minor version number */ + int revision; /* PDFlib revision number */ + + int reserved; /* reserved */ + + void (PDFLIB_CALL * PDF_activate_item)(PDF *p, int id); + int (PDFLIB_CALL * PDF_add_bookmark)(PDF *p, const char *text, + int parent, int open); + int (PDFLIB_CALL * PDF_add_bookmark2)(PDF *p, const char *text, int len, + int parent, int open); + void (PDFLIB_CALL * PDF_add_launchlink)(PDF *p, + double llx, double lly, double urx, + double ury, const char *filename); + void (PDFLIB_CALL * PDF_add_locallink)(PDF *p, + double llx, double lly, double urx, + double ury, int page, const char *optlist); + void (PDFLIB_CALL * PDF_add_nameddest)(PDF *p, const char *name, + int len, const char *optlist); + void (PDFLIB_CALL * PDF_add_note)(PDF *p, double llx, double lly, + double urx, double ury, const char *contents, const char *title, + const char *icon, int open); + void (PDFLIB_CALL * PDF_add_note2)(PDF *p, double llx, double lly, + double urx, double ury, const char *contents, int len_cont, + const char *title, int len_title, const char *icon, int open); + void (PDFLIB_CALL * PDF_add_pdflink)(PDF *p, + double llx, double lly, double urx, double ury, + const char *filename, int page, const char *optlist); + int (PDFLIB_CALL * PDF_add_table_cell)(PDF *p, int table, int column, + int row, const char *text, int len, const char *optlist); + int (PDFLIB_CALL * PDF_add_textflow)(PDF *p, int textflow, const char *text, + int len, const char *optlist); + void (PDFLIB_CALL * PDF_add_thumbnail)(PDF *p, int image); + void (PDFLIB_CALL * PDF_add_weblink)(PDF *p, double llx, + double lly, double urx, double ury, const char *url); + void (PDFLIB_CALL * PDF_arc)(PDF *p, double x, double y, + double r, double alpha, double beta); + void (PDFLIB_CALL * PDF_arcn)(PDF *p, double x, double y, + double r, double alpha, double beta); + void (PDFLIB_CALL * PDF_attach_file)(PDF *p, double llx, double lly, + double urx, double ury, const char *filename, + const char *description, + const char *author, const char *mimetype, const char *icon); + void (PDFLIB_CALL * PDF_attach_file2)(PDF *p, double llx, double lly, + double urx, double ury, const char *filename, int len_filename, + const char *description, int len_descr, const char *author, + int len_auth, const char *mimetype, const char *icon); + int (PDFLIB_CALL * PDF_begin_document)(PDF *p, const char *filename, + int len, const char *optlist); + void (PDFLIB_CALL * PDF_begin_document_callback)(PDF *p, + writeproc_t writeproc, const char *optlist); + void (PDFLIB_CALL * PDF_begin_font)(PDF *p, const char *fontname, + int len, double a, double b, double c, double d, double e, + double f, const char *optlist); + void (PDFLIB_CALL * PDF_begin_glyph)(PDF *p, const char *glyphname, + double wx, double llx, double lly, double urx, double ury); + int (PDFLIB_CALL * PDF_begin_item)(PDF *p, const char *tag, + const char *optlist); + void (PDFLIB_CALL * PDF_begin_layer)(PDF *p, int layer); + void (PDFLIB_CALL * PDF_begin_mc)(PDF *p, + const char *tag, const char *optlist); + void (PDFLIB_CALL * PDF_begin_page)(PDF *p, double width, double height); + void (PDFLIB_CALL * PDF_begin_page_ext)(PDF *p, double width, + double height, const char *optlist); + int (PDFLIB_CALL * PDF_begin_pattern)(PDF *p, double width, double height, + double xstep, double ystep, int painttype); + int (PDFLIB_CALL * PDF_begin_template)(PDF *p, + double width, double height); + int (PDFLIB_CALL * PDF_begin_template_ext)(PDF *p, + double width, double height, const char *optlist); + void (PDFLIB_CALL * PDF_boot)(void); + int (PDFLIB_CALL * PDF_check_context)(PDF *p); + void (PDFLIB_CALL * PDF_circle)(PDF *p, double x, double y, double r); + void (PDFLIB_CALL * PDF_clip)(PDF *p); + void (PDFLIB_CALL * PDF_close)(PDF *p); + void (PDFLIB_CALL * PDF_close_image)(PDF *p, int image); + void (PDFLIB_CALL * PDF_close_pdi)(PDF *p, int doc); + void (PDFLIB_CALL * PDF_close_pdi_document)(PDF *p, int doc); + void (PDFLIB_CALL * PDF_close_pdi_page)(PDF *p, int page); + void (PDFLIB_CALL * PDF_closepath)(PDF *p); + void (PDFLIB_CALL * PDF_closepath_fill_stroke)(PDF *p); + void (PDFLIB_CALL * PDF_closepath_stroke)(PDF *p); + void (PDFLIB_CALL * PDF_concat)(PDF *p, double a, double b, + double c, double d, double e, double f); + void (PDFLIB_CALL * PDF_continue_text)(PDF *p, const char *text); + void (PDFLIB_CALL * PDF_continue_text2)(PDF *p, const char *text, int len); + int (PDFLIB_CALL * PDF_create_3dview)(PDF *p, const char *username, + int len, const char *optlist); + int (PDFLIB_CALL * PDF_create_action)(PDF *p, const char *type, + const char *optlist); + void (PDFLIB_CALL * PDF_create_annotation)(PDF *p, + double llx, double lly, double urx, double ury, + const char *type, const char *optlist); + int (PDFLIB_CALL * PDF_create_bookmark)(PDF *p, const char *text, int len, + const char *optlist); + void (PDFLIB_CALL * PDF_create_field)(PDF *p, double llx, double lly, + double urx, double ury, const char *name, int len, + const char *type, const char *optlist); + void (PDFLIB_CALL * PDF_create_fieldgroup)(PDF *p, const char *name, + int len, const char *optlist); + int (PDFLIB_CALL * PDF_create_gstate)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_create_pvf)(PDF *p, const char *filename, + int len, const void *data, size_t size, const char *optlist); + int (PDFLIB_CALL * PDF_create_textflow)(PDF *p, const char *text, int len, + const char *optlist); + void (PDFLIB_CALL * PDF_curveto)(PDF *p, double x_1, double y_1, + double x_2, double y_2, double x_3, double y_3); + int (PDFLIB_CALL * PDF_define_layer)(PDF *p, const char *name, int len, + const char *optlist); + void (PDFLIB_CALL * PDF_delete)(PDF *); + int (PDFLIB_CALL * PDF_delete_pvf)(PDF *p, const char *filename, int len); + void (PDFLIB_CALL * PDF_delete_table)(PDF *p, int table, + const char *optlist); + void (PDFLIB_CALL * PDF_delete_textflow)(PDF *p, int textflow); + void (PDFLIB_CALL * PDF_encoding_set_char)(PDF *p, const char *encoding, + int slot, const char *glyphname, int uv); + void (PDFLIB_CALL * PDF_end_document)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_end_font)(PDF *p); + void (PDFLIB_CALL * PDF_end_glyph)(PDF *p); + void (PDFLIB_CALL * PDF_end_item)(PDF *p, int id); + void (PDFLIB_CALL * PDF_end_layer)(PDF *p); + void (PDFLIB_CALL * PDF_end_mc)(PDF *p); + void (PDFLIB_CALL * PDF_end_page)(PDF *p); + void (PDFLIB_CALL * PDF_end_page_ext)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_end_pattern)(PDF *p); + void (PDFLIB_CALL * PDF_end_template)(PDF *p); + void (PDFLIB_CALL * PDF_endpath)(PDF *p); + void (PDFLIB_CALL * PDF_fill)(PDF *p); + int (PDFLIB_CALL * PDF_fill_imageblock)(PDF *p, int page, + const char *blockname, int image, const char *optlist); + int (PDFLIB_CALL * PDF_fill_pdfblock)(PDF *p, int page, + const char *blockname, int contents, const char *optlist); + void (PDFLIB_CALL * PDF_fill_stroke)(PDF *p); + int (PDFLIB_CALL * PDF_fill_textblock)(PDF *p, int page, + const char *blockname, const char *text, int len, + const char *optlist); + int (PDFLIB_CALL * PDF_findfont)(PDF *p, const char *fontname, + const char *encoding, int embed); + void (PDFLIB_CALL * PDF_fit_image)(PDF *p, int image, double x, double y, + const char *optlist); + void (PDFLIB_CALL * PDF_fit_pdi_page)(PDF *p, int page, double x, + double y, const char *optlist); + const char * (PDFLIB_CALL * PDF_fit_table)(PDF *p, int table, + double llx, double lly, double urx, double ury, + const char *optlist); + const char * (PDFLIB_CALL * PDF_fit_textflow)(PDF *p, int textflow, + double llx, double lly, double urx, double ury, + const char *optlist); + void (PDFLIB_CALL * PDF_fit_textline)(PDF *p, const char *text, + int len, double x, double y, const char *optlist); + const PDFlib_api * (PDFLIB_CALL * PDF_get_api)(void); + const char * (PDFLIB_CALL * PDF_get_apiname)(PDF *p); + const char * (PDFLIB_CALL * PDF_get_buffer)(PDF *p, long *size); + const char * (PDFLIB_CALL * PDF_get_errmsg)(PDF *p); + int (PDFLIB_CALL * PDF_get_errnum)(PDF *p); + int (PDFLIB_CALL * PDF_get_minorversion)(void); + int (PDFLIB_CALL * PDF_get_majorversion)(void); + void * (PDFLIB_CALL * PDF_get_opaque)(PDF *p); + const char * (PDFLIB_CALL * PDF_get_parameter)(PDF *p, + const char *key, double modifier); + const char * (PDFLIB_CALL * PDF_get_pdi_parameter)(PDF *p, + const char *key, int doc, int page, int reserved, int *len); + double (PDFLIB_CALL * PDF_get_pdi_value)(PDF *p, const char *key, + int doc, int page, int reserved); + double (PDFLIB_CALL * PDF_get_value)(PDF *p, const char *key, + double modifier); + double (PDFLIB_CALL * PDF_info_font)(PDF *p, int font, const char *keyword, + const char *optlist); + double (PDFLIB_CALL * PDF_info_matchbox)(PDF *p, const char *boxname, + int len, int num, const char *keyword); + double (PDFLIB_CALL * PDF_info_table)(PDF *p, int table, + const char *keyword); + double (PDFLIB_CALL * PDF_info_textflow)(PDF *p, int textflow, + const char *keyword); + double (PDFLIB_CALL * PDF_info_textline)(PDF *p, const char *text, int len, + const char *keyword, const char *optlist); + void (PDFLIB_CALL * PDF_initgraphics)(PDF *p); + void (PDFLIB_CALL * PDF_lineto)(PDF *p, double x, double y); + int (PDFLIB_CALL * PDF_load_3ddata)(PDF *p, const char *filename, int len, + const char *optlist); + int (PDFLIB_CALL * PDF_load_font)(PDF *p, const char *fontname, + int len, const char *encoding, const char *optlist); + int (PDFLIB_CALL * PDF_load_iccprofile)(PDF *p, const char *profilename, + int len, const char *optlist); + int (PDFLIB_CALL * PDF_load_image)(PDF *p, const char *imagetype, + const char *filename, int len, const char *optlist); + int (PDFLIB_CALL * PDF_makespotcolor)(PDF *p, const char *spotname, + int len); + void (PDFLIB_CALL * PDF_mc_point)(PDF *p, + const char *tag, const char *optlist); + void (PDFLIB_CALL * PDF_moveto)(PDF *p, double x, double y); + PDF* (PDFLIB_CALL * PDF_new)(void); + PDF* (PDFLIB_CALL * PDF_new2)(errorproc_t errorhandler, + allocproc_t allocproc, reallocproc_t reallocproc, + freeproc_t freeproc, void *opaque); + int (PDFLIB_CALL * PDF_open_CCITT)(PDF *p, const char *filename, + int width, int height, int BitReverse, int K, int BlackIs1); + int (PDFLIB_CALL * PDF_open_file)(PDF *p, const char *filename); + int (PDFLIB_CALL * PDF_open_image)(PDF *p, const char *imagetype, + const char *source, const char *data, long length, int width, + int height, int components, int bpc, const char *params); + int (PDFLIB_CALL * PDF_open_image_file)(PDF *p, const char *imagetype, + const char *filename, const char *stringparam, int intparam); + void (PDFLIB_CALL * PDF_open_mem)(PDF *p, writeproc_t writeproc); + int (PDFLIB_CALL * PDF_open_pdi)(PDF *p, const char *filename, + const char *optlist, int len); + int (PDFLIB_CALL * PDF_open_pdi_callback)(PDF *p, void *opaque, + size_t filesize, size_t (*readproc)(void *opaque, void *buffer, + size_t size), int (*seekproc)(void *opaque, long offset), + const char *optlist); + int (PDFLIB_CALL * PDF_open_pdi_document)(PDF *p, const char *filename, + int len, const char *optlist); + int (PDFLIB_CALL * PDF_open_pdi_page)(PDF *p, + int doc, int pagenumber, const char *optlist); + double (PDFLIB_CALL * PDF_pcos_get_number)(PDF *p, + int doc, const char *path, ...); + const char * (PDFLIB_CALL * PDF_pcos_get_string)(PDF *p, + int doc, const char *path, ...); + const unsigned char * (PDFLIB_CALL * PDF_pcos_get_stream)(PDF *p, + int doc, int *length, const char *optlist, + const char *path, ...); + void (PDFLIB_CALL * PDF_place_image)(PDF *p, int image, + double x, double y, double scale); + void (PDFLIB_CALL * PDF_place_pdi_page)(PDF *p, int page, + double x, double y, double sx, double sy); + int (PDFLIB_CALL * PDF_process_pdi)(PDF *p, int doc, int page, + const char *optlist); + void (PDFLIB_CALL * PDF_rect)(PDF *p, double x, double y, + double width, double height); + void (PDFLIB_CALL * PDF_restore)(PDF *p); + void (PDFLIB_CALL * PDF_resume_page)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_rotate)(PDF *p, double phi); + void (PDFLIB_CALL * PDF_save)(PDF *p); + void (PDFLIB_CALL * PDF_scale)(PDF *p, double sx, double sy); + void (PDFLIB_CALL * PDF_set_border_color)(PDF *p, + double red, double green, double blue); + void (PDFLIB_CALL * PDF_set_border_dash)(PDF *p, double b, double w); + void (PDFLIB_CALL * PDF_set_border_style)(PDF *p, + const char *style, double width); + void (PDFLIB_CALL * PDF_set_gstate)(PDF *p, int gstate); + void (PDFLIB_CALL * PDF_set_info)(PDF *p, const char *key, + const char *value); + void (PDFLIB_CALL * PDF_set_info2)(PDF *p, const char *key, + const char *value, int len); + void (PDFLIB_CALL * PDF_set_layer_dependency)(PDF *p, const char *type, + const char *optlist); + void (PDFLIB_CALL * PDF_set_parameter)(PDF *p, const char *key, + const char *value); + void (PDFLIB_CALL * PDF_set_text_pos)(PDF *p, double x, double y); + void (PDFLIB_CALL * PDF_set_value)(PDF *p, const char *key, double value); + void (PDFLIB_CALL * PDF_setcolor)(PDF *p, const char *fstype, + const char *colorspace, double c1, double c2, + double c3, double c4); + void (PDFLIB_CALL * PDF_setdash)(PDF *p, double b, double w); + void (PDFLIB_CALL * PDF_setdashpattern)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_setflat)(PDF *p, double flatness); + void (PDFLIB_CALL * PDF_setfont)(PDF *p, int font, double fontsize); + void (PDFLIB_CALL * PDF_setgray)(PDF *p, double gray); + void (PDFLIB_CALL * PDF_setgray_fill)(PDF *p, double gray); + void (PDFLIB_CALL * PDF_setgray_stroke)(PDF *p, double gray); + void (PDFLIB_CALL * PDF_setlinecap)(PDF *p, int linecap); + void (PDFLIB_CALL * PDF_setlinejoin)(PDF *p, int linejoin); + void (PDFLIB_CALL * PDF_setlinewidth)(PDF *p, double width); + void (PDFLIB_CALL * PDF_setmatrix)(PDF *p, double a, double b, + double c, double d, double e, double f); + void (PDFLIB_CALL * PDF_setmiterlimit)(PDF *p, double miter); + void (PDFLIB_CALL * PDF_setpolydash)(PDF *p, float *dasharray, int length); + void (PDFLIB_CALL * PDF_setrgbcolor)(PDF *p, double red, double green, + double blue); + void (PDFLIB_CALL * PDF_setrgbcolor_fill)(PDF *p, + double red, double green, double blue); + void (PDFLIB_CALL * PDF_setrgbcolor_stroke)(PDF *p, + double red, double green, double blue); + int (PDFLIB_CALL * PDF_shading)(PDF *p, const char *shtype, double x_0, + double y_0, double x_1, double y_1, double c_1, double c_2, + double c_3, double c_4, const char *optlist); + int (PDFLIB_CALL * PDF_shading_pattern)(PDF *p, int shading, + const char *optlist); + void (PDFLIB_CALL * PDF_shfill)(PDF *p, int shading); + void (PDFLIB_CALL * PDF_show)(PDF *p, const char *text); + void (PDFLIB_CALL * PDF_show2)(PDF *p, const char *text, int len); + int (PDFLIB_CALL * PDF_show_boxed)(PDF *p, const char *text, + double left, double top, double width, double height, + const char *hmode, const char *feature); + int (PDFLIB_CALL * PDF_show_boxed2)(PDF *p, const char *text, int len, + double left, double top, double width, double height, + const char *hmode, const char *feature); + void (PDFLIB_CALL * PDF_show_xy)(PDF *p, const char *text, double x, + double y); + void (PDFLIB_CALL * PDF_show_xy2)(PDF *p, const char *text, + int len, double x, double y); + void (PDFLIB_CALL * PDF_shutdown)(void); + void (PDFLIB_CALL * PDF_skew)(PDF *p, double alpha, double beta); + double (PDFLIB_CALL * PDF_stringwidth)(PDF *p, const char *text, + int font, double fontsize); + double (PDFLIB_CALL * PDF_stringwidth2)(PDF *p, const char *text, + int len, int font, double fontsize); + void (PDFLIB_CALL * PDF_stroke)(PDF *p); + void (PDFLIB_CALL * PDF_suspend_page)(PDF *p, const char *optlist); + void (PDFLIB_CALL * PDF_translate)(PDF *p, double tx, double ty); + const char * (PDFLIB_CALL * PDF_utf16_to_utf8)(PDF *p, + const char *utf16string, int len, int *size); + const char * (PDFLIB_CALL * PDF_utf32_to_utf16)(PDF *p, + const char *utf32string, int len, const char *ordering, + int *size); + const char * (PDFLIB_CALL * PDF_utf8_to_utf16)(PDF *p, + const char *utf8string, const char *format, int *size); + void (PDFLIB_CALL * PDF_xshow)(PDF *p, const char *text, int len, + const double *xadvancelist); + + int (PDFLIB_CALL * pdf_catch)(PDF *p); + void (PDFLIB_CALL * pdf_exit_try)(PDF *p); + pdf_jmpbuf * (PDFLIB_CALL * pdf_jbuf)(PDF *p); + void (PDFLIB_CALL * pdf_rethrow)(PDF *p); +}; + + +/* + * ---------------------------------------------------------------------- + * pCOS-specific enums and defines + * ---------------------------------------------------------------------- + */ + +/* + * PDFlib GmbH products implement the following pCOS interface numbers: + * + * pCOS interface Products + * 1 TET 2.0, 2.1 + * 2 pCOS 1.x + * 3 PDFlib 7.0.x + */ + +#ifndef PCOS_INTERFACE +#define PCOS_INTERFACE 3 + +/* document access levels. +*/ +typedef enum +{ + pcos_mode_minimum = 0, /* encrypted doc (opened w/o password) */ + pcos_mode_restricted = 1, /* encrypted doc (opened w/ user password) */ + pcos_mode_full = 2 /* unencrypted doc or opened w/ master password */ +} pcos_mode; + + +/* object types. +*/ +typedef enum +{ + pcos_ot_null = 0, + pcos_ot_boolean = 1, + pcos_ot_number = 2, + pcos_ot_name = 3, + pcos_ot_string = 4, + pcos_ot_array = 5, + pcos_ot_dict = 6, + pcos_ot_stream = 7, + pcos_ot_fstream = 8 +} pcos_object_type; + +#endif /* PCOS_INTERFACE */ + + +/* + * ---------------------------------------------------------------------- + * Exception handling with try/catch implementation + * ---------------------------------------------------------------------- + */ + +/* Set up an exception handling frame; must always be paired with PDF_CATCH().*/ + +#define PDF_TRY(p) if (p) { if (setjmp(pdf_jbuf(p)->jbuf) == 0) + +/* Inform the exception machinery that a PDF_TRY() will be left without + entering the corresponding PDF_CATCH( ) clause. */ +#define PDF_EXIT_TRY(p) pdf_exit_try(p) + +/* Catch an exception; must always be paired with PDF_TRY(). */ +#define PDF_CATCH(p) } if (pdf_catch(p)) + +/* Re-throw an exception to another handler. */ +#define PDF_RETHROW(p) pdf_rethrow(p) + + +/* + * ---------------------------------------------------------------------- + * End of supported public declarations + * ---------------------------------------------------------------------- + */ + +/* + * ------------------------------------------------------------------------ + * Deprecated: macros for page size formats + * ------------------------------------------------------------------------ + */ + +/* + * The page sizes are only available to the C and C++ bindings. + * These are deprecated; corresponding options are supported in + * PDF_begin_page_ext(). + */ + +#define a0_width 2380.0 +#define a0_height 3368.0 +#define a1_width 1684.0 +#define a1_height 2380.0 +#define a2_width 1190.0 +#define a2_height 1684.0 +#define a3_width 842.0 +#define a3_height 1190.0 +#define a4_width 595.0 +#define a4_height 842.0 +#define a5_width 421.0 +#define a5_height 595.0 +#define a6_width 297.0 +#define a6_height 421.0 +#define b5_width 501.0 +#define b5_height 709.0 +#define letter_width 612.0 +#define letter_height 792.0 +#define legal_width 612.0 +#define legal_height 1008.0 +#define ledger_width 1224.0 +#define ledger_height 792.0 +#define p11x17_width 792.0 +#define p11x17_height 1224.0 + + +/* + * ---------------------------------------------------------------------- + * Deprecated: Error classes + * ---------------------------------------------------------------------- + */ + +/* + * Error classes are deprecated; use PDF_TRY/PDF_CATCH instead. + * Note that old-style error handlers are still supported, but + * they will always receive PDF_UnknownError. + */ + +#define PDF_MemoryError 1 +#define PDF_IOError 2 +#define PDF_RuntimeError 3 +#define PDF_IndexError 4 +#define PDF_TypeError 5 +#define PDF_DivisionByZero 6 +#define PDF_OverflowError 7 +#define PDF_SyntaxError 8 +#define PDF_ValueError 9 +#define PDF_SystemError 10 +#define PDF_NonfatalError 11 +#define PDF_UnknownError 12 + + +/* + * ---------------------------------------------------------------------- + * Deprecated functions (should no longer be used) + * ---------------------------------------------------------------------- + */ + +#if _MSC_VER >= 1310 /* VS .NET 2003 and later */ +#pragma deprecated(PDF_add_bookmark) +#pragma deprecated(PDF_add_bookmark2) +#pragma deprecated(PDF_add_launchlink) +#pragma deprecated(PDF_add_locallink) +#pragma deprecated(PDF_add_note) +#pragma deprecated(PDF_add_note2) +#pragma deprecated(PDF_add_pdflink) +#pragma deprecated(PDF_add_weblink) +#pragma deprecated(PDF_attach_file) +#pragma deprecated(PDF_attach_file2) +#pragma deprecated(PDF_begin_page) +#pragma deprecated(PDF_begin_template) +#pragma deprecated(PDF_boot) +#pragma deprecated(PDF_close) +#pragma deprecated(PDF_end_page) +#pragma deprecated(PDF_findfont) +#pragma deprecated(PDF_get_majorversion) +#pragma deprecated(PDF_get_minorversion) +#pragma deprecated(PDF_get_pdi_value) +#pragma deprecated(PDF_get_pdi_parameter) +#pragma deprecated(PDF_open_CCITT) +#pragma deprecated(PDF_open_file) +#pragma deprecated(PDF_open_image) +#pragma deprecated(PDF_open_image_file) +#pragma deprecated(PDF_open_mem) +#pragma deprecated(PDF_place_image) +#pragma deprecated(PDF_place_pdi_page) +#pragma deprecated(PDF_set_border_color) +#pragma deprecated(PDF_set_border_dash) +#pragma deprecated(PDF_set_border_style) +#pragma deprecated(PDF_setgray) +#pragma deprecated(PDF_setgray_fill) +#pragma deprecated(PDF_setgray_stroke) +#pragma deprecated(PDF_setpolydash) +#pragma deprecated(PDF_setrgbcolor) +#pragma deprecated(PDF_setrgbcolor_fill) +#pragma deprecated(PDF_setrgbcolor_stroke) +#pragma deprecated(PDF_show_boxed) +#pragma deprecated(PDF_show_boxed2) +#pragma deprecated(PDF_shutdown) +#endif + +/* + * ---------------------------------------------------------------------- + * Private stuff, do not use explicitly but only via the macros above! + * ---------------------------------------------------------------------- + */ + +PDFLIB_API pdf_jmpbuf * PDFLIB_CALL +pdf_jbuf(PDF *p); + +PDFLIB_API void PDFLIB_CALL +pdf_exit_try(PDF *p); + +PDFLIB_API int PDFLIB_CALL +pdf_catch(PDF *p); + +PDFLIB_API void PDFLIB_CALL +pdf_rethrow(PDF *p); + +PDFLIB_API void PDFLIB_CALL +pdf_throw(PDF *p, const char *binding, const char *apiname, const char *errmsg); + + +/* + * ---------------------------------------------------------------------- + * End of useful stuff + * ---------------------------------------------------------------------- + */ + +#if defined(__MWERKS__) && defined(PDFLIB_EXPORTS) +#pragma export off +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PDFLIB_H */ + +/* + * vim600: sw=4 fdm=marker + */ diff --git a/src/rgb2map.c b/src/rgb2map.c new file mode 100644 index 0000000..fa6a3bd --- /dev/null +++ b/src/rgb2map.c @@ -0,0 +1,976 @@ +/** \file + * \brief RGB2Map Conversion + * + * See Copyright Notice in cd.h + */ + + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" + +#define PARM(a) a +typedef unsigned char byte; +/* RANGE forces a to be in the range b..c (inclusive) */ +#define RANGE(a,b,c) { if (a < b) a = b; if (a > c) a = c; } +typedef unsigned long uu_long; +typedef unsigned short uu_short; +#define INT32 int +#define TRUE 1 +#define FALSE 0 + + +static void xvbzero(char *s, size_t len) +{ + for ( ; len>0; len--) *s++ = 0; +} + +static void xvbcopy(char *src, char *dst, size_t len) +{ + /* determine if the regions overlap + * + * 3 cases: src=dst, src<dst, src>dst + * + * if src=dst, they overlap completely, but nothing needs to be moved + * if src<dst and src+len>dst then they overlap + * if src>dst and src<dst+len then they overlap + */ + + if (src==dst || len<=0) return; /* nothin' to do */ + + if (src<dst && src+len>dst) { /* do a backward copy */ + src = src + len - 1; + dst = dst + len - 1; + for ( ; len>0; len--, src--, dst--) *dst = *src; + } + + else { /* they either overlap (src>dst) or they don't overlap */ + /* do a forward copy */ + for ( ; len>0; len--, src++, dst++) *dst = *src; + } +} + +/****************************/ +static int quick_map(const byte *red, const byte *green, const byte *blue, int w, int h, byte *map, byte *rmap, byte *gmap, byte *bmap, int *maxcol) +{ +/* scans picture until it finds more than 'maxcol' different colors. If it +finds more than 'maxcol' colors, it returns '0'. If it DOESN'T, it does +the 24-to-8 conversion by simply sticking the colors it found into +a colormap, and changing instances of a color in pic24 into colormap + indicies (in pic8) */ + + unsigned long colors[256],col; + int i, nc, low, high, mid; + const byte *pred, *pgreen, *pblue; + byte *pix; + + /* put the first color in the table by hand */ + nc = 0; mid = 0; + + for (i=w*h,pred=red,pgreen=green,pblue=blue; i; i--) + { + col = (((uu_long) *pred++) << 16); + col += (((uu_long) *pgreen++) << 8); + col += *pblue++; + + /* binary search the 'colors' array to see if it's in there */ + low = 0; high = nc-1; + while (low <= high) + { + mid = (low+high)/2; + if (col < colors[mid]) high = mid - 1; + else if (col > colors[mid]) low = mid + 1; + else break; + } + + if (high < low) + { /* didn't find color in list, add it. */ + if (nc>=*maxcol) + return 0; + + xvbcopy((char *) &colors[low], (char *) &colors[low+1], (nc - low) * sizeof(uu_long)); + colors[low] = col; + nc++; + } + } + + /* run through the data a second time, this time mapping pixel values in + pic24 into colormap offsets into 'colors' */ + + for (i=w*h,pred=red,pgreen=green,pblue=blue, pix=map; i; i--,pix++) + { + col = (((uu_long) *pred++) << 16); + col += (((uu_long) *pgreen++) << 8); + col += *pblue++; + + /* binary search the 'colors' array. It *IS* in there */ + low = 0; high = nc-1; + while (low <= high) + { + mid = (low+high)/2; + if (col < colors[mid]) high = mid - 1; + else if (col > colors[mid]) low = mid + 1; + else break; + } + + if (high < low) + return 0; + + *pix = (unsigned char)mid; + } + + /* and load up the 'desired colormap' */ + for (i=0; i<nc; i++) + { + rmap[i] = (unsigned char)( colors[i]>>16); + gmap[i] = (unsigned char)((colors[i]>>8) & 0xff); + bmap[i] = (unsigned char)( colors[i] & 0xff); + } + + *maxcol = nc; + + return 1; +} + + + +/***************************************************************/ +/* The following is based on jquant2.c from version 5 */ +/* of the IJG JPEG software, which is */ +/* Copyright (C) 1991-1994, Thomas G. Lane. */ +/***************************************************************/ + +#define MAXNUMCOLORS 256 /* maximum size of colormap */ + +#define C0_SCALE 2 /* scale R distances by this much */ +#define C1_SCALE 3 /* scale G distances by this much */ +#define C2_SCALE 1 /* and B by this much */ + +#define HIST_C0_BITS 5 /* bits of precision in R histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<<HIST_C0_BITS) +#define HIST_C1_ELEMS (1<<HIST_C1_BITS) +#define HIST_C2_ELEMS (1<<HIST_C2_BITS) + +/* These are the amounts to shift an input value to get a histogram index. */ +#define C0_SHIFT (8-HIST_C0_BITS) +#define C1_SHIFT (8-HIST_C1_BITS) +#define C2_SHIFT (8-HIST_C2_BITS) + + +typedef unsigned char JSAMPLE; +typedef JSAMPLE * JSAMPROW; + +typedef uu_short histcell; /* histogram cell; prefer an unsigned type */ + +typedef histcell * histptr; /* for pointers to histogram cells */ + +typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the histogram array */ +typedef hist1d hist2d[HIST_C1_ELEMS]; +typedef hist2d hist3d[HIST_C0_ELEMS]; + +typedef short FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ + +typedef FSERROR *FSERRPTR; /* pointer to error array */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; +typedef box * boxptr; + +/* Local state for the IJG quantizer */ + +static hist2d * sl_histogram; /* pointer to the 3D histogram array */ +static FSERRPTR sl_fserrors; /* accumulated-errors array */ +static int * sl_error_limiter; /* table for clamping the applied error */ +static int sl_on_odd_row; /* flag to remember which row we are on */ +static JSAMPROW sl_colormap[3]; /* selected colormap */ +static int sl_num_colors; /* number of selected colors */ + + +static void slow_fill_histogram PARM((const byte*, const byte*, const byte*, int)); +static boxptr find_biggest_color_pop PARM((boxptr, int)); +static boxptr find_biggest_volume PARM((boxptr, int)); +static void update_box PARM((boxptr)); +static int median_cut PARM((boxptr, int, int)); +static void compute_color PARM((boxptr, int)); +static void slow_select_colors PARM((int*)); +static int find_nearby_colors PARM((int, int, int, JSAMPLE [])); +static void find_best_colors PARM((int,int,int,int, JSAMPLE [], JSAMPLE [])); +static void fill_inverse_cmap PARM((int, int, int)); +static void slow_map_pixels PARM((const byte*, const byte*, const byte*, int, int, byte*)); +static void init_error_limit PARM((void)); + + +/* Master control for slow quantizer. */ +static int slow_quant(const byte *red, const byte *green, const byte *blue, int w, int h, byte *map, byte *rm, byte *gm, byte *bm, int *descols) +{ + size_t fs_arraysize = (w + 2) * (3 * sizeof(FSERROR)); + + /* Allocate all the temporary storage needed */ + init_error_limit(); + + sl_histogram = (hist2d *) malloc(sizeof(hist3d)); + sl_fserrors = (FSERRPTR) malloc(fs_arraysize); + + if (! sl_error_limiter || ! sl_histogram || ! sl_fserrors) + { + if (sl_error_limiter) free(sl_error_limiter-255); + if (sl_fserrors) free(sl_fserrors); + if (sl_histogram) free(sl_histogram); + return 1; + } + + sl_colormap[0] = (JSAMPROW) rm; + sl_colormap[1] = (JSAMPROW) gm; + sl_colormap[2] = (JSAMPROW) bm; + + /* Compute the color histogram */ + slow_fill_histogram(red, green, blue, w*h); + + /* Select the colormap */ + slow_select_colors(descols); + + /* Zero the histogram: now to be used as inverse color map */ + xvbzero((char *) sl_histogram, sizeof(hist3d)); + + /* Initialize the propagated errors to zero. */ + xvbzero((char *) sl_fserrors, fs_arraysize); + sl_on_odd_row = FALSE; + + /* Map the image. */ + slow_map_pixels(red, green, blue, w, h, map); + + /* Release working memory. */ + free(sl_histogram); + free(sl_error_limiter-255); + free(sl_fserrors); + + return 0; +} + + +static void slow_fill_histogram(register const byte *red, register const byte *green, register const byte *blue, int numpixels) +{ + register histptr histp; + register hist2d * histogram = sl_histogram; + + xvbzero((char *) histogram, sizeof(hist3d)); + + while (numpixels-- > 0) + { + /* get pixel value and index into the histogram */ + histp = & histogram[*red >> C0_SHIFT] [*green >> C1_SHIFT] [*blue >> C2_SHIFT]; + + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + + red++; + green++; + blue++; + } +} + + +static boxptr find_biggest_color_pop (boxptr boxlist, int numboxes) +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +static boxptr find_biggest_volume (boxptr boxlist, int numboxes) +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +static void update_box (boxptr boxp) +{ + hist2d * histogram = sl_histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } +have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } +have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } +have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } +have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } +have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } +have_c2max: + + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +static int median_cut (boxptr boxlist, int numboxes, int desired_colors) +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(b1); + update_box(b2); + numboxes++; + } + return numboxes; +} + + +static void compute_color (boxptr boxp, int icolor) +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + hist2d * histogram = sl_histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count; + } + } + } + + sl_colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + sl_colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + sl_colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +static void slow_select_colors (int *descolors) +/* Master routine for color selection */ +{ + box boxlist[MAXNUMCOLORS]; + int numboxes; + int i; + + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = 255 >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = 255 >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = 255 >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(& boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(boxlist, numboxes, *descolors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(& boxlist[i], i); + sl_num_colors = numboxes; + + *descolors = sl_num_colors; +} + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */ +#define BOX_C1_ELEMS (1<<BOX_C1_LOG) +#define BOX_C2_ELEMS (1<<BOX_C2_LOG) + +#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG) +#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG) +#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG) + + +static int find_nearby_colors (int minc0, int minc1, int minc2, JSAMPLE colorlist[]) +{ + int numcolors = sl_num_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = sl_colormap[0][i]; + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = sl_colormap[1][i]; + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = sl_colormap[2][i]; + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +static void find_best_colors (int minc0, int minc1, int minc2, int numcolors, + JSAMPLE colorlist[], JSAMPLE bestcolor[]) +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = colorlist[i]; + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - (int) sl_colormap[0][icolor]) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - (int) sl_colormap[1][icolor]) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - (int) sl_colormap[2][icolor]) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +static void fill_inverse_cmap (int c0, int c1, int c2) +{ + hist2d * histogram = sl_histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + numcolors = find_nearby_colors(minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(minc0, minc1, minc2, numcolors, colorlist, bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (*cptr++ + 1); + } + } + } +} + + +static void slow_map_pixels(const byte *red, const byte *green, const byte *blue, int width, int height, byte *map) +{ + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inRptr, inGptr, inBptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing errorptr */ + int row, col, offset; + int *error_limit = sl_error_limiter; + JSAMPROW colormap0 = sl_colormap[0]; + JSAMPROW colormap1 = sl_colormap[1]; + JSAMPROW colormap2 = sl_colormap[2]; + hist2d * histogram = sl_histogram; + + for (row = 0; row < height; row++) + { + offset = row * width; + + inRptr = (JSAMPROW)&red[offset]; + inGptr = (JSAMPROW)&green[offset]; + inBptr = (JSAMPROW)&blue[offset]; + outptr = &map[offset]; + + if (sl_on_odd_row) + { + /* work right to left in this row */ + offset = width-1; + + inRptr += offset; /* so point to rightmost pixel */ + inGptr += offset; /* so point to rightmost pixel */ + inBptr += offset; /* so point to rightmost pixel */ + + outptr += offset; + + dir = -1; + dir3 = -3; + errorptr = sl_fserrors + (width+1)*3; /* => entry after last column */ + sl_on_odd_row = FALSE; /* flip for next time */ + } + else + { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = sl_fserrors; /* => entry before first real column */ + sl_on_odd_row = TRUE; /* flip for next time */ + } + + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) + { + cur0 = (cur0 + errorptr[dir3+0] + 8) >> 4; + cur1 = (cur1 + errorptr[dir3+1] + 8) >> 4; + cur2 = (cur2 + errorptr[dir3+2] + 8) >> 4; + + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + + cur0 += inRptr[0]; + cur1 += inGptr[0]; + cur2 += inBptr[0]; + + RANGE(cur0, 0, 255); + RANGE(cur1, 0, 255); + RANGE(cur2, 0, 255); + + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cur0>>C0_SHIFT, cur1>>C1_SHIFT, cur2>>C2_SHIFT); + + /* Now emit the colormap index for this cell */ + { + register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= (int) colormap0[pixcode]; + cur1 -= (int) colormap1[pixcode]; + cur2 -= (int) colormap2[pixcode]; + } + + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. */ + { + register LOCFSERROR bnexterr, delta; + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inRptr += dir; /* Advance pixel pointers to next column */ + inGptr += dir; /* Advance pixel pointers to next column */ + inBptr += dir; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* Allocate and fill in the error_limiter table */ +static void init_error_limit (void) +{ + int * table; + int in, out, STEPSIZE; + + table = (int *) malloc((size_t) ((255*2+1) * sizeof(int))); + if (! table) return; + + table += 255; /* so can index -255 .. +255 */ + sl_error_limiter = table; + + STEPSIZE = ((255+1)/16); + + /* Map errors 1:1 up to +- 255/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) + { + table[in] = out; + table[-in] = -out; + } + + /* Map errors 1:2 up to +- 3*255/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) + { + table[in] = out; + table[-in] = -out; + } + + /* Clamp the rest to final out value (which is (255+1)/8) */ + for (; in <= 255; in++) + { + table[in] = out; + table[-in] = -out; + } +} + +void cdRGB2Map(int width, int height, const unsigned char *red, const unsigned char *green, const unsigned char *blue, unsigned char *map, int pal_size, long *colors) +{ + int i, err; + byte rm[256], gm[256], bm[256]; + int num_colors; + + if (pal_size <= 0 || pal_size > 256) + pal_size = 256; + + num_colors = pal_size; + + if (!quick_map(red, green, blue, width, height, map, rm, gm, bm, &num_colors)) + { + err = slow_quant(red, green, blue, width, height, map, rm, gm, bm, &num_colors); + if (err) + return; + } + + for (i=0; i < num_colors; i++) + *colors++ = cdEncodeColor(rm[i], gm[i], bm[i]); + + if (num_colors < pal_size) + { + for (i=num_colors; i < pal_size; i++) + *colors++ = 0; + } +} diff --git a/src/sim/cd_truetype.c b/src/sim/cd_truetype.c new file mode 100644 index 0000000..71593c0 --- /dev/null +++ b/src/sim/cd_truetype.c @@ -0,0 +1,181 @@ +/** \file + * \brief Text and Font Simulation using FreeType library. + * + * See Copyright Notice in cd.h + */ + +#include <string.h> +#include <stdlib.h> +#include <memory.h> +#include <stdio.h> + +#include "cd_truetype.h" + +/******************************************* + Inicializa o Rasterizador +********************************************/ +static char *getCdDir(void) +{ + static char *env = NULL; + if (env) return env; + env = getenv("CDDIR"); + if (!env) env = "."; + return env; +} + +#ifdef WIN32 +#include <windows.h> +static int ReadStringKey(HKEY base_key, char* key_name, char* value_name, char* value) +{ + HKEY key; + DWORD max_size = 512; + + if (RegOpenKeyEx(base_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS) + return 0; + + if (RegQueryValueEx(key, value_name, NULL, NULL, (LPBYTE)value, &max_size) != ERROR_SUCCESS) + { + RegCloseKey(key); + return 0; + } + + RegCloseKey(key); + return 1; +} + +char* GetFontDir(void) +{ + static char font_dir[512]; + if (!ReadStringKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Fonts", font_dir)) + return ""; + else + { + int i, size = (int)strlen(font_dir); + for(i = 0; i < size; i++) + { + if (font_dir[i] == '\\') + font_dir[i] = '/'; + } + return font_dir; + } +} +#endif + +int cdTT_load(cdTT_Text * tt_text, const char *font, int size, double xres, double yres) +{ + char filename[10240]; + FILE *file; /* usado apenas para procurar pelo arquivo */ + FT_Error error; + FT_Face face; + + /* abre arq. no dir. corrente */ + sprintf(filename, "%s.ttf", font); + file = fopen(filename, "r"); + + if (file) + fclose(file); + else + { + /* se nao conseguiu, abre arq. no dir. do cd, */ + sprintf(filename, "%s/%s.ttf", getCdDir(), font); + file = fopen(filename, "r"); + + if (file) + fclose(file); + else + { +#ifdef WIN32 + /* no caso do Windows procura no seu diretorio de fontes. */ + sprintf(filename, "%s/%s.ttf", GetFontDir(), font); + file = fopen(filename, "r"); + + if (file) + fclose(file); + else + return 0; +#else + return 0; +#endif + } + } + + error = FT_New_Face(tt_text->library, filename, 0, &face ); + if (error) + return 0; + + /* char_height is 1/64th of points */ + error = FT_Set_Char_Size(face, 0, size*64, (int)(xres*25.4), (int)(yres*25.4)); + if (error) + { + FT_Done_Face(face); + return 0; + } + + if (tt_text->face && tt_text->face != face) + FT_Done_Face(tt_text->face); + + tt_text->face = face; + + tt_text->ascent = face->size->metrics.ascender >> 6; + tt_text->descent = abs(face->size->metrics.descender >> 6); + tt_text->max_height = face->size->metrics.height >> 6; + tt_text->max_width = face->size->metrics.max_advance >> 6; + + if (!face->charmap) + FT_Set_Charmap(face, face->charmaps[0]); + + return 1; +} + +static void cdTT_checkversion(cdTT_Text* tt_text) +{ + FT_Int major, minor, patch; + FT_Library_Version(tt_text->library, &major, &minor, &patch); + if (major != FREETYPE_MAJOR || + minor != FREETYPE_MINOR || + patch != FREETYPE_PATCH) + { + printf("CD - Canvas Draw: Warning - Different FreeType library used!\n" + " Compiled = %d.%d.%d\n" + " RunTime = %d.%d.%d\n", + FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH, major, minor, patch); + } +} + +/******************************************* + Inicializaccao +********************************************/ +cdTT_Text* cdTT_create(void) +{ + cdTT_Text * tt_text = malloc(sizeof(cdTT_Text)); + memset(tt_text, 0, sizeof(cdTT_Text)); + + FT_Init_FreeType(&tt_text->library); + + cdTT_checkversion(tt_text); + + return tt_text; +} + +/******************************************* + Desaloca Recursos +********************************************/ +void cdTT_free(cdTT_Text * tt_text) +{ + if (tt_text->rgba_data) + free(tt_text->rgba_data); + + if (tt_text->face) + FT_Done_Face(tt_text->face); + + FT_Done_FreeType(tt_text->library); + + free(tt_text); +} + +#ifdef SunOS_OLD +void *memmove( void *dest, const void *src, size_t count ) +{ + return memcpy(dest, src, count); +} +#endif diff --git a/src/sim/cd_truetype.h b/src/sim/cd_truetype.h new file mode 100644 index 0000000..5675998 --- /dev/null +++ b/src/sim/cd_truetype.h @@ -0,0 +1,46 @@ +/** \file + * \brief Text and Font Simulation using FreeType library. + * + * See Copyright Notice in cd.h + */ + +#ifndef __TRUETYPE_H +#define __TRUETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ft2build.h" +#include FT_FREETYPE_H + +/* + In CD version 4.4 we start to use FreeType 2. + Only TrueType font support is enabled. +*/ + +typedef struct _cdTT_Text +{ + FT_Library library; + FT_Face face; + + unsigned char* rgba_data; + int rgba_data_size; + + int max_height; + int max_width; + int descent; + int ascent; + +}cdTT_Text; + +cdTT_Text* cdTT_create(void); +void cdTT_free(cdTT_Text * tt_text); +int cdTT_load(cdTT_Text * tt_text, const char *font,int size, double xres, double yres); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _CD_TRUETYPE_ */ + diff --git a/src/sim/cdfontex.c b/src/sim/cdfontex.c new file mode 100644 index 0000000..699b06f --- /dev/null +++ b/src/sim/cdfontex.c @@ -0,0 +1,669 @@ +/** \file + * \brief Font Properties Estimation + * + * See Copyright Notice in cd.h + */ + + +#include "cd.h" +#include "cd_private.h" +#include <stdlib.h> +#include <string.h> + +typedef struct _cd_font_styles +{ + unsigned char s[4]; +}cd_font_styles; + +static cd_font_styles helv[256] = { +{0, 0, 0, 0}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{30, 30, 30, 30}, +{30, 30, 30, 35}, +{35, 50, 35, 50}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{90, 85, 90, 90}, +{70, 75, 70, 75}, +{20, 25, 20, 25}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{40, 40, 40, 40}, +{60, 60, 60, 60}, +{30, 30, 30, 30}, +{35, 35, 35, 35}, +{30, 30, 30, 30}, +{30, 30, 30, 30}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{30, 35, 30, 35}, +{30, 35, 30, 35}, +{60, 60, 60, 60}, +{60, 60, 60, 60}, +{60, 60, 60, 60}, +{55, 65, 55, 60}, +{100, 100, 100, 100}, +{65, 70, 70, 75}, +{70, 70, 70, 70}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{70, 65, 70, 70}, +{60, 60, 65, 65}, +{80, 80, 80, 80}, +{70, 70, 75, 75}, +{25, 30, 30, 30}, +{50, 55, 55, 55}, +{70, 75, 70, 75}, +{55, 65, 55, 65}, +{80, 85, 85, 90}, +{70, 70, 75, 75}, +{80, 80, 80, 80}, +{65, 70, 70, 70}, +{80, 80, 80, 80}, +{75, 70, 75, 75}, +{70, 70, 70, 70}, +{60, 65, 65, 65}, +{70, 70, 75, 75}, +{65, 70, 70, 70}, +{100, 95, 100, 95}, +{65, 70, 70, 70}, +{65, 65, 70, 65}, +{60, 60, 65, 65}, +{30, 35, 30, 35}, +{30, 30, 30, 30}, +{30, 35, 30, 35}, +{45, 60, 50, 60}, +{55, 55, 55, 55}, +{35, 35, 35, 35}, +{55, 60, 55, 60}, +{55, 65, 60, 65}, +{55, 55, 55, 55}, +{55, 65, 55, 60}, +{55, 60, 55, 55}, +{30, 35, 30, 35}, +{55, 65, 55, 60}, +{55, 65, 55, 65}, +{25, 30, 25, 30}, +{25, 30, 25, 30}, +{50, 60, 55, 60}, +{25, 30, 25, 30}, +{85, 90, 85, 90}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 65, 55, 60}, +{55, 65, 55, 65}, +{35, 40, 35, 40}, +{55, 55, 55, 55}, +{30, 35, 30, 35}, +{55, 65, 55, 60}, +{50, 55, 50, 55}, +{75, 80, 70, 80}, +{50, 60, 50, 55}, +{50, 55, 50, 55}, +{50, 55, 50, 50}, +{35, 40, 35, 40}, +{25, 30, 25, 30}, +{35, 40, 35, 40}, +{60, 60, 60, 60}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{25, 30, 25, 30}, +{55, 55, 55, 55}, +{35, 55, 30, 55}, +{100, 100, 100, 100}, +{55, 55, 55, 55}, +{55, 55, 55, 55}, +{35, 35, 35, 35}, +{100, 105, 100, 100}, +{70, 70, 70, 70}, +{35, 35, 35, 35}, +{100, 105, 100, 100}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{25, 30, 20, 30}, +{25, 30, 20, 30}, +{35, 55, 35, 55}, +{35, 55, 30, 55}, +{35, 35, 35, 35}, +{55, 55, 55, 55}, +{100, 100, 100, 100}, +{30, 35, 30, 35}, +{100, 100, 100, 100}, +{55, 55, 55, 55}, +{35, 35, 35, 35}, +{95, 95, 95, 95}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{65, 65, 70, 65}, +{30, 30, 30, 30}, +{30, 30, 35, 35}, +{55, 55, 55, 60}, +{55, 55, 55, 55}, +{60, 55, 60, 55}, +{55, 55, 55, 55}, +{25, 30, 25, 30}, +{55, 55, 55, 55}, +{35, 35, 35, 35}, +{75, 75, 75, 80}, +{35, 40, 40, 40}, +{55, 55, 55, 55}, +{60, 60, 60, 60}, +{35, 35, 35, 35}, +{75, 75, 75, 80}, +{55, 55, 55, 55}, +{40, 40, 40, 40}, +{55, 55, 55, 60}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{60, 60, 55, 60}, +{55, 55, 55, 55}, +{30, 30, 30, 30}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{40, 40, 40, 40}, +{55, 55, 55, 55}, +{85, 85, 85, 85}, +{85, 85, 85, 85}, +{85, 85, 85, 85}, +{60, 65, 65, 60}, +{65, 70, 70, 75}, +{65, 70, 70, 75}, +{65, 70, 70, 75}, +{65, 70, 70, 75}, +{65, 70, 70, 75}, +{65, 70, 70, 75}, +{100, 100, 100, 100}, +{75, 75, 75, 75}, +{70, 65, 70, 70}, +{70, 65, 70, 70}, +{70, 65, 70, 70}, +{70, 65, 70, 70}, +{25, 30, 30, 30}, +{25, 30, 30, 30}, +{25, 30, 30, 30}, +{25, 30, 30, 30}, +{75, 75, 75, 75}, +{70, 70, 75, 75}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{60, 60, 60, 60}, +{80, 80, 80, 80}, +{70, 70, 75, 75}, +{70, 70, 75, 75}, +{70, 70, 75, 75}, +{70, 70, 75, 75}, +{65, 65, 70, 65}, +{70, 70, 70, 70}, +{65, 65, 65, 65}, +{55, 60, 55, 60}, +{55, 60, 55, 60}, +{55, 60, 55, 60}, +{55, 60, 55, 60}, +{55, 60, 55, 60}, +{55, 60, 55, 60}, +{90, 90, 90, 90}, +{55, 55, 55, 55}, +{55, 60, 55, 55}, +{55, 60, 55, 55}, +{55, 60, 55, 55}, +{55, 60, 55, 55}, +{25, 30, 25, 30}, +{25, 30, 25, 30}, +{25, 30, 25, 30}, +{25, 30, 25, 30}, +{55, 65, 55, 60}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 65, 55, 65}, +{55, 55, 55, 55}, +{60, 65, 65, 60}, +{55, 65, 55, 60}, +{55, 65, 55, 60}, +{55, 65, 55, 60}, +{55, 65, 55, 60}, +{50, 55, 50, 55}, +{55, 65, 55, 65}, +{50, 55, 50, 55} +}; + +static cd_font_styles times[256] = { +{0, 0, 0, 0}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{25, 25, 25, 25}, +{35, 35, 30, 35}, +{40, 55, 45, 55}, +{55, 55, 55, 50}, +{50, 55, 55, 55}, +{85, 100, 85, 85}, +{80, 85, 75, 80}, +{20, 30, 25, 30}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{50, 55, 55, 55}, +{60, 60, 70, 60}, +{25, 25, 25, 25}, +{35, 35, 35, 35}, +{25, 25, 25, 25}, +{30, 30, 30, 30}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{25, 35, 35, 35}, +{30, 35, 35, 35}, +{60, 60, 70, 60}, +{60, 60, 70, 60}, +{60, 60, 70, 60}, +{45, 55, 55, 55}, +{95, 95, 95, 85}, +{70, 70, 60, 70}, +{65, 70, 65, 70}, +{70, 75, 70, 70}, +{75, 75, 75, 75}, +{60, 65, 65, 70}, +{55, 60, 60, 70}, +{70, 80, 75, 75}, +{75, 80, 75, 80}, +{35, 40, 35, 40}, +{40, 55, 45, 50}, +{75, 80, 65, 70}, +{60, 65, 55, 65}, +{90, 95, 85, 90}, +{75, 75, 70, 75}, +{75, 80, 75, 75}, +{60, 65, 60, 65}, +{75, 80, 75, 75}, +{65, 75, 65, 70}, +{55, 60, 55, 55}, +{65, 65, 55, 65}, +{70, 70, 75, 75}, +{70, 70, 60, 65}, +{95, 100, 80, 90}, +{70, 70, 65, 70}, +{70, 70, 55, 65}, +{60, 65, 55, 65}, +{35, 35, 40, 35}, +{30, 30, 30, 30}, +{35, 35, 45, 35}, +{45, 60, 45, 60}, +{55, 55, 55, 55}, +{35, 35, 35, 35}, +{45, 50, 55, 55}, +{50, 55, 55, 50}, +{45, 45, 45, 45}, +{50, 55, 55, 55}, +{45, 50, 45, 45}, +{35, 35, 30, 35}, +{50, 55, 55, 50}, +{50, 55, 55, 55}, +{25, 30, 30, 30}, +{25, 35, 30, 30}, +{50, 55, 50, 55}, +{25, 30, 30, 30}, +{75, 85, 75, 80}, +{50, 55, 55, 55}, +{50, 50, 55, 50}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{35, 45, 40, 40}, +{40, 40, 40, 40}, +{30, 35, 30, 30}, +{50, 55, 55, 55}, +{50, 50, 45, 45}, +{70, 70, 65, 70}, +{50, 50, 45, 55}, +{50, 50, 45, 45}, +{45, 45, 40, 40}, +{50, 40, 40, 35}, +{20, 25, 30, 25}, +{50, 40, 40, 35}, +{55, 55, 55, 60}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{35, 35, 35, 35}, +{50, 55, 50, 55}, +{45, 55, 55, 55}, +{100, 100, 90, 100}, +{50, 50, 55, 55}, +{50, 55, 55, 55}, +{35, 35, 35, 35}, +{100, 100, 100, 105}, +{55, 60, 55, 55}, +{35, 35, 35, 35}, +{90, 100, 95, 95}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{35, 35, 35, 35}, +{35, 35, 35, 35}, +{45, 55, 55, 55}, +{45, 55, 55, 55}, +{35, 40, 35, 35}, +{55, 55, 55, 55}, +{100, 100, 90, 100}, +{35, 35, 35, 35}, +{100, 105, 100, 100}, +{40, 40, 40, 40}, +{35, 35, 35, 35}, +{75, 75, 70, 75}, +{80, 80, 80, 80}, +{80, 80, 80, 80}, +{70, 70, 55, 65}, +{25, 25, 25, 25}, +{35, 30, 40, 35}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{55, 55, 50, 50}, +{55, 55, 55, 55}, +{20, 25, 30, 25}, +{50, 55, 55, 55}, +{35, 40, 30, 35}, +{75, 75, 75, 75}, +{30, 30, 30, 30}, +{50, 55, 55, 55}, +{60, 60, 70, 60}, +{35, 35, 35, 35}, +{75, 75, 80, 75}, +{55, 55, 55, 55}, +{40, 40, 40, 40}, +{55, 55, 55, 55}, +{30, 30, 30, 30}, +{30, 30, 30, 30}, +{30, 35, 35, 35}, +{55, 60, 60, 60}, +{45, 55, 55, 55}, +{25, 25, 25, 25}, +{30, 35, 35, 35}, +{30, 30, 30, 30}, +{30, 35, 35, 30}, +{50, 55, 55, 55}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{75, 75, 75, 75}, +{45, 55, 50, 55}, +{70, 70, 60, 70}, +{70, 70, 60, 70}, +{70, 70, 60, 70}, +{70, 70, 60, 70}, +{70, 70, 60, 70}, +{70, 70, 60, 70}, +{90, 100, 90, 95}, +{70, 75, 70, 70}, +{60, 65, 65, 70}, +{60, 65, 65, 70}, +{60, 65, 65, 70}, +{60, 65, 65, 70}, +{35, 40, 35, 40}, +{35, 40, 35, 40}, +{35, 40, 35, 40}, +{35, 40, 35, 40}, +{75, 75, 75, 75}, +{75, 75, 70, 75}, +{75, 80, 75, 75}, +{75, 80, 75, 75}, +{75, 80, 75, 75}, +{75, 80, 75, 75}, +{75, 80, 75, 75}, +{60, 60, 70, 60}, +{75, 80, 75, 75}, +{75, 70, 75, 75}, +{75, 70, 75, 75}, +{75, 70, 75, 75}, +{75, 70, 75, 75}, +{70, 70, 55, 65}, +{60, 65, 65, 65}, +{50, 55, 55, 55}, +{45, 50, 55, 55}, +{45, 50, 55, 55}, +{45, 50, 55, 55}, +{45, 50, 55, 55}, +{45, 50, 55, 55}, +{45, 50, 55, 55}, +{70, 75, 70, 75}, +{45, 45, 45, 45}, +{45, 50, 45, 45}, +{45, 50, 45, 45}, +{45, 50, 45, 45}, +{45, 50, 45, 45}, +{30, 30, 30, 30}, +{30, 30, 30, 30}, +{30, 30, 30, 30}, +{30, 30, 30, 30}, +{55, 50, 55, 55}, +{50, 55, 55, 55}, +{50, 50, 55, 50}, +{50, 50, 55, 50}, +{50, 50, 55, 50}, +{50, 50, 55, 50}, +{50, 50, 55, 50}, +{55, 55, 55, 55}, +{55, 50, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 55, 55, 55}, +{50, 50, 45, 45}, +{55, 55, 50, 50}, +{50, 50, 45, 45} +}; + + +typedef struct _cdFontType +{ + int max_width, line_height, ascent, descent, style, size; + double sizex; + int (*CharWidth)(char c); +}cdFontType; + + +static cdFontType font; + + +static int CharWidthCourier(char c) +{ + (void)c; + return (int)(0.60 * font.sizex + 0.5); +} + + +static int CharWidthTimesRoman(char c) +{ + return (int)(times[(int)c].s[font.style] * font.sizex / 100 + 0.5); +} + + +static int CharWidthHelvetica(char c) +{ + return (int)(helv[(int)c].s[font.style] * font.sizex / 100 + 0.5); +} + + +static void cdFontEx(cdCanvas* canvas, const char* type_face, int style, int size) +{ + double mm_dx, mm_dy; + double sizey, sizex; + + font.style = style; + + if (size < 0) + { + double size_mm; + cdCanvasPixel2MM(canvas, -size, 0, &size_mm, NULL); + size = (int)(size_mm * CD_MM2PT + 0.5); + } + + font.size = size; + + cdCanvasPixel2MM(canvas, 1, 1, &mm_dx, &mm_dy); + + sizey = ((25.4 / 72) / mm_dy) * size; + sizex = ((25.4 / 72) / mm_dx) * size; + + font.sizex = sizex; + + font.line_height = (int)(1.2 * sizey + 0.5); + font.ascent = (int)(0.75 * font.line_height + 0.5); + font.descent = (int)(0.20 * font.line_height + 0.5); + + if (strcmp(type_face, "Times")==0) + { + if (style == CD_PLAIN || style == CD_BOLD) + font.max_width = (int)(1.05 * sizex + 0.5); + else + font.max_width = (int)(1.15 * sizex + 0.5); + + font.CharWidth = CharWidthTimesRoman; + } + else if (strcmp(type_face, "Helvetica")==0) + { + if (style == CD_PLAIN || style == CD_BOLD) + font.max_width = (int)(1.05 * sizex + 0.5); + else + font.max_width = (int)(1.15 * sizex + 0.5); + + font.CharWidth = CharWidthHelvetica; + } + else + { + if (style == CD_PLAIN || style == CD_ITALIC) + font.max_width = (int)(0.65 * sizex + 0.5); + else + font.max_width = (int)(0.80 * sizex + 0.5); + + font.CharWidth = CharWidthCourier; + } +} + +static void cdGetFontDimEx(int *max_width, int *line_height, int *ascent, int *descent) +{ + if (line_height) *line_height = font.line_height; + if (max_width) *max_width = font.max_width; + if (ascent) *ascent = font.ascent; + if (descent) *descent = font.descent; +} + +static void cdGetTextSizeEx(const char *s, int *width, int *height) +{ + int i = 0, numlin = 1, max_line_width = 0, line_width = 0; + + while (s[i] != '\0') + { + if (s[i] == '\n') + { + numlin++; + line_width = 0; + } + else + { + line_width += font.CharWidth(s[i]); + } + + if (line_width > max_line_width) + max_line_width = line_width; + + i++; + } + + if (height) *height = numlin * font.line_height; + if (width) *width = max_line_width; +} + +void cdgetfontdimEX(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdFontEx(canvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + cdGetFontDimEx(max_width, height, ascent, descent); +} + +void cdgettextsizeEX(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdFontEx(canvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + cdGetTextSizeEx(s, width, height); +} diff --git a/src/sim/sim.c b/src/sim/sim.c new file mode 100644 index 0000000..0c657fa --- /dev/null +++ b/src/sim/sim.c @@ -0,0 +1,328 @@ +/** \file + * \brief Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" + + +static unsigned char SimHatchBits[6][8] = { /* [style][y] (8x8) */ + {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, /* CD_HORIZONTAL */ + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /* CD_VERTICAL */ + {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* CD_BDIAGONAL */ + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* CD_FDIAGONAL */ + {0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10}, /* CD_CROSS */ + {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}};/* CD_DIAGCROSS */ + +#define CalcYPat(y, h) (canvas->invert_yaxis? h-1-(y%h): y%h) +#define CalcYHatch(y, h) (canvas->invert_yaxis? h-(y&h): y&h) + +void simFillDrawAAPixel(cdCanvas *canvas, int x, int y, unsigned short alpha_weigth) +{ + unsigned char aa_alpha; + long color, aa_color; + + switch(canvas->interior_style) + { + default: /* CD_SOLID */ + { + color = canvas->foreground; + break; + } + case CD_PATTERN: + { + long *pattern = canvas->pattern; + int yp = CalcYPat(y, canvas->pattern_h); + int xp = x % canvas->pattern_w; + color = pattern[canvas->pattern_w*yp + xp]; + break; + } + case CD_HATCH: + { + unsigned char hatch = SimHatchBits[canvas->hatch_style][CalcYHatch(y, 7)]; + unsigned char n = (unsigned char)(x&7); + simRotateHatchN(hatch, n); + if (hatch & 0x80) + color = canvas->foreground; + else if (canvas->back_opacity == CD_OPAQUE) + color = canvas->background; + else + return; + break; + } + case CD_STIPPLE: + { + unsigned char *stipple = canvas->stipple; + int yp = CalcYPat(y, canvas->stipple_h); + int xp = x % canvas->stipple_w; + if(stipple[canvas->stipple_w*yp + xp]) + color = canvas->foreground; + else if (canvas->back_opacity == CD_OPAQUE) + color = canvas->background; + else + return; + break; + } + } + + aa_alpha = (unsigned char)((alpha_weigth * cdAlpha(color)) / 255); + aa_color = cdEncodeAlpha(color, aa_alpha); + canvas->cxPixel(canvas->ctxcanvas, x, y, aa_color); +} + +void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax) +{ + cdCanvas* canvas = simulation->canvas; + + if(xmin > xmax) + _cdSwapInt(xmin, xmax); + + switch(canvas->interior_style) + { + case CD_SOLID: + simulation->SolidLine(canvas, xmin,y,xmax); + break; + case CD_PATTERN: + simulation->PatternLine(canvas, xmin,xmax,y,canvas->pattern_w, + canvas->pattern + + canvas->pattern_w*CalcYPat(y, canvas->pattern_h)); + break; + case CD_HATCH: + simulation->HatchLine(canvas, xmin,xmax,y,SimHatchBits[canvas->hatch_style][CalcYHatch(y, 7)]); + break; + case CD_STIPPLE: + simulation->StippleLine(canvas, xmin, xmax, y, + canvas->stipple_w, + canvas->stipple + + canvas->stipple_w*CalcYPat(y, canvas->stipple_h)); + } +} + +static void simSolidLine(cdCanvas* canvas, int xmin, int y, int xmax) +{ + /* cdpolySIM and cdboxSIM will set line attributes so this can work */ + canvas->cxLine(canvas->ctxcanvas, xmin, y, xmax, y); +} + +static void simPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern) +{ + cdSimulation* simulation = canvas->simulation; + int x,i; + int xb; + long curColor, old_color; + + i = xmin % pw; + + old_color = canvas->foreground; + + for (x = xmin; x <= xmax;) + { + if (i == pw) + i = 0; + + curColor=pattern[i]; + xb=x; + + while(pattern[i]==curColor && (x <= xmax)) + { + i++; + if (i == pw) + i = 0; + x++; + } + + if(xb==x-1) + canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor); + else + { + cdCanvasSetForeground(canvas, curColor); + simulation->SolidLine(canvas, xb,y,x-1); + } + } + + cdCanvasSetForeground(canvas, old_color); +} + +static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple) +{ + cdSimulation* simulation = canvas->simulation; + int x,xb,i; + long fgColor,bgColor; + int opacity; + int curCase; + + fgColor = canvas->foreground; + opacity=canvas->back_opacity; + + if(opacity==CD_OPAQUE) + { + bgColor=canvas->background; + cdCanvasSetForeground(canvas, fgColor); + for (x = xmin, i=xmin%pw ; x <= xmax;) + { + if(i==pw) + i=0; + xb=x; + curCase=stipple[i]; + while (stipple[i]==curCase && (x<=xmax)) + { + x++; + i++; + if(i==pw) + i=0; + } + if (curCase) + { + if(xb==x-1) + canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); + else + simulation->SolidLine(canvas, xb,y,x-1); + } + } + cdCanvasSetForeground(canvas, bgColor); + for (x = xmin, i=xmin%pw ; x <= xmax;) + { + if(i==pw) + i=0; + xb=x; + curCase=stipple[i]; + while (stipple[i]==curCase && (x<=xmax)) + { + x++; + i++; + if(i==pw) + i=0; + } + if (!curCase) + { + if(xb==x-1) + canvas->cxPixel(canvas->ctxcanvas, xb,y,bgColor); + else + simulation->SolidLine(canvas, xb,y,x-1); + } + } + } + else + { + cdCanvasSetForeground(canvas, fgColor); + for (x = xmin,i=xmin%pw; x <= xmax;) + { + xb=x; + curCase=stipple[i]; + while (stipple[i]==curCase && (x<=xmax)) + { + i++; + x++; + if(i==pw) + i=0; + } + if(curCase) + { + if(xb==x-1) + canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); + else + simulation->SolidLine(canvas, xb,y,x-1); + } + } + } + cdCanvasSetForeground(canvas, fgColor); +} + +static void simHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch) +{ + cdSimulation* simulation = canvas->simulation; + int x,xb; + int opacity, mask; + unsigned char startp, n; + long curColor, fgColor, bgColor; + + n = (unsigned char)(xmin&7); + simRotateHatchN(hatch,n); + fgColor=canvas->foreground; + opacity=canvas->back_opacity; + + if(opacity==CD_OPAQUE) + { + bgColor=canvas->background; + for (x = xmin; x <= xmax; x++) + { + curColor=(hatch&0x80)?fgColor:bgColor; + + xb=x; + startp = hatch&0x80? 1: 0; + _cdRotateHatch(hatch); + while (startp == (hatch&0x80? 1: 0) && x <= xmax) + { + x++; + _cdRotateHatch(hatch); + } + + if(xb==x) + canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor); + else + { + cdCanvasSetForeground(canvas, curColor); + simulation->SolidLine(canvas, xb,y,x); + } + } + } + else + { + cdCanvasSetForeground(canvas, fgColor); + for (x = xmin; x <= xmax; x++) + { + mask=(hatch&0x80)?1:0; + + xb=x; + startp = hatch&0x80? 1: 0; + _cdRotateHatch(hatch); + while (startp == (hatch&0x80? 1: 0) && x <= xmax) + { + x++; + _cdRotateHatch(hatch); + } + + if(mask) + { + if(xb==x) + canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); + else + simulation->SolidLine(canvas, xb,y,x); + } + } + } + + cdCanvasSetForeground(canvas, fgColor); +} + +cdSimulation* cdCreateSimulation(cdCanvas* canvas) +{ + cdSimulation* simulation = (cdSimulation*)malloc(sizeof(cdSimulation)); + memset(simulation, 0, sizeof(cdSimulation)); + + simulation->canvas = canvas; + + simulation->SolidLine = simSolidLine; + simulation->PatternLine = simPatternLine; + simulation->StippleLine = simStippleLine; + simulation->HatchLine = simHatchLine; + + return simulation; +} + +void cdKillSimulation(cdSimulation* simulation) +{ + if (simulation->tt_text) cdTT_free(simulation->tt_text); + + memset(simulation, 0, sizeof(cdSimulation)); + free(simulation); +} diff --git a/src/sim/sim.h b/src/sim/sim.h new file mode 100644 index 0000000..16189a1 --- /dev/null +++ b/src/sim/sim.h @@ -0,0 +1,58 @@ +/** \file + * \brief Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __SIM_H +#define __SIM_H + + +struct _cdSimulation +{ + cdTT_Text* tt_text; /* TrueType Font Simulation using FreeType library */ + + int antialias; + + cdCanvas *canvas; + + const char* font_map[100]; + int font_map_n; + + /* horizontal line draw functions */ + void (*SolidLine)(cdCanvas* canvas, int xmin, int y, int xmax); + void (*PatternLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern); + void (*StippleLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple); + void (*HatchLine)(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch); +}; + +#define simRotateHatchN(_x,_n) ((_x) = ((_x) << (_n)) | ((_x) >> (8-(_n)))) + +void simFillDrawAAPixel(cdCanvas *canvas, int x, int y, unsigned short alpha_weigth); +void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax); +void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, FT_Matrix *matrix, FT_Vector *pen); +int simIsPointInPolyWind(cdPoint* poly, int n, int x, int y); + +/* list of non-horizontal line segments */ +typedef struct _simLineSegment +{ + int x1, y1; /* always y1 < y2 */ + int x2, y2; /* (x2,y2) is not included in the segment to avoid duplicated intersections */ + int x; /* incremental x from x2 to x1 */ + int DeltaX, DeltaY, XDir; + unsigned short ErrorInc, ErrorAcc; +} simLineSegment; + +void simAddSegment(simLineSegment* segment, int x1, int y1, int x2, int y2, int *y_max, int *y_min); +int simSegmentInc(simLineSegment* segment, cdCanvas* canvas, int y); + +void simPolyFill(cdSimulation* simulation, cdPoint* poly, int n); +void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2); +void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2); +void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b); +extern int simLineStyleNoReset; + +int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height); + +#endif + diff --git a/src/sim/sim_linepolyfill.c b/src/sim/sim_linepolyfill.c new file mode 100644 index 0000000..1a20907 --- /dev/null +++ b/src/sim/sim_linepolyfill.c @@ -0,0 +1,1000 @@ +/** \file + * \brief Primitives of the Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> +#include <assert.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" + + +/* para estilos de linha usando rotacao de bits */ +static const unsigned short int simLineStyleBitTable[5]= +{ + 0xFFFF, /* CD_CONTINUOUS */ + 0xFF00, /* CD_DASHED */ + 0x1111, /* CD_DOTTED */ + 0xFE10, /* CD_DASH_DOT */ + 0xFF24, /* CD_DASH_DOT_DOT*/ +}; +int simLineStyleNoReset = 0; +static unsigned short int simLineStyleLastBits = 0; + +#define simRotateLineStyle(_x) (((_x) & 0x8000)? ((_x) << 1)|(0x0001): ((_x) << 1)) + +#define INTENSITYSHIFT 8 /* # of bits by which to shift ErrorAcc to get intensity level */ + + +/* Point in Polygon was obtained from: + www.geometryalgorithms.com/Archive/algorithm_0103/algorithm_0103.htm + + Copyright 2001, softSurfer (www.softsurfer.com) + This code may be freely used and modified for any purpose + providing that this copyright notice is included with it. + SoftSurfer makes no warranty for this code, and cannot be held + liable for any real or imagined damage resulting from its use. +*/ + +#define isLeft( _P0, _P1, _x, _y ) ((_P1.x - _P0.x)*(_y - _P0.y) - (_x - _P0.x)*(_P1.y - _P0.y)) + +int simIsPointInPolyWind(cdPoint* poly, int n, int x, int y) +{ + int i, i1, + wn = 0; /* the winding number counter */ + + for (i = 0; i < n; i++) + { + i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */ + + if (poly[i].y <= y) + { + if (poly[i1].y > y) /* an upward crossing */ + if (isLeft(poly[i], poly[i1], x, y) > 0) /* P left of edge */ + ++wn; /* have a valid up intersect */ + } + else + { + if (poly[i1].y <= y) /* a downward crossing */ + if (isLeft(poly[i], poly[i1], x, y) < 0) /* P right of edge */ + --wn; /* have a valid down intersect */ + } + } + + return wn; +} + +static int compare_int(const int* xx1, const int* xx2) +{ + return *xx1 - *xx2; +} + +void simAddSegment(simLineSegment* segment, int x1, int y1, int x2, int y2, int *y_max, int *y_min) +{ + /* Make sure p2.y > p1.y */ + if (y1 > y2) + { + _cdSwapInt(y1, y2); + _cdSwapInt(x1, x2); + } + + segment->x1 = x1; + segment->y1 = y1; + segment->x2 = x2; + segment->y2 = y2; + + segment->x = x2; /* initial value */ + + segment->DeltaY = y2 - y1; + segment->DeltaX = x2 - x1; + if (segment->DeltaX >= 0) + segment->XDir = -1; /* inverted from simLineThin since here is from p2 to p1 */ + else + { + segment->XDir = 1; + segment->DeltaX = -segment->DeltaX; /* make DeltaX positive */ + } + + segment->ErrorAcc = 0; /* initialize the line error accumulator to 0 */ + + /* Is this an X-major or Y-major line? */ + if (segment->DeltaY > segment->DeltaX) + { + if (segment->DeltaY==0) /* do not compute for horizontal segments */ + return; + + /* Y-major line; calculate 16-bit fixed-point fractional part of a + pixel that X advances each time Y advances 1 pixel, truncating the + result so that we won't overrun the endpoint along the X axis */ + segment->ErrorInc = (unsigned short)(((unsigned long)segment->DeltaX << 16) / (unsigned long)segment->DeltaY); + } + else + { + if (segment->DeltaX==0) /* do not compute for vertical segments */ + return; + + /* It's an X-major line; calculate 16-bit fixed-point fractional part of a + pixel that Y advances each time X advances 1 pixel, truncating the + result to avoid overrunning the endpoint along the X axis */ + segment->ErrorInc = (unsigned short)(((unsigned long)segment->DeltaY << 16) / (unsigned long)segment->DeltaX); + } + + /* also calculates y_max and y_min of the polygon */ + if (y2 > *y_max) + *y_max = y2; + if (y1 < *y_min) + *y_min = y1; +} + +int simSegmentInc(simLineSegment* segment, cdCanvas* canvas, int y) +{ + unsigned short ErrorAccTemp, Weighting; + + if (segment->DeltaY == 0) + { + /* Horizontal line */ + while (segment->DeltaX-- != 0) + segment->x += segment->XDir; + return segment->x; + } + + if (segment->DeltaX == 0) + { + /* Vertical line */ + segment->DeltaY--; + return segment->x; + } + + if (segment->DeltaX == segment->DeltaY) + { + /* Perfect Diagonal line */ + segment->x += segment->XDir; + segment->DeltaY--; + return segment->x; + } + + /* Is this an X-major or Y-major line? */ + if (segment->DeltaY > segment->DeltaX) + { + /* Increment pixels other than the first and last */ + ErrorAccTemp = segment->ErrorAcc; /* remember currrent accumulated error */ + segment->ErrorAcc += segment->ErrorInc; /* calculate error for next pixel */ + if (segment->ErrorAcc <= ErrorAccTemp) + { + /* The error accumulator turned over, so advance the X coord */ + segment->x += segment->XDir; + } + + Weighting = segment->ErrorAcc >> INTENSITYSHIFT; + + if (Weighting < 128) + return segment->x; + else + return segment->x + segment->XDir; + } + else + { + /* Increment all pixels other than the first and last */ + int hline_end = 0; + while (!hline_end) + { + ErrorAccTemp = segment->ErrorAcc; /* remember currrent accumulated error */ + segment->ErrorAcc += segment->ErrorInc; /* calculate error for next pixel */ + if (segment->ErrorAcc <= ErrorAccTemp) + { + /* The error accumulator turned over, so advance the Y coord */ + hline_end = 1; + } + + segment->x += segment->XDir; /* X-major, so always advance X */ + } + + return segment->x; + } +} + +typedef struct _simIntervalList +{ + int* xx; + int n, count; +} simIntervalList; + +static int simFillCheckAAPixel(simIntervalList* line_int_list, int x) +{ + int i, *xx = line_int_list->xx; + for (i = 0; i < line_int_list->n; i+=2) + { + if (xx[i] <= x && x <= xx[i+1]) + return 0; /* inside, already drawn, do not draw */ + } + return 1; +} + +static void simPolyAAPixels(cdCanvas *canvas, simIntervalList* line_int_list, int y_min, int y_max, int x1, int y1, int x2, int y2) +{ + unsigned short ErrorInc, ErrorAcc; + unsigned short ErrorAccTemp, Weighting; + int DeltaX, DeltaY, XDir; + int no_antialias = !(canvas->simulation->antialias); + + /* Make sure p2.y > p1.y */ + if (y1 > y2) + { + _cdSwapInt(y1, y2); + _cdSwapInt(x1, x2); + } + + DeltaX = x2 - x1; + if (DeltaX >= 0) + XDir = 1; + else + { + XDir = -1; + DeltaX = -DeltaX; /* make DeltaX positive */ + } + + /* Special-case horizontal, vertical, and diagonal lines, which + require no weighting because they go right through the center of + every pixel */ + DeltaY = y2 - y1; + if (DeltaY == 0 || DeltaX == 0 || DeltaX == DeltaY) return; + + /* Line is not horizontal, diagonal, or vertical */ + + /* start and end pixels are not necessary + since they are always drawn in the previous step. */ + + ErrorAcc = 0; /* initialize the line error accumulator to 0 */ + + /* Is this an X-major or Y-major line? */ + if (DeltaY > DeltaX) + { + ErrorInc = (unsigned short)(((unsigned long)DeltaX << 16) / (unsigned long)DeltaY); + + /* Draw all pixels other than the first and last */ + while (--DeltaY) + { + ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ + ErrorAcc += ErrorInc; /* calculate error for next pixel */ + if (ErrorAcc <= ErrorAccTemp) + x1 += XDir; + + y1++; /* Y-major, so always advance Y */ + + Weighting = ErrorAcc >> INTENSITYSHIFT; + + if (y1 < y_min || y1 > y_max) continue; + + if (no_antialias) + { + if (Weighting < 128) + { + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1, 255); + } + else + { + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1 + XDir)) + simFillDrawAAPixel(canvas, x1 + XDir, y1, 255); + } + } + else + { + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1, 255-Weighting); + + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1 + XDir)) + simFillDrawAAPixel(canvas, x1 + XDir, y1, Weighting); + } + } + } + else + { + ErrorInc = (unsigned short)(((unsigned long)DeltaY << 16) / (unsigned long)DeltaX); + + /* Draw all pixels other than the first and last */ + while (--DeltaX) + { + ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ + ErrorAcc += ErrorInc; /* calculate error for next pixel */ + if (ErrorAcc <= ErrorAccTemp) + y1++; + + x1 += XDir; /* X-major, so always advance X */ + + Weighting = ErrorAcc >> INTENSITYSHIFT; + + if (y1 < y_min || y1 > y_max) continue; + + if (no_antialias) + { + if (Weighting < 128) + { + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1, 255); + } + else + { + if (y1+1 < y_min || y1+1 > y_max) continue; + + if (simFillCheckAAPixel(line_int_list+(y1+1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1+1, 255); + } + } + else + { + if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1, 255-Weighting); + + if (y1+1 < y_min || y1+1 > y_max) continue; + + if (simFillCheckAAPixel(line_int_list+(y1+1-y_min), x1)) + simFillDrawAAPixel(canvas, x1, y1+1, Weighting); + } + } + } +} + +static void simLineIntervallInit(simIntervalList* line_int_list, int count) +{ + line_int_list->xx = malloc(sizeof(int)*count); + line_int_list->n = 0; + line_int_list->count = count; +} + +static void simLineIntervallAdd(simIntervalList* line_int_list, int x1, int x2) +{ + int i = line_int_list->n; + line_int_list->xx[i] = x1; + line_int_list->xx[i+1] = x2; + line_int_list->n += 2; +} + +void simPolyFill(cdSimulation* simulation, cdPoint* poly, int n) +{ + simLineSegment *seg_i; + simIntervalList* line_int_list, *line_il; + int y_max, y_min, i, y, i1, fill_mode, num_lines, + inter_count, width, height, *xx; + + simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment)); + + width = simulation->canvas->w; + height = simulation->canvas->h; + fill_mode = simulation->canvas->fill_mode; + + y_max = poly[0].y; + y_min = poly[0].y; + for(i = 0; i < n; i++) + { + i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */ + simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min); + } + + if (y_min > height-1 || y_max < 0) + { + free(segment); + return; + } + + if (y_min < 0) + y_min = 0; + + if (y_max > height-1) + num_lines = height-y_min; + else + num_lines = y_max-y_min+1; + + line_int_list = malloc(sizeof(simIntervalList)*num_lines); + memset(line_int_list, 0, sizeof(simIntervalList)*num_lines); + + xx = (int*)malloc((n+1)*sizeof(int)); + + /* for all horizontal lines between y_max and y_min */ + for(y = y_max; y >= y_min; y--) + { + inter_count = 0; + + /* for all segments, calculates the intervals to be filled + from the intersection with the horizontal line y. */ + for(i = 0; i < n; i++) + { + seg_i = segment + i; + + /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */ + /* if it is an horizontal line, then ignore the segment. */ + if (seg_i->y1 > y || + seg_i->y1 == seg_i->y2) + continue; + + if (y == seg_i->y1) /* intersection at the start point (x1,y1) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* always save at least one intersection point for (y1) */ + + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + + /* check for missing bottom-corner points (|_|), must duplicate the intersection */ + if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */ + { + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + } + } + else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */ + { + xx[inter_count++] = simSegmentInc(seg_i, simulation->canvas, y); /* save the intersection point */ + } + else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* only save the intersection point for (y2) if not handled by (y1) of another segment */ + + /* check for missing top-corner points (^) or (|¯¯|) */ + if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */ + (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) || + (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1)) + { + xx[inter_count++] = seg_i->x2; /* save the intersection point */ + } + } + } + + /* if outside the canvas, ignore the intervals and */ + /* continue since the segments where updated. */ + if (y > height-1 || inter_count == 0) + continue; + + /* sort the intervals */ + qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int); + + line_il = line_int_list+(y-y_min); + simLineIntervallInit(line_il, inter_count*2); + + /* for all intervals, fill the interval */ + for(i = 0; i < inter_count; i += 2) /* process only pairs */ + { + if (fill_mode == CD_EVENODD) + { + /* since it fills only pairs of intervals, */ + /* it is the EVENODD fill rule. */ + simFillHorizLine(simulation, xx[i], y, xx[i+1]); + simLineIntervallAdd(line_il, xx[i], xx[i+1]); + } + else + { + simFillHorizLine(simulation, xx[i], y, xx[i+1]); + simLineIntervallAdd(line_il, xx[i], xx[i+1]); + if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */ + if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */ + { + simFillHorizLine(simulation, xx[i+1], y, xx[i+2]); + simLineIntervallAdd(line_il, xx[i+1], xx[i+2]); + } + } + } + } + + free(xx); + free(segment); + + /* Once the polygon has been filled, now let's draw the + * antialiased and incomplete pixels at the edges */ + + if (y_max > height-1) + y_max = height-1; + + /* Go through all line segments of the poly */ + for(i = 0; i < n; i++) + { + i1 = (i+1)%n; + simPolyAAPixels(simulation->canvas, line_int_list, y_min, y_max, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y); + } + + for (i = 0; i < num_lines; i++) + { + if (line_int_list[i].xx) + free(line_int_list[i].xx); + } + free(line_int_list); +} + +/*************************************************************************************/ +/*************************************************************************************/ + +#define _cdLineDrawPixel(_canvas, _x1, _y1, _ls, _fgcolor, _bgcolor) \ +{ \ + if (_ls & 1) \ + _canvas->cxPixel(_canvas->ctxcanvas, _x1, _y1, _fgcolor); \ + else if (canvas->back_opacity == CD_OPAQUE) \ + _canvas->cxPixel(_canvas->ctxcanvas, _x1, _y1, _bgcolor); \ +} + +void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2) +{ + const int interior = canvas->interior_style; + const int width = canvas->line_width; + const int style = canvas->line_style; + + const int dx = x2-x1; + const int dy = y2-y1; + + const double len = hypot(dx,dy); + + const double dnx = dx/len; + const double dny = dy/len; + + const int w1 = (int)width/2; + const int w2 = width-w1; + + const int n1x = cdRound( w1*dny); + const int n1y = cdRound(-w1*dnx); + + const int n2x = cdRound(-w2*dny); + const int n2y = cdRound( w2*dnx); + + const int p1x = x1 + n1x; + const int p1y = y1 + n1y; + const int p2x = x1 + n2x; + const int p2y = y1 + n2y; + const int p3x = p2x + dx; + const int p3y = p2y + dy; + const int p4x = p1x + dx; + const int p4y = p1y + dy; + + cdPoint poly[4]; + + cdCanvasLineWidth(canvas, 1); + cdCanvasInteriorStyle(canvas, CD_SOLID); + cdCanvasLineStyle(canvas, CD_CONTINUOUS); + + poly[0].x = p1x; + poly[0].y = p1y; + poly[1].x = p2x; + poly[1].y = p2y; + poly[2].x = p3x; + poly[2].y = p3y; + poly[3].x = p4x; + poly[3].y = p4y; + + simPolyFill(canvas->simulation, poly, 4); + + cdCanvasLineWidth(canvas, width); + cdCanvasInteriorStyle(canvas, interior); + cdCanvasLineStyle(canvas, style); +} + +void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2) +{ + unsigned short ErrorInc, ErrorAcc; + unsigned short ErrorAccTemp, Weighting; + int DeltaX, DeltaY, XDir; + long aa_fgcolor; + unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha; + int no_antialias = !(canvas->simulation->antialias); + unsigned short int ls; + long fgcolor = canvas->foreground; + long bgcolor = canvas->background; + + if (simLineStyleNoReset == 2) + ls = simLineStyleLastBits; + else + { + ls = simLineStyleBitTable[canvas->line_style]; + + if (simLineStyleNoReset == 1) + simLineStyleNoReset = 2; + } + + /* Make sure p2.y > p1.y */ + if (y1 > y2) + { + _cdSwapInt(y1, y2); + _cdSwapInt(x1, x2); + } + + /* Draw the initial pixel, which is always exactly intersected by + the line and so needs no weighting */ + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + + DeltaX = x2 - x1; + if (DeltaX >= 0) + XDir = 1; + else + { + XDir = -1; + DeltaX = -DeltaX; /* make DeltaX positive */ + } + + /* Special-case horizontal, vertical, and diagonal lines, which + require no weighting because they go right through the center of + every pixel */ + DeltaY = y2 - y1; + if (DeltaY == 0) + { + /* Horizontal line */ + while (DeltaX-- != 0) + { + x1 += XDir; + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } + simLineStyleLastBits = ls; + return; + } + + if (DeltaX == 0) + { + /* Vertical line */ + do + { + y1++; + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } while (--DeltaY != 0); + simLineStyleLastBits = ls; + return; + } + + if (DeltaX == DeltaY) + { + /* Perfect Diagonal line */ + do + { + x1 += XDir; + y1++; + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } while (--DeltaY != 0); + simLineStyleLastBits = ls; + return; + } + + /* Line is not horizontal, diagonal, or vertical */ + + ErrorAcc = 0; /* initialize the line error accumulator to 0 */ + + /* Is this an X-major or Y-major line? */ + if (DeltaY > DeltaX) + { + /* Y-major line; calculate 16-bit fixed-point fractional part of a + pixel that X advances each time Y advances 1 pixel, truncating the + result so that we won't overrun the endpoint along the X axis */ + ErrorInc = (unsigned short)(((unsigned long)DeltaX << 16) / (unsigned long)DeltaY); + + /* Draw all pixels other than the first and last */ + while (--DeltaY) + { + ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ + ErrorAcc += ErrorInc; /* calculate error for next pixel */ + if (ErrorAcc <= ErrorAccTemp) + { + /* The error accumulator turned over, so advance the X coord */ + x1 += XDir; + } + + y1++; /* Y-major, so always advance Y */ + + Weighting = ErrorAcc >> INTENSITYSHIFT; + + if (no_antialias) + { + if (Weighting < 128) + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor) + else + _cdLineDrawPixel(canvas, x1 + XDir, y1, ls, fgcolor, bgcolor) + ls = simRotateLineStyle(ls); + } + else + { + /* The IntensityBits most significant bits of ErrorAcc give us the + intensity weighting for this pixel, and the complement of the + weighting for the paired pixel. + Combine the Weighting with the existing alpha, + When Weighting is zero alpha must be fully preserved. */ + aa_alpha = ((255-Weighting) * alpha) / 255; + + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor, bgcolor); + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, x1 + XDir, y1, ls, aa_fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } + } + /* Draw the final pixel, which is always exactly intersected by the line + and so needs no weighting */ + _cdLineDrawPixel(canvas, x2, y2, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } + else + { + /* It's an X-major line; calculate 16-bit fixed-point fractional part of a + pixel that Y advances each time X advances 1 pixel, truncating the + result to avoid overrunning the endpoint along the X axis */ + ErrorInc = (unsigned short)(((unsigned long)DeltaY << 16) / (unsigned long)DeltaX); + + /* Draw all pixels other than the first and last */ + while (--DeltaX) + { + ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ + ErrorAcc += ErrorInc; /* calculate error for next pixel */ + if (ErrorAcc <= ErrorAccTemp) + { + /* The error accumulator turned over, so advance the Y coord */ + y1++; + } + + x1 += XDir; /* X-major, so always advance X */ + + Weighting = ErrorAcc >> INTENSITYSHIFT; + + if (no_antialias) + { + if (Weighting < 128) + _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor) + else + _cdLineDrawPixel(canvas, x1, y1+1, ls, fgcolor, bgcolor) + ls = simRotateLineStyle(ls); + } + else + { + /* The IntensityBits most significant bits of ErrorAcc give us the + intensity weighting for this pixel, and the complement of the + weighting for the paired pixel. + Combine the Weighting with the existing alpha, + When Weighting is zero alpha must be fully preserved. */ + aa_alpha = ((255-Weighting) * alpha) / 255; + + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor, bgcolor); + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, x1, y1+1, ls, aa_fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } + } + + /* Draw the final pixel, which is always exactly intersected by the line + and so needs no weighting */ + _cdLineDrawPixel(canvas, x2, y2, ls, fgcolor, bgcolor); + ls = simRotateLineStyle(ls); + } + + simLineStyleLastBits = ls; +} + +void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b) +{ + double DeltaX, DeltaY, a, b; + long aa_fgcolor; + unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha; + int no_antialias = !(canvas->simulation->antialias); + int yi, xi, update_a = 1, update_b = 1; + unsigned short int ls; + long fgcolor = canvas->foreground; + long bgcolor = canvas->background; + + if (simLineStyleNoReset == 2) + ls = simLineStyleLastBits; + else + { + ls = simLineStyleBitTable[canvas->line_style]; + + if (simLineStyleNoReset == 1) + simLineStyleNoReset = 2; + } + + DeltaX = fabs(x2 - x1); + DeltaY = fabs(y2 - y1); + + if (DeltaX > 0.0001) + { + a = (y1-y2)/(x1-x2); + b = y1 - a*x1; + } + else + { + a = 0; + b = x1; + } + + /* NOTICE: all the complexity of this function + is related to check and update the previous point */ + + /* Is this an X-major or Y-major line? */ + if (DeltaY > DeltaX) + { + /* Increment in Y */ + int y1i = _cdRound(y1), + y2i = _cdRound(y2); + int yi_first = y1i; + int yi_last = y2i, xi_last; + + if (y1i > y2i) + _cdSwapInt(y1i, y2i); + + for (yi = y1i; yi <= y2i; yi++) + { + double x; + if (a) + x = (yi - b)/a; + else + x = b; + + xi = (int)floor(x); + + /* if at the last pixel, store the return value */ + if (yi == yi_last) + xi_last = xi; + + /* Combine the Weighting with the existing alpha, + When Weighting is zero alpha must be fully preserved. */ + aa_alpha = (int)((1.0-(x - xi)) * alpha); + + if (no_antialias) + { + if (aa_alpha > 128) + _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor, bgcolor) + else + _cdLineDrawPixel(canvas, xi+1, yi, ls, fgcolor, bgcolor) + } + else + { + if (yi == yi_first) + { + if (yi == yi_last) /* one pixel only */ + { + update_a = 0; + update_b = 0; + } + + /* if at first, compare with the last two previously drawn */ + /* if the new is equal to the previous, do NOT draw */ + if ((xi != *last_xi_a || yi != *last_yi_a) && + (xi != *last_xi_b || yi != *last_yi_b)) + { + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor); + + if (yi == yi_last) /* one pixel only */ + update_a = 1; + } + + if ((xi+1 != *last_xi_a || yi != *last_yi_a) && + (xi+1 != *last_xi_b || yi != *last_yi_b)) + { + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor, bgcolor); + + if (yi == yi_last) /* one pixel only */ + update_b = 1; + } + } + else + { + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor); + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor, bgcolor); + } + } + + ls = simRotateLineStyle(ls); + } + + if (update_a) + { + *last_xi_a = xi_last; + *last_yi_a = yi_last; + } + if (update_b) + { + *last_xi_b = xi_last+1; + *last_yi_b = yi_last; + } + } + else + { + /* Increment in X */ + int x1i = _cdRound(x1), + x2i = _cdRound(x2); + int xi_first = x1i; + int xi_last = x2i, yi_last; + + if (x1i > x2i) + _cdSwapInt(x1i, x2i); + + for (xi = x1i; xi <= x2i; xi++) + { + double y = a*xi + b; + yi = (int)floor(y); + + /* if at the last pixel, store the return value */ + if (xi == xi_last) + yi_last = yi; + + /* Combine the Weighting with the existing alpha, + When Weighting is zero alpha must be fully preserved. */ + aa_alpha = (int)((1.0-(y - yi)) * alpha); + + if (no_antialias) + { + if (aa_alpha > 128) + _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor, bgcolor) + else + _cdLineDrawPixel(canvas, xi, yi+1, ls, fgcolor, bgcolor) + } + else + { + if (xi == xi_first) + { + if (xi == xi_last) /* one pixel only */ + { + update_a = 0; + update_b = 0; + } + + /* if at first, compare with the last to draw */ + /* if new is equal to the previous, do NOT draw */ + if ((xi != *last_xi_a || yi != *last_yi_a) && + (xi != *last_xi_b || yi != *last_yi_b)) + { + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor); + + if (xi == xi_last) /* one pixel only */ + update_a = 1; + } + + if ((xi != *last_xi_a || yi+1 != *last_yi_a) && + (xi != *last_xi_b || yi+1 != *last_yi_b)) + { + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor, bgcolor); + + if (xi == xi_last) /* one pixel only */ + update_b = 1; + } + } + else + { + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor); + aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor, bgcolor); + } + } + + ls = simRotateLineStyle(ls); + } + + if (update_a) + { + *last_xi_a = xi_last; + *last_yi_a = yi_last; + } + if (update_b) + { + *last_xi_b = xi_last; + *last_yi_b = yi_last+1; + } + } + + simLineStyleLastBits = ls; +} diff --git a/src/sim/sim_other.c b/src/sim/sim_other.c new file mode 100644 index 0000000..0954406 --- /dev/null +++ b/src/sim/sim_other.c @@ -0,0 +1,411 @@ +/** \file + * \brief Simulation that is independent of the Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> + +#include "cd.h" +#include "cd_private.h" + + +void cdSimMark(cdCanvas* canvas, int x, int y) +{ + int oldinteriorstyle = canvas->interior_style; + int oldlinestyle = canvas->line_style; + int oldlinewidth = canvas->line_width; + int size = canvas->mark_size; + int half_size = size/2; + int bottom = y-half_size; + int top = y+half_size; + int left = x-half_size; + int right = x+half_size; + + if (canvas->interior_style != CD_SOLID && + (canvas->mark_type == CD_CIRCLE || + canvas->mark_type == CD_BOX || + canvas->mark_type == CD_DIAMOND)) + cdCanvasInteriorStyle(canvas, CD_SOLID); + + if (canvas->line_style != CD_CONTINUOUS && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineStyle(canvas, CD_CONTINUOUS); + + if (canvas->line_width != 1 && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineWidth(canvas, 1); + + switch (canvas->mark_type) + { + case CD_STAR: + canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); + canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); + /* continue */ + case CD_PLUS: + canvas->cxLine(canvas->ctxcanvas, left, y, right, y); + canvas->cxLine(canvas->ctxcanvas, x, bottom, x, top); + break; + case CD_HOLLOW_CIRCLE: + canvas->cxArc(canvas->ctxcanvas, x, y, size, size, 0, 360); + break; + case CD_HOLLOW_BOX: + canvas->cxRect(canvas->ctxcanvas, left, right, bottom, top); + break; + case CD_HOLLOW_DIAMOND: + canvas->cxLine(canvas->ctxcanvas, left, y, x, top); + canvas->cxLine(canvas->ctxcanvas, x, top, right, y); + canvas->cxLine(canvas->ctxcanvas, right, y, x, bottom); + canvas->cxLine(canvas->ctxcanvas, x, bottom, left, y); + break; + case CD_X: + canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); + canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); + break; + case CD_CIRCLE: + canvas->cxSector(canvas->ctxcanvas, x, y, size, size, 0, 360); + break; + case CD_BOX: + canvas->cxBox(canvas->ctxcanvas, left, right, bottom, top); + break; + case CD_DIAMOND: + { + cdPoint poly[5]; + poly[0].x = left; + poly[0].y = y; + poly[1].x = x; + poly[1].y = top; + poly[2].x = right; + poly[2].y = y; + poly[3].x = x; + poly[3].y = bottom; + canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); + } + break; + } + + if (canvas->interior_style != oldinteriorstyle && + (canvas->mark_type == CD_CIRCLE || + canvas->mark_type == CD_BOX || + canvas->mark_type == CD_DIAMOND)) + cdCanvasInteriorStyle(canvas, oldinteriorstyle); + + if (canvas->line_style != oldlinestyle && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineStyle(canvas, oldlinestyle); + + if (canvas->line_width != oldlinewidth && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineWidth(canvas, oldlinewidth); +} + +/* Setup Bezier coefficient array once for each control polygon. + */ +static void BezierForm(const cdPoint* p, cdfPoint* c) +{ + int k; + static int choose[4] = {1, 3, 3, 1}; + for (k = 0; k < 4; k++) + { + c[k].x = p[k].x * choose[k]; + c[k].y = p[k].y * choose[k]; + } +} + +static void fBezierForm(const cdfPoint* p, cdfPoint* c) +{ + int k; + static int choose[4] = {1, 3, 3, 1}; + for (k = 0; k < 4; k++) + { + c[k].x = p[k].x * choose[k]; + c[k].y = p[k].y * choose[k]; + } +} + +/* Return Point pt(t), t <= 0 <= 1 from C. + * BezierForm must be called once for any given control polygon. + */ +static void BezierCurve(const cdfPoint* c, cdfPoint *pt, double t) +{ + int k; + double t1, tt, u; + cdfPoint b[4]; + + u = t; + + b[0].x = c[0].x; + b[0].y = c[0].y; + for(k = 1; k < 4; k++) + { + b[k].x = c[k].x * u; + b[k].y = c[k].y * u; + u =u*t; + } + + pt->x = b[3].x; + pt->y = b[3].y; + t1 = 1-t; + tt = t1; + for(k = 2; k >= 0; k--) + { + pt->x += b[k].x * tt; + pt->y += b[k].y * tt; + tt =tt*t1; + } +} + +static int BezierNumSegments(cdCanvas* canvas, const cdPoint* p) +{ + int i, K, dx, dy, d, + xmax = p[0].x, + ymax = p[0].y, + xmin = p[0].x, + ymin = p[0].y; + + for (i = 1; i < 4; i++) + { + if (p[i].x > xmax) + xmax = p[i].x; + if (p[i].y > ymax) + ymax = p[i].y; + if (p[i].x < xmin) + xmin = p[i].x; + if (p[i].y < ymin) + ymin = p[i].y; + } + + if (canvas->use_matrix) + { + cdMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin); + cdMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax); + } + + /* diagonal of the bouding box */ + dx = (xmax-xmin); + dy = (ymax-ymin); + d = (int)(sqrt(dx*dx + dy*dy)); + K = d / 8; + if (K < 8) K = 8; + return K; +} + +static int fBezierNumSegments(cdCanvas* canvas, const cdfPoint* p) +{ + int i, K, d; + double dx, dy, + xmax = p[0].x, + ymax = p[0].y, + xmin = p[0].x, + ymin = p[0].y; + + for (i = 1; i < 4; i++) + { + if (p[i].x > xmax) + xmax = p[i].x; + if (p[i].y > ymax) + ymax = p[i].y; + if (p[i].x < xmin) + xmin = p[i].x; + if (p[i].y < ymin) + ymin = p[i].y; + } + + /* diagonal of the bouding box */ + dx = (xmax-xmin); + dy = (ymax-ymin); + d = (int)(sqrt(dx*dx + dy*dy)); + K = d / 8; + if (K < 8) K = 8; + return K; +} + +/* from sim.h */ +void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b); + +/* Quick and Simple Bezier Curve Drawing --- Robert D. Miller + * Graphics GEMS V */ +void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n) +{ + int i = 0, k, K, poly_max = 0; + cdfPoint pt, prev_pt; + cdfPoint bezier_control[4]; + cdPoint* poly = NULL; + int use_poly = 0, + last_xi_a = -65535, + last_yi_a = -65535, + last_xi_b = -65535, + last_yi_b = -65535; + + /* Use special floating point anti-alias line draw when + line_width==1, and NOT using cdlineSIM. */ + if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM) + use_poly = 1; + + n--; /* first n is 4 */ + while (n >= 3) + { + BezierForm(points+i, bezier_control); + K = BezierNumSegments(canvas, points+i); + + if (use_poly && poly_max < K+1) + { + poly = realloc(poly, sizeof(cdPoint)*(K+1)); /* K+1 points */ + if (!poly) return; + poly_max = K+1; + } + + /* first segment */ + BezierCurve(bezier_control, &pt, 0); + if (use_poly) + { + poly[0].x = _cdRound(pt.x); + poly[0].y = _cdRound(pt.y); + } + else + prev_pt = pt; + + for(k = 1; k < K+1; k++) + { + BezierCurve(bezier_control, &pt, (double)k/(double)K); + + if (use_poly) + { + poly[k].x = _cdRound(pt.x); + poly[k].y = _cdRound(pt.y); + } + else + { + int old_use_matrix = canvas->use_matrix; + double x1 = prev_pt.x, + y1 = prev_pt.y, + x2 = pt.x, + y2 = pt.y; + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + } + + /* must disable transformation here, because line simulation use cxPixel */ + canvas->use_matrix = 0; + + simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); + + canvas->use_matrix = old_use_matrix; + prev_pt = pt; + } + } + + if (use_poly) + canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k); + + n -= 3; i += 3; + } + + if (poly) free(poly); +} + +void cdfSimPolyBezier(cdCanvas* canvas, const cdfPoint* points, int n) +{ + int i = 0, k, K, poly_max = 0; + cdfPoint pt; + cdfPoint bezier_control[4]; + cdfPoint* poly = NULL; + + n--; /* first n is 4 */ + while (n >= 3) + { + fBezierForm(points+i, bezier_control); + K = fBezierNumSegments(canvas, points+i); + + if (poly_max < K+1) + { + poly = realloc(poly, sizeof(cdfPoint)*(K+1)); /* K+1 points */ + if (!poly) return; + poly_max = K+1; + } + + /* first segment */ + BezierCurve(bezier_control, &pt, 0); + poly[0].x = _cdRound(pt.x); + poly[0].y = _cdRound(pt.y); + + for(k = 1; k < K+1; k++) + { + BezierCurve(bezier_control, &pt, (double)k/(double)K); + + poly[k].x = _cdRound(pt.x); + poly[k].y = _cdRound(pt.y); + } + + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k); + n -= 3; i += 3; + } + + if (poly) free(poly); +} + +void cdSimPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int size, i, j, dst, src, *fx, *fy, rw, rh; + unsigned char *ar, *ag, *ab, al; + + size = w * h; + ar = (unsigned char*)malloc(size*3); + if (!ar) return; + ag = ar + size; + ab = ag + size; + + canvas->cxGetImageRGB(canvas->ctxcanvas, ar, ag, ab, x, y, w, h); + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + fx = cdGetZoomTable(w, rw, xmin); + fy = cdGetZoomTable(h, rh, ymin); + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + dst = j * w + i; + src = fy[j] * iw + fx[i]; + al = a[src]; + ar[dst] = CD_ALPHA_BLEND(r[src], ar[dst], al); + ag[dst] = CD_ALPHA_BLEND(g[src], ag[dst], al); + ab[dst] = CD_ALPHA_BLEND(b[src], ab[dst], al); + } + } + + canvas->cxPutImageRectRGB(canvas->ctxcanvas, w, h, ar, ag, ab, x, y, w, h, 0, 0, 0, 0); + + free(ar); + + free(fx); + free(fy); +} diff --git a/src/sim/sim_primitives.c b/src/sim/sim_primitives.c new file mode 100644 index 0000000..5f5e0a3 --- /dev/null +++ b/src/sim/sim_primitives.c @@ -0,0 +1,524 @@ +/** \file + * \brief Primitives of the Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" + +void cdlineSIM(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + int old_use_matrix = canvas->use_matrix; + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + } + + /* must disable transformation here, because line simulation use cxPixel */ + canvas->use_matrix = 0; + + if(canvas->line_width > 1) + simLineThick(canvas, x1, y1, x2, y2); + else + simLineThin(canvas, x1, y1, x2, y2); + + canvas->use_matrix = old_use_matrix; +} + +void cdrectSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdPoint poly[5]; /* leave room of one more point */ + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + canvas->cxPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); +} + +void cdboxSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + + if (canvas->use_matrix) + { + cdPoint poly[5]; /* leave room of one more point */ + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); + } + else + { + cdSimulation* simulation = canvas->simulation; + int y; + + /* must set line attributes here, because fill simulation use cxLine and cxPixel */ + int old_line_style = cdCanvasLineStyle(canvas, CD_CONTINUOUS); + int old_line_width = cdCanvasLineWidth(canvas, 1); + + for(y=ymin;y<=ymax;y++) + simFillHorizLine(simulation, xmin, y, xmax); + + cdCanvasLineStyle(canvas, old_line_style); + cdCanvasLineWidth(canvas, old_line_width); + } +} + +void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdfPoint poly[5]; /* leave room of one more point */ + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4); +} + +void cdfSimRect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdfPoint poly[5]; /* leave room of one more point */ + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + canvas->cxFPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); +} + +int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height) +{ + int n, dx, dy, hd; + int w2 = width/2; + int h2 = height/2; + int x1 = xc-w2, + y1 = yc-h2, + x2 = xc+w2, + y2 = yc+h2; + + if (canvas->use_matrix) + { + cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + } + + dx = (x1-x2); + dy = (y1-y2); + hd = (int)(sqrt(dx*dx + dy*dy)/2); + + /* Estimation Heuristic: + use half diagonal to estimate the number of segments for 360 degrees. + Use the difference of the half diagonal and its projection to calculate the minimum angle: + cos(min_angle) = hd / (hd + 1) or min_angle = acos(hd / (hd + 1)) + The number of segments will be 360 / min_angle. + */ + + n = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ + + /* multiple of 4 */ + n = ((n + 3)/4)*4; + + /* minimum number is 4 */ + if (n < 4) n = 4; + + return n; +} + +void cdarcSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + double c, s, sx, sy, x, y, prev_x, prev_y; + double da; + int i, yc2 = 2*yc, p, + last_xi_a = -65535, + last_yi_a = -65535, + last_xi_b = -65535, + last_yi_b = -65535; + cdPoint* poly = NULL; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); + + /* Use special floating point anti-alias line draw when + line_width==1, and NOT using cdlineSIM. */ + if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM) + { + poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+1)); /* n+1 points */ + if (!poly) return; + } + + /* number of segments for the arc */ + n = cdRound((fabs(angle2-angle1)*n)/360); + if (n < 1) n = 1; + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = cos(da); + s = sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = (width/2.0f)*cos(angle1); + y = (height/2.0f)*sin(angle1); + prev_x = x; + prev_y = y; + if (poly) + { + poly[0].x = _cdRound(x)+xc; + poly[0].y = _cdRound(y)+yc; + + if (canvas->invert_yaxis) /* must invert because of the angle orientation */ + poly[0].y = yc2 - poly[0].y; + + p = 1; + } + else + simLineStyleNoReset = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = c*prev_x + sx*prev_y; + y = sy*prev_x + c*prev_y; + + if (poly) + { + poly[p].x = _cdRound(x)+xc; + poly[p].y = _cdRound(y)+yc; + + if (canvas->invert_yaxis) /* must invert because of the angle orientation */ + poly[p].y = yc2 - poly[p].y; + + if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) + p++; + } + else + { + int old_use_matrix = canvas->use_matrix; + double x1 = prev_x+xc, + y1 = prev_y+yc, + x2 = x+xc, + y2 = y+yc; + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + } + + /* must disable transformation here, because line simulation use cxPixel */ + canvas->use_matrix = 0; + + if (canvas->invert_yaxis) /* must invert because of the angle orientation */ + { + y1 = yc2 - y1; + y2 = yc2 - y2; + } + + simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); + + canvas->use_matrix = old_use_matrix; + } + + prev_x = x; + prev_y = y; + } + + if (poly) + { + canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p); + free(poly); + } + else + simLineStyleNoReset = 0; +} + +void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + double c, s, sx, sy, x, y, prev_x, prev_y, da; + int i, p; + cdfPoint* poly = NULL; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height); + + poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+1)); /* n+1 points */ + if (!poly) return; + + /* number of segments for the arc */ + n = cdRound((fabs(angle2-angle1)*n)/360); + if (n < 1) n = 1; + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = cos(da); + s = sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = (width/2.0f)*cos(angle1); + y = (height/2.0f)*sin(angle1); + prev_x = x; + prev_y = y; + poly[0].x = x+xc; + poly[0].y = y+yc; + + p = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = c*prev_x + sx*prev_y; + y = sy*prev_x + c*prev_y; + + poly[p].x = x+xc; + poly[p].y = y+yc; + + if (poly[p-1].x != poly[p].x || + poly[p-1].y != poly[p].y) + p++; + + prev_x = x; + prev_y = y; + } + + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p); + free(poly); +} + +void cdfSimElipse(cdCtxCanvas* ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2, int sector) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + double c, s, sx, sy, x, y, prev_x, prev_y, da; + int i, p; + cdfPoint* poly; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height); + + /* number of segments for the arc */ + n = cdRound(((angle2-angle1)*n)/360); + if (n < 1) n = 1; + + poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+2+1)); /* n+1 points +1 center */ + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = cos(da); + s = sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = xc + (width/2.0)*cos(angle1); + y = yc + (height/2.0)*sin(angle1); + prev_x = x; + prev_y = y; + + poly[0].x = x; + poly[0].y = y; + p = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = xc + c*(prev_x-xc) + sx*(prev_y-yc); + y = yc + sy*(prev_x-xc) + c*(prev_y-yc); + + poly[p].x = x; + poly[p].y = y; + + if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) + p++; + + prev_x = x; + prev_y = y; + } + + if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) + { + if (sector) /* cdSector */ + { + /* add center */ + poly[p].x = xc; + poly[p].y = yc; + } + else /* cdChord */ + { + /* add initial point */ + poly[p].x = poly[0].x; + poly[p].y = poly[0].y; + } + p++; + } + + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, p); + free(poly); +} + +static void cdSimElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + float c, s, sx, sy, x, y, prev_x, prev_y; + double da; + int i, p, yc2 = 2*yc; + cdPoint* poly; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); + + /* number of segments for the arc */ + n = cdRound(((angle2-angle1)*n)/360); + if (n < 1) n = 1; + + poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */ + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = (float)cos(da); + s = (float)sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = xc + (width/2.0f)*(float)cos(angle1); + y = yc + (height/2.0f)*(float)sin(angle1); + prev_x = x; + prev_y = y; + + poly[0].x = _cdRound(x); + poly[0].y = _cdRound(y); + if (canvas->invert_yaxis) + poly[0].y = yc2 - poly[0].y; + p = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = xc + c*(prev_x-xc) + sx*(prev_y-yc); + y = yc + sy*(prev_x-xc) + c*(prev_y-yc); + + poly[p].x = _cdRound(x); + poly[p].y = _cdRound(y); + + if (canvas->invert_yaxis) + poly[p].y = yc2 - poly[p].y; + + if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) + p++; + + prev_x = x; + prev_y = y; + } + + if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) + { + if (sector) /* cdSector */ + { + /* add center */ + poly[p].x = xc; + poly[p].y = yc; + } + else /* cdChord */ + { + /* add initial point */ + poly[p].x = poly[0].x; + poly[p].y = poly[0].y; + } + p++; + } + + canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, p); + + free(poly); +} + +void cdsectorSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +{ + cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 1); +} + +void cdchordSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +{ + cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 0); +} + +void cdpolySIM(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + int i, reset = 1; + + switch(mode) + { + case CD_CLOSED_LINES: + poly[n] = poly[0]; + n++; + /* continue */ + case CD_OPEN_LINES: + if (simLineStyleNoReset) /* Bezier simulation use several poly */ + { + reset = 0; + simLineStyleNoReset = 1; + } + for (i = 0; i< n - 1; i++) + canvas->cxLine(canvas->ctxcanvas, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y); + if (reset) simLineStyleNoReset = 0; + break; + case CD_BEZIER: + simLineStyleNoReset = 1; + cdSimPolyBezier(canvas, poly, n); + simLineStyleNoReset = 0; + break; + case CD_FILL: + { + /* must set line attributes here, because fill simulation use cxLine */ + int oldwidth = cdCanvasLineWidth(canvas, 1); + int oldstyle = cdCanvasLineStyle(canvas, CD_CONTINUOUS); + int old_use_matrix = canvas->use_matrix; + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + for(i = 0; i < n; i++) + cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); + } + + /* must disable transformation here, because line simulation use cxPixel */ + canvas->use_matrix = 0; + + simPolyFill(canvas->simulation, poly, n); + + canvas->use_matrix = old_use_matrix; + cdCanvasLineStyle(canvas, oldstyle); + cdCanvasLineWidth(canvas, oldwidth); + } + break; + } +} diff --git a/src/sim/sim_text.c b/src/sim/sim_text.c new file mode 100644 index 0000000..3ea7aef --- /dev/null +++ b/src/sim/sim_text.c @@ -0,0 +1,371 @@ +/** \file + * \brief Text and Font Functions of the Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> +#include <ctype.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" +#include FT_GLYPH_H + + +static int font_name_match(const char* map, const char* name) +{ + while (*map != '=') + { + if (tolower(*map) != tolower(*name)) + return 0; + + map++; + name++; + } + + return 1; +} + +static void cdSimAddFontMap(cdSimulation* simulation, const char* map) +{ + int i; + + if (!strstr(map, "=")) + return; + + for (i = 0; i < simulation->font_map_n; i++) + { + if (font_name_match(simulation->font_map[i], map)) + { + /* replace */ + simulation->font_map[i] = map; + return; + } + } + + /* not found add */ + simulation->font_map[i] = map; + simulation->font_map_n++; +} + +static void set_addfontmap(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimAddFontMap(canvas->simulation, data); + } +} + +static cdAttribute addfontmap_attrib = +{ + "ADDFONTMAP", + set_addfontmap, + NULL +}; + +void cdSimInitText(cdSimulation* simulation) +{ + if (!simulation->tt_text) + simulation->tt_text = cdTT_create(); + + cdRegisterAttribute(simulation->canvas, &addfontmap_attrib); +} + +static const char* find_font_filename(cdSimulation* simulation, const char* name) +{ + int i; + for (i = 0; i < simulation->font_map_n; i++) + { + if (font_name_match(simulation->font_map[i], name)) + return strstr(simulation->font_map[i], "=")+1; + } + return NULL; +} + +int cdfontSIM(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + + /* check for the pre-defined names */ + if (cdStrEqualNoCase(type_face, "System")) + type_face = "cour"; + else if (cdStrEqualNoCase(type_face, "Courier")) + type_face = "cour"; + else if (cdStrEqualNoCase(type_face, "Times")) + type_face = "times"; + else if (cdStrEqualNoCase(type_face, "Helvetica")) + type_face = "arial"; + else + { + /* use the font map */ + const char* filename = find_font_filename(canvas->simulation, type_face); + if (filename) + return cdTT_load(canvas->simulation->tt_text, filename, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres); + else + { + /* try the type_face name without change */ + if (cdTT_load(canvas->simulation->tt_text, type_face, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres)) + return 1; + } + } + + { + static char * cd_ttf_font_style[4] = { + "", + "bd", + "i", + "bi"}; + char font[10240]; /* can have a path */ + sprintf(font, "%s%s", type_face, cd_ttf_font_style[style&3]); + return cdTT_load(canvas->simulation->tt_text, font, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres); + } +} + +void cdgetfontdimSIM(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + + if (!simulation->tt_text->face) + return; + + if(ascent) *ascent = simulation->tt_text->ascent; + if(descent) *descent= simulation->tt_text->descent; + if(max_width) *max_width= simulation->tt_text->max_width; + if(height) *height= simulation->tt_text->max_height; +} + +void cdgettextsizeSIM(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + int w = 0; + FT_Face face; + FT_GlyphSlot slot; + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* set transformation */ + FT_Set_Transform( face, NULL, NULL ); + + while(*s) + { + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char( face, *(unsigned char*)s, FT_LOAD_DEFAULT ); + if (error) {s++; continue;} /* ignore errors */ + + w += slot->advance.x; + + s++; + } + + if (height) *height = simulation->tt_text->max_height; + if (width) *width = w >> 6; +} + +static void simDrawTextBitmap(cdSimulation* simulation, FT_Bitmap* bitmap, int x, int y) +{ + unsigned char *red, *green, *blue, *alpha, *bitmap_data; + int width = bitmap->width; + int height = bitmap->rows; + int size = width*height; + int rgba_data_size = size*4; + int olduse_matrix = simulation->canvas->use_matrix; + + /* avoid spaces */ + if (width == 0 || height == 0) + return; + + if (!simulation->tt_text->rgba_data) + simulation->tt_text->rgba_data = malloc(rgba_data_size); + else if (rgba_data_size > simulation->tt_text->rgba_data_size) + { + simulation->tt_text->rgba_data = realloc(simulation->tt_text->rgba_data, rgba_data_size); + simulation->tt_text->rgba_data_size = rgba_data_size; + } + + /* disable image transformation */ + simulation->canvas->use_matrix = 0; + + bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */ + red = simulation->tt_text->rgba_data; + green = red + size; + blue = green + size; + alpha = blue + size; + + if (!simulation->canvas->cxPutImageRectRGBA && !simulation->canvas->cxGetImageRGB) + { + int i, j; + unsigned char bg_red, bg_green, bg_blue, fg_red, fg_green, fg_blue; + long int c; + c = simulation->canvas->background; + bg_red = cdRed(c); + bg_green = cdGreen(c); + bg_blue = cdBlue(c); + c = simulation->canvas->foreground; + fg_red = cdRed(c); + fg_green = cdGreen(c); + fg_blue = cdBlue(c); + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + *red++ = (fg_red*bitmap_data[j] + bg_red*(255-bitmap_data[j]))/255; + *green++ = (fg_green*bitmap_data[j] + bg_green*(255-bitmap_data[j]))/255; + *blue++ = (fg_blue*bitmap_data[j] + bg_blue*(255-bitmap_data[j]))/255; + } + + bitmap_data -= width; + } + + red = simulation->tt_text->rgba_data; + green = red + size; + blue = green + size; + simulation->canvas->cxPutImageRectRGB(simulation->canvas->ctxcanvas, width,height,red,green,blue,x,y,width,height,0,width-1,0,height-1); + } + else + { + int i; + long int fg = simulation->canvas->foreground; + memset(red, cdRed(fg), size); + memset(green, cdGreen(fg), size); + memset(blue, cdBlue(fg), size); + for (i = 0; i < height; i++) + { + memcpy(alpha, bitmap_data, width); + alpha += width; + bitmap_data -= width; + } + + alpha = blue + size; + simulation->canvas->cxPutImageRectRGBA(simulation->canvas->ctxcanvas, width,height,red,green,blue,alpha,x,y,width,height,0,width-1,0,height-1); + } + + simulation->canvas->use_matrix = olduse_matrix; +} + +void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, FT_Matrix *matrix, FT_Vector *pen) +{ + int ox = x, oy = y; + int old_invert_yaxis = canvas->invert_yaxis; + int w, h, ascent, height, baseline; + + cdCanvasGetTextSize(canvas, s, &w, &h); + cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + /* in this case we are always upwards */ + + /* move to bottom left */ + canvas->invert_yaxis = 0; + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &x, &y); + canvas->invert_yaxis = old_invert_yaxis; + + /* move to the base line */ + y += baseline; + + /* set up matrix */ + matrix->xx = (FT_Fixed)0x10000L; + matrix->xy = (FT_Fixed)0; + matrix->yx = (FT_Fixed)0; + matrix->yy = (FT_Fixed)0x10000L; + + if (canvas->text_orientation) + { + FT_Matrix text_matrix; + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + + /* manually rotate the initial point */ + canvas->invert_yaxis = 0; + cdRotatePoint(canvas, x, y, ox, oy, &x, &y, sin_theta, cos_theta); + canvas->invert_yaxis = old_invert_yaxis; + + text_matrix.xx = (FT_Fixed)( cos_theta*0x10000L); + text_matrix.xy = (FT_Fixed)(-sin_theta*0x10000L); + text_matrix.yx = (FT_Fixed)( sin_theta*0x10000L); + text_matrix.yy = (FT_Fixed)( cos_theta*0x10000L); + + FT_Matrix_Multiply(&text_matrix, matrix); + } + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + FT_Matrix trans_matrix; + trans_matrix.xx = (FT_Fixed)(canvas->matrix[0]*0x10000L); + trans_matrix.yx = (FT_Fixed)(canvas->matrix[1]*0x10000L); + trans_matrix.xy = (FT_Fixed)(canvas->matrix[2]*0x10000L); + trans_matrix.yy = (FT_Fixed)(canvas->matrix[3]*0x10000L); + + FT_Matrix_Multiply(&trans_matrix, matrix); + + /* manually transform the initial point */ + cdMatrixTransformPoint(canvas->matrix, x, y, &x, &y); + } + + /* the pen position in 26.6 scale */ + pen->x = x * 64; + pen->y = y * 64; + +} + +void cdtextSIM(cdCtxCanvas* ctxcanvas, int x, int y, const char * s) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix matrix; /* transformation matrix */ + FT_Vector pen; /* untransformed origin */ + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* the pen position is in cartesian space coordinates */ + if (simulation->canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); /* y is already inverted, invert back to cartesian space */ + + /* move the reference point to the baseline-left */ + simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen); + + while(*s) + { + /* set transformation */ + FT_Set_Transform(face, &matrix, &pen); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER); + if (error) {s++; continue;} /* ignore errors */ + + x = slot->bitmap_left; + y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */ + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + /* now, draw to our target surface (convert position) */ + simDrawTextBitmap(simulation, &slot->bitmap, x, y); + + /* increment pen position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + s++; + } +} diff --git a/src/sim/truetype.h b/src/sim/truetype.h new file mode 100644 index 0000000..5675998 --- /dev/null +++ b/src/sim/truetype.h @@ -0,0 +1,46 @@ +/** \file + * \brief Text and Font Simulation using FreeType library. + * + * See Copyright Notice in cd.h + */ + +#ifndef __TRUETYPE_H +#define __TRUETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ft2build.h" +#include FT_FREETYPE_H + +/* + In CD version 4.4 we start to use FreeType 2. + Only TrueType font support is enabled. +*/ + +typedef struct _cdTT_Text +{ + FT_Library library; + FT_Face face; + + unsigned char* rgba_data; + int rgba_data_size; + + int max_height; + int max_width; + int descent; + int ascent; + +}cdTT_Text; + +cdTT_Text* cdTT_create(void); +void cdTT_free(cdTT_Text * tt_text); +int cdTT_load(cdTT_Text * tt_text, const char *font,int size, double xres, double yres); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _CD_TRUETYPE_ */ + diff --git a/src/tecmake_compact.mak b/src/tecmake_compact.mak new file mode 100644 index 0000000..77c92b6 --- /dev/null +++ b/src/tecmake_compact.mak @@ -0,0 +1,1080 @@ +#-------------------------------------------------------------------------# +#- Tecmake (Compact Version) -# +#- Generic Makefile to build applications and libraries at TeCGraf -# +#- The user makefile usually has the name "config.mak". -# +#-------------------------------------------------------------------------# + +# Tecmake Version +VERSION = 3.15 + +# First target +.PHONY: build +build: tecmake + + +#---------------------------------# +# System Variables Definitions + +# Base Defintions +TEC_SYSNAME:=$(shell uname -s) +TEC_SYSVERSION:=$(shell uname -r|cut -f1 -d.) +TEC_SYSMINOR:=$(shell uname -r|cut -f2 -d.) +TEC_SYSARCH:=$(shell uname -m) + +# Fixes +ifeq ($(TEC_SYSNAME), SunOS) + TEC_SYSARCH:=$(shell uname -p) +endif +ifeq ($(TEC_SYSNAME), IRIX) + TEC_SYSARCH:=$(shell uname -p) +endif +ifeq ($(TEC_SYSNAME), FreeBSD) + TEC_SYSMINOR:=$(shell uname -r|cut -f2 -d.|cut -f1 -d-) +endif +ifeq ($(TEC_SYSNAME), AIX) + TEC_SYSVERSION:=$(shell uname -v) + TEC_SYSMINOR:=$(shell uname -r) + TEC_SYSARCH:=ppc +endif +ifeq ($(TEC_SYSNAME), Darwin) + TEC_SYSARCH:=$(shell uname -p) +endif + +ifeq ($(TEC_SYSARCH), powerpc) + TEC_SYSARCH:=ppc +endif +ifeq ($(TEC_SYSARCH), i686) + TEC_SYSARCH:=x86 +endif +ifeq ($(TEC_SYSARCH), i386) + TEC_SYSARCH:=x86 +endif + +# Compose +TEC_SYSRELEASE:=$(TEC_SYSVERSION).$(TEC_SYSMINOR) +TEC_UNAME:=$(TEC_SYSNAME)$(TEC_SYSVERSION)$(TEC_SYSMINOR) + +# Linux 2.4 and GCC 3.x +ifeq ($(TEC_UNAME), Linux24) + GCCVER:=$(shell gcc -dumpversion|cut -f1 -d.) + ifeq ($(GCCVER), 3) + TEC_UNAME:=$(TEC_UNAME)g3 + endif +endif + +# Linux 2.6 and GCC 4.x +ifeq ($(TEC_UNAME), Linux26) + GCCVER:=$(shell gcc -dumpversion|cut -f1 -d.) + ifeq ($(GCCVER), 4) + TEC_UNAME:=$(TEC_UNAME)g4 + endif +endif + +# Linux and PowerPC +ifeq ($(TEC_SYSNAME), Linux) + ifeq ($(TEC_SYSARCH), ppc) + TEC_UNAME:=$(TEC_UNAME)ppc + endif +endif + +# 64-bits Linux +ifeq ($(TEC_SYSARCH), x86_64) + BUILD_64=Yes + TEC_UNAME:=$(TEC_UNAME)_64 +endif + +ifeq ($(TEC_SYSARCH), ia64) + BUILD_64=Yes + TEC_UNAME:=$(TEC_UNAME)_ia64 +endif + +# Solaris and Intel +ifeq ($(TEC_SYSNAME), SunOS) + ifeq ($(TEC_SYSARCH) , x86) + TEC_UNAME:=$(TEC_UNAME)x86 + endif +endif + +# Darwin and Intel +ifeq ($(TEC_SYSNAME), Darwin) +ifeq ($(TEC_SYSARCH), x86) + TEC_UNAME:=$(TEC_UNAME)x86 + endif +endif + +# System Info +.PHONY: sysinfo +sysinfo: + @echo ''; echo 'Tecmake - System Info' + @echo 'TEC_SYSNAME = $(TEC_SYSNAME)' + @echo 'TEC_SYSVERSION = $(TEC_SYSVERSION)' + @echo 'TEC_SYSMINOR = $(TEC_SYSMINOR)' + @echo 'TEC_SYSARCH = $(TEC_SYSARCH)' + @echo 'TEC_UNAME = $(TEC_UNAME)'; echo '' + +#---------------------------------# +# Directories Definitions +PROJDIR = .. +SRCDIR = . +OBJROOT = $(PROJDIR)/obj + + +#---------------------------------# +# Byte Order and Word Size + +ifneq ($(findstring x86, $(TEC_SYSARCH)), ) + TEC_BYTEORDER = TEC_LITTLEENDIAN +else + TEC_BYTEORDER = TEC_BIGENDIAN +endif + +ifeq ($(TEC_SYSARCH), x86_64) + TEC_WORDSIZE = TEC_64 +else +ifdef BUILD_64 + TEC_WORDSIZE = TEC_64 +else + TEC_WORDSIZE = TEC_32 +endif +endif + +# Itanium Exception +ifeq ($(TEC_SYSARCH), ia64) + TEC_BYTEORDER = TEC_LITTLEENDIAN + TEC_WORDSIZE = TEC_64 +endif + + +#---------------------------------# +# Compilation Flags +STDFLAGS := -Wall +STDDEFS := -DTEC_UNAME=$(TEC_UNAME) -DTEC_SYSNAME=$(TEC_SYSNAME) -D$(TEC_SYSNAME)=$(TEC_SYSRELEASE) -D$(TEC_BYTEORDER) -D$(TEC_WORDSIZE) -DFUNCPROTO=15 +STDINCS := +OPTFLAGS := -O2 +STDLFLAGS := r +DEBUGFLAGS := -g +STDLDFLAGS := -shared +DLIBEXT := so + +#---------------------------------# +# Build Tools + +CC := gcc +CPPC := g++ +FF := g77 +RANLIB := ranlib +AR := ar +DEBUGGER := gdb +RCC := windres +LD := gcc + +ifeq ($(TEC_UNAME), gcc2) + ifdef USE_GCC_2 + CC := $(CC)-2 + CPPC := $(CPPC)-2 + FF := $(FF)-2 + endif +endif + + +#---------------------------------# +# User Configuration File + +MAKENAME = config.mak + +ifdef MF + MAKENAME = $(MF).mak +endif + +################### +include $(MAKENAME) +################### + + +#---------------------------------# +# Definitions of public variables + +ifdef LIBNAME + TARGETNAME = $(LIBNAME) + MAKETYPE = LIB +else + TARGETNAME = $(APPNAME) + MAKETYPE = APP +endif + +ifndef TARGETNAME + $(error LIBNAME nor APPNAME defined in $(MAKENAME)) +endif + +PROJNAME ?= $(TARGETNAME) + +DEPEND := $(TARGETNAME).dep + +ifdef DEPENDDIR + DEPEND := $(DEPENDDIR)/$(TARGETNAME).dep.$(TEC_UNAME) +endif + +SRCLUADIR ?= $(SRCDIR) +LOHDIR ?= $(SRCLUADIR) + +ifeq ($(MAKETYPE), APP) + TARGETROOT ?= $(PROJDIR)/bin +else + TARGETROOT ?= $(PROJDIR)/lib +endif + +ifneq ($(PROJNAME), $(TARGETNAME)) + OBJROOT := $(OBJROOT)/$(TARGETNAME) +endif + +ifdef DBG + STDFLAGS += $(DEBUGFLAGS) + STDDEFS += -DDEBUG +else + STDDEFS += -DNDEBUG + ifdef OPT + STDFLAGS += $(OPTFLAGS) + ifeq ($(findstring gcc, $(TEC_UNAME)), ) + STRIP ?= Yes + endif + endif +endif + +ifdef BUILD_64 + ifneq ($(findstring SunOS, $(TEC_UNAME)), ) + USE_CC = Yes + BUILD_64_DIR = Yes + endif + ifneq ($(findstring AIX, $(TEC_UNAME)), ) + USE_CC = Yes + BUILD_64_DIR = Yes + endif + ifneq ($(findstring IRIX, $(TEC_UNAME)), ) + USE_CC = Yes + BUILD_64_DIR = Yes + endif +endif + +ifdef USE_CC + CC := cc + CPPC := CC + STDFLAGS = + ifdef USE_CC_DIR + TEC_UNAME := $(TEC_UNAME)cc + endif +endif + +ifdef BUILD_64 + ifdef BUILD_64_DIR + TEC_UNAME := $(TEC_UNAME)_64 + endif +endif + +TEC_UNAME_DIR := $(TEC_UNAME) +ifdef DBG + ifdef DBG_DIR + TEC_UNAME_DIR := $(TEC_UNAME_DIR)d + endif +endif + +OBJDIR := $(OBJROOT)/$(TEC_UNAME_DIR) +TARGETDIR := $(TARGETROOT)/$(TEC_UNAME_DIR) + +# Change linker if any C++ source +ifndef LINKER + ifneq "$(findstring .cpp, $(SRC))" "" + LINKER := $(CPPC) + else + LINKER := $(CC) + endif +endif + + +#---------------------------------# +# LO and LOH Suffix + +ifeq ($(TEC_BYTEORDER), TEC_BIGENDIAN) + ifeq ($(TEC_WORDSIZE), TEC_64) + LO_SUFFIX ?= _be64 + else + LO_SUFFIX ?= _be32 + endif +else + ifeq ($(TEC_WORDSIZE), TEC_64) + LO_SUFFIX ?= _le64 + else + LO_SUFFIX ?= + endif +endif + + +#---------------------------------# +# Platform specific variables + +# Definicoes para o X11 +X11_LIBS := Xmu Xt Xext X11 +#X11_LIB := +#X11_INC := #include <X11/X.h> + +# Definicoes para o OpenGL +OPENGL_LIBS := GLU GL +#OPENGL_LIB := +#OPENGL_INC := #include <GL/gl.h> and possibly +MOTIFGL_LIB := GLw #include <GL/GLwMDrawA.h> + +# Definicoes para o Motif +#MOTIF_LIB := +#MOTIF_INC := #include <Xm/Xm.h> + +# Definicoes para o GLUT +#GLUT_LIB := +#GLUT_INC := + + +ifneq ($(findstring cygw, $(TEC_UNAME)), ) + NO_DYNAMIC ?= Yes + X11_LIBS := Xpm $(X11_LIBS) + ifdef BUILD_64 + X11_LIB := /usr/X11R6/lib64 + else + X11_LIB := /usr/X11R6/lib + endif + X11_INC := /usr/X11R6/include + MOTIFGL_LIB := +endif + +ifneq ($(findstring Linux, $(TEC_UNAME)), ) + X11_LIBS := Xpm $(X11_LIBS) + ifdef BUILD_64 + ifeq ($(TEC_SYSARCH), ia64) + STDFLAGS += -fPIC + X11_LIB := /usr/X11R6/lib + else + STDFLAGS += -m64 -fPIC + X11_LIB := /usr/X11R6/lib64 + endif + else + X11_LIB := /usr/X11R6/lib + endif + X11_INC := /usr/X11R6/include + MOTIFGL_LIB := +endif + +ifneq ($(findstring IRIX, $(TEC_UNAME)), ) # any IRIX + LD = ld + STDLDFLAGS := -elf -shared -rdata_shared -soname lib$(TARGETNAME).so + RANLIB := /bin/true + X11_LIBS := Xmu Xt X11 + ifdef BUILD_64 + ifdef USE_CC + STDFLAGS += -64 -KPIC + STDLDFLAGS += -64 + LINKER += -64 + endif + X11_LIB := /usr/Motif-2.1/lib64 /usr/lib64 # 64-bit libs + else + X11_LIB := /usr/Motif-2.1/lib32 /usr/lib32 # N32 libs + endif + MOTIF_INC = /usr/Motif-2.1/include +endif + +ifneq ($(findstring AIX, $(TEC_UNAME)), ) + NO_DYNAMIC ?= Yes + ifdef BUILD_64 + ifdef USE_CC + STDFLAGS += -q64 # to compilers C and C++ + STDLFLAGS := -X64 $(STDLFLAGS) # to librarian + STDLDFLAGS += -64 + LINKER += -q64 # to linker + endif + endif +endif + +ifneq ($(findstring HP-UX, $(TEC_UNAME)), ) + NO_DYNAMIC ?= Yes + MOTIF_INC := /usr/include/Motif2.1 + X11_LIBS := Xt Xext X11 + OPENGL_LIB := /opt/graphics/OpenGL/lib + OPENGL_INC := /opt/graphics/OpenGL/include + STDDEFS := -DTEC_UNAME=$(TEC_UNAME) -DTEC_SYSNAME=$(TEC_SYSNAME) -D$(TEC_BYTEORDER) -D$(TEC_WORDSIZE) -DFUNCPROTO=15 + CC := aCC + CPPC := aCC + LINKER := aCC +endif + +ifneq ($(findstring SunOS, $(TEC_UNAME)), ) + LD = ld + STDLDFLAGS := -G + X11_INC := /usr/openwin/share/include + X11_LIB := /usr/openwin/lib + MOTIF_INC := /usr/dt/share/include + MOTIF_LIB := /usr/dt/lib + OPENGL_INC := /usr/openwin/share/include/X11 + GLUT_LIB := /usr/local/glut-3.7/lib/glut + GLUT_INC := /usr/local/glut-3.7/include + ifdef BUILD_64 + ifdef USE_CC + STDFLAGS += -xarch=v9 -KPIC + # have to force these PATHs because of a conflict with standard PATHs + STDLDFLAGS += -64 -L/usr/lib/64 -L/usr/ucblib/sparcv9 + LINKER += -xarch=v9 + endif + endif +endif + +ifneq ($(findstring Darwin, $(TEC_UNAME)), ) + X11_LIBS := Xmu Xp Xt Xext X11 + X11_LIB := /usr/X11R6/lib + X11_INC := /usr/X11R6/include + MOTIF_INC := /usr/OpenMotif/include + MOTIF_LIB := /usr/OpenMotif/lib + ifdef BUILD_DYLIB + STDLDFLAGS := -dynamiclib -install_name lib$(TARGETNAME).dylib + DLIBEXT := dylib + else + STDLDFLAGS := -bundle -undefined dynamic_lookup + endif +endif + +ifneq ($(findstring FreeBSD, $(TEC_UNAME)), ) + X11_LIB := /usr/X11R6/lib + X11_INC := /usr/X11R6/include +endif + + +################################ +# Allows an extra configuration file. +ifdef EXTRA_CONFIG +include $(EXTRA_CONFIG) +endif +################################ + + +#---------------------------------# +# Tecgraf Libraries Location +TECTOOLS_HOME ?= /home/tecgraf + +IUP=$(TECTOOLS_HOME)/iup +CD=$(TECTOOLS_HOME)/cd +IM=$(TECTOOLS_HOME)/im +LUA=$(TECTOOLS_HOME)/lua +LUA51?=$(TECTOOLS_HOME)/lua5.1 + + +#---------------------------------# +# Pre-defined libraries + +# Library order: +# user + iupcd + cd + iup + motif + X +# Library path order is the oposite + +ifdef USE_LUA + LUASUFX := + LIBLUASUFX := 3 +endif + +ifdef USE_LUA4 + LUASUFX := 4 + LIBLUASUFX := 4 + override USE_LUA = Yes + LUA := $(LUA4) +endif + +ifdef USE_LUA5 + LUASUFX := 5 + LIBLUASUFX := 5 + override USE_LUA = Yes + LUA := $(LUA5) +endif + +ifdef USE_LUA50 + LUASUFX := 50 + LIBLUASUFX := 5 + override USE_LUA = Yes + LUA := $(LUA50) + NO_LUALIB := Yes +endif + +ifdef USE_LUA51 + LUASUFX := 5.1 + LIBLUASUFX := 51 + override USE_LUA = Yes + LUA := $(LUA51) + NO_LUALIB := Yes +endif + +ifdef USE_IUPBETA + IUP := $(IUP)/beta +endif + +ifdef USE_CDBETA + CD := $(CD)/beta +endif + +ifdef USE_IMBETA + IM := $(IM)/beta +endif + +ifdef USE_GLUT + override USE_OPENGL = Yes +endif + +ifdef USE_IUPCONTROLS + override USE_CD = Yes + override USE_IUP = Yes + ifdef USE_IUPLUA + ifdef USE_STATIC + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupluacontrols$(LIBLUASUFX).a + else + LIBS += iupluacontrols$(LIBLUASUFX) + endif + override USE_CDLUA = Yes + endif + ifdef USE_STATIC + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupcontrols.a + else + LIBS += iupcontrols + endif +endif + +ifdef USE_IMLUA + override USE_IM = Yes + ifdef USE_STATIC + SLIB += $(IM)/lib/$(TEC_UNAME)/libimlua$(LIBLUASUFX).a + else + LIBS += imlua$(LIBLUASUFX) + endif +endif + +ifdef USE_CDLUA + override USE_CD = Yes + ifdef USE_STATIC + ifdef USE_IUP + ifndef USE_NEWNAMES + SLIB += $(CD)/lib/$(TEC_UNAME)/libcdluaiup$(LIBLUASUFX).a + endif + endif + SLIB += $(CD)/lib/$(TEC_UNAME)/libcdlua$(LIBLUASUFX).a + else + ifdef USE_IUP + ifndef USE_NEWNAMES + LIBS += cdluaiup$(LIBLUASUFX) + endif + endif + LIBS += cdlua$(LIBLUASUFX) + endif +endif + +ifdef USE_IUPLUA + override USE_IUP = Yes + ifdef USE_STATIC + ifdef USE_CD + ifdef USE_NEWNAMES + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupluacd$(LIBLUASUFX).a + endif + endif + ifdef USE_OPENGL + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupluagl$(LIBLUASUFX).a + endif + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiuplua$(LIBLUASUFX).a + else + ifdef USE_CD + ifdef USE_NEWNAMES + LIBS += iupluacd$(LIBLUASUFX) + endif + endif + ifdef USE_OPENGL + LIBS += iupluagl$(LIBLUASUFX) + endif + LIBS += iuplua$(LIBLUASUFX) + endif +endif + +ifdef USE_LUA + ifdef USE_STATIC + ifndef NO_LUALIB + SLIB += $(LUA)/lib/$(TEC_UNAME)/liblualib$(LUASUFX).a + endif + SLIB += $(LUA)/lib/$(TEC_UNAME)/liblua$(LUASUFX).a + else + ifndef NO_LUALIB + LIBS += lualib$(LUASUFX) + endif + LIBS += lua$(LUASUFX) + LDIR += $(LUA)/lib/$(TEC_UNAME) + endif + INCLUDES += $(LUA)/include + LUABINDIR := $(LUA)/bin/$(TEC_UNAME) + BIN2C := $(LUABINDIR)/bin2c$(LUASUFX) + LUAC := $(LUABINDIR)/luac$(LUASUFX) + LUABIN := $(LUABINDIR)/lua$(LUASUFX) +endif + +ifdef USE_IUP + ifdef USE_GTK + override USE_X11 = Yes + LIB_SFX = gtk + else + override USE_MOTIF = Yes + LIB_SFX = + endif + ifdef USE_STATIC + ifdef USE_CD + ifdef USE_NEWNAMES + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupcd.a + endif + endif + ifdef USE_OPENGL + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiupgl.a + endif + SLIB += $(IUP)/lib/$(TEC_UNAME)/libiup$(LIB_SFX).a + else + ifdef USE_CD + ifdef USE_NEWNAMES + LIBS += iupcd + endif + endif + ifdef USE_OPENGL + LIBS += iupgl + endif + LIBS += iup$(LIB_SFX) + LDIR += $(IUP)/lib/$(TEC_UNAME) + endif + INCLUDES += $(IUP)/include +endif + +ifdef USE_CD + override USE_X11 = Yes + ifdef USE_STATIC + ifdef USE_IUP + ifndef USE_NEWNAMES + SLIB += $(CD)/lib/$(TEC_UNAME)/libcdiup.a + endif + endif + ifdef USE_XRENDER + ifndef USE_NEWNAMES + SLIB += $(CD)/lib/$(TEC_UNAME)/libcdxrender.a + else + SLIB += $(CD)/lib/$(TEC_UNAME)/libcdcontextplus.a + endif + endif + SLIB += $(CD)/lib/$(TEC_UNAME)/libcd.a + ifdef USE_XRENDER + LIBS += Xrender Xft + else + ifndef USE_GTK + ifdef USE_NEWNAMES + # Freetype is included in GTK + SLIB += $(CD)/lib/$(TEC_UNAME)/libfreetype.a + endif + endif + endif + else + ifdef USE_XRENDER + ifndef USE_NEWNAMES + LIBS += cdxrender + else + LIBS += cdcontextplus + endif + endif + LIBS += cd + LDIR += $(CD)/lib/$(TEC_UNAME) + ifdef USE_XRENDER + LIBS += Xrender Xft + else + ifndef USE_GTK + ifdef USE_NEWNAMES + # Freetype is included in GTK + LIBS += freetype + endif + endif + endif + endif + INCLUDES += $(CD)/include +endif + +ifdef USE_IM + ifdef USE_STATIC + SLIB += $(IM)/lib/$(TEC_UNAME)/libim.a + else + LIBS += im + LDIR += $(IM)/lib/$(TEC_UNAME) + endif + INCLUDES += $(IM)/include +endif + +# All except gcc in Windows (Cygwin) +ifeq ($(findstring gcc, $(TEC_UNAME)), ) + +ifdef USE_GLUT + LIBS += glut + LDIR += $(GLUT_LIB) + STDINCS += $(GLUT_INC) +endif + +ifdef USE_OPENGL + override USE_X11 = Yes + ifdef USE_MOTIF + LIBS += $(MOTIFGL_LIB) + endif + LIBS += $(OPENGL_LIBS) + LDIR += $(OPENGL_LIB) + STDINCS += $(OPENGL_INC) +endif + +ifdef USE_MOTIF + override USE_X11 = Yes + LIBS += Xm + LDIR += $(MOTIF_LIB) + STDINCS += $(MOTIF_INC) +endif + +ifdef USE_GTK + override USE_X11 = Yes + LIBS += gtk-x11-2.0 gdk-x11-2.0 gdk_pixbuf-2.0 pango-1.0 pangox-1.0 gobject-2.0 gmodule-2.0 glib-2.0 + STDINCS += /usr/include/atk-1.0 /usr/include/gtk-2.0 /usr/include/cairo /usr/include/pango-1.0 /usr/include/glib-2.0 /usr/lib/glib-2.0/include /usr/lib/gtk-2.0/include +endif + +ifdef USE_X11 + LIBS += $(X11_LIBS) + LDIR += $(X11_LIB) + STDINCS += $(X11_INC) +endif + +LIBS += m + +else + # gcc in Windows + NO_DYNAMIC ?= Yes + STDDEFS += -DWIN32 + + ifdef USE_NOCYGWIN + STDFLAGS += -mno-cygwin + endif + + ifeq ($(MAKETYPE), APP) + TARGETDIR := $(TARGETROOT)/$(TEC_SYSNAME) + endif + + ifdef USE_GLUT + LIBS += glut32 + endif + + ifdef USE_OPENGL + LIBS += opengl32 glu32 glaux + endif + + LIBS += gdi32 winspool comdlg32 comctl32 ole32 + + ifdef USE_GTK + LIBS += gtk-win32-2.0 gdk-win32-2.0 gdk_pixbuf-2.0 pango-1.0 pangowin32-1.0 gobject-2.0 gmodule-2.0 glib-2.0 + LDIR += $(GTK)/lib + STDINCS += $(GTK)/include/atk-1.0 $(GTK)/include/gtk-2.0 $(GTK)/include/cairo $(GTK)/include/pango-1.0 $(GTK)/include/glib-2.0 $(GTK)/lib/glib-2.0/include $(GTK)/lib/gtk-2.0/include + endif + + APPTYPE ?= windows + + ifeq ($(APPTYPE), windows) + LFLAGS += -mwindows + + ifdef USE_NOCYGWIN + LFLAGS += -mno-cygwin + endif + endif +endif + + +#---------------------------------# +# Building compilation flags that are sets + +INCLUDES := $(addprefix -I, $(INCLUDES)) +STDINCS := $(addprefix -I, $(STDINCS)) +EXTRAINCS := $(addprefix -I, $(EXTRAINCS)) +DEFINES := $(addprefix -D, $(DEFINES)) + +LIBS := $(addprefix -l, $(LIBS)) +ifdef LDIR + LDIR := $(addprefix -L, $(LDIR)) +endif + + +#---------------------------------# +# Definitions of private variables + +# Library flags for application linker +LFLAGS += $(LDIR) $(LIBS) +# Library flags for dynamic library linker +ifdef ADDTO_LDFLAGS + LDFLAGS += $(LFLAGS) +endif + +# C compiler flags +CFLAGS = $(FLAGS) $(STDFLAGS) $(INCLUDES) $(STDINCS) $(EXTRAINCS) $(DEFINES) $(STDDEFS) +# C++ compiler flags +CXXFLAGS = $(CPPFLAGS) $(STDFLAGS) $(INCLUDES) $(STDINCS) $(EXTRAINCS) $(DEFINES) $(STDDEFS) + +# Sources with relative path +SOURCES := $(addprefix $(SRCDIR)/, $(SRC)) + +# Target for applications or libraries +ifeq ($(MAKETYPE), APP) + TARGET := $(TARGETDIR)/$(TARGETNAME) +else + ifeq ($(NO_DYNAMIC), Yes) + TARGET := $(TARGETDIR)/lib$(TARGETNAME).a + else + TARGET := $(TARGETDIR)/lib$(TARGETNAME).a $(TARGETDIR)/lib$(TARGETNAME).$(DLIBEXT) + endif +endif + +# OBJ: list of .o, without path +# OBJS: list of .o with relative path +OBJ = $(notdir $(SRC)) +OBJ := $(OBJ:.c=.o) +OBJ := $(OBJ:.cpp=.o) +OBJ := $(OBJ:.cxx=.o) +OBJ := $(OBJ:.cc=.o) +OBJ := $(OBJ:.f=.o) +OBJ := $(OBJ:.for=.o) +OBJ := $(OBJ:.rc=.ro) +OBJS = $(addprefix $(OBJDIR)/, $(OBJ)) + +# LOH: list of .loh, without path +# LOHS: list of .loh, with relative path +LO = $(notdir $(SRCLUA)) +LO := $(LO:.lua=$(LO_SUFFIX).lo) +LOS = $(addprefix $(OBJROOT)/, $(LO)) + +LOH = $(notdir $(SRCLUA)) +LOH := $(LOH:.lua=$(LO_SUFFIX).loh) +LOHS = $(addprefix $(LOHDIR)/, $(LOH)) + +# Construct VPATH variable +P-SRC = $(dir $(SRC)) +P-SRC += $(dir $(SRCLUA)) +VPATH = .:$(foreach dir,$(P-SRC),$(if $(dir)="./",:$(dir))) + + +#---------------------------------# +# Main Rule - Build Everything that it is necessary + +.PHONY: tecmake +ifeq ($(MAKETYPE), APP) + tecmake: print-start directories application scripts +else + ifeq ($(NO_DYNAMIC), Yes) + tecmake: print-start directories static-lib + else + tecmake: print-start directories static-lib dynamic-lib + endif +endif + +.PHONY: print-start +print-start: + @echo ''; echo 'Tecmake - Starting [ $(TARGETNAME):$(TEC_UNAME) ]' + + +#---------------------------------# +# Dynamic Library Build + +.PHONY: dynamic-lib +dynamic-lib: $(TARGETDIR)/lib$(TARGETNAME).$(DLIBEXT) + +$(TARGETDIR)/lib$(TARGETNAME).$(DLIBEXT) : $(LOHS) $(OBJS) $(EXTRADEPS) + $(LD) $(STDLDFLAGS) -o $@ $(OBJS) $(SLIB) $(LDFLAGS) + @echo 'Tecmake - Dynamic Library ($@) Done.'; echo '' + + +#---------------------------------# +# Static Library Build + +.PHONY: static-lib +static-lib: $(TARGETDIR)/lib$(TARGETNAME).a + +$(TARGETDIR)/lib$(TARGETNAME).a : $(LOHS) $(OBJS) $(EXTRADEPS) + $(AR) $(STDLFLAGS) $@ $(OBJS) $(SLIB) + -$(RANLIB) $@ + @echo 'Tecmake - Static Library ($@) Done.'; echo '' + + +#---------------------------------# +# Application Build + +.PHONY: application +application: $(TARGETDIR)/$(TARGETNAME) + +$(TARGETDIR)/$(TARGETNAME) : $(LOHS) $(OBJS) $(EXTRADEPS) + $(LINKER) -o $@ $(OBJS) $(SLIB) $(LFLAGS) + @if [ ! -z "$(STRIP)" ]; then \ + echo "Striping debug information" ;\ + strip $@ ;\ + fi + @echo 'Tecmake - Application ($@) Done.'; echo '' + + +#---------------------------------# +# Application Scripts + +# Script name +SRELEASE := $(SRCDIR)/$(TARGETNAME) + +.PHONY: scripts +ifdef NO_SCRIPTS + scripts: ; +else + scripts: $(SRELEASE) ; +endif + +$(SRELEASE): $(MAKENAME) + @echo 'Building script $(@F)' + @echo "#!/bin/csh" > $@ + @echo "# Script generated automatically by tecmake v$(VERSION)" >> $@ + @echo "# Remove the comment bellow to set the LD_LIBRARY_PATH if needed." >> $@ + @echo '#setenv LD_LIBRARY_PATH $(MYLIB1)/lib/$${TEC_UNAME}:$(MYLIB2)/lib/$${TEC_UNAME}:$$LD_LIBRARY_PATH' >> $@ + @echo 'if ( -r app.env ) source app.env' >> $@ + @echo 'exec $(TARGETROOT)/$$TEC_UNAME/$(TARGETNAME) $$*' >> $@ + @chmod a+x $@ + + +#---------------------------------# +# Directories Creation + +.PHONY: directories +directories: $(OBJDIR) $(TARGETDIR) $(EXTRADIR) + +$(OBJDIR) $(TARGETDIR): + if [ ! -d $@ ] ; then mkdir -p $@ ; fi + +ifdef EXTRADIR + $(EXTRADIR): + if [ ! -d $@ ] ; then mkdir -p $@ ; fi +else + $(EXTRADIR): ; +endif + + +#---------------------------------# +# Compilation Rules + +$(OBJDIR)/%.o: $(SRCDIR)/%.c + @echo Compiling $(<F)... + $(CC) -c $(CFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + @echo Compiling $(<F)... + $(CPPC) -c $(CXXFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.cxx + @echo Compiling $(<F)... + $(CPPC) -c $(CXXFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.cc + @echo Compiling $(<F)... + $(CPPC) -c $(CXXFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.f + @echo Compiling $(<F)... + $(FC) -c $(FFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.for + @echo Compiling $(<F)... + $(FC) -c $(FFLAGS) -o $@ $< + +$(OBJDIR)/%.ro: $(SRCDIR)/%.rc + @echo Compiling $(<F)... + $(RCC) $(RCFLAGS) -O coff -o $@ $< + +$(LOHDIR)/%.loh: $(OBJROOT)/%.lo + @echo Generating $(<F)... + $(BIN2C) $< > $@ + +$(OBJROOT)/%$(LO_SUFFIX).lo: $(SRCLUADIR)/%.lua + @echo Compiling $(<F)... + $(LUAC) -o $@ $< + + +#---------------------------------# +# Dependencies + +# make depend +# Build dependencies +.PHONY: depend +depend: $(DEPEND) + +$(DEPEND): $(MAKENAME) + ifdef SRC + @echo "" > $(DEPEND) + @which gcc 2> /dev/null 1>&2 ;\ + if [ $$? -eq 0 ]; then \ + echo "Building dependencies... (can be slow)" ;\ + g++ $(INCLUDES) $(DEFINES) $(STDDEFS) -MM $(SOURCES) | \ + sed -e '1,$$s/^\([^ ]\)/$$(OBJDIR)\/\1/' > $(DEPEND) ;\ + else \ + echo "" ;\ + echo "g++ not found. Dependencies can not be built." ;\ + echo "Must set USE_NODEPEND=Yes." ;\ + echo "" ;\ + exit 1 ;\ + fi + endif + +################### +ifndef USE_NODEPEND +include $(DEPEND) +endif +################### + + +#---------------------------------# +# Management Rules + +# make clean-extra +# Remove extra files +.PHONY: clean-extra +clean-extra: + rm -f $(DEPEND) $(SRELEASE) so_locations + +# make clean-lohs +# Remove Lua object inclusion files +.PHONY: clean-lohs +clean-lohs: + rm -f $(LOS) $(LOHS) + +# make clean-obj +# Remove object files +.PHONY: clean-obj +clean-obj: + rm -f $(OBJS) + +# make clean-target +# Remove target +.PHONY: clean-target +clean-target: + rm -f $(TARGET) + +# make clean +# Remove target and object files +.PHONY: clean +clean: clean-target clean-obj + +# make rebuild +# Remove symbols from executables +.PHONY: strip +strip: + test -r $(TARGETDIR)/$(TARGETNAME) && strip $(TARGETDIR)/$(TARGETNAME) + +# make rebuild +# Rebuild target and object files +.PHONY: rebuild +rebuild: clean-extra clean-lohs clean-obj clean-target tecmake + +# make relink +# Rebuild target without rebuilding object files +.PHONY: relink +relink: clean-target tecmake + +.PHONY: version +version: + @echo "Tecmake Compact Version $(VERSION)" + +#---------------------------------# diff --git a/src/wd.c b/src/wd.c new file mode 100644 index 0000000..85e01dd --- /dev/null +++ b/src/wd.c @@ -0,0 +1,473 @@ +/** \file + * \brief World Coordinate Functions + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <memory.h> + +#include "cd.h" +#include "wd.h" + +#include "cd_private.h" + + +static void wdUpdateTransformation(cdCanvas* canvas) +{ + if (canvas->window.xmax != canvas->window.xmin) + canvas->sx = (canvas->viewport.xmax - canvas->viewport.xmin)/(canvas->window.xmax - canvas->window.xmin); + else + canvas->sx = 0; + canvas->tx = canvas->viewport.xmin - canvas->window.xmin*canvas->sx; + + if (canvas->window.ymax != canvas->window.ymin) + canvas->sy = (canvas->viewport.ymax - canvas->viewport.ymin)/(canvas->window.ymax - canvas->window.ymin); + else + canvas->sy = 0; + canvas->ty = canvas->viewport.ymin - canvas->window.ymin*canvas->sy; + + canvas->s = sqrt(canvas->sx * canvas->sx + canvas->sy * canvas->sy); +} + +void wdSetDefaults(cdCanvas* canvas) +{ + canvas->window.xmin = 0; + canvas->window.xmax = canvas->w_mm; + canvas->window.ymin = 0; + canvas->window.ymax = canvas->h_mm; + + canvas->viewport.xmin = 0; + canvas->viewport.xmax = canvas->w-1; + canvas->viewport.ymin = 0; + canvas->viewport.ymax = canvas->h-1; + + wdUpdateTransformation(canvas); +} + +void wdCanvasWindow(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + canvas->window.xmin = xmin; + canvas->window.xmax = xmax; + canvas->window.ymin = ymin; + canvas->window.ymax = ymax; + + wdUpdateTransformation(canvas); +} + +void wdCanvasGetWindow (cdCanvas* canvas, double *xmin, double *xmax, double *ymin, double *ymax) +{ + if (xmin) *xmin = canvas->window.xmin; + if (xmax) *xmax = canvas->window.xmax; + if (ymin) *ymin = canvas->window.ymin; + if (ymax) *ymax = canvas->window.ymax; +} + +void wdCanvasViewport(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax) +{ + canvas->viewport.xmin = xmin; + canvas->viewport.xmax = xmax; + canvas->viewport.ymin = ymin; + canvas->viewport.ymax = ymax; + + wdUpdateTransformation(canvas); +} + +void wdCanvasGetViewport(cdCanvas* canvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + if (xmin) *xmin = canvas->viewport.xmin; + if (xmax) *xmax = canvas->viewport.xmax; + if (ymin) *ymin = canvas->viewport.ymin; + if (ymax) *ymax = canvas->viewport.ymax; +} + +#define _wWorld2Canvas(_canvas, _xw, _yw, _xv, _yv) \ +{ \ + _xv = cdRound(_canvas->sx*(_xw) + _canvas->tx); \ + _yv = cdRound(_canvas->sy*(_yw) + _canvas->ty); \ +} + +#define _wfWorld2Canvas(_canvas, _xw, _yw, _xv, _yv) \ +{ \ + _xv = (_canvas->sx*(_xw) + _canvas->tx); \ + _yv = (_canvas->sy*(_yw) + _canvas->ty); \ +} + +void wdCanvasWorld2Canvas(cdCanvas* canvas, double xw, double yw, int *xv, int *yv) +{ + if (xv) *xv = cdRound(canvas->sx*xw + canvas->tx); + if (yv) *yv = cdRound(canvas->sy*yw + canvas->ty); +} + +#define _wWorld2CanvasSize(_canvas, _Ww, _Hw, _Wv, _Hv) \ +{ \ + _Wv = cdRound(_canvas->sx*(_Ww)); \ + _Hv = cdRound(_canvas->sy*(_Hw)); \ +} + +#define _wfWorld2CanvasSize(_canvas, _Ww, _Hw, _Wv, _Hv) \ +{ \ + _Wv = (_canvas->sx*(_Ww)); \ + _Hv = (_canvas->sy*(_Hw)); \ +} + +void wdCanvasWorld2CanvasSize(cdCanvas* canvas, double hw, double vw, int *hv, int *vv) +{ + if (hv) *hv = cdRound(canvas->sx*hw); + if (vv) *vv = cdRound(canvas->sy*vw); +} + +#define _wCanvas2World(_canvas, _xv, _yv, _xw, _yw) \ +{ \ + _xw = ((double)(_xv) - _canvas->tx)/_canvas->sx; \ + _yw = ((double)(_yv) - _canvas->ty)/_canvas->sy; \ +} + +void wdCanvasCanvas2World(cdCanvas* canvas, int xv, int yv, double *xw, double *yw) +{ + if (xw) *xw = ((double)xv - canvas->tx)/canvas->sx; + if (yw) *yw = ((double)yv - canvas->ty)/canvas->sy; +} + +void wdCanvasClipArea(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + int xminr, xmaxr, yminr, ymaxr; + + _wWorld2Canvas(canvas, xmin, ymin, xminr, yminr); + _wWorld2Canvas(canvas, xmax, ymax, xmaxr, ymaxr); + + cdCanvasClipArea(canvas, xminr, xmaxr, yminr, ymaxr); +} + +int wdCanvasIsPointInRegion(cdCanvas* canvas, double x, double y) +{ + int xr, yr; + _wWorld2Canvas(canvas, x, y, xr, yr); + return cdCanvasIsPointInRegion(canvas, xr, yr); +} + +void wdCanvasOffsetRegion(cdCanvas* canvas, double x, double y) +{ + int xr, yr; + _wWorld2Canvas(canvas, x, y, xr, yr); + cdCanvasOffsetRegion(canvas, xr, yr); +} + +void wdCanvasGetRegionBox(cdCanvas* canvas, double *xmin, double *xmax, double *ymin, double *ymax) +{ + int xminr, xmaxr, yminr, ymaxr; + cdCanvasGetRegionBox(canvas, &xminr, &xmaxr, &yminr, &ymaxr); + _wCanvas2World(canvas, xminr, yminr, *xmin, *ymin); + _wCanvas2World(canvas, xmaxr, ymaxr, *xmax, *ymax); +} + +int wdCanvasGetClipArea(cdCanvas* canvas, double *xmin, double *xmax, double *ymin, double *ymax) +{ + int xminr, xmaxr, yminr, ymaxr; + int clip = cdCanvasGetClipArea(canvas, &xminr, &xmaxr, &yminr, &ymaxr); + _wCanvas2World(canvas, xminr, yminr, *xmin, *ymin); + _wCanvas2World(canvas, xmaxr, ymaxr, *xmax, *ymax); + return clip; +} + +void wdCanvasLine(cdCanvas* canvas, double x1, double y1, double x2, double y2) +{ + double xr1, xr2, yr1, yr2; + _wfWorld2Canvas(canvas, x1, y1, xr1, yr1); + _wfWorld2Canvas(canvas, x2, y2, xr2, yr2); + cdfCanvasLine(canvas, xr1, yr1, xr2, yr2); +} + +void wdCanvasBox(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + double xminr, xmaxr, yminr, ymaxr; + _wfWorld2Canvas(canvas, xmin, ymin, xminr, yminr); + _wfWorld2Canvas(canvas, xmax, ymax, xmaxr, ymaxr); + cdfCanvasBox(canvas, xminr, xmaxr, yminr, ymaxr); +} + +void wdCanvasRect(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) +{ + double xminr, xmaxr, yminr, ymaxr; + _wfWorld2Canvas(canvas, xmin, ymin, xminr, yminr); + _wfWorld2Canvas(canvas, xmax, ymax, xmaxr, ymaxr); + cdfCanvasRect(canvas, xminr, xmaxr, yminr, ymaxr); +} + +void wdCanvasArc(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + double xcr, ycr, wr, hr; + _wfWorld2Canvas(canvas, xc, yc, xcr, ycr); + _wfWorld2CanvasSize(canvas, w, h, wr, hr); + cdfCanvasArc(canvas, xcr, ycr, wr, hr, angle1, angle2); +} + +void wdCanvasSector(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + double xcr, ycr, wr, hr; + _wfWorld2Canvas(canvas, xc, yc, xcr, ycr); + _wfWorld2CanvasSize(canvas, w, h, wr, hr); + cdfCanvasSector(canvas, xcr, ycr, wr, hr, angle1, angle2); +} + +void wdCanvasChord(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) +{ + double xcr, ycr, wr, hr; + _wfWorld2Canvas(canvas, xc, yc, xcr, ycr); + _wfWorld2CanvasSize(canvas, w, h, wr, hr); + cdfCanvasChord(canvas, xcr, ycr, wr, hr, angle1, angle2); +} + +void wdCanvasText(cdCanvas* canvas, double x, double y, const char *s) +{ + double xr, yr; + _wfWorld2Canvas(canvas, x, y, xr, yr); + cdfCanvasText(canvas, xr, yr, s); +} + +void wdCanvasVertex(cdCanvas* canvas, double x, double y) +{ + double xr, yr; + _wfWorld2Canvas(canvas, x, y, xr, yr); + cdfCanvasVertex(canvas, xr, yr); +} + +void wdCanvasMark(cdCanvas* canvas, double x, double y) +{ + int xr, yr; + _wWorld2Canvas(canvas, x, y, xr, yr); + cdCanvasMark(canvas, xr, yr); +} + +void wdCanvasPixel(cdCanvas* canvas, double x, double y, long color) +{ + int xr, yr; + _wWorld2Canvas(canvas, x, y, xr, yr); + cdCanvasPixel(canvas, xr, yr, color); +} + +void wdCanvasPutImageRect(cdCanvas* canvas, cdImage* image, double x, double y, int xmin, int xmax, int ymin, int ymax) +{ + int xr, yr; + _wWorld2Canvas(canvas, x, y, xr, yr); + cdCanvasPutImageRect(canvas, image, xr, yr, xmin, xmax, ymin, ymax); +} + +void wdCanvasPutImageRectRGB(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + int xr, yr, wr, hr; + _wWorld2Canvas(canvas, x, y, xr, yr); + _wWorld2CanvasSize(canvas, w, h, wr, hr); + cdCanvasPutImageRectRGB(canvas, iw, ih, r, g, b, xr, yr, wr, hr, xmin, xmax, ymin, ymax); +} + +void wdCanvasPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + int xr, yr, wr, hr; + _wWorld2Canvas(canvas, x, y, xr, yr); + _wWorld2CanvasSize(canvas, w, h, wr, hr); + cdCanvasPutImageRectRGBA(canvas, iw, ih, r, g, b, a, xr, yr, wr, hr, xmin, xmax, ymin, ymax); +} + +void wdCanvasPutImageRectMap(cdCanvas* canvas, int iw, int ih, const unsigned char *index, const long *colors, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) +{ + int xr, yr, wr, hr; + _wWorld2Canvas(canvas, x, y, xr, yr); + _wWorld2CanvasSize(canvas, w, h, wr, hr); + cdCanvasPutImageRectMap(canvas, iw, ih, index, colors, xr, yr, wr, hr, xmin, xmax, ymin, ymax); +} + +void wdCanvasPutBitmap(cdCanvas* canvas, cdBitmap* image, double x, double y, double w, double h) +{ + int xr, yr, wr, hr; + _wWorld2Canvas(canvas, x, y, xr, yr); + _wWorld2CanvasSize(canvas, w, h, wr, hr); + cdCanvasPutBitmap(canvas, image, xr, yr, wr, hr); +} + +double wdCanvasLineWidth(cdCanvas* canvas, double width_mm) +{ + int width; + double line_width_mm = canvas->line_width/canvas->xres; + + if (width_mm == CD_QUERY) + return line_width_mm; + + width = cdRound(width_mm*canvas->xres); + if (width < 1) width = 1; + + cdCanvasLineWidth(canvas, width); + + return line_width_mm; +} + +int wdCanvasFont(cdCanvas* canvas, const char* type_face, int style, double size_mm) +{ + return cdCanvasFont(canvas, type_face, style, cdRound(size_mm*CD_MM2PT)); +} + +void wdCanvasGetFont(cdCanvas* canvas, char *type_face, int *style, double *size) +{ + int point_size; + cdCanvasGetFont(canvas, type_face, style, &point_size); + if (point_size<0) + { + if (size) cdCanvasPixel2MM(canvas, -point_size, 0, size, NULL); + } + else + { + if (size) *size = ((double)point_size) / CD_MM2PT; + } +} + +double wdCanvasMarkSize(cdCanvas* canvas, double size_mm) +{ + int size; + double mark_size_mm = canvas->mark_size/canvas->xres; + + if (size_mm == CD_QUERY) + return mark_size_mm; + + size = cdRound(size_mm*canvas->xres); + if (size < 1) size = 1; + + canvas->mark_size = size; + + return mark_size_mm; +} + +void wdCanvasGetFontDim(cdCanvas* canvas, double *max_width, double *height, double *ascent, double *descent) +{ + double origin_x, origin_y, tmp = 0; + double distance_x, distance_y; + int font_max_width, font_height, font_ascent, font_descent; + cdCanvasGetFontDim(canvas, &font_max_width, &font_height, &font_ascent, &font_descent); + _wCanvas2World(canvas, 0, 0, origin_x, origin_y); + _wCanvas2World(canvas, font_max_width, font_height, distance_x, distance_y); + if (max_width) *max_width = fabs(distance_x - origin_x); + if (height) *height = fabs(distance_y - origin_y); + _wCanvas2World(canvas, tmp, font_ascent, tmp, distance_y); + if (ascent) *ascent = fabs(distance_y - origin_y); + _wCanvas2World(canvas, tmp, font_descent, tmp, distance_y); + if (descent) *descent = fabs(distance_y - origin_y); +} + +void wdCanvasGetTextSize(cdCanvas* canvas, const char *s, double *width, double *height) +{ + int text_width, text_height; + double origin_x, origin_y; + double text_x, text_y; + _wCanvas2World(canvas, 0, 0, origin_x, origin_y); + cdCanvasGetTextSize(canvas, s, &text_width, &text_height); + _wCanvas2World(canvas, text_width, text_height, text_x, text_y); + if (width) *width = fabs(text_x - origin_x); + if (height) *height = fabs(text_y - origin_y); +} + +void wdCanvasGetTextBox(cdCanvas* canvas, double x, double y, const char *s, double *xmin, double *xmax, double *ymin, double *ymax) +{ + int rx, ry, rxmin, rxmax, rymin, rymax; + + _wWorld2Canvas(canvas, x, y, rx, ry); + cdCanvasGetTextBox(canvas, rx, ry, s, &rxmin, &rxmax, &rymin, &rymax); + + _wCanvas2World(canvas, rxmin, rymin, *xmin, *ymin); + _wCanvas2World(canvas, rxmax, rymax, *xmax, *ymax); +} + +void wdCanvasGetTextBounds(cdCanvas* canvas, double x, double y, const char *s, double *rect) +{ + int rx, ry, rrect[8]; + + _wWorld2Canvas(canvas, x, y, rx, ry); + cdCanvasGetTextBounds(canvas, rx, ry, s, rrect); + + _wCanvas2World(canvas, rrect[0], rrect[1], rect[0], rect[1]); + _wCanvas2World(canvas, rrect[2], rrect[3], rect[2], rect[3]); + _wCanvas2World(canvas, rrect[4], rrect[5], rect[4], rect[5]); + _wCanvas2World(canvas, rrect[6], rrect[7], rect[6], rect[7]); +} + +void wdCanvasPattern(cdCanvas* canvas, int w, int h, const long *color, double w_mm, double h_mm) +{ + long *pattern = 0; + int w_pxl, h_pxl, x, y, cx, cy; + int wratio, hratio; + int *XTab, *YTab; + + cdCanvasMM2Pixel(canvas, w_mm, h_mm, &w_pxl, &h_pxl); + + wratio = cdRound((double)w_pxl/(double)w); + hratio = cdRound((double)h_pxl/(double)h); + + wratio = (wratio <= 0)? 1: wratio; + hratio = (hratio <= 0)? 1: hratio; + + w_pxl = wratio * w; + h_pxl = hratio * h; + + pattern = (long*)malloc(w_pxl*h_pxl*sizeof(long)); + + XTab = cdGetZoomTable(w_pxl, w, 0); + YTab = cdGetZoomTable(h_pxl, h, 0); + + for (y=0; y<h_pxl; y++) + { + cy = YTab[y]; + for (x=0; x<w_pxl; x++) + { + cx = XTab[x]; + pattern[x + y*w_pxl] = color[cx + cy*w]; + } + } + + cdCanvasPattern(canvas, w_pxl, h_pxl, pattern); + + free(XTab); + free(YTab); + free(pattern); +} + +void wdCanvasStipple(cdCanvas* canvas, int w, int h, const unsigned char *fgbg, double w_mm, double h_mm) +{ + unsigned char *stipple = 0; + int w_pxl, h_pxl, x, y, cx, cy; + int wratio, hratio; + int *XTab, *YTab; + + cdCanvasMM2Pixel(canvas, w_mm, h_mm, &w_pxl, &h_pxl); + + wratio = cdRound((double)w_pxl/(double)w); + hratio = cdRound((double)h_pxl/(double)h); + + wratio = (wratio <= 0)? 1: wratio; + hratio = (hratio <= 0)? 1: hratio; + + w_pxl = wratio * w; + h_pxl = hratio * h; + + stipple = (unsigned char*)malloc(w_pxl*h_pxl); + + XTab = cdGetZoomTable(w_pxl, w, 0); + YTab = cdGetZoomTable(h_pxl, h, 0); + + for (y=0; y<h_pxl; y++) + { + cy = YTab[y]; + for (x=0; x<w_pxl; x++) + { + cx = XTab[x]; + stipple[x + y*w_pxl] = fgbg[cx + cy*w]; + } + } + + cdCanvasStipple(canvas, w_pxl, h_pxl, stipple); + + free(XTab); + free(YTab); + free(stipple); +} + diff --git a/src/wdhdcpy.c b/src/wdhdcpy.c new file mode 100644 index 0000000..f804d17 --- /dev/null +++ b/src/wdhdcpy.c @@ -0,0 +1,101 @@ +/** \file + * \brief WD Hardcopy Client function + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cd.h" +#include "wd.h" + +/* from cd_private.h */ +int cdRound(double x); + +/* re-declared here to ignore CD_NO_OLD_INTERFACE definition */ +int cdActivate(cdCanvas* canvas); +cdCanvas* cdActiveCanvas(void); + +/* +** --------------------------------------------------------------- +** Private functions: +*/ + +static void _wdHdcpyDoit(cdCanvas *canvas, cdCanvas *canvas_copy, void (*draw_func)(cdCanvas *canvas_copy)) +{ + cdCanvas *old_active; + double left, right, bottom, top; /* canvas visualization window */ + int canvas_hsize, canvas_vsize; /* canvas sizes in pixels */ + int hdcpy_hsize, hdcpy_vsize; /* paper sizes in points */ + double canvas_vpr; /* canvas viewport distortion ratio */ + double hdcpy_vpr; /* paper viewport distortion ratio */ + int xc, yc; /* paper center in pixels */ + int xmin, xmax, ymin, ymax; /* paper viewport */ + + /* Activate canvas visualization surface. */ + if (cdCanvasActivate(canvas) != CD_OK) return; + + /* Get current canvas window parameters and sizes. */ + wdCanvasGetWindow(canvas, &left, &right, &bottom, &top); + cdCanvasGetSize(canvas, &canvas_hsize, &canvas_vsize, 0L, 0L); + + /* Activate hardcopy visualization surface. */ + if (cdCanvasActivate(canvas_copy) != CD_OK) return; + + /* Set window parameters on hardcopy surface. */ + wdCanvasWindow(canvas_copy, left, right, bottom, top); + + /* Adjust paper viewport, centralized, matching canvas viewport. */ + canvas_vpr = (double)canvas_vsize / (double)canvas_hsize; + cdCanvasGetSize(canvas_copy, &hdcpy_hsize, &hdcpy_vsize, 0L, 0L); + hdcpy_vpr = (double)hdcpy_vsize / (double)hdcpy_hsize; + xc = (int)((double)hdcpy_hsize/2.0); + yc = (int)((double)hdcpy_vsize/2.0); + + if (canvas_vpr < hdcpy_vpr) + { + xmin = 0; + xmax = hdcpy_hsize; + ymin = yc - (int)((double)hdcpy_hsize*(double)canvas_vpr/2.0); + ymax = yc + (int)((double)hdcpy_hsize*(double)canvas_vpr/2.0); + } + else + { + xmin = xc - (int)((double)hdcpy_vsize/(double)canvas_vpr/2.0); + xmax = xc + (int)((double)hdcpy_vsize/(double)canvas_vpr/2.0); + ymin = 0; + ymax = hdcpy_vsize; + } + + cdCanvasClipArea(canvas_copy, xmin, xmax, ymin, ymax); + cdCanvasClip(canvas_copy, CD_CLIPAREA); + wdCanvasViewport(canvas_copy, xmin, xmax, ymin, ymax); + + /* for backward compatibility */ + old_active = cdActiveCanvas(); + cdActivate(canvas_copy); + + /* Draw on hardcopy surface. */ + draw_func(canvas_copy); + + if (old_active) cdActivate(old_active); +} + +/* +** --------------------------------------------------------------- +** Entry points begin here: +*/ + +void wdCanvasHardcopy(cdCanvas *canvas, cdContext* ctx, void *data, void(*draw_func)(cdCanvas *canvas_copy)) +{ + /* Create a visualization surface. */ + cdCanvas *canvas_copy = cdCreateCanvas(ctx, data); + if (!canvas_copy) return; + + /* Do hardcopy. */ + _wdHdcpyDoit(canvas, canvas_copy, draw_func); + + /* Destroy visualization surface. */ + cdKillCanvas(canvas_copy); +} diff --git a/src/win32/cdwclp.c b/src/win32/cdwclp.c new file mode 100644 index 0000000..e39cb7f --- /dev/null +++ b/src/win32/cdwclp.c @@ -0,0 +1,551 @@ +/** \file + * \brief Windows Clipboard Driver + * + * See Copyright Notice in cd.h + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdemf.h" +#include "cdwmf.h" +#include "cdmf_private.h" + + +static cdSizeCB cdsizecb = NULL; + +static int cdregistercallback(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecb = (cdSizeCB)func; + return CD_OK; + } + + return CD_ERROR; +} + +/* +%F cdPlay para Clipboard. +Interpreta os dados do clipboard, seja metafile ou bitmap. +*/ +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char tmpPath[512]; + char filename[1024]; + HANDLE hFile; + DWORD dwSize, nBytesWrite; + int err; + char* buffer; + + if (IsClipboardFormatAvailable(CF_TEXT)) + { + HANDLE Handle; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + OpenClipboard(NULL); + Handle = GetClipboardData(CF_TEXT); + if (Handle == NULL) + { + CloseClipboard(); + return CD_ERROR; + } + + buffer = (char*)GlobalLock(Handle); + dwSize = (DWORD)strlen(buffer); + + hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL); + CloseHandle(hFile); + + GlobalUnlock(Handle); + + CloseClipboard(); + + err = cdCanvasPlay(canvas, CD_METAFILE, xmin, xmax, ymin, ymax, filename); + + DeleteFile(filename); + + if (err == CD_OK) + return err; + } + + if (IsClipboardFormatAvailable(CF_ENHMETAFILE)) + { + HENHMETAFILE Handle; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + OpenClipboard(NULL); + Handle = (HENHMETAFILE)GetClipboardData(CF_ENHMETAFILE); + if (Handle == NULL) + { + CloseClipboard(); + return CD_ERROR; + } + + dwSize = GetEnhMetaFileBits(Handle, 0, NULL); + + buffer = (char*)malloc(dwSize); + + GetEnhMetaFileBits(Handle, dwSize, buffer); + + hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL); + CloseHandle(hFile); + + free(buffer); + + CloseClipboard(); + + err = cdCanvasPlay(canvas, CD_EMF, xmin, xmax, ymin, ymax, filename); + + DeleteFile(filename); + + return err; + } + + if (IsClipboardFormatAvailable(CF_METAFILEPICT)) + { + HANDLE Handle; + METAFILEPICT* lpMFP; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + OpenClipboard(NULL); + Handle = GetClipboardData(CF_METAFILEPICT); + if (Handle == NULL) + { + CloseClipboard(); + return CD_ERROR; + } + + lpMFP = (METAFILEPICT*) GlobalLock(Handle); + + dwSize = GetMetaFileBitsEx(lpMFP->hMF, 0, NULL); + buffer = (char*)malloc(dwSize); + + GetMetaFileBitsEx(lpMFP->hMF, dwSize, buffer); + + hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + wmfWritePlacebleFile(hFile, buffer, dwSize, lpMFP->mm, lpMFP->xExt, lpMFP->yExt); + CloseHandle(hFile); + + GlobalUnlock(Handle); + free(buffer); + + CloseClipboard(); + + err = cdCanvasPlay(canvas, CD_WMF, xmin, xmax, ymin, ymax, filename); + + DeleteFile(filename); + + return err; + } + + if (IsClipboardFormatAvailable(CF_DIB)) + { + HANDLE Handle; + int size; + cdwDIB dib; + + OpenClipboard(NULL); + Handle = GetClipboardData(CF_DIB); + if (Handle == NULL) + { + CloseClipboard(); + return CD_ERROR; + } + + cdwDIBReference(&dib, (BYTE*) GlobalLock(Handle), NULL); + + if (dib.type == -1) + { + GlobalUnlock(Handle); + CloseClipboard(); + return CD_ERROR; + } + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, dib.w, dib.h, dib.w, dib.h); + if (err) + { + GlobalUnlock(Handle); + CloseClipboard(); + return CD_ERROR; + } + } + + size = dib.w*dib.h; + + if (xmax == 0) xmax = dib.w + xmin - 1; + if (ymax == 0) ymax = dib.h + ymin - 1; + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, dib.h, r, g, b, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, dib.h, index, colors, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1, 0, 0, 0, 0); + + free(index); + free(colors); + } + + GlobalUnlock(Handle); + + CloseClipboard(); + + return CD_ERROR; + } + + if (IsClipboardFormatAvailable(CF_BITMAP)) + { + HBITMAP Handle; + int size, type; + cdwDIB dib; + HDC ScreenDC; + SIZE sz; + + OpenClipboard(NULL); + Handle = GetClipboardData(CF_BITMAP); + if (Handle == NULL) + { + CloseClipboard(); + return CD_ERROR; + } + + GetBitmapDimensionEx(Handle, &sz); + + ScreenDC = GetDC(NULL); + if (GetDeviceCaps(ScreenDC, BITSPIXEL) > 8) + type = 0; + else + type = 1; + + dib.w = sz.cx; + dib.h = sz.cy; + dib.type = type; + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, dib.w, dib.h, dib.w, dib.h); + if (err) + { + ReleaseDC(NULL, ScreenDC); + CloseClipboard(); + return CD_ERROR; + } + } + + cdwCreateDIB(&dib); + + GetDIBits(ScreenDC, Handle, 0, sz.cy, dib.bits, dib.bmi, DIB_RGB_COLORS); + ReleaseDC(NULL, ScreenDC); + + size = dib.w*dib.h; + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, dib.h, r, g, b, 0, 0, dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, dib.h, index, colors, 0, 0, dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdwKillDIB(&dib); + + CloseClipboard(); + + return CD_ERROR; + } + + return CD_ERROR; +} + +static void cdkillcanvasCLIPBDMF (cdCtxCanvas *ctxcanvas) +{ + HANDLE Handle, hFile; + char* buffer; + DWORD dwSize, nBytesRead; + char filename[10240]; + cdCanvasMF* mfcanvas = (cdCanvasMF*)ctxcanvas; + + /* guardar antes de remover o canvas */ + strcpy(filename, mfcanvas->filename); + + OpenClipboard(NULL); + EmptyClipboard(); + + cdkillcanvasMF(mfcanvas); /* this will close the file */ + + hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); + dwSize = GetFileSize (hFile, NULL) ; + + Handle = GlobalAlloc(GMEM_MOVEABLE, dwSize+1); + buffer = (char*)GlobalLock(Handle); + ReadFile(hFile, buffer, dwSize, &nBytesRead, NULL); + buffer[dwSize] = 0; + GlobalUnlock(Handle); + + CloseHandle(hFile); + + SetClipboardData(CF_TEXT, Handle); + + CloseClipboard(); +} + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + cdwKillCanvas(ctxcanvas); + + OpenClipboard(NULL); + EmptyClipboard(); + + if (ctxcanvas->wtype == CDW_WMF) + { + HMETAFILE hmf = CloseMetaFile(ctxcanvas->hDC); + + HANDLE hMemG; + METAFILEPICT* lpMFP; + + hMemG = GlobalAlloc(GHND|GMEM_DDESHARE, (DWORD)sizeof(METAFILEPICT)); + lpMFP = (METAFILEPICT*) GlobalLock(hMemG); + + lpMFP->mm = MM_ANISOTROPIC; + lpMFP->xExt = (long)(100 * ctxcanvas->canvas->w_mm); + lpMFP->yExt = (long)(100 * ctxcanvas->canvas->h_mm); + + lpMFP->hMF = hmf; + + GlobalUnlock(hMemG); + SetClipboardData(CF_METAFILEPICT, hMemG); + } + else if (ctxcanvas->wtype == CDW_EMF) + { + HENHMETAFILE hmf = CloseEnhMetaFile(ctxcanvas->hDC); + SetClipboardData(CF_ENHMETAFILE, hmf); + } + else + { + HANDLE hDib; + + GdiFlush(); + + hDib = cdwCreateCopyHDIB(&ctxcanvas->bmiClip, ctxcanvas->bitsClip); + + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBitmapClip); + DeleteObject(ctxcanvas->hBitmapClip); + DeleteDC(ctxcanvas->hDC); + + SetClipboardData(CF_DIB, hDib); + } + + CloseClipboard(); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char* strsize = (char*)data; + int w = 0, h = 0, wtype = CDW_EMF; /* default clipboard type */ + double xres=0, yres=0; + HDC hDC; + BITMAPINFO bmi; + BYTE* bits; + HBITMAP hBitmapClip, hOldBitmapClip; + + /* Inicializa parametros */ + if (strsize == NULL) + return; + + if (strstr(strsize, "-b") != NULL) + wtype = CDW_BMP; + else if (strstr(strsize, "-m") != NULL) + wtype = -1; /* CD METAFILE */ + + if (wtype != -1) + { + sscanf(strsize,"%dx%d",&w, &h); + if (w == 0 || h == 0) + return; + } + + if (wtype == CDW_EMF) + { + HDC ScreenDC = GetDC(NULL); + RECT rect; + /* LOGPIXELS can not be used for EMF */ + xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + rect.left = 0; + rect.top = 0; + rect.right = (int)(100. * w / xres); + rect.bottom = (int)(100. * h / yres); + hDC = CreateEnhMetaFile(ScreenDC,NULL,&rect,NULL); + ReleaseDC(NULL, ScreenDC); + } + else if (wtype == CDW_BMP) + { + HDC ScreenDC = GetDC(NULL); + hDC = CreateCompatibleDC(ScreenDC); + xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = (long)(GetDeviceCaps(ScreenDC, LOGPIXELSX) / 0.0254); + bmi.bmiHeader.biYPelsPerMeter = (long)(GetDeviceCaps(ScreenDC, LOGPIXELSY) / 0.0254); + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + hBitmapClip = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); + + ReleaseDC(NULL, ScreenDC); + + if (!hBitmapClip) + return; + + hOldBitmapClip = SelectObject(hDC, hBitmapClip); + } + + if (wtype == -1) + { + char filename[1024]; + char tmpPath[512]; + char str[1024]; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + sprintf(str, "%s %s", filename, strsize); + cdcreatecanvasMF(canvas, str); + } + else + { + cdCtxCanvas* ctxcanvas; + + /* Inicializa driver WIN32 */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, wtype); + + canvas->w = w; + canvas->h = h; + canvas->xres = xres; + canvas->yres = yres; + canvas->w_mm = ((double)w) / xres; + canvas->h_mm = ((double)h) / yres; + canvas->bpp = 24; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; + + if (wtype == CDW_BMP) + { + ctxcanvas->hBitmapClip = hBitmapClip; + ctxcanvas->hOldBitmapClip = hOldBitmapClip; + ctxcanvas->bmiClip = bmi; + ctxcanvas->bitsClip = bits; + } + } +} + +static void cdinittable(cdCanvas* canvas) +{ + if (canvas->invert_yaxis == 0) /* a simple way to distinguish MF from WIN */ + { + cdinittableMF(canvas); + canvas->cxKillCanvas = cdkillcanvasCLIPBDMF; + } + else + { + cdwInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; + } +} + +static cdContext cdClipboardContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + cdplay, + cdregistercallback +}; + +cdContext* cdContextClipboard(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_CLIPBOARD); + if (ctx != NULL) + return ctx; + } + + return &cdClipboardContext; +} diff --git a/src/win32/cdwdbuf.c b/src/win32/cdwdbuf.c new file mode 100644 index 0000000..035e29e --- /dev/null +++ b/src/win32/cdwdbuf.c @@ -0,0 +1,169 @@ +/** \file + * \brief Windows Double Buffer + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cddbuf.h" + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdKillImage(ctxcanvas->image_dbuffer); + cdwKillCanvas(ctxcanvas); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + int old_writemode; + cdImage* image_dbuffer = ctxcanvas->image_dbuffer; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + GdiFlush(); + + /* this is done in the canvas_dbuffer context */ + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + cdCanvasPutImageRect(canvas_dbuffer, image_dbuffer, 0, 0, 0, 0, 0, 0); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static void cdcreatecanvas(cdCanvas* canvas, cdCanvas* canvas_dbuffer) +{ + cdCtxCanvas* ctxcanvas; + cdImage* image_dbuffer; + cdCtxImage* ctximage; + + /* this is done in the canvas_dbuffer context */ + image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, canvas_dbuffer->w, canvas_dbuffer->h); + if (!image_dbuffer) + return; + + ctximage = image_dbuffer->ctximage; + + /* Inicializa driver DBuffer */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, ctximage->hDC, CDW_BMP); + + ctxcanvas->image_dbuffer = image_dbuffer; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; + + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->w_mm = ctximage->w_mm; + canvas->h_mm = ctximage->h_mm; + canvas->bpp = ctximage->bpp; + canvas->xres = ctximage->xres; + canvas->yres = ctximage->yres; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = ctximage->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = ctximage->h - 1; +} + +static int cdactivate(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->image_dbuffer->w || + canvas_dbuffer->h != ctxcanvas->image_dbuffer->h) + { + cdCanvas* canvas = ctxcanvas->canvas; + /* save the current, if the rebuild fail */ + cdImage* old_image_dbuffer = ctxcanvas->image_dbuffer; + cdCtxCanvas* old_ctxcanvas = ctxcanvas; + + /* if the image is rebuild, the canvas that uses the image must be also rebuild */ + + /* rebuild the image and the canvas */ + canvas->ctxcanvas = NULL; + cdcreatecanvas(canvas, canvas_dbuffer); + if (!canvas->ctxcanvas) + { + canvas->ctxcanvas = old_ctxcanvas; + return CD_ERROR; + } + + /* remove the old image and canvas */ + cdKillImage(old_image_dbuffer); + cdwKillCanvas(old_ctxcanvas); + free(old_ctxcanvas); + + ctxcanvas = canvas->ctxcanvas; + + /* update canvas attributes */ + canvas->cxBackground(ctxcanvas, canvas->background); + canvas->cxForeground(ctxcanvas, canvas->foreground); + canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity); + canvas->cxWriteMode(ctxcanvas, canvas->write_mode); + canvas->cxLineStyle(ctxcanvas, canvas->line_style); + canvas->cxLineWidth(ctxcanvas, canvas->line_width); + canvas->cxLineCap(ctxcanvas, canvas->line_cap); + canvas->cxLineJoin(ctxcanvas, canvas->line_join); + canvas->cxHatch(ctxcanvas, canvas->hatch_style); + if (canvas->stipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple); + if (canvas->pattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern); + canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style); + if (canvas->native_font[0] == 0) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + else canvas->cxNativeFont(ctxcanvas, canvas->native_font); + canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); + canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); + if (canvas->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix); + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax); +/* if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); */ + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n); +/* if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); */ + if (canvas->clip_mode != CD_CLIPOFF) canvas->cxClip(ctxcanvas, canvas->clip_mode); + } + + return CD_OK; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxFlush = cdflush; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdDBufferContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDBuffer(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_DBUFFER); + if (ctx != NULL) + return ctx; + } + + return &cdDBufferContext; +} diff --git a/src/win32/cdwdib.c b/src/win32/cdwdib.c new file mode 100644 index 0000000..aff3f64 --- /dev/null +++ b/src/win32/cdwdib.c @@ -0,0 +1,662 @@ +/** \file + * \brief Windows DIB Utilities + * + * See Copyright Notice in cd.h + */ + +#include "cdwin.h" + + +/* +%F Calcula o tamanho de uma linha. O DIB existe em uma "long boundary", +ou seja cada linha e' um multiplo de quatro bytes ou 32 bits. +*/ +static int cdwDIBLineSize(int width, int bpp) +{ + return ((width * bpp + 31L) / 32L) * 4L; +} + + +/* +%F Alloca memoria para o DIB com os par^ametros do cdwDIB. +*/ +int cdwCreateDIB(cdwDIB* dib) +{ + int dibSize, pal_size; + BITMAPINFOHEADER* bmih; + + pal_size = dib->type? 256: 0; + dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h; + + dib->dib = (BYTE*) calloc(dibSize, 1); + if (dib->dib == NULL) + return 0; + + dib->bmi = (BITMAPINFO*)dib->dib; + dib->bmih = (BITMAPINFOHEADER*)dib->dib; + dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER)); + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + + bmih = dib->bmih; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = dib->w; + bmih->biHeight = dib->h; + bmih->biPlanes = 1; + bmih->biBitCount = dib->type? 8: 24; + bmih->biCompression = 0; + bmih->biSizeImage = 0; + bmih->biXPelsPerMeter = 0; + bmih->biYPelsPerMeter = 0; + bmih->biClrUsed = dib->type? 256: 0; + bmih->biClrImportant = dib->type? 256: 0; + + return 1; +} + +HANDLE cdwCreateCopyHDIB(BITMAPINFO* bmi, BYTE* bits) +{ + int dibSize, pal_size, headerSize; + HANDLE hDib; unsigned char* pDib; + + if (bmi->bmiHeader.biBitCount > 8) + { + pal_size = 0; + + if (bmi->bmiHeader.biCompression == BI_BITFIELDS) + pal_size = 3; + } + else + { + if (bmi->bmiHeader.biClrUsed != 0) + pal_size = bmi->bmiHeader.biClrUsed; + else + pal_size = 1 << bmi->bmiHeader.biBitCount; + } + + /* calc size */ + headerSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + dibSize = headerSize + cdwDIBLineSize(bmi->bmiHeader.biWidth, bmi->bmiHeader.biBitCount) * bmi->bmiHeader.biHeight; + + hDib = GlobalAlloc(GHND, dibSize); + if (!hDib) + return NULL; + + /* Get a pointer to the memory block */ + pDib = (LPBYTE)GlobalLock(hDib); + + /* copy struct data */ + CopyMemory(pDib, bmi, headerSize); + + /* copy dib data */ + CopyMemory(pDib + headerSize, bits, dibSize - headerSize); + + GlobalUnlock(hDib); + + return hDib; +} + +int cdwCreateDIBRefBuffer(cdwDIB* dib, unsigned char* *bits, int *size) +{ + int dibSize, pal_size; + BITMAPINFOHEADER* bmih; + + pal_size = dib->type? 256: 0; + dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h; + + /* bits may contains an allocated buffer, but no dib */ + if (*bits && *size >= dibSize) + dib->dib = *bits; + else + { + *size = dibSize; + + if (*bits) + *bits = realloc(*bits, *size); + else + *bits = malloc(*size); + + dib->dib = *bits; + } + + if (dib->dib == NULL) + return 0; + + dib->bmi = (BITMAPINFO*)dib->dib; + dib->bmih = (BITMAPINFOHEADER*)dib->dib; + dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER)); + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + + bmih = dib->bmih; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = dib->w; + bmih->biHeight = dib->h; + bmih->biPlanes = 1; + bmih->biBitCount = dib->type? 8: 24; + bmih->biCompression = 0; + bmih->biSizeImage = 0; + bmih->biXPelsPerMeter = 0; + bmih->biYPelsPerMeter = 0; + bmih->biClrUsed = dib->type? 256: 0; + bmih->biClrImportant = dib->type? 256: 0; + + return 1; +} + +void cdwCreateDIBRefBits(cdwDIB* dib, unsigned char *bits) +{ + BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO)); + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = dib->w; + bmi->bmiHeader.biHeight = dib->h; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = dib->type==0? 24: 32; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biSizeImage = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; + + cdwDIBReference(dib, (BYTE*)bmi, bits); + + /* restore correct type */ + if (bmi->bmiHeader.biBitCount == 32) + dib->type = 2; +} + +HBITMAP cdwCreateDIBSection(cdwDIB* dib, HDC hDC) +{ + HBITMAP hbitmap; + BYTE *pvBits; + BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO)); + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = dib->w; + bmi->bmiHeader.biHeight = dib->h; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = dib->type==0? 24: 32; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biXPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSX) / 0.0254); + bmi->bmiHeader.biYPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSY) / 0.0254); + bmi->bmiHeader.biSizeImage = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; + + hbitmap = CreateDIBSection(hDC, bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0); + + if (hbitmap) + { + cdwDIBReference(dib, (BYTE*)bmi, pvBits); + + /* restore correct type */ + if (bmi->bmiHeader.biBitCount == 32) + dib->type = 2; + } + else + free(bmi); + + return hbitmap; +} + +void cdwDIBReference(cdwDIB* dib, BYTE* bmi, BYTE* bits) +{ + int pal_size; + + dib->dib = bmi; + + dib->bmi = (BITMAPINFO*)bmi; + dib->bmih = &dib->bmi->bmiHeader; + dib->bmic = dib->bmi->bmiColors; + + if (dib->bmih->biBitCount > 8) + { + dib->type = 0; + pal_size = 0; + + if (dib->bmih->biCompression == BI_BITFIELDS) + pal_size = 3; + } + else + { + dib->type = 1; + + if (dib->bmih->biClrUsed != 0) + pal_size = dib->bmih->biClrUsed; + else + pal_size = 1 << dib->bmih->biBitCount; + } + + if (bits == NULL) + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + else + dib->bits = bits; + + dib->w = dib->bmih->biWidth; + dib->h = dib->bmih->biHeight; +} + + +/* %F Libera a memoria alocada para o DIB. */ +void cdwKillDIB(cdwDIB* dib) +{ + free(dib->dib); +} + +/* %F Converte cor de CD para DIB. */ +static RGBQUAD sColorToDIB(long cd_color) +{ + RGBQUAD color; + color.rgbRed = cdRed(cd_color); + color.rgbGreen = cdGreen(cd_color); + color.rgbBlue = cdBlue(cd_color); + return color; +} + +void cdwDIBEncodeRGBRect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + red = red + offset; + green = green + offset; + blue = blue + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = *blue++; + *bits++ = *green++; + *bits++ = *red++; + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + } +} + +/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */ +#define CD_ALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255) + +void cdwDIBEncodeRGBARect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + red = red + offset; + green = green + offset; + blue = blue + offset; + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = CD_ALPHAPRE(*blue, *alpha); blue++; + *bits++ = CD_ALPHAPRE(*green, *alpha); green++; + *bits++ = CD_ALPHAPRE(*red, *alpha); red++; + *bits++ = *alpha++; + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + alpha += resto2; + } +} + +void cdwDIBEncodeAlphaRect(cdwDIB* dib, const unsigned char *alpha, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = *alpha++; + } + + bits += resto1; + alpha += resto2; + } +} + +void cdwDIBEncodeRGBARectZoom(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int w, int h, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + const unsigned char *_red, *_green, *_blue, *_alpha; + unsigned char a; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + + if (dib->w != wi || dib->h != hi) + { + int* XTab = cdGetZoomTable(dib->w, wi, xi); + int* YTab = cdGetZoomTable(dib->h, hi, yi); + + for (y = 0; y < dib->h; y++) + { + offset = YTab[y] * w; + _red = red + offset; + _green = green + offset; + _blue = blue + offset; + _alpha = alpha + offset; + + for (x = 0; x < dib->w; x++) + { + offset = XTab[x]; + a = _alpha[offset]; + *bits++ = CD_ALPHA_BLEND(_blue[offset], *bits, a); + *bits++ = CD_ALPHA_BLEND(_green[offset], *bits, a); + *bits++ = CD_ALPHA_BLEND(_red[offset], *bits, a); + } + + bits += resto1; + } + + free(XTab); + free(YTab); + } + else + { + resto2 = w - wi; + + offset = w * yi + xi; + red = red + offset; + green = green + offset; + blue = blue + offset; + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + a = *alpha++; + *bits++ = CD_ALPHA_BLEND(*blue++, *bits, a); + *bits++ = CD_ALPHA_BLEND(*green++, *bits, a); + *bits++ = CD_ALPHA_BLEND(*red++, *bits, a); + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + alpha += resto2; + } + } +} + +/* +%F Copia os pixels de um DIB em 3 matrizes red, green e +blue, respectivamente. As matrizes, armazenadas num vetor de bytes devem +ter a mesma dimens~ao da imagem. +*/ +void cdwDIBDecodeRGB(cdwDIB* dib, unsigned char *red, unsigned char *green, unsigned char *blue) +{ + int x,y, offset; + unsigned short color; + BYTE* bits; + unsigned long rmask=0, gmask=0, bmask=0, + roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */ + + bits = dib->bits; + + if (dib->bmih->biBitCount == 16) + offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount); + else + offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount) - dib->w * (dib->bmih->biBitCount == 24?3:4); + + if (dib->bmih->biCompression == BI_BITFIELDS) + { + unsigned long Mask; + unsigned long* palette = (unsigned long*)dib->bmic; + + rmask = Mask = palette[0]; + while (!(Mask & 0x01)) + {Mask >>= 1; roff++;} + + gmask = Mask = palette[1]; + while (!(Mask & 0x01)) + {Mask >>= 1; goff++;} + + bmask = Mask = palette[2]; + while (!(Mask & 0x01)) + {Mask >>= 1; boff++;} + } + else if (dib->bmih->biBitCount == 16) + { + bmask = 0x001F; + gmask = 0x03E0; + rmask = 0x7C00; + boff = 0; + goff = 5; + roff = 10; + } + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (dib->bmih->biBitCount != 16) + { + *blue++ = *bits++; + *green++ = *bits++; + *red++ = *bits++; + + if (dib->bmih->biBitCount == 32) + bits++; + } + else + { + color = ((unsigned short*)bits)[x]; + *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff)); + *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff)); + *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff)); + } + } + + bits += offset; + } +} + +void cdwDIBDecodeMap(cdwDIB* dib, unsigned char *index, long *colors) +{ + int x,y, line_size,c,pal_size; + BYTE* bits; + RGBQUAD* bmic; + + bmic = dib->bmic; + bits = dib->bits; + line_size = cdwDIBLineSize(dib->w, dib->bmih->biBitCount); + pal_size = dib->bmih->biClrUsed != 0? dib->bmih->biClrUsed: 1 << dib->bmih->biBitCount; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + switch (dib->bmih->biBitCount) + { + case 1: + *index++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01); + break; + case 4: + *index++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F); + break; + case 8: + *index++ = bits[x]; + break; + } + } + + bits += line_size; + } + + for (c = 0; c < pal_size; c++) + { + colors[c] = cdEncodeColor(bmic->rgbRed, bmic->rgbGreen, bmic->rgbBlue); + bmic++; + } +} + +/* +%F Cria uma Logical palette a partir da palette do DIB. +*/ +HPALETTE cdwDIBLogicalPalette(cdwDIB* dib) +{ + LOGPALETTE* pLogPal; + PALETTEENTRY* pPalEntry; + HPALETTE hPal; + RGBQUAD* bmic; + int c; + + pLogPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)); + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = 256; + + bmic = dib->bmic; + pPalEntry = pLogPal->palPalEntry; + + for (c = 0; c < 256; c++) + { + pPalEntry->peRed = bmic->rgbRed; + pPalEntry->peGreen = bmic->rgbGreen; + pPalEntry->peBlue = bmic->rgbBlue; + pPalEntry->peFlags = PC_NOCOLLAPSE; + + pPalEntry++; + bmic++; + } + + hPal = CreatePalette(pLogPal); + free(pLogPal); + + return hPal; +} + +/* +%F Copia os pixels definidos por uma matriz de indices e palheta de +de cores num DIB de mesma dimens~ao. +*/ +void cdwDIBEncodeMap(cdwDIB* dib, unsigned char *index, long int *colors) +{ + int x,y, pal_size, resto, c; + BYTE* bits; + RGBQUAD* bmic; + + bits = dib->bits; + bmic = dib->bmic; + resto = cdwDIBLineSize(dib->w, 8) - dib->w; + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = *index; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (*index > pal_size) + pal_size = *index; + + *bits++ = *index++; + } + + bits += resto; + } + + pal_size++; + + for (c = 0; c < pal_size; c++) + *bmic++ = sColorToDIB(colors[c]); +} + +void cdwDIBEncodeMapRect(cdwDIB* dib, const unsigned char *index, const long int *colors, int xi, int yi, int wi, int hi) +{ + int x,y, pal_size, resto1, resto2, c; + BYTE* bits; + RGBQUAD* bmic; + + bits = dib->bits; + bmic = dib->bmic; + resto1 = cdwDIBLineSize(dib->w, 8) - dib->w; + resto2 = wi - dib->w; + + index = index + (wi * yi + xi); + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = *index; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (*index > pal_size) + pal_size = *index; + + *bits++ = *index++; + } + + bits += resto1; + index += resto2; + } + + pal_size++; + + for (c = 0; c < pal_size; c++) + *bmic++ = sColorToDIB(colors[c]); +} + +void cdwDIBEncodePattern(cdwDIB* dib, const long int *colors) +{ + int x,y, resto1; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = cdBlue(*colors); + *bits++ = cdGreen(*colors); + *bits++ = cdRed(*colors); + colors++; + } + bits += resto1; + } +} diff --git a/src/win32/cdwemf.c b/src/win32/cdwemf.c new file mode 100644 index 0000000..ad037c9 --- /dev/null +++ b/src/win32/cdwemf.c @@ -0,0 +1,117 @@ +/** \file + * \brief Windows EMF Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdemf.h" + + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + HENHMETAFILE hmf; + + cdwKillCanvas(ctxcanvas); + + hmf = CloseEnhMetaFile(ctxcanvas->hDC); + DeleteEnhMetaFile(hmf); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/* +%F cdCreateCanvas para EMF. +O DC é um EMF em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas* ctxcanvas; + char* strdata = (char*)data; + int w = 0, h = 0; + double xres, yres; + FILE* file; + char filename[10240] = ""; + HDC ScreenDC, hDC; + RECT rect; + + /* Inicializa parametros */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata,"%dx%d", &w, &h); + if (w == 0 || h == 0) + return; + + /* Verifica se o arquivo pode ser aberto para escrita */ + file = fopen(filename, "wb"); + if (file == NULL) return; + fclose(file); + + ScreenDC = GetDC(NULL); + /* LOGPIXELS can not be used for EMF */ + xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + rect.left = 0; + rect.top = 0; + rect.right = (int)(100. * w / xres); + rect.bottom = (int)(100. * h / yres); + hDC = CreateEnhMetaFile(ScreenDC,filename,&rect,NULL); + ReleaseDC(NULL, ScreenDC); + + if(!hDC) + return; + + /* Inicializa driver WIN32 */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, CDW_EMF); + + canvas->w = w; + canvas->h = h; + canvas->xres = xres; + canvas->yres = yres; + canvas->w_mm = ((double)w) / xres; + canvas->h_mm = ((double)h) / yres; + canvas->bpp = 24; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdEMFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + cdplayEMF, + cdregistercallbackEMF +}; + +cdContext* cdContextEMF(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_EMF); + if (ctx != NULL) + return ctx; + } + + return &cdEMFContext; +} diff --git a/src/win32/cdwimg.c b/src/win32/cdwimg.c new file mode 100644 index 0000000..47d99f9 --- /dev/null +++ b/src/win32/cdwimg.c @@ -0,0 +1,83 @@ +/** \file + * \brief Windows Image Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdimage.h" + + + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + cdwKillCanvas(ctxcanvas); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/* +%F cdCreateCanvas para Image. +O DC é um BITMAP em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + cdCtxImage* ctximage; + + if (data == NULL) + return; + + ctximage = ((cdImage*)data)->ctximage; + + /* Inicializa parametros */ + if (ctximage == NULL) + return; + + /* Inicializa driver Image */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, ctximage->hDC, CDW_BMP); + + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->w_mm = ctximage->w_mm; + canvas->h_mm = ctximage->h_mm; + canvas->bpp = ctximage->bpp; + canvas->xres = ctximage->xres; + canvas->yres = ctximage->yres; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextImage(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_IMAGE); + if (ctx != NULL) + return ctx; + } + + return &cdImageContext; +} diff --git a/src/win32/cdwin.c b/src/win32/cdwin.c new file mode 100644 index 0000000..3a71746 --- /dev/null +++ b/src/win32/cdwin.c @@ -0,0 +1,2368 @@ +/** \file + * \brief Windows Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "cdwin.h" + +#ifndef AC_SRC_ALPHA +#define AC_SRC_ALPHA 0x01 +#endif + +/* CD region combine to WIN32 region combine */ +static int sCombineRegion2win [] ={RGN_OR, RGN_AND, RGN_DIFF, RGN_XOR}; + +typedef BOOL (CALLBACK* AlphaBlendFunc)( HDC hdcDest, + int xoriginDest, int yoriginDest, + int wDest, int hDest, HDC hdcSrc, + int xoriginSrc, int yoriginSrc, + int wSrc, int hSrc, + BLENDFUNCTION ftn); +static AlphaBlendFunc cdwAlphaBlend = NULL; + +/* +%F Libera memoria e handles alocados pelo driver Windows. +*/ +void cdwKillCanvas(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_pnt != NULL) + free(ctxcanvas->clip_pnt); + + if (ctxcanvas->dib_bits != NULL) + free(ctxcanvas->dib_bits); + + /* apaga as areas de memoria do windows para os padroes */ + + if (ctxcanvas->clip_hrgn) DeleteObject(ctxcanvas->clip_hrgn); + if (ctxcanvas->new_rgn) DeleteObject(ctxcanvas->new_rgn); + + if (ctxcanvas->hOldBitmapPat) SelectObject(ctxcanvas->hDCMemPat, ctxcanvas->hOldBitmapPat); + if (ctxcanvas->hBitmapPat) DeleteObject(ctxcanvas->hBitmapPat); + if (ctxcanvas->hDCMemPat) DeleteDC(ctxcanvas->hDCMemPat); + + if (ctxcanvas->hOldBitmapStip) SelectObject(ctxcanvas->hDCMemStip, ctxcanvas->hOldBitmapStip); + if (ctxcanvas->hBitmapStip) DeleteObject(ctxcanvas->hBitmapStip); + if (ctxcanvas->hDCMemStip) DeleteDC(ctxcanvas->hDCMemStip); + + if (ctxcanvas->img_mask) DeleteObject(ctxcanvas->img_mask); + + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont); + DeleteObject(ctxcanvas->hFont); /* Fonte */ + + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen); /* restaura os objetos */ + DeleteObject(ctxcanvas->hPen); /* Pen corrente */ + + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); /* default do canvas */ + DeleteObject(ctxcanvas->hBrush); /* Brush corrente */ + + DeleteObject(ctxcanvas->hNullPen); /* Pen para tirar borda */ + DeleteObject(ctxcanvas->hBkBrush); /* Brush para o background */ + + /* ctxcanvas e ctxcanvas->hDC sao liberados em cada driver */ +} + +/* +Restaura os atributos do CD que sao guardados no DC do Windows quando +ha uma troca de DC. Usado pelos drivers Native Window e Printer. +*/ +void cdwRestoreDC(cdCtxCanvas *ctxcanvas) +{ + /* cdClipArea */ + SelectClipRgn(ctxcanvas->hDC, ctxcanvas->clip_hrgn); + + /* cdForeground */ + SetTextColor(ctxcanvas->hDC, ctxcanvas->fg); + + /* cdBackground */ + SetBkColor(ctxcanvas->hDC, ctxcanvas->bg); + + /* cdBackOpacity */ + switch (ctxcanvas->canvas->back_opacity) + { + case CD_TRANSPARENT: + SetBkMode(ctxcanvas->hDC, TRANSPARENT); + break; + case CD_OPAQUE: + SetBkMode(ctxcanvas->hDC, OPAQUE); + break; + } + + /* cdWriteMode */ + switch (ctxcanvas->canvas->write_mode) + { + case CD_REPLACE: + SetROP2(ctxcanvas->hDC, R2_COPYPEN); + break; + case CD_XOR: + SetROP2(ctxcanvas->hDC, R2_XORPEN); + break; + case CD_NOT_XOR: + SetROP2(ctxcanvas->hDC, R2_NOTXORPEN); + break; + } + + /* Text Alignment is calculated from this state */ + SetTextAlign(ctxcanvas->hDC,TA_LEFT|TA_BASELINE); + + /* cdLineStyle e cdLineWidth */ + ctxcanvas->hOldPen = SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); + + /* cdInteriorStyle */ + ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); + + /* cdFont */ + ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont); +} + + +/*********************************************************************/ +/* +%S Cor +*/ +/*********************************************************************/ + +static long int sColorFromWindows(COLORREF color) +{ + return cdEncodeColor(GetRValue(color),GetGValue(color),GetBValue(color)); +} + +static COLORREF sColorToWindows(cdCtxCanvas* ctxcanvas, long int cd_color) +{ + unsigned char red,green,blue; + COLORREF color; + + cdDecodeColor(cd_color,&red,&green,&blue); + + if (ctxcanvas->canvas->bpp <= 8) + color=PALETTERGB((BYTE)red,(BYTE)green,(BYTE)blue); + else + color=RGB((BYTE)red,(BYTE)green,(BYTE)blue); + + return color; +} + +static long int cdforeground (cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->fg = sColorToWindows(ctxcanvas, color); + SetTextColor(ctxcanvas->hDC, ctxcanvas->fg); + ctxcanvas->rebuild_pen = 1; + return color; +} + +static void sCreatePen(cdCtxCanvas* ctxcanvas) +{ + int cd2win_cap[] = {PS_ENDCAP_FLAT, PS_ENDCAP_SQUARE, PS_ENDCAP_ROUND}; + int cd2win_join[] = {PS_JOIN_MITER, PS_JOIN_BEVEL, PS_JOIN_ROUND}; + + ctxcanvas->logPen.lopnColor = ctxcanvas->fg; + + if (ctxcanvas->hOldPen) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen); + if (ctxcanvas->hPen) DeleteObject(ctxcanvas->hPen); + + if (ctxcanvas->logPen.lopnWidth.x == 1) + { + LOGBRUSH LogBrush; + LogBrush.lbStyle = BS_SOLID; + LogBrush.lbColor = ctxcanvas->logPen.lopnColor; + LogBrush.lbHatch = 0; + + if (ctxcanvas->canvas->line_style == CD_CUSTOM) + { + ctxcanvas->hPen = ExtCreatePen(PS_COSMETIC | PS_USERSTYLE, + 1, &LogBrush, + ctxcanvas->canvas->line_dashes_count, (DWORD*)ctxcanvas->canvas->line_dashes); + } + else + { + ctxcanvas->hPen = ExtCreatePen(PS_COSMETIC | ctxcanvas->logPen.lopnStyle, + 1, &LogBrush, + 0, NULL); + } + } + else + { + int style = PS_GEOMETRIC; + LOGBRUSH LogBrush; + LogBrush.lbStyle = BS_SOLID; + LogBrush.lbColor = ctxcanvas->logPen.lopnColor; + LogBrush.lbHatch = 0; + + style |= cd2win_cap[ctxcanvas->canvas->line_cap]; + style |= cd2win_join[ctxcanvas->canvas->line_join]; + + if (ctxcanvas->canvas->line_style == CD_CUSTOM) + { + ctxcanvas->hPen = ExtCreatePen( PS_USERSTYLE | style, + ctxcanvas->logPen.lopnWidth.x, &LogBrush, + ctxcanvas->canvas->line_dashes_count, (DWORD*)ctxcanvas->canvas->line_dashes); + } + else + ctxcanvas->hPen = ExtCreatePen( ctxcanvas->logPen.lopnStyle | style, + ctxcanvas->logPen.lopnWidth.x, &LogBrush, + 0, NULL); + } + + ctxcanvas->hOldPen = SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); + ctxcanvas->rebuild_pen = 0; +} + +static int cdbackopacity (cdCtxCanvas* ctxcanvas, int opacity) +{ + switch (opacity) + { + case CD_TRANSPARENT: + SetBkMode(ctxcanvas->hDC, TRANSPARENT); + break; + case CD_OPAQUE: + SetBkMode(ctxcanvas->hDC, OPAQUE); + break; + } + + return opacity; +} + +static int cdwritemode (cdCtxCanvas* ctxcanvas, int mode) +{ + switch (mode) + { + case CD_REPLACE: + SetROP2(ctxcanvas->hDC, R2_COPYPEN); + ctxcanvas->RopBlt = SRCCOPY; + break; + case CD_XOR: + SetROP2(ctxcanvas->hDC, R2_XORPEN); + ctxcanvas->RopBlt = SRCINVERT; + break; + case CD_NOT_XOR: + SetROP2(ctxcanvas->hDC, R2_NOTXORPEN); + ctxcanvas->RopBlt = SRCINVERT; + break; + } + + return mode; +} + +static long int cdbackground (cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->bg = sColorToWindows(ctxcanvas, color); + SetBkColor(ctxcanvas->hDC, ctxcanvas->bg); + + if (ctxcanvas->hBkBrush) DeleteObject(ctxcanvas->hBkBrush); + ctxcanvas->hBkBrush = CreateSolidBrush(ctxcanvas->bg); + + return color; +} + +static void cdpalette(cdCtxCanvas* ctxcanvas, int n, const long int *palette, int mode) +{ + LOGPALETTE* pLogPal; + unsigned char red,green,blue; + int k, np = n; + (void)mode; + + if (ctxcanvas->canvas->bpp > 8) /* se o sistema for true color */ + return; + + if (n < 246) + np += 10; + + pLogPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + np * sizeof(PALETTEENTRY)); + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = (WORD)np; + + if (n < 246) + { + k = 10; + GetSystemPaletteEntries(ctxcanvas->hDC, 0, 10, pLogPal->palPalEntry); + } + else + k=0; + + for (; k < np; k++) + { + cdDecodeColor(palette[k],&red,&green,&blue); + + pLogPal->palPalEntry[k].peRed = (BYTE)red; + pLogPal->palPalEntry[k].peGreen = (BYTE)green; + pLogPal->palPalEntry[k].peBlue = (BYTE)blue; + pLogPal->palPalEntry[k].peFlags = PC_NOCOLLAPSE; + } + + if (ctxcanvas->hPal) + { + if (ctxcanvas->hOldPal) SelectPalette(ctxcanvas->hDC, ctxcanvas->hOldPal, FALSE); + DeleteObject(ctxcanvas->hPal); + } + + ctxcanvas->hPal = CreatePalette(pLogPal); + ctxcanvas->hOldPal = SelectPalette(ctxcanvas->hDC, ctxcanvas->hPal, FALSE); + + RealizePalette(ctxcanvas->hDC); + + free(pLogPal); +} + + +/*********************************************************************/ +/* +%S Canvas e clipping +*/ +/*********************************************************************/ + +static HRGN sClipRect(cdCtxCanvas* ctxcanvas) +{ + HRGN clip_hrgn; + + if (ctxcanvas->clip_hrgn) + DeleteObject(ctxcanvas->clip_hrgn); + + clip_hrgn = CreateRectRgn(ctxcanvas->canvas->clip_rect.xmin, ctxcanvas->canvas->clip_rect.ymin, + ctxcanvas->canvas->clip_rect.xmax+1, ctxcanvas->canvas->clip_rect.ymax+1); + + SelectClipRgn(ctxcanvas->hDC, clip_hrgn); + return clip_hrgn; +} + +static HRGN sClipPoly(cdCtxCanvas* ctxcanvas) +{ + HRGN clip_hrgn; + + if (ctxcanvas->clip_hrgn) + DeleteObject(ctxcanvas->clip_hrgn); + + clip_hrgn = CreatePolygonRgn(ctxcanvas->clip_pnt, + ctxcanvas->clip_pnt_n, + ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); + SelectClipRgn(ctxcanvas->hDC, clip_hrgn); + return clip_hrgn; +} + +static int cdclip (cdCtxCanvas* ctxcanvas, int clip_mode) +{ + if (ctxcanvas->wtype == CDW_WMF) + return clip_mode; + + switch (clip_mode) + { + case CD_CLIPOFF: + SelectClipRgn(ctxcanvas->hDC, NULL); /* toda 'area do canvas */ + if (ctxcanvas->clip_hrgn) + DeleteObject(ctxcanvas->clip_hrgn); + ctxcanvas->clip_hrgn = NULL; + break; + case CD_CLIPAREA: + ctxcanvas->clip_hrgn = sClipRect(ctxcanvas); + break; + case CD_CLIPPOLYGON: + ctxcanvas->clip_hrgn = sClipPoly(ctxcanvas); + break; + case CD_CLIPREGION: + if (ctxcanvas->clip_hrgn) + DeleteObject(ctxcanvas->clip_hrgn); + ctxcanvas->clip_hrgn = CreateRectRgn(0,0,0,0); + CombineRgn(ctxcanvas->clip_hrgn, ctxcanvas->new_rgn, NULL, RGN_COPY); + SelectClipRgn(ctxcanvas->hDC, ctxcanvas->clip_hrgn); + break; + } + + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->wtype == CDW_WMF) + return; + + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.ymax = ymax; + ctxcanvas->clip_hrgn = sClipRect(ctxcanvas); + } +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->new_rgn) + DeleteObject(ctxcanvas->new_rgn); + ctxcanvas->new_rgn = CreateRectRgn(0, 0, 0, 0); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_rgn) + return 0; + + if (PtInRegion(ctxcanvas->new_rgn, x, y)) + return 1; + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_rgn) + return; + + OffsetRgn(ctxcanvas->new_rgn, x, y); +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + RECT rect; + + if (!ctxcanvas->new_rgn) + return; + + GetRgnBox(ctxcanvas->new_rgn, &rect); + + /* RECT in Windows does not includes the right, bottom. */ + *xmin = rect.left; + *xmax = rect.right-1; + *ymin = rect.top; + *ymax = rect.bottom-1; +} + +/******************************************************************/ +/* +%S Primitivas e seus atributos +*/ +/******************************************************************/ + +static int cdlinestyle (cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + ctxcanvas->logPen.lopnStyle = PS_SOLID; + break; + case CD_DASHED: + ctxcanvas->logPen.lopnStyle = PS_DASH; + break; + case CD_DOTTED: + ctxcanvas->logPen.lopnStyle = PS_DOT; + break; + case CD_DASH_DOT: + ctxcanvas->logPen.lopnStyle = PS_DASHDOT; + break; + case CD_DASH_DOT_DOT: + ctxcanvas->logPen.lopnStyle = PS_DASHDOTDOT; + break; + } + + ctxcanvas->rebuild_pen = 1; + + return style; +} + +static int cdlinewidth (cdCtxCanvas* ctxcanvas, int width) +{ + ctxcanvas->logPen.lopnWidth.x = width; + ctxcanvas->rebuild_pen = 1; + return width; +} + +static int cdlinecap (cdCtxCanvas* ctxcanvas, int cap) +{ + ctxcanvas->rebuild_pen = 1; + return cap; +} + +static int cdlinejoin (cdCtxCanvas* ctxcanvas, int join) +{ + ctxcanvas->rebuild_pen = 1; + return join; +} + +static int cdhatch (cdCtxCanvas* ctxcanvas, int hatch_style) +{ + switch (hatch_style) + { + case CD_HORIZONTAL: + ctxcanvas->logBrush.lbHatch = HS_HORIZONTAL; + break; + case CD_VERTICAL: + ctxcanvas->logBrush.lbHatch = HS_VERTICAL; + break; + case CD_FDIAGONAL: + ctxcanvas->logBrush.lbHatch = HS_FDIAGONAL; + break; + case CD_BDIAGONAL: + ctxcanvas->logBrush.lbHatch = HS_BDIAGONAL; + break; + case CD_CROSS: + ctxcanvas->logBrush.lbHatch = HS_CROSS; + break; + case CD_DIAGCROSS: + ctxcanvas->logBrush.lbHatch = HS_DIAGCROSS; + break; + } + + ctxcanvas->logBrush.lbColor=ctxcanvas->fg; + ctxcanvas->logBrush.lbStyle=BS_HATCHED; + + if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); + if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush); + + ctxcanvas->hBrush = CreateBrushIndirect(&ctxcanvas->logBrush); + ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); + + return hatch_style; +} + +static HBITMAP Stipple2Bitmap(int w, int h, const unsigned char *index, int negative) +{ + HBITMAP hBitmap; + BYTE *buffer; + + int nb; /* number of bytes per line */ + int x,y,k,offset; + + /* Cria um bitmap com os indices dados */ + nb = ((w + 15) / 16) * 2; /* Must be in a word boundary. */ + buffer = (BYTE *) malloc (nb*h); + memset(buffer, 0xff, nb*h); + + for (y=0; y<h; y++) + { + k=y*nb; + offset = ((h - 1) - y)*w; /* always consider a top-down bitmap */ + + for (x=0;x<w;x++) + { + if ((x % 8 == 0) && (x != 0)) + k++; + + /* In Windows: 0 is foreground, 1 is background. */ + if (index[offset + x] != 0) + buffer[k] &= (BYTE)~(1 << (7 - x % 8)); + } + } + + if (negative) + { + for (k = 0; k < nb*h; k++) + buffer[k] = ~buffer[k]; + } + + hBitmap = CreateBitmap(w,h,1,1,(LPSTR)buffer); + + free(buffer); + + return hBitmap; +} + +static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index) +{ + HBITMAP hBitmap = Stipple2Bitmap(w, h, index, 0); + + /* Cria um pincel com o Bitmap */ + if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); + if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush); + + ctxcanvas->hBrush = CreatePatternBrush(hBitmap); + ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); + + DeleteObject(hBitmap); +} + +static void cdpattern(cdCtxCanvas* ctxcanvas, int w, int h, const long int *colors) +{ + cdwDIB dib; + HBRUSH hBrush; + + if (ctxcanvas->wtype == CDW_WMF) + return; + + dib.w = w; + dib.h = h; + dib.type = 0; + if (!cdwCreateDIB(&dib)) + return; + + cdwDIBEncodePattern(&dib, colors); + hBrush = CreateDIBPatternBrushPt(dib.dib, DIB_RGB_COLORS); + cdwKillDIB(&dib); + + if (hBrush) + { + if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); + if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush); + + ctxcanvas->hBrush = hBrush; + ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); + } +} + +static int cdinteriorstyle (cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case CD_SOLID: + ctxcanvas->logBrush.lbStyle=BS_SOLID; + ctxcanvas->logBrush.lbColor=ctxcanvas->fg; + + if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); + if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush); + + ctxcanvas->hBrush = CreateBrushIndirect(&ctxcanvas->logBrush); + ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); + break; + case CD_HATCH: + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + break; + case CD_STIPPLE: + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + break; + case CD_PATTERN: + if (ctxcanvas->wtype == CDW_WMF) + return style; + cdpattern(ctxcanvas, ctxcanvas->canvas->pattern_w, ctxcanvas->canvas->pattern_h, ctxcanvas->canvas->pattern); + break; + } + + return style; +} + +static void cdline (cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + if (ctxcanvas->rebuild_pen) + sCreatePen(ctxcanvas); + + MoveToEx( ctxcanvas->hDC, x1, y1, NULL ); + LineTo( ctxcanvas->hDC, x2, y2 ); + SetPixelV(ctxcanvas->hDC, x2, y2, ctxcanvas->fg); +} + +static void cdrect (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + HBRUSH oldBrush; + + if (ctxcanvas->rebuild_pen) + sCreatePen(ctxcanvas); + + oldBrush = SelectObject(ctxcanvas->hDC, GetStockObject(NULL_BRUSH)); /* tira o desenho do interior */ + Rectangle(ctxcanvas->hDC, xmin, ymin, xmax+1, ymax+1); /* +1 porque nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, oldBrush); /* restaura o brush corrente */ +} + +static void cdbox (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) && + (ctxcanvas->canvas->interior_style != CD_PATTERN) ) + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + if (ctxcanvas->canvas->new_region) + { + HRGN rgn = CreateRectRgn(xmin, ymin, xmax+1, ymax+1); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + else + { + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + Rectangle(ctxcanvas->hDC, xmin, ymin, xmax+2, ymax+2); /* +2 porque a pena e' NULL NULL e o nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + } +} + +typedef struct _winArcParam +{ + int LeftRect, /* x-coordinate of upper-left corner of bounding rectangle */ + TopRect, /* y-coordinate of upper-left corner of bounding rectangle */ + RightRect, /* x-coordinate of lower-right corner of bounding rectangle */ + BottomRect, /* y-coordinate of lower-right corner of bounding rectangle */ + XStartArc, /* first radial ending point */ + YStartArc, /* first radial ending point */ + XEndArc, /* second radial ending point */ + YEndArc; /* second radial ending point */ +} winArcParam; + +static void calcArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2, winArcParam* arc) +{ + arc->LeftRect = xc - w/2; + arc->RightRect = xc + w/2 + 1; + arc->XStartArc = xc + cdRound(w * cos(CD_DEG2RAD * angle1) / 2.0); + arc->XEndArc = xc + cdRound(w * cos(CD_DEG2RAD * angle2) / 2.0); + + if (ctxcanvas->canvas->invert_yaxis) + { + arc->TopRect = yc - h/2; + arc->BottomRect = yc + h/2 + 1; + arc->YStartArc = yc - cdRound(h * sin(CD_DEG2RAD * angle1) / 2.0); + arc->YEndArc = yc - cdRound(h * sin(CD_DEG2RAD * angle2) / 2.0); + } + else + { + arc->BottomRect = yc - h/2; + arc->TopRect = yc + h/2 + 1; + arc->YStartArc = yc + cdRound(h * sin(CD_DEG2RAD * angle1) / 2.0); + arc->YEndArc = yc + cdRound(h * sin(CD_DEG2RAD * angle2) / 2.0); + + /* it is clock-wise when axis inverted */ + _cdSwapInt(arc->XStartArc, arc->XEndArc); + _cdSwapInt(arc->YStartArc, arc->YEndArc); + } +} + +static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + winArcParam arc; + calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + + if (ctxcanvas->rebuild_pen) + sCreatePen(ctxcanvas); + + Arc(ctxcanvas->hDC, arc.LeftRect, arc.TopRect, arc.RightRect, arc.BottomRect, arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); +} + +static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + winArcParam arc; + calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + + if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) && + (ctxcanvas->canvas->interior_style != CD_PATTERN) ) + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + if (angle1==0 && angle2==360) + { + if (ctxcanvas->canvas->new_region) + { + HRGN rgn = CreateEllipticRgn(arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + else + { + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + Ellipse(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + } + } + else + { + if (ctxcanvas->canvas->new_region) + BeginPath(ctxcanvas->hDC); + + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + Pie(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1,arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + + if (ctxcanvas->canvas->new_region) + { + HRGN rgn; + EndPath(ctxcanvas->hDC); + rgn = PathToRegion(ctxcanvas->hDC); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + } +} + +static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + winArcParam arc; + calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + + if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) && + (ctxcanvas->canvas->interior_style != CD_PATTERN) ) + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + if (angle1==0 && angle2==360) + { + if (ctxcanvas->canvas->new_region) + { + HRGN rgn = CreateEllipticRgn(arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + else + { + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + Ellipse(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + } + } + else + { + if (ctxcanvas->canvas->new_region) + BeginPath(ctxcanvas->hDC); + + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + Chord(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1,arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); /* +2 porque a pena e' NULL e o nao inclue right/bottom */ + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + + if (ctxcanvas->canvas->new_region) + { + HRGN rgn; + EndPath(ctxcanvas->hDC); + rgn = PathToRegion(ctxcanvas->hDC); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + } +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i, t, nc; + POINT* pnt; + HPEN oldPen = NULL, Pen = NULL; + + switch( mode ) + { + case CD_CLOSED_LINES: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + /* continua */ + case CD_OPEN_LINES: + if (ctxcanvas->rebuild_pen) + sCreatePen(ctxcanvas); + Polyline(ctxcanvas->hDC, (POINT*)poly, n); + break; + case CD_BEZIER: + if (ctxcanvas->rebuild_pen) + sCreatePen(ctxcanvas); + PolyBezier(ctxcanvas->hDC, (POINT*)poly, n); + break; + case CD_FILL: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + if (ctxcanvas->canvas->new_region) + { + HRGN rgn = CreatePolygonRgn((POINT*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + else + { + if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) && + (ctxcanvas->canvas->interior_style != CD_PATTERN)) + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + if (ctxcanvas->canvas->interior_style != CD_SOLID || ctxcanvas->fill_attrib[0] == '0') + { + SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */ + } + else + { + Pen = CreatePen(PS_SOLID, 1, ctxcanvas->fg); + oldPen = SelectObject(ctxcanvas->hDC, Pen); + } + + SetPolyFillMode(ctxcanvas->hDC, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); + Polygon(ctxcanvas->hDC, (POINT*)poly, n); + + if (ctxcanvas->canvas->interior_style != CD_SOLID || ctxcanvas->fill_attrib[0] == '0') + { + SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */ + } + else + { + SelectObject(ctxcanvas->hDC, oldPen); + DeleteObject(Pen); + } + } + break; + case CD_CLIP: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + + if (ctxcanvas->wtype == CDW_WMF) + return; + + if (ctxcanvas->clip_pnt) + free(ctxcanvas->clip_pnt); + + ctxcanvas->clip_pnt = (POINT*)malloc(n*sizeof(POINT)); + + pnt = (POINT*)poly; + t = n; + nc = 1; + + ctxcanvas->clip_pnt[0] = *pnt; + pnt++; + + for (i = 1; i < t-1; i++, pnt++) + { + if (!((pnt->x == ctxcanvas->clip_pnt[nc-1].x && pnt->x == (pnt + 1)->x) || + (pnt->y == ctxcanvas->clip_pnt[nc-1].y && pnt->y == (pnt + 1)->y))) + { + ctxcanvas->clip_pnt[nc] = *pnt; + nc++; + } + } + + ctxcanvas->clip_pnt_n = nc; + + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + ctxcanvas->clip_hrgn = sClipPoly(ctxcanvas); + + break; + } +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + { + XFORM xForm; + SetGraphicsMode(ctxcanvas->hDC, GM_ADVANCED); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + + /* configure a bottom-up coordinate system */ + + /* Equivalent of: + SetMapMode(ctxcanvas->hDC, MM_ISOTROPIC); + SetWindowExtEx(ctxcanvas->hDC, ctxcanvas->canvas->w-1, ctxcanvas->canvas->h-1, NULL); + SetWindowOrgEx(ctxcanvas->hDC, 0, 0, NULL); + SetViewportExtEx(ctxcanvas->hDC, ctxcanvas->canvas->w-1, -(ctxcanvas->canvas->h-1), NULL); + SetViewportOrgEx(ctxcanvas->hDC, 0, ctxcanvas->canvas->h-1, NULL); + */ + + xForm.eM11 = (FLOAT)1; + xForm.eM12 = (FLOAT)0; + xForm.eM21 = (FLOAT)0; + xForm.eM22 = (FLOAT)-1; + xForm.eDx = (FLOAT)0; + xForm.eDy = (FLOAT)(ctxcanvas->canvas->h-1); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + ctxcanvas->canvas->invert_yaxis = 0; + + xForm.eM11 = (FLOAT)matrix[0]; + xForm.eM12 = (FLOAT)matrix[1]; + xForm.eM21 = (FLOAT)matrix[2]; + xForm.eM22 = (FLOAT)matrix[3]; + xForm.eDx = (FLOAT)matrix[4]; + xForm.eDy = (FLOAT)matrix[5]; + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + } + else + { + ctxcanvas->canvas->invert_yaxis = 1; + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); + } +} + +static void sTextOutBlt(cdCtxCanvas* ctxcanvas, int px, int py, const char* s, int n) +{ + HDC hBitmapDC; + HBITMAP hBitmap, hOldBitmap; + HFONT hOldFont; + int w, h, wt, ht, x, y, off, px_off = 0, py_off = 0; + double teta = ctxcanvas->canvas->text_orientation*CD_DEG2RAD; + double cos_teta = cos(teta); + double sin_teta = sin(teta); + + cdCanvasGetTextSize(ctxcanvas->canvas, s, &w, &h); + wt = w; + ht = h; + + if (ctxcanvas->canvas->text_orientation != 0) + { + /* novo tamanho da imagem */ + w = (int)(w * cos_teta + h * sin_teta); + h = (int)(h * cos_teta + w * sin_teta); + } + + /* coloca no centro da imagem */ + y = h/2; + x = w/2; + + /* corrige alinhamento do centro */ + off = ht/2 - ctxcanvas->font.descent; + if (ctxcanvas->canvas->text_orientation != 0) + { + y += (int)(off * cos_teta); + x += (int)(off * sin_teta); + } + else + y += off; + + /* calcula o alinhamento da imagem no canvas */ + if (ctxcanvas->canvas->text_orientation != 0) + { + double d = sqrt(wt*wt + ht*ht); + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_CENTER: + py_off = 0; + px_off = 0; + break; + case CD_BASE_LEFT: + py_off = - (int)(off * cos_teta + w/2 * sin_teta); + px_off = (int)(w/2 * cos_teta - off * sin_teta); + break; + case CD_BASE_CENTER: + py_off = - (int)(off * cos_teta); + px_off = - (int)(off * sin_teta); + break; + case CD_BASE_RIGHT: + py_off = - (int)(off * cos_teta - w/2 * sin_teta); + px_off = - (int)(w/2 * cos_teta + off * sin_teta); + break; + case CD_NORTH: + py_off = (int)(ht/2 * cos_teta); + px_off = (int)(ht/2 * sin_teta); + break; + case CD_SOUTH: + py_off = - (int)(ht/2 * cos_teta); + px_off = - (int)(ht/2 * sin_teta); + break; + case CD_EAST: + py_off = (int)(wt/2 * sin_teta); + px_off = - (int)(wt/2 * cos_teta); + break; + case CD_WEST: + py_off = - (int)(wt/2 * sin_teta); + px_off = (int)(wt/2 * cos_teta); + break; + case CD_NORTH_EAST: + py_off = (int)(h/2); + px_off = - (int)(sqrt(d*d - h*h)/2); + break; + case CD_NORTH_WEST: + py_off = (int)(sqrt(d*d - w*w)/2); + px_off = - (int)(w/2); + break; + case CD_SOUTH_WEST: + py_off = - (int)(h/2); + px_off = (int)(sqrt(d*d - h*h)/2); + break; + case CD_SOUTH_EAST: + py_off = - (int)(sqrt(d*d - w*w)/2); + px_off = (int)(w/2); + break; + } + } + else + { + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + px_off = - w/2; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + px_off = 0; + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + px_off = w/2; + break; + } + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + py_off = - off; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + py_off = - h/2; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + py_off = + h/2; + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + py_off = py; + break; + } + } + + /* move do centro da imagem para o canto superior esquerdo da imagem */ + px_off -= w/2; + py_off -= h/2; + + /* desloca o ponto dado */ + if (ctxcanvas->canvas->invert_yaxis) + { + px += px_off; + py += py_off; + } + else + { + px += px_off; + py -= py_off; + } + + hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, w, h); + hBitmapDC = CreateCompatibleDC(ctxcanvas->hDC); + + hOldBitmap = SelectObject(hBitmapDC, hBitmap); + + /* copia a area do canvas para o bitmap */ + BitBlt(hBitmapDC, 0, 0, w, h, ctxcanvas->hDC, px, py, SRCCOPY); + + /* compensa a ROP antes de desenhar */ + BitBlt(hBitmapDC, 0, 0, w, h, ctxcanvas->hDC, px, py, ctxcanvas->RopBlt); + + SetBkMode(hBitmapDC, TRANSPARENT); + SetBkColor(hBitmapDC, ctxcanvas->bg); + SetTextColor(hBitmapDC, ctxcanvas->fg); + SetTextAlign(hBitmapDC, TA_CENTER | TA_BASELINE); + hOldFont = SelectObject(hBitmapDC, ctxcanvas->hFont); + + TextOut(hBitmapDC, x, y, s, n); + + if (ctxcanvas->canvas->invert_yaxis) + BitBlt(ctxcanvas->hDC, px, py, w, h, hBitmapDC, 0, 0, ctxcanvas->RopBlt); + else + StretchBlt(ctxcanvas->hDC, px, py, w, -h, hBitmapDC, 0, 0, w, h, ctxcanvas->RopBlt); + + SelectObject(hBitmapDC, hOldFont); + SelectObject(hBitmapDC, hOldBitmap); + + DeleteObject(hBitmap); + DeleteDC(hBitmapDC); +} + +static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + SIZE size; + + GetTextExtentPoint32(ctxcanvas->hDC, s, (int)strlen(s), &size); + + if (width) + *width = size.cx; + + if (height) + *height = size.cy; +} + +static void cdwCanvasGetTextHeight(cdCanvas* canvas, int x, int y, const char *s, int *hbox, int *hoff) +{ + int w, h, ascent, height, baseline; + int xmin, xmax, ymin, ymax; + + cdCanvasGetTextSize(canvas, s, &w, &h); + cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + /* move to bottom-left */ + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin); + + *hoff = y - ymin; + + xmax = xmin + w-1; + ymax = ymin + h-1; + + if (canvas->text_orientation) + { + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + int rectY[4]; + + *hoff = (int)(*hoff * cos_theta); + + cdRotatePointY(canvas, xmin, ymin, x, y, &rectY[0], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymin, x, y, &rectY[1], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymax, x, y, &rectY[2], sin_theta, cos_theta); + cdRotatePointY(canvas, xmin, ymax, x, y, &rectY[3], sin_theta, cos_theta); + + ymin = ymax = rectY[0]; + if (rectY[1] < ymin) ymin = rectY[1]; + if (rectY[2] < ymin) ymin = rectY[2]; + if (rectY[3] < ymin) ymin = rectY[3]; + if (rectY[1] > ymax) ymax = rectY[1]; + if (rectY[2] > ymax) ymax = rectY[2]; + if (rectY[3] > ymax) ymax = rectY[3]; + } + + *hbox = ymax-ymin+1; +} + +static void cdwTextTransform(cdCtxCanvas* ctxcanvas, const char* s, int *x, int *y) +{ + XFORM xForm; + int hoff, h; + + cdwCanvasGetTextHeight(ctxcanvas->canvas, *x, *y, s, &h, &hoff); + + /* move to (x,y) and remove a vertical offset since text reference point is top-left */ + xForm.eM11 = (FLOAT)1; + xForm.eM12 = (FLOAT)0; + xForm.eM21 = (FLOAT)0; + xForm.eM22 = (FLOAT)1; + xForm.eDx = (FLOAT)*x; + xForm.eDy = (FLOAT)(*y - (h-1) - hoff); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + /* invert the text vertical orientation, relative to itself */ + xForm.eM11 = (FLOAT)1; + xForm.eM12 = (FLOAT)0; + xForm.eM21 = (FLOAT)0; + xForm.eM22 = (FLOAT)-1; + xForm.eDx = (FLOAT)0; + xForm.eDy = (FLOAT)(h-1); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + *x = 0; + *y = 0; +} + +static void cdtext(cdCtxCanvas* ctxcanvas, int x, int y, const char *s) +{ + int n = (int)strlen(s); + + if (ctxcanvas->canvas->write_mode == CD_REPLACE || + ctxcanvas->wtype == CDW_EMF || + ctxcanvas->wtype == CDW_WMF || + ctxcanvas->canvas->new_region) + { + int h = -1; + + if ((ctxcanvas->canvas->text_alignment == CD_CENTER || + ctxcanvas->canvas->text_alignment == CD_EAST || + ctxcanvas->canvas->text_alignment == CD_WEST) && + ctxcanvas->wtype != CDW_WMF) + { + /* compensa deficiencia do alinhamento no windows */ + int off; + cdCanvasGetTextSize(ctxcanvas->canvas, s, NULL, &h); + off = h/2 - ctxcanvas->font.descent; + + if (ctxcanvas->canvas->text_orientation != 0) + { + y += (int)(off * cos(ctxcanvas->canvas->text_orientation*CD_DEG2RAD)); + x += (int)(off * sin(ctxcanvas->canvas->text_orientation*CD_DEG2RAD)); + } + else + y += off; + } + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + SetBkMode(ctxcanvas->hDC, TRANSPARENT); + + if (ctxcanvas->canvas->new_region) + BeginPath(ctxcanvas->hDC); + + if (ctxcanvas->canvas->use_matrix) + cdwTextTransform(ctxcanvas, s, &x, &y); + + TextOut(ctxcanvas->hDC, x, y+1, s, n); /* compensa erro de desenho com +1 */ + + if (ctxcanvas->canvas->use_matrix) + cdtransform(ctxcanvas, ctxcanvas->canvas->matrix); + + if (ctxcanvas->canvas->new_region) + { + HRGN rgn; + EndPath(ctxcanvas->hDC); + rgn = PathToRegion(ctxcanvas->hDC); + CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]); + DeleteObject(rgn); + } + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + SetBkMode(ctxcanvas->hDC, OPAQUE); + } + else + sTextOutBlt(ctxcanvas, x, y+1, s, n); +} + +static int cdtextalignment(cdCtxCanvas* ctxcanvas, int text_align) +{ + int align = TA_NOUPDATECP; + + switch (text_align) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + align |= TA_RIGHT; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + align |= TA_CENTER; + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + align |= TA_LEFT; + break; + } + + switch (text_align) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + align |= TA_BASELINE; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + align |= TA_BOTTOM; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + align |= TA_TOP; + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + align |= TA_BASELINE; /* tem que compensar ao desenhar o texto */ + break; + } + + SetTextAlign(ctxcanvas->hDC, align); + + return text_align; +} + +static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + TEXTMETRIC tm; + DWORD bold, italic = 0, underline = 0, strikeout = 0; + int angle, size_pixel; + HFONT hFont; + + if (style&CD_BOLD) + bold = FW_BOLD; + else + bold = FW_NORMAL; + + if (style&CD_ITALIC) + italic = 1; + + if (style&CD_UNDERLINE) + underline = 1; + + if (style&CD_STRIKEOUT) + strikeout = 1; + + angle = ctxcanvas->font_angle; + + if (cdStrEqualNoCase(type_face, "Courier") || cdStrEqualNoCase(type_face, "Monospace")) + type_face = "Courier New"; + else if (cdStrEqualNoCase(type_face, "Times") || cdStrEqualNoCase(type_face, "Serif")) + type_face = "Times New Roman"; + else if (cdStrEqualNoCase(type_face, "Helvetica") || cdStrEqualNoCase(type_face, "Sans")) + type_face = "Arial"; + + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + hFont = CreateFont(-size_pixel, 0, angle, angle, bold, italic, underline, strikeout, + DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH, + type_face); + if (!hFont) return 0; + + if (ctxcanvas->hOldFont) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont); + if (ctxcanvas->hFont) DeleteObject(ctxcanvas->hFont); + ctxcanvas->hFont = hFont; + ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont); + + GetTextMetrics (ctxcanvas->hDC, &tm); + ctxcanvas->font.max_width = tm.tmMaxCharWidth; + ctxcanvas->font.height = tm.tmHeight + tm.tmExternalLeading ; + ctxcanvas->font.ascent = tm.tmAscent; + ctxcanvas->font.descent = tm.tmDescent; + + return 1; +} + +static int cdnativefont (cdCtxCanvas* ctxcanvas, const char* nativefont) +{ + TEXTMETRIC tm; + HFONT hFont; + int size = 12, bold = FW_NORMAL, italic = 0, + style = CD_PLAIN, underline = 0, strikeout = 0, + size_pixel; + char type_face[1024]; + + if (nativefont[0] == '-' && nativefont[1] == 'd') + { + COLORREF rgbColors; + CHOOSEFONT cf; + LOGFONT lf; + + ZeroMemory(&cf, sizeof(CHOOSEFONT)); + + cf.lStructSize = sizeof(CHOOSEFONT); + cf.hwndOwner = GetForegroundWindow(); + cf.lpLogFont = &lf; + cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT; + rgbColors = cf.rgbColors = ctxcanvas->fg; + + GetTextFace(ctxcanvas->hDC, 50, type_face); + GetTextMetrics(ctxcanvas->hDC, &tm); /* get the current selected nativefont */ + + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + + strcpy(lf.lfFaceName, type_face); + lf.lfWeight = tm.tmWeight; + lf.lfHeight = -size_pixel; + lf.lfItalic = tm.tmItalic; + lf.lfUnderline = tm.tmUnderlined; + lf.lfStrikeOut = tm.tmStruckOut; + lf.lfCharSet = tm.tmCharSet; + lf.lfEscapement = ctxcanvas->font_angle; + lf.lfOrientation = ctxcanvas->font_angle; + lf.lfWidth = 0; + lf.lfOutPrecision = OUT_TT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH; + + if (ChooseFont(&cf)) + { + if (rgbColors != cf.rgbColors) + cdCanvasSetForeground(ctxcanvas->canvas, sColorFromWindows(cf.rgbColors)); + + hFont = CreateFontIndirect(&lf); + } + else + return 0; + + bold = lf.lfWeight; + italic = lf.lfItalic; + size = lf.lfHeight; + strcpy(type_face, lf.lfFaceName); + underline = lf.lfUnderline; + strikeout = lf.lfStrikeOut; + + if (bold!=FW_NORMAL) style |= CD_BOLD; + if (italic) style |= CD_ITALIC; + if (underline) style |= CD_UNDERLINE; + if (strikeout) style |= CD_STRIKEOUT; + } + else + { + if (!cdParseIupWinFont(nativefont, type_face, &style, &size)) + { + if (!cdParsePangoFont(nativefont, type_face, &style, &size)) + return 0; + } + + if (style&CD_BOLD) + bold = FW_BOLD; + if (style&CD_ITALIC) + italic = 1; + if (style&CD_UNDERLINE) + underline = 1; + if (style&CD_STRIKEOUT) + strikeout = 1; + + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + + hFont = CreateFont(-size_pixel, 0, ctxcanvas->font_angle, ctxcanvas->font_angle, + bold, italic, underline, strikeout, + DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH, type_face); + if (!hFont) return 0; + } + + if (ctxcanvas->hOldFont) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont); + DeleteObject(ctxcanvas->hFont); + ctxcanvas->hFont = hFont; + ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont); + + GetTextMetrics(ctxcanvas->hDC, &tm); + ctxcanvas->font.max_width = tm.tmMaxCharWidth; + ctxcanvas->font.height = tm.tmHeight + tm.tmExternalLeading; + ctxcanvas->font.ascent = tm.tmAscent; + ctxcanvas->font.descent = tm.tmDescent; + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, type_face); + + return 1; +} + +static double cdtextorientation(cdCtxCanvas* ctxcanvas, double angle) +{ + if (ctxcanvas->font_angle == angle) /* first time angle=0, do not create font twice */ + return angle; + + ctxcanvas->font_angle = (int)(angle * 10); + + cdfont(ctxcanvas, ctxcanvas->canvas->font_type_face, ctxcanvas->canvas->font_style, ctxcanvas->canvas->font_size); + + return angle; +} + +static void cdgetfontdim (cdCtxCanvas* ctxcanvas, int *max_width, int *line_height, int *ascent, int *descent) +{ + if (max_width) + *max_width = ctxcanvas->font.max_width; + + if (line_height) + *line_height = ctxcanvas->font.height; + + if (ascent) + *ascent = ctxcanvas->font.ascent; + + if (descent) + *descent = ctxcanvas->font.descent; + + return; +} + +/* +%F Desenha um retangulo no canvas todo com a cor do fundo. +*/ +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + RECT rect; + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + SelectClipRgn( ctxcanvas->hDC, NULL ); /* toda 'area do canvas */ + + SetRect(&rect, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + FillRect(ctxcanvas->hDC, &rect, ctxcanvas->hBkBrush); + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); +} + + +/******************************************************************/ +/* +%S Funcoes de imagens do cliente +*/ +/******************************************************************/ + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned char *green, unsigned char *blue, int x, int y, int w, int h) +{ + XFORM xForm; + cdwDIB dib; + HDC hDCMem; + HBITMAP hOldBitmap,hBitmap; + int yr; + + hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, w, h); + if (hBitmap == NULL) + return; + + hDCMem = CreateCompatibleDC(ctxcanvas->hDC); + + hOldBitmap = SelectObject(hDCMem, hBitmap); + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + { + GetWorldTransform(ctxcanvas->hDC, &xForm); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + } + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + yr = y - (h - 1); /* y starts at the bottom of the image */ + BitBlt(hDCMem,0,0,w,h,ctxcanvas->hDC, x, yr, SRCCOPY); + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + dib.w = w; + dib.h = h; + dib.type = 0; + + if (!cdwCreateDIB(&dib)) + { + SelectObject(hDCMem, hOldBitmap); + DeleteObject(hBitmap); + DeleteDC(hDCMem); + return; + } + + GetDIBits(ctxcanvas->hDC, hBitmap, 0, h, dib.bits, dib.bmi, DIB_RGB_COLORS); + + SelectObject(hDCMem, hOldBitmap); + DeleteObject(hBitmap); + DeleteDC(hDCMem); + + cdwDIBDecodeRGB(&dib, red, green, blue); + + cdwKillDIB(&dib); +} + +static void sFixImageY(cdCanvas* canvas, int *y, int *h) +{ + /* Here, y is from top to bottom, + is at the bottom-left corner of the image if h>0 + is at the top-left corner of the image if h<0. (Undocumented feature) + cdCalcZoom expects Y at top-left if h>0 + and Y at bottom-left if h<0 + if h<0 then eh<0 to StretchDIBits mirror the image. + BUT!!!!!! AlphaBlend will NOT mirror the image. */ + + if (!canvas->invert_yaxis) + *h = -(*h); + + if (*h < 0) + *y -= ((*h) + 1); /* compensate for cdCalcZoom */ + else + *y -= ((*h) - 1); /* move Y to top-left corner, since it was at the bottom of the image */ +} + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + cdwDIB dib; + int ew, eh, ex, ey; /* posicao da imagem com zoom no canvas e tamanho da imagem com zoom depois de otimizado */ + int bw, bh, bx, by; /* posicao dentro da imagem e tamanho dentro da imagem do pedaco que sera desenhado depois de otimizado */ + int rw, rh; /* tamanho dentro da imagem antes de otimizado */ + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + sFixImageY(ctxcanvas->canvas, &y, &h); + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + dib.w = bw; + dib.h = bh; + dib.type = 1; + + if (!cdwCreateDIBRefBuffer(&dib, &ctxcanvas->dib_bits, &ctxcanvas->bits_size)) + return; + + cdwDIBEncodeMapRect(&dib, index, colors, bx, by, width, height); + + StretchDIBits(ctxcanvas->hDC, + ex, ey, ew, eh, + 0, 0, bw, bh, + dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt); +} + +static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, const unsigned char *blue, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + cdwDIB dib; + int ew, eh, ex, ey; + int bw, bh, bx, by; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + sFixImageY(ctxcanvas->canvas, &y, &h); + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + dib.w = bw; + dib.h = bh; + dib.type = 0; + + if (!cdwCreateDIBRefBuffer(&dib, &ctxcanvas->dib_bits, &ctxcanvas->bits_size)) + return; + + cdwDIBEncodeRGBRect(&dib, red, green, blue, bx, by, width, height); + + StretchDIBits(ctxcanvas->hDC, + ex, ey, ew, eh, + 0, 0, bw, bh, + dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt); +} + +static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + cdwDIB dib; + HDC hDCMem; + HBITMAP hOldBitmap, hBitmap; + int ew, eh, ex, ey; + int bw, bh, bx, by; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + sFixImageY(ctxcanvas->canvas, &y, &h); + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + hDCMem = CreateCompatibleDC(ctxcanvas->hDC); + + if (cdwAlphaBlend) + { + BLENDFUNCTION blendfunc; + + dib.w = bw; + dib.h = bh; + dib.type = 2; /* RGBA */ + + hBitmap = cdwCreateDIBSection(&dib, hDCMem); + if (!hBitmap) + { + DeleteDC(hDCMem); + return; + } + + cdwDIBEncodeRGBARect(&dib, red, green, blue, alpha, bx, by, width, height); + + if (eh < 0) /* must mirror the image */ + { + XFORM xForm; + + eh = -eh; + + SetGraphicsMode(hDCMem, GM_ADVANCED); + ModifyWorldTransform(hDCMem, NULL, MWT_IDENTITY); + + /* configure a bottom-up coordinate system */ + xForm.eM11 = (FLOAT)1; + xForm.eM12 = (FLOAT)0; + xForm.eM21 = (FLOAT)0; + xForm.eM22 = (FLOAT)-1; + xForm.eDx = (FLOAT)0; + xForm.eDy = (FLOAT)(bh-1); + ModifyWorldTransform(hDCMem, &xForm, MWT_LEFTMULTIPLY); + } + + hOldBitmap = SelectObject(hDCMem, hBitmap); + + blendfunc.BlendOp = AC_SRC_OVER; + blendfunc.BlendFlags = 0; + blendfunc.SourceConstantAlpha = 0xFF; + blendfunc.AlphaFormat = AC_SRC_ALPHA; + + cdwAlphaBlend(ctxcanvas->hDC, + ex, ey, ew, eh, + hDCMem, + 0, 0, bw, bh, + blendfunc); + } + else + { + hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, ew, eh); /* captura do tamanho do destino */ + if (!hBitmap) + { + DeleteDC(hDCMem); + return; + } + + hOldBitmap = SelectObject(hDCMem, hBitmap); + + BitBlt(hDCMem, 0, 0, ew, eh, ctxcanvas->hDC, ex, ey, SRCCOPY); + + dib.w = ew; /* neste caso o tamanho usado e´ o de destino */ + dib.h = eh; + dib.type = 0; + + if (!cdwCreateDIB(&dib)) + { + SelectObject(hDCMem, hOldBitmap); + DeleteObject(hBitmap); + DeleteDC(hDCMem); + return; + } + + GetDIBits(hDCMem, hBitmap, 0, eh, dib.bits, dib.bmi, DIB_RGB_COLORS); + + cdwDIBEncodeRGBARectZoom(&dib, red, green, blue, alpha, width, height, bx, by, bw, bh); + + StretchDIBits(ctxcanvas->hDC, + ex, ey, ew, eh, + 0, 0, ew, eh, /* Nao tem zoom neste caso, pois e´ feito manualmente pela EncodeRGBA */ + dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt); + } + + SelectObject(hDCMem, hOldBitmap); + DeleteObject(hBitmap); + DeleteDC(hDCMem); + cdwKillDIB(&dib); +} + + +/********************************************************************/ +/* +%S Funcoes de imagens do servidor +*/ +/********************************************************************/ + +static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int cd_color) +{ + SetPixelV(ctxcanvas->hDC, x, y, sColorToWindows(ctxcanvas, cd_color)); +} + +static cdCtxImage *cdcreateimage(cdCtxCanvas* ctxcanvas, int width, int height) +{ + HDC hDCMem; + HBITMAP hOldBitmap,hBitmap; + cdCtxImage *ctximage; + void* rgba_dib = NULL; + unsigned char* alpha = NULL; + + if (ctxcanvas->img_format) + { + cdwDIB dib; + + dib.w = width; + dib.h = height; + if (ctxcanvas->img_format == 32) + dib.type = CDW_RGBA; + else + dib.type = CDW_RGB; + + hBitmap = cdwCreateDIBSection(&dib, ctxcanvas->hDC); + if (!hBitmap) + return NULL; + + rgba_dib = dib.bits; + alpha = ctxcanvas->img_alpha; + + cdwKillDIB(&dib); /* this will just remove the headers not the dib bits in this case */ + } + else + { + hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, width, height); + if (!hBitmap) + return NULL; + } + + hDCMem = CreateCompatibleDC(ctxcanvas->hDC); + hOldBitmap = SelectObject(hDCMem, hBitmap); + + PatBlt(hDCMem, 0, 0, width, height, WHITENESS); + + /* salva o contexto desta imagem */ + ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage)); + + ctximage->hDC = hDCMem; + ctximage->hBitmap = hBitmap; + ctximage->hOldBitmap = hOldBitmap; + ctximage->w = width; + ctximage->h = height; + ctximage->rgba_dib = rgba_dib; + ctximage->alpha = alpha; + + ctximage->bpp = ctxcanvas->canvas->bpp; + ctximage->xres = ctxcanvas->canvas->xres; + ctximage->yres = ctxcanvas->canvas->yres; + + ctximage->w_mm = ctximage->w / ctximage->xres; + ctximage->h_mm = ctximage->h / ctximage->yres; + + return ctximage; +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + int yr; + XFORM xForm; + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + { + GetWorldTransform(ctxcanvas->hDC, &xForm); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + } + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + yr = y - (ctximage->h - 1); + BitBlt(ctximage->hDC, 0, 0, ctximage->w, ctximage->h, ctxcanvas->hDC, x, yr, SRCCOPY); + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x0, int y0, int xmin, int xmax, int ymin, int ymax) +{ + int yr = y0 - (ymax-ymin+1)+1; /* y0 starts at the bottom of the image */ + + if (ctximage->alpha && ctximage->bpp == 32 && cdwAlphaBlend) + { + cdwDIB dib; + BLENDFUNCTION blendfunc; + blendfunc.BlendOp = AC_SRC_OVER; + blendfunc.BlendFlags = 0; + blendfunc.SourceConstantAlpha = 0xFF; + blendfunc.AlphaFormat = AC_SRC_ALPHA; + + dib.w = ctximage->w; + dib.h = ctximage->h; + dib.type = CDW_RGBA; + cdwCreateDIBRefBits(&dib, ctximage->rgba_dib); + + cdwDIBEncodeAlphaRect(&dib, ctximage->alpha, 0, 0, ctximage->w, ctximage->h); + + GdiFlush(); + cdwAlphaBlend(ctxcanvas->hDC, + x0, yr, xmax-xmin+1, ymax-ymin+1, + ctximage->hDC, + xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1, + blendfunc); + + cdwKillDIB(&dib); + } + else if(ctxcanvas->use_img_points) + { + POINT pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].y); + pts[1].y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].y); + pts[2].y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].y); + } + PlgBlt(ctxcanvas->hDC, pts, ctximage->hDC, xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1, ctxcanvas->img_mask, 0, 0); + } + else if (ctxcanvas->img_mask) + MaskBlt(ctxcanvas->hDC,x0,yr, xmax-xmin+1, ymax-ymin+1, ctximage->hDC, xmin, ctximage->h-ymax-1, ctxcanvas->img_mask, 0, 0, MAKEROP4(ctxcanvas->RopBlt, 0xAA0000)); + else + BitBlt(ctxcanvas->hDC,x0,yr, xmax-xmin+1, ymax-ymin+1, ctximage->hDC, xmin, ctximage->h-ymax-1, ctxcanvas->RopBlt); +} + +static void cdkillimage(cdCtxImage *ctximage) +{ + SelectObject(ctximage->hDC, ctximage->hOldBitmap); + DeleteObject(ctximage->hBitmap); + DeleteDC(ctximage->hDC); + free(ctximage); +} + +static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + XFORM xForm; + RECT rect; + rect.left = xmin; + rect.right = xmax+1; + rect.top = ymin; + rect.bottom = ymax+1; + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + { + GetWorldTransform(ctxcanvas->hDC, &xForm); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + } + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + { + dy = -dy; + ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); + ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + ScrollDC(ctxcanvas->hDC, dx, dy, &rect, NULL, NULL, NULL); + + if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + (void)ctxcanvas; + GdiFlush(); +} + +/********************************************************************/ +/* +%S Atributos personalizados +*/ +/********************************************************************/ + +static void set_img_format_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_format = 0; + else + { + int bpp = 0; + sscanf(data, "%d", &bpp); + if (bpp == 0) + return; + + if (bpp == 32) + ctxcanvas->img_format = 32; + else + ctxcanvas->img_format = 24; + } +} + +static char* get_img_format_attrib(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->img_format) + return NULL; + + if (ctxcanvas->img_format == 32) + return "32"; + else + return "24"; +} + +static cdAttribute img_format_attrib = +{ + "IMAGEFORMAT", + set_img_format_attrib, + get_img_format_attrib +}; + +static void set_img_alpha_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_alpha = NULL; + else + ctxcanvas->img_alpha = (unsigned char*)data; +} + +static char* get_img_alpha_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->img_alpha; +} + +static cdAttribute img_alpha_attrib = +{ + "IMAGEALPHA", + set_img_alpha_attrib, + get_img_alpha_attrib +}; + +static void set_img_mask_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + { + if (ctxcanvas->img_mask) DeleteObject(ctxcanvas->img_mask); + ctxcanvas->img_mask = NULL; + } + else + { + int w = 0, h = 0; + unsigned char *index = 0; + sscanf(data, "%d %d %p", &w, &h, &index); + if (w && h && index) + ctxcanvas->img_mask = Stipple2Bitmap(w, h, index, 1); + } +} + +static cdAttribute img_mask_attrib = +{ + "IMAGEMASK", + set_img_mask_attrib, + NULL +}; + +static void set_img_points_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + int p[6]; + + if (!data) + { + ctxcanvas->use_img_points = 0; + return; + } + + sscanf(data, "%d %d %d %d %d %d", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]); + + ctxcanvas->img_points[0].x = p[0]; + ctxcanvas->img_points[0].y = p[1]; + ctxcanvas->img_points[1].x = p[2]; + ctxcanvas->img_points[1].y = p[3]; + ctxcanvas->img_points[2].x = p[4]; + ctxcanvas->img_points[2].y = p[5]; + + ctxcanvas->use_img_points = 1; +} + +static char* get_img_points_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->use_img_points) + return NULL; + + sprintf(data, "%d %d %d %d %d %d", ctxcanvas->img_points[0].x, + ctxcanvas->img_points[0].y, + ctxcanvas->img_points[1].x, + ctxcanvas->img_points[1].y, + ctxcanvas->img_points[2].x, + ctxcanvas->img_points[2].y); + + return data; +} + +static cdAttribute img_points_attrib = +{ + "IMAGEPOINTS", + set_img_points_attrib, + get_img_points_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + XFORM xForm; + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + + /* the rotation must be corrected because of the Y axis orientation */ + + SetGraphicsMode(ctxcanvas->hDC, GM_ADVANCED); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + + xForm.eM11 = (FLOAT) cos(-CD_DEG2RAD*ctxcanvas->rotate_angle); + xForm.eM12 = (FLOAT) sin(-CD_DEG2RAD*ctxcanvas->rotate_angle); + xForm.eM21 = (FLOAT) -xForm.eM12; + xForm.eM22 = (FLOAT) xForm.eM11; + xForm.eDx = (FLOAT) ctxcanvas->rotate_center_x; + xForm.eDy = (FLOAT) _cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + xForm.eM11 = (FLOAT) 1; + xForm.eM12 = (FLOAT) 0; + xForm.eM21 = (FLOAT) 0; + xForm.eM22 = (FLOAT) 1; + xForm.eDx = (FLOAT) -ctxcanvas->rotate_center_x; + xForm.eDy = (FLOAT) -_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); + } +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_fill_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + ctxcanvas->fill_attrib[0] = data[0]; +} + +static char* get_fill_attrib(cdCtxCanvas* ctxcanvas) +{ + return ctxcanvas->fill_attrib; +} + +static cdAttribute fill_attrib = +{ + "PENFILLPOLY", + set_fill_attrib, + get_fill_attrib +}; + +static void set_window_rgn(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + HRGN hrgn = CreateRectRgn(0,0,0,0); + CombineRgn(hrgn, ctxcanvas->new_rgn, NULL, RGN_COPY); + SetWindowRgn(ctxcanvas->hWnd, hrgn, TRUE); + } + else + SetWindowRgn(ctxcanvas->hWnd, NULL, TRUE); +} + +static cdAttribute window_rgn_attrib = +{ + "WINDOWRGN", + set_window_rgn, + NULL +}; + +static char* get_hdc_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->hDC; +} + +static cdAttribute hdc_attrib = +{ + "HDC", + NULL, + get_hdc_attrib +}; + +/* +%F Cria o canvas para o driver Windows. +*/ +cdCtxCanvas *cdwCreateCanvas(cdCanvas* canvas, HWND hWnd, HDC hDC, int wtype) +{ + cdCtxCanvas* ctxcanvas; + LOGPEN logNullPen; + + ctxcanvas = (cdCtxCanvas*)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + /* store the base canvas */ + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->hWnd = hWnd; + ctxcanvas->hDC = hDC; + canvas->invert_yaxis = 1; + + /* linha nula para fill de interior apenas */ + logNullPen.lopnStyle = PS_NULL; + ctxcanvas->hNullPen = CreatePenIndirect(&logNullPen); + + ctxcanvas->logPen.lopnStyle = PS_SOLID; + ctxcanvas->logPen.lopnWidth.x = 1; /* 1 para que a linha possa ter estilo */ + ctxcanvas->logPen.lopnColor = 0; + ctxcanvas->rebuild_pen = 1; + + ctxcanvas->logBrush.lbStyle = BS_SOLID; + ctxcanvas->logBrush.lbColor = 0; + ctxcanvas->logBrush.lbHatch = HS_BDIAGONAL; + + ctxcanvas->clip_pnt = (POINT*)malloc(sizeof(POINT)*4); + memset(ctxcanvas->clip_pnt, 0, sizeof(POINT)*4); + ctxcanvas->clip_pnt_n = 4; + + ctxcanvas->wtype = wtype; + + SetStretchBltMode(ctxcanvas->hDC, COLORONCOLOR); + + ctxcanvas->fill_attrib[0] = '1'; + ctxcanvas->fill_attrib[1] = 0; + + cdRegisterAttribute(canvas, &hdc_attrib); + cdRegisterAttribute(canvas, &fill_attrib); + cdRegisterAttribute(canvas, &img_points_attrib); + cdRegisterAttribute(canvas, &img_mask_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &img_alpha_attrib); + cdRegisterAttribute(canvas, &img_format_attrib); + cdRegisterAttribute(canvas, &window_rgn_attrib); + + if (!cdwAlphaBlend) + { + HINSTANCE lib = LoadLibrary("Msimg32"); + if (lib) + cdwAlphaBlend = (AlphaBlendFunc)GetProcAddress(lib, "AlphaBlend"); + } + + return ctxcanvas; +} + +void cdwInitTable(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas = canvas->ctxcanvas; + + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxScrollArea = cdscrollarea; + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxTextOrientation = cdtextorientation; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxTransform = cdtransform; + + canvas->cxKillCanvas = cdwKillCanvas; + canvas->cxFlush = cdflush; + + if (ctxcanvas->wtype == CDW_WIN || ctxcanvas->wtype == CDW_BMP) + { + canvas->cxClear = cdclear; + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + } + + if (ctxcanvas->wtype == CDW_EMF) + canvas->cxPutImageRectRGBA = cdputimagerectrgba; +} diff --git a/src/win32/cdwin.h b/src/win32/cdwin.h new file mode 100644 index 0000000..1f4434f --- /dev/null +++ b/src/win32/cdwin.h @@ -0,0 +1,181 @@ +/** \file + * \brief Windows Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDWIN_H +#define __CDWIN_H + +#include <windows.h> +#include "cd.h" +#include "cd_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Contexto de cada imagem no servidor */ +struct _cdCtxImage +{ + HDC hDC; /* handle para o contexto de imagem na memoria */ + HBITMAP hBitmap; /* handle para o bitmap associado */ + HBITMAP hOldBitmap; /* handle para o bitmap associado inicialmente */ + int w; /* largura da imagem */ + int h; /* altura da imagem */ + double w_mm, h_mm; /* size in mm */ + double xres, yres; /* resolution in pixels/mm */ + int bpp; + + void* rgba_dib; /* used by 32 bpp to set alpha before putimage */ + unsigned char* alpha; /* the alpha values must be stored here */ +}; + +/* Contexto de cada canvas (CanvasContext). */ +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + HWND hWnd; /* handle para janela */ + HDC hDC; /* contexto gr'afico para janela */ + int release_dc; + + COLORREF fg, bg; /* foreground, backgound */ + + LOGPEN logPen; /* pena logica - struct com tipo, cor,... */ + HPEN hPen; /* handle para a pena corrente */ + HPEN hNullPen; /* handle da pena que nao desenha nada */ + HPEN hOldPen; /* pena anterior selecionado */ + int rebuild_pen; + + LOGBRUSH logBrush; /* pincel l'ogico - struct com tipo, cor,... */ + HBRUSH hBrush; /* handle para o pincel corrente */ + HBRUSH hOldBrush; /* brush anterior selecionado */ + HBRUSH hBkBrush; /* handle para o pincel com a cor de fundo */ + + HDC hDCMemPat; + HBITMAP hOldBitmapPat,hBitmapPat; + + HDC hDCMemStip; + HBITMAP hOldBitmapStip,hBitmapStip; + + HFONT hFont; /* handle para o fonte corrente */ + HFONT hOldFont; + + int font_angle; + + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + struct + { + int max_width; + int height; + int ascent; + int descent; + } font; + + POINT *clip_pnt; /* coordenadas do pixel no X,Y */ + int clip_pnt_n; /* numero de pontos correntes */ + HRGN clip_hrgn; + + HRGN new_rgn; + + HPALETTE hPal, hOldPal; /* handle para a paleta corrente */ + LOGPALETTE* pLogPal; /* paleta logica do canvas */ + + char *filename; /* Nome do arquivo para WMF */ + int wtype; /* Flag indicando qual o tipo de superficie */ + + HBITMAP hBitmapClip, hOldBitmapClip; /* Bitmap para copiar para clipboard */ + BITMAPINFO bmiClip; + BYTE* bitsClip; + DWORD RopBlt; /* Raster Operation for bitmaps */ + int isOwnedDC; /* usado pelo Native canvas */ + + BYTE* dib_bits; + int bits_size; + + cdImage* image_dbuffer; /* utilizado pelo driver de Double buffer */ + cdCanvas* canvas_dbuffer; + + HBITMAP img_mask; /* used by PutImage with mask and rotation and transparency */ + + POINT img_points[3]; + int use_img_points; + + char fill_attrib[2]; + + int img_format; + unsigned char* img_alpha; +}; + +enum{CDW_WIN, CDW_BMP, CDW_WMF, CDW_EMF}; + +/* Cria um canvas no driver Windows e inicializa valores default */ +cdCtxCanvas *cdwCreateCanvas(cdCanvas* canvas, HWND hWnd, HDC hDC, int wtype); +void cdwInitTable(cdCanvas* canvas); +void cdwRestoreDC(cdCtxCanvas *ctxcanvas); + +/* Remove valores comuns do driver Windows, deve ser chamado por todos os drivers */ +void cdwKillCanvas(cdCtxCanvas* canvas); + + +/* implemented in the wmfmeta.c module */ +void wmfMakePlaceableMetafile(HMETAFILE hmf, char* filename, int w, int h); +void wmfWritePlacebleFile(HANDLE hFile, char* buffer, DWORD dwSize, LONG mm, LONG xExt, LONG yExt); + +/* implemented in the wmf_emf.c module */ +int cdplayWMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data); +int cdregistercallbackWMF(int cb, cdCallback func); +int cdplayEMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data); +int cdregistercallbackEMF(int cb, cdCallback func); + +/* Estrutura que descreve um DIB. The secondary members are pointers to the main dib pointer. */ +typedef struct _cdwDIB +{ + BYTE* dib; /* The DIB as it is defined */ + BITMAPINFO* bmi; /* Bitmap Info = Bitmap Info Header + Palette*/ + BITMAPINFOHEADER* bmih; /* Bitmap Info Header */ + RGBQUAD* bmic; /* Palette */ + BYTE* bits; /* Bitmap Bits */ + int w; + int h; + int type; /* RGB = 0 or MAP = 1 or RGBA = 2 (dib section only) */ +} cdwDIB; + +enum {CDW_RGB, CDW_MAP, CDW_RGBA}; + +int cdwCreateDIB(cdwDIB* dib); +void cdwKillDIB(cdwDIB* dib); + +HANDLE cdwCreateCopyHDIB(BITMAPINFO* bmi, BYTE* bits); +void cdwDIBReference(cdwDIB* dib, BYTE* bmi, BYTE* bits); +int cdwCreateDIBRefBuffer(cdwDIB* dib, unsigned char* *bits, int *size); +void cdwCreateDIBRefBits(cdwDIB* dib, unsigned char *bits); +HBITMAP cdwCreateDIBSection(cdwDIB* dib, HDC hDC); + +HPALETTE cdwDIBLogicalPalette(cdwDIB* dib); + +/* copy from DIB */ +void cdwDIBDecodeRGB(cdwDIB* dib, unsigned char *red, unsigned char *green, unsigned char *blue); +void cdwDIBDecodeMap(cdwDIB* dib, unsigned char *index, long *colors); + +/* copy to DIB */ +void cdwDIBEncodePattern(cdwDIB* dib, const long int *colors); +void cdwDIBEncodeMapRect(cdwDIB* dib, const unsigned char *index, const long int *colors, int xi, int yi, int wi, int hi); +void cdwDIBEncodeRGBRect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, int xi, int yi, int wi, int hi); +void cdwDIBEncodeRGBARect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int xi, int yi, int wi, int hi); +void cdwDIBEncodeRGBARectZoom(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int w, int h, int xi, int yi, int wi, int hi); +void cdwDIBEncodeAlphaRect(cdwDIB* dib, const unsigned char *alpha, int xi, int yi, int wi, int hi); + + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef CDWIN_H */ + diff --git a/src/win32/cdwnative.c b/src/win32/cdwnative.c new file mode 100644 index 0000000..fdc223e --- /dev/null +++ b/src/win32/cdwnative.c @@ -0,0 +1,209 @@ +/** \file + * \brief Windows Native Window Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdnative.h" + + +int cdGetScreenColorPlanes(void) +{ + int bpp; + HDC ScreenDC = GetDC(NULL); + bpp = GetDeviceCaps(ScreenDC, BITSPIXEL); + ReleaseDC(NULL, ScreenDC); + return bpp; +} + +void cdGetScreenSize(int *width, int *height, double *width_mm, double *height_mm) +{ + HDC ScreenDC = GetDC(NULL); + if (width) *width = GetDeviceCaps(ScreenDC, HORZRES); + if (height) *height = GetDeviceCaps(ScreenDC, VERTRES); + if (width_mm) *width_mm = ((GetDeviceCaps(ScreenDC, HORZRES) * 25.4) / GetDeviceCaps(ScreenDC, LOGPIXELSX)); + if (height_mm) *height_mm = ((GetDeviceCaps(ScreenDC, VERTRES) * 25.4) / GetDeviceCaps(ScreenDC, LOGPIXELSY)); + ReleaseDC(NULL, ScreenDC); +} + +static void cdwReleaseDC(cdCtxCanvas *ctxcanvas) +{ + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen); + SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont); + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + ctxcanvas->hDC = NULL; +} + +static int cdactivate(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->hWnd) + { + RECT rect; + HDC ScreenDC; + GetClientRect(ctxcanvas->hWnd, &rect); + ctxcanvas->canvas->w = rect.right - rect.left; + ctxcanvas->canvas->h = rect.bottom - rect.top; + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + ScreenDC = GetDC(NULL); + ctxcanvas->canvas->bpp = GetDeviceCaps(ScreenDC, BITSPIXEL); + ReleaseDC(NULL, ScreenDC); + + if (ctxcanvas->canvas->use_matrix) + ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + } + + /* Se nao e' ownwer, tem que restaurar o contexto */ + if (!ctxcanvas->isOwnedDC) + { + if (ctxcanvas->hDC) /* deactivate not called */ + cdwReleaseDC(ctxcanvas); + + ctxcanvas->hDC = GetDC(ctxcanvas->hWnd); + cdwRestoreDC(ctxcanvas); + } + + return CD_OK; +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + /* Se nao e' ownwer, tem que liberar o contexto */ + if (!ctxcanvas->isOwnedDC && ctxcanvas->hDC) + cdwReleaseDC(ctxcanvas); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + /* se nao e' owner e nao esta' ativo, simula ativacao */ + if (!ctxcanvas->isOwnedDC && !ctxcanvas->hDC) + { + ctxcanvas->hDC = GetDC(ctxcanvas->hWnd); + cdwRestoreDC(ctxcanvas); + } + + cdwKillCanvas(ctxcanvas); + + if (ctxcanvas->release_dc) + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + HWND hWnd = NULL; + HDC hDC, ScreenDC; + int release_dc = 0; + + ScreenDC = GetDC(NULL); + canvas->bpp = GetDeviceCaps(ScreenDC, BITSPIXEL); + canvas->xres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSX)) / 25.4); + canvas->yres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSY)) / 25.4); + ReleaseDC(NULL, ScreenDC); + + if (!data) + { + hDC = GetDC(NULL); + release_dc = 1; + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + } + else if (IsWindow((HWND)data)) + { + RECT rect; + hWnd = (HWND)data; + + hDC = GetDC(hWnd); + release_dc = 1; + + GetClientRect(hWnd, &rect); + canvas->w = rect.right - rect.left; + canvas->h = rect.bottom - rect.top; + } + else /* can be a HDC or a string */ + { + DWORD objtype = GetObjectType((HGDIOBJ)data); + if (objtype == OBJ_DC || objtype == OBJ_MEMDC || + objtype == OBJ_ENHMETADC || objtype == OBJ_METADC) + { + hDC = (HDC)data; + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + } + else + { + hDC = NULL; + canvas->w = 0; + canvas->h = 0; + sscanf((char*)data,"%p %dx%d", &hDC, &canvas->w, &canvas->h); + + if (!hDC || !canvas->w || !canvas->h) + return; + } + release_dc = 0; + } + + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + + /* Inicializa driver WIN32 */ + ctxcanvas = cdwCreateCanvas(canvas, hWnd, hDC, CDW_WIN); + + ctxcanvas->release_dc = release_dc; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; + + if (hWnd) + { + LONG style; + style = GetClassLong(hWnd, GCL_STYLE); + ctxcanvas->isOwnedDC = (int) ((style & CS_OWNDC) || (style & CS_CLASSDC)); + } + else + ctxcanvas->isOwnedDC = 1; + + /* Se nao e' ownwer, tem que liberar o contexto */ + if (!ctxcanvas->isOwnedDC) + cdwReleaseDC(ctxcanvas); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; +} + +static cdContext cdNativeContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextNativeWindow(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_NATIVEWINDOW); + if (ctx != NULL) + return ctx; + } + + return &cdNativeContext; +} diff --git a/src/win32/cdwprn.c b/src/win32/cdwprn.c new file mode 100644 index 0000000..95e4aca --- /dev/null +++ b/src/win32/cdwprn.c @@ -0,0 +1,184 @@ +/** \file + * \brief Windows Printer Driver + * + * See Copyright Notice in cd.h + */ + + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdprint.h" + +#ifndef DC_COLORDEVICE +#define DC_COLORDEVICE 32 /* declared only if WINVER 0x0500 */ +#endif + +/* +%F cdKillCanvas para Printer. +Termina a pagina e termina o documento, enviando-o para a impressora. +*/ +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + EndPage(ctxcanvas->hDC); + EndDoc(ctxcanvas->hDC); + + cdwKillCanvas(ctxcanvas); + + DeleteDC(ctxcanvas->hDC); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/* +%F cdFlush para Printer. +Termina uma pagina e inicia outra. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + GdiFlush(); + EndPage(ctxcanvas->hDC); + + StartPage(ctxcanvas->hDC); + cdwRestoreDC(ctxcanvas); +} + +/* +%F cdCreateCanvas para Impresora. +Usa a impressora default. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + char *data_str = (char*) data; + char docname[256] = "CD - Canvas Draw Document"; + DOCINFO di; + HDC hDC; + int dialog = 0, wtype; + PRINTDLG pd; + + /* Inicializa parametros */ + if (data_str == NULL) + return; + + if (data_str[0] != 0) + { + char *ptr = strstr(data_str, "-d"); + + if (ptr != NULL) + dialog = 1; + + if (data_str[0] != '-') + { + strcpy(docname, data_str); + + if (dialog) + docname[ptr - data_str - 1] = 0; + } + } + + ZeroMemory(&pd, sizeof(PRINTDLG)); + pd.lStructSize = sizeof(PRINTDLG); + pd.nCopies = 1; + + if (dialog) + { + pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIES | PD_COLLATE | PD_NOPAGENUMS | PD_NOSELECTION; + pd.hwndOwner = GetForegroundWindow(); + } + else + { + pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; + } + + if (!PrintDlg(&pd)) + { + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); + return; + } + + hDC = pd.hDC; + + /* Inicializa documento */ + di.cbSize = sizeof(DOCINFO); + di.lpszDocName = docname; + di.lpszOutput = (LPTSTR) NULL; + di.lpszDatatype = (LPTSTR) NULL; + di.fwType = 0; + + StartDoc(hDC, &di); + + StartPage(hDC); + + wtype = CDW_EMF; + + /* Inicializa driver WIN32 */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, wtype); + + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + canvas->w_mm = (double) GetDeviceCaps(hDC, HORZSIZE); + canvas->h_mm = (double) GetDeviceCaps(hDC, VERTSIZE); + canvas->bpp = GetDeviceCaps(hDC, BITSPIXEL); + canvas->xres = canvas->w / canvas->w_mm; + canvas->yres = canvas->h / canvas->h_mm; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; + + /* PDF Writer returns bpp=1, so we check if color is supported and overwrite this value */ + if (canvas->bpp==1 && pd.hDevNames) + { + unsigned char* devnames = (unsigned char*)GlobalLock(pd.hDevNames); + DEVNAMES* dn = (DEVNAMES*)devnames; + char* name = (char*)(devnames + dn->wDeviceOffset); + char* port = (char*)(devnames + dn->wOutputOffset); + + if (DeviceCapabilities(name, port, DC_COLORDEVICE, NULL, NULL)) + canvas->bpp = 24; + + GlobalUnlock(pd.hDevNames); + } + + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxFlush = cdflush; +} + +static cdContext cdPrinterContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextPrinter(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_PRINTER); + if (ctx != NULL) + return ctx; + } + + return &cdPrinterContext; +} diff --git a/src/win32/cdwwmf.c b/src/win32/cdwwmf.c new file mode 100644 index 0000000..6b47aa5 --- /dev/null +++ b/src/win32/cdwwmf.c @@ -0,0 +1,109 @@ +/** \file + * \brief Windows WMF Driver + * Aldus Placeable Metafile + * + * See Copyright Notice in cd.h + */ + + +#include <stdlib.h> +#include <stdio.h> + +#include "cdwin.h" +#include "cdwmf.h" + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + HMETAFILE hmf; + + cdwKillCanvas(ctxcanvas); + + hmf = CloseMetaFile(ctxcanvas->hDC); + wmfMakePlaceableMetafile(hmf, ctxcanvas->filename, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + DeleteMetaFile(hmf); + + free(ctxcanvas->filename); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas* ctxcanvas; + char* strdata = (char*)data; + int w = 0, h = 0; + float res; + HDC ScreenDC; + FILE* fh; + char filename[10240] = ""; + + /* Inicializa parametros */ + if (strdata == NULL) + return; + + ScreenDC = GetDC(NULL); + res = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSX)) / 25.4); + ReleaseDC(NULL, ScreenDC); + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata,"%dx%d %g", &w, &h, &res); + if (w == 0 || h == 0) + return; + + /* Verifica se o arquivo pode ser aberto para escrita */ + fh = fopen(filename, "w"); + if (fh == 0) + return; + + fclose(fh); + + /* Inicializa driver WIN32 */ + ctxcanvas = cdwCreateCanvas(canvas, NULL, CreateMetaFile(NULL), CDW_WMF); + + canvas->w = w; + canvas->h = h; + canvas->xres = res; + canvas->yres = res; + canvas->w_mm = ((double)w) / res; + canvas->h_mm = ((double)h) / res; + canvas->bpp = 24; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1; + ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1; + + /* Inicializacao de variaveis particulares para o WMF */ + ctxcanvas->filename = strdup(filename); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + + /* overwrite the base Win32 driver functions */ + canvas->cxGetTextSize = cdgettextsizeEX; +} + +static cdContext cdWMFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS | CD_CAP_TEXTSIZE | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + cdplayWMF, + cdregistercallbackWMF +}; + +cdContext* cdContextWMF(void) +{ + return &cdWMFContext; +} diff --git a/src/win32/wmf_emf.c b/src/win32/wmf_emf.c new file mode 100644 index 0000000..36aeed0 --- /dev/null +++ b/src/win32/wmf_emf.c @@ -0,0 +1,2121 @@ +/** \file + * \brief EMF and WMF Play + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <fcntl.h> +#include <math.h> + +#include "cdwin.h" +#include "cdwmf.h" +#include "cdemf.h" + +/* placeable metafile data definitions */ +#define ALDUSKEY 0x9AC6CDD7 + +#ifndef PS_JOIN_MASK +#define PS_JOIN_MASK 0x0000F000 +#endif + +/* +%F Definicao do header do APM. Ver comentario no final deste arquivo. +*/ +typedef struct _APMFILEHEADER +{ + WORD key1, + key2, + hmf, + bleft, btop, bright, bbottom, + inch, + reserved1, + reserved2, + checksum; +} APMFILEHEADER; + + +/* coordinates convertion */ + +static double wmf_xfactor = 1; +static double wmf_yfactor = -1; /* negative because top-down orientation */ +static int wmf_xmin = 0; +static int wmf_ymin = 0; +static int wmf_left = 0; +static int wmf_bottom = 0; /* bottom and right are not included */ +static int wmf_top = 0; +static int wmf_right = 0; + +static int sScaleX(int x) +{ + return cdRound((x - wmf_left) * wmf_xfactor + wmf_xmin); +} + +static int sScaleY(int y) +{ + return cdRound((y - (wmf_bottom-1)) * wmf_yfactor + wmf_ymin); +} + +static int sScaleW(int w) +{ + int s = (int)(w * fabs(wmf_xfactor) + 0.5); + return s > 0? s: 1; +} + +static int sScaleH(int h) +{ + int s = (int)(h * fabs(wmf_yfactor) + 0.5); + return s > 0? s: 1; +} + +static void sCalcSizeX(int x) +{ + if (x < wmf_left) + { + wmf_left = x; + return; + } + + if (x+1 > wmf_right) + { + wmf_right = x+1; + return; + } +} + +static void sCalcSizeY(int y) +{ + if (y < wmf_top) + { + wmf_top = y; + return; + } + + if (y+1 > wmf_bottom) + { + wmf_bottom = y+1; + return; + } +} + +static int CALLBACK CalcSizeEMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) +{ + switch (lpEMFR->iType) + { + case EMR_POLYGON: + { + EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYLINE: + { + EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYLINETO: + { + EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYPOLYLINE: + { + EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + { + sCalcSizeX(aptl->x); + sCalcSizeY(aptl->y); + } + } + break; + } + case EMR_POLYPOLYGON: + { + EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + { + sCalcSizeX(aptl->x); + sCalcSizeY(aptl->y); + } + } + break; + } + case EMR_SETPIXELV: + { + EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR; + sCalcSizeX(data->ptlPixel.x); + sCalcSizeY(data->ptlPixel.y); + break; + } + case EMR_MOVETOEX: + { + EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR; + sCalcSizeX(data->ptl.x); + sCalcSizeY(data->ptl.y); + break; + } + case EMR_ANGLEARC: + { + EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR; + int x, y; + + x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + + sCalcSizeX(data->ptlCenter.x); + sCalcSizeY(data->ptlCenter.y); + sCalcSizeX(x); + sCalcSizeY(y); + break; + } + case EMR_ELLIPSE: + { + EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_RECTANGLE: + { + EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.bottom); + sCalcSizeY(data->rclBox.top); + break; + } + case EMR_ROUNDRECT: + { + EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.bottom); + sCalcSizeY(data->rclBox.top); + break; + } + case EMR_ARC: + { + EMRARC* data = (EMRARC*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_CHORD: + { + EMRCHORD* data = (EMRCHORD*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_PIE: + { + EMRPIE* data = (EMRPIE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_LINETO: + { + EMRLINETO* data = (EMRLINETO*)lpEMFR; + sCalcSizeX(data->ptl.x); + sCalcSizeY(data->ptl.y); + break; + } + case EMR_ARCTO: + { + EMRARCTO* data = (EMRARCTO*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_POLYDRAW: + { + int p; + EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR; + + for(p = 0; p < (int)data->cptl; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + sCalcSizeX(data->aptl[p].x); + sCalcSizeY(data->aptl[p].y); + break; + } + case PT_LINETO: + { + sCalcSizeX(data->aptl[p].x); + sCalcSizeY(data->aptl[p].y); + break; + } + } + } + break; + } + case EMR_BITBLT: + { + EMRBITBLT* data = (EMRBITBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_STRETCHBLT: + { + EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + data->cxDest); + sCalcSizeY(data->yDest + data->cyDest); + break; + } + case EMR_MASKBLT: + { + EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_SETDIBITSTODEVICE: + { + EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_STRETCHDIBITS: + { + EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + data->cxDest); + sCalcSizeY(data->yDest + data->cyDest); + break; + } + case EMR_EXTTEXTOUTA: + { + EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR; + sCalcSizeX(data->emrtext.ptlReference.x); + sCalcSizeY(data->emrtext.ptlReference.y); + break; + } + case EMR_EXTTEXTOUTW: + { + EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR; + sCalcSizeX(data->emrtext.ptlReference.x); + sCalcSizeY(data->emrtext.ptlReference.y); + break; + } + case EMR_POLYGON16: + { + EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYLINE16: + { + EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYLINETO16: + { + EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYPOLYLINE16: + { + EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + { + sCalcSizeX(apts->x); + sCalcSizeY(apts->y); + } + } + break; + } + case EMR_POLYPOLYGON16: + { + EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + { + sCalcSizeX(apts->x); + sCalcSizeY(apts->y); + } + } + break; + } + case EMR_POLYDRAW16: + { + EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR; + int p; + for(p = 0; p < (int)data->cpts; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + sCalcSizeX(data->apts[p].x); + sCalcSizeY(data->apts[p].y); + break; + } + case PT_LINETO: + { + sCalcSizeX(data->apts[p].x); + sCalcSizeY(data->apts[p].y); + break; + } + } + } + break; + } + case EMR_POLYTEXTOUTA: + { + EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR; + int t; + for (t = 0; t < data->cStrings; t++) + { + sCalcSizeX(data->aemrtext[t].ptlReference.x); + sCalcSizeY(data->aemrtext[t].ptlReference.y); + } + break; + } + case EMR_POLYTEXTOUTW: + { + EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR; + int t; + for (t = 0; t < data->cStrings; t++) + { + sCalcSizeX(data->aemrtext[t].ptlReference.x); + sCalcSizeY(data->aemrtext[t].ptlReference.y); + } + break; + } + } + + return 1; +} + +static int CALLBACK EMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) +{ + static int curx = 0, cury = 0; + static int upd_xy = 0; + cdCanvas* canvas = (cdCanvas*)lpData; + + switch (lpEMFR->iType) + { + case EMR_SETWORLDTRANSFORM: + { + double matrix[6]; + EMRSETWORLDTRANSFORM* data = (EMRSETWORLDTRANSFORM*)lpEMFR; + matrix[0] = data->xform.eM11; + matrix[1] = data->xform.eM12; + matrix[2] = data->xform.eM21; + matrix[3] = data->xform.eM22; + matrix[4] = data->xform.eDx; + matrix[5] = data->xform.eDy; + cdCanvasTransform(canvas, matrix); + break; + } + case EMR_MODIFYWORLDTRANSFORM: + { + EMRMODIFYWORLDTRANSFORM* data = (EMRMODIFYWORLDTRANSFORM*)lpEMFR; + if (data->iMode == MWT_IDENTITY) + cdCanvasTransform(canvas, NULL); + else if (data->iMode == MWT_LEFTMULTIPLY) + { + double matrix[6]; + matrix[0] = data->xform.eM11; + matrix[1] = data->xform.eM12; + matrix[2] = data->xform.eM21; + matrix[3] = data->xform.eM22; + matrix[4] = data->xform.eDx; + matrix[5] = data->xform.eDy; + cdCanvasTransformMultiply(canvas, matrix); + } + break; + } + case EMR_POLYGON: + { + EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINE: + { + EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIER: + { + EMRPOLYBEZIER* data = (EMRPOLYBEZIER*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINETO: + { + EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + curx = data->aptl[data->cptl - 1].x; + cury = data->aptl[data->cptl - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIERTO: + { + EMRPOLYBEZIERTO* data = (EMRPOLYBEZIERTO*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + curx = data->aptl[data->cptl - 1].x; + cury = data->aptl[data->cptl - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYPOLYLINE: + { + EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYPOLYGON: + { + EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_SETPIXELV: + { + EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR; + cdCanvasPixel(canvas, sScaleX(data->ptlPixel.x), sScaleY(data->ptlPixel.y), cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_SETBKMODE: + { + EMRSETBKMODE* data = (EMRSETBKMODE*)lpEMFR; + cdCanvasBackOpacity(canvas, data->iMode == TRANSPARENT? CD_TRANSPARENT: CD_OPAQUE); + break; + } + case EMR_SETROP2: + { + EMRSETROP2* data = (EMRSETROP2*)lpEMFR; + cdCanvasWriteMode(canvas, data->iMode == R2_NOTXORPEN? CD_NOT_XOR: (data->iMode == R2_XORPEN? CD_XOR: CD_REPLACE)); + break; + } + case EMR_SETTEXTALIGN: + { + EMRSETTEXTALIGN* data = (EMRSETTEXTALIGN*)lpEMFR; + upd_xy = 0; + + if (data->iMode & TA_UPDATECP) + { + upd_xy = 1; + data->iMode &= ~TA_UPDATECP; + } + + switch (data->iMode) + { + case 0: /* top-left */ + cdCanvasTextAlignment(canvas, CD_NORTH_WEST); + break; + case 2: /* top-right */ + cdCanvasTextAlignment(canvas, CD_NORTH_EAST); + break; + case 6: /* top-center */ + cdCanvasTextAlignment(canvas, CD_NORTH); + break; + case 8: /* bottom-left */ + cdCanvasTextAlignment(canvas, CD_SOUTH_WEST); + break; + case 10: /* bottom-right */ + cdCanvasTextAlignment(canvas, CD_SOUTH_EAST); + break; + case 14: /* bottom-center */ + cdCanvasTextAlignment(canvas, CD_SOUTH); + break; + case 24: /* baseline-left */ + cdCanvasTextAlignment(canvas, CD_BASE_LEFT); + break; + case 26: /* baseline-right */ + cdCanvasTextAlignment(canvas, CD_BASE_RIGHT); + break; + case 30: /* baseline-center */ + cdCanvasTextAlignment(canvas, CD_BASE_CENTER); + break; + } + + break; + } + case EMR_SETTEXTCOLOR: + { + EMRSETTEXTCOLOR* data = (EMRSETTEXTCOLOR*)lpEMFR; + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_SETBKCOLOR: + { + EMRSETBKCOLOR* data = (EMRSETBKCOLOR*)lpEMFR; + cdCanvasSetBackground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_MOVETOEX: + { + EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR; + curx = data->ptl.x; + cury = data->ptl.y; + break; + } + case EMR_CREATEPEN: + { + EMRCREATEPEN* data = (EMRCREATEPEN*)lpEMFR; + int style; + + switch (data->lopn.lopnStyle) + { + case PS_SOLID: + style = CD_CONTINUOUS; + break; + case PS_DASH: + style = CD_DASHED; + break; + case PS_DOT: + style = CD_DOTTED; + break; + case PS_DASHDOT: + style = CD_DASH_DOT; + break; + case PS_DASHDOTDOT: + style = CD_DASH_DOT_DOT; + break; + case PS_NULL: + style = -1; + break; + default: + style = CD_CONTINUOUS; + break; + } + + if (style != -1) + { + cdCanvasLineStyle(canvas, style); + cdCanvasLineWidth(canvas, sScaleW(data->lopn.lopnWidth.x == 0? 1: data->lopn.lopnWidth.x)); + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lopn.lopnColor),GetGValue(data->lopn.lopnColor),GetBValue(data->lopn.lopnColor))); + } + break; + } + case EMR_EXTCREATEPEN: + { + EMREXTCREATEPEN* data = (EMREXTCREATEPEN*)lpEMFR; + int style; + + switch (data->elp.elpPenStyle & PS_STYLE_MASK) + { + case PS_SOLID: + style = CD_CONTINUOUS; + break; + case PS_DASH: + style = CD_DASHED; + break; + case PS_DOT: + style = CD_DOTTED; + break; + case PS_DASHDOT: + style = CD_DASH_DOT; + break; + case PS_DASHDOTDOT: + style = CD_DASH_DOT_DOT; + break; + case PS_NULL: + style = -1; + break; + case PS_USERSTYLE: + style = CD_CUSTOM; + cdCanvasLineStyleDashes(canvas, (int*)data->elp.elpStyleEntry, data->elp.elpNumEntries); + break; + default: + style = CD_CONTINUOUS; + break; + } + + if (style != -1) + { + switch (data->elp.elpPenStyle & PS_ENDCAP_MASK) + { + case PS_ENDCAP_FLAT: + cdCanvasLineCap(canvas, CD_CAPFLAT); + break; + case PS_ENDCAP_ROUND: + cdCanvasLineCap(canvas, CD_CAPROUND); + break; + case PS_ENDCAP_SQUARE: + cdCanvasLineCap(canvas, CD_CAPSQUARE); + break; + } + + switch (data->elp.elpPenStyle & PS_JOIN_MASK) + { + case PS_JOIN_MITER: + cdCanvasLineJoin(canvas, CD_MITER); + break; + case PS_JOIN_BEVEL: + cdCanvasLineJoin(canvas, CD_BEVEL); + break; + case PS_JOIN_ROUND: + cdCanvasLineJoin(canvas, CD_ROUND); + break; + } + + cdCanvasLineStyle(canvas, style); + cdCanvasLineWidth(canvas, sScaleW(data->elp.elpWidth == 0? 1: data->elp.elpWidth)); + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->elp.elpColor),GetGValue(data->elp.elpColor),GetBValue(data->elp.elpColor))); + } + break; + } + case EMR_CREATEBRUSHINDIRECT: + { + EMRCREATEBRUSHINDIRECT* data = (EMRCREATEBRUSHINDIRECT*)lpEMFR; + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lb.lbColor),GetGValue(data->lb.lbColor),GetBValue(data->lb.lbColor))); + + switch (data->lb.lbStyle) + { + case BS_HATCHED: + { + int hatch = 0; + + switch (data->lb.lbHatch) + { + case HS_BDIAGONAL: + hatch = CD_BDIAGONAL; + break; + case HS_CROSS: + hatch = CD_CROSS; + break; + case HS_DIAGCROSS: + hatch = CD_DIAGCROSS; + break; + case HS_FDIAGONAL: + hatch = CD_FDIAGONAL; + break; + case HS_HORIZONTAL: + hatch = CD_HORIZONTAL; + break; + case HS_VERTICAL: + hatch = CD_VERTICAL; + break; + } + + cdCanvasHatch(canvas, hatch); + cdCanvasInteriorStyle(canvas, CD_HATCH); + break; + } + case BS_SOLID: + cdCanvasInteriorStyle(canvas, CD_SOLID); + break; + case BS_NULL: + cdCanvasInteriorStyle(canvas, CD_HOLLOW); + break; + default: + break; + } + break; + } + case EMR_ANGLEARC: + { + EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR; + int x, y; + + x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + + cdCanvasLine(canvas, sScaleX(data->ptlCenter.x), sScaleY(data->ptlCenter.y), sScaleX(x), sScaleY(y)); + cdCanvasArc(canvas, data->ptlCenter.x, data->ptlCenter.y, 2 * data->nRadius, 2 * data->nRadius, data->eStartAngle, data->eStartAngle + data->eSweepAngle); + break; + } + case EMR_ELLIPSE: + { + EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR; + int xc, yc, w, h; + + xc = sScaleX((data->rclBox.left + data->rclBox.right - 1) / 2); + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + yc = sScaleY((data->rclBox.top + data->rclBox.bottom - 1) / 2); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + cdCanvasSector(canvas, xc, yc, w, h, 0, 360); + break; + } + case EMR_RECTANGLE: + { + EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR; + cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top)); + break; + } + case EMR_ROUNDRECT: + { + EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR; + cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top)); + break; + } + case EMR_ARC: + { + EMRARC* data = (EMRARC*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_CHORD: + { + EMRCHORD* data = (EMRCHORD*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasChord(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_PIE: + { + EMRPIE* data = (EMRPIE*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasSector(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_CREATEPALETTE: + { + int k; + EMRCREATEPALETTE* data = (EMRCREATEPALETTE*)lpEMFR; + long palette[256]; + + for (k=0; k < data->lgpl.palNumEntries; k++) + palette[k] = cdEncodeColor(data->lgpl.palPalEntry[k].peRed, data->lgpl.palPalEntry[k].peGreen, data->lgpl.palPalEntry[k].peBlue); + + cdCanvasPalette(canvas, data->lgpl.palNumEntries, palette, CD_POLITE); + break; + } + case EMR_LINETO: + { + EMRLINETO* data = (EMRLINETO*)lpEMFR; + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->ptl.x), sScaleY(data->ptl.y)); + curx = data->ptl.x; + cury = data->ptl.y; + break; + } + case EMR_ARCTO: + { + EMRARCTO* data = (EMRARCTO*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + curx = data->ptlEnd.x; /* isto nao esta' certo mas e' a minha melhor aproximacao */ + cury = data->ptlEnd.y; + break; + } + case EMR_POLYDRAW: + { + int p; + EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR; + + for(p = 0; p < (int)data->cptl; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + curx = data->aptl[p].x; + cury = data->aptl[p].y; + break; + } + case PT_LINETO: + { + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->aptl[p].x), sScaleY(data->aptl[p].y)); + curx = data->aptl[p].x; + cury = data->aptl[p].y; + break; + } + } + } + break; + } + case EMR_BITBLT: + { + EMRBITBLT* data = (EMRBITBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_STRETCHBLT: + { + EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_MASKBLT: + { + EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_SETDIBITSTODEVICE: + { + EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR; + int size; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + break; + } + case EMR_STRETCHDIBITS: + { + EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR; + int size; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(index); + free(colors); + } + break; + } + case EMR_EXTCREATEFONTINDIRECTW: + { + EMREXTCREATEFONTINDIRECTW* data = (EMREXTCREATEFONTINDIRECTW*)lpEMFR; + int style, size; + char type_face[256]; + + style = CD_PLAIN; + + if (data->elfw.elfLogFont.lfWeight >= FW_BOLD) + style = CD_BOLD; + + if (data->elfw.elfLogFont.lfItalic == 1) + style = CD_ITALIC; + + if (data->elfw.elfLogFont.lfWeight >= FW_BOLD && data->elfw.elfLogFont.lfItalic == 1) + style = CD_BOLD_ITALIC; + + if (data->elfw.elfLogFont.lfUnderline) + style |= CD_UNDERLINE; + + if (data->elfw.elfLogFont.lfStrikeOut) + style |= CD_STRIKEOUT; + + WideCharToMultiByte(CP_ACP, 0, data->elfw.elfLogFont.lfFaceName, LF_FACESIZE, type_face, 256, NULL, NULL); + + size = sScaleH(abs(data->elfw.elfLogFont.lfHeight)); + if (size < 5) size = 5; + + if (data->elfw.elfLogFont.lfOrientation) + cdCanvasTextOrientation(canvas, data->elfw.elfLogFont.lfOrientation/10); + + cdCanvasFont(canvas, type_face, style, -size); + break; + } + case EMR_EXTTEXTOUTA: + { + EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR; + + char* str = malloc(data->emrtext.nChars + 1); + memcpy(str, ((unsigned char*)data) + data->emrtext.offString, data->emrtext.nChars + 1); + str[data->emrtext.nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str); + + if (upd_xy == 1) + { + curx = data->emrtext.ptlReference.x; + cury = data->emrtext.ptlReference.y; + } + + free(str); + break; + } + case EMR_EXTTEXTOUTW: + { + EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR; + char str[256]; + + WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->emrtext.offString), data->emrtext.nChars, str, 256, NULL, NULL); + + str[data->emrtext.nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str); + + if (upd_xy == 1) + { + curx = data->emrtext.ptlReference.x; + cury = data->emrtext.ptlReference.y; + } + break; + } + case EMR_SETPOLYFILLMODE: + { + EMRSETPOLYFILLMODE* data = (EMRSETPOLYFILLMODE*)lpEMFR; + if (data->iMode == ALTERNATE) + cdCanvasFillMode(canvas, CD_EVENODD); + else + cdCanvasFillMode(canvas, CD_WINDING); + break; + } + case EMR_POLYGON16: + { + EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINE16: + { + EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINETO16: + { + EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + curx = data->apts[data->cpts - 1].x; + cury = data->apts[data->cpts - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIER16: + { + EMRPOLYBEZIER16* data = (EMRPOLYBEZIER16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIERTO16: + { + EMRPOLYBEZIERTO16* data = (EMRPOLYBEZIERTO16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + curx = data->apts[data->cpts - 1].x; + cury = data->apts[data->cpts - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYPOLYLINE16: + { + EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYPOLYGON16: + { + EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYDRAW16: + { + int p; + EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR; + + for(p = 0; p < (int)data->cpts; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + curx = data->apts[p].x; + cury = data->apts[p].y; + break; + } + case PT_LINETO: + { + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->apts[p].x), sScaleY(data->apts[p].y)); + curx = data->apts[p].x; + cury = data->apts[p].y; + break; + } + } + } + break; + } + case EMR_CREATEMONOBRUSH: + { + EMRCREATEMONOBRUSH* data = (EMRCREATEMONOBRUSH*)lpEMFR; + int size, i; + cdwDIB dib; + long *pattern; + unsigned char *stipple; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.bmih->biBitCount == 1) + stipple = malloc(size); + else + pattern = (long*)malloc(size*sizeof(long)); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + for (i = 0; i < size; i++) + pattern[i] = cdEncodeColor(r[i], g[i], b[i]); + + free(r); + free(g); + free(b); + } + else + { + unsigned char *index; + long *colors; + + index = (unsigned char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + if (dib.bmih->biBitCount == 1) + { + for (i = 0; i < size; i++) + stipple[i] = index[i]? 0: 1; + } + else + { + for (i = 0; i < size; i++) + pattern[i] = colors[index[i]]; + } + + free(index); + free(colors); + } + + if (dib.bmih->biBitCount == 1) + { + cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple); + free(stipple); + } + else + { + cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern); + free(pattern); + } + break; + } + case EMR_CREATEDIBPATTERNBRUSHPT: + { + EMRCREATEDIBPATTERNBRUSHPT* data = (EMRCREATEDIBPATTERNBRUSHPT*)lpEMFR; + int size, i; + cdwDIB dib; + long *pattern; + unsigned char *stipple; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.bmih->biBitCount == 1) + stipple = malloc(size); + else + pattern = malloc(size*sizeof(long)); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + for (i = 0; i < size; i++) + pattern[i] = cdEncodeColor(r[i], g[i], b[i]); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + if (dib.bmih->biBitCount == 1) + { + for (i = 0; i < size; i++) + stipple[i] = index[i]? 0: 1; + } + else + { + for (i = 0; i < size; i++) + pattern[i] = colors[index[i]]; + } + + free(index); + free(colors); + } + + if (dib.bmih->biBitCount == 1) + { + cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple); + free(stipple); + } + else + { + cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern); + free(pattern); + } + break; + } + case EMR_POLYTEXTOUTA: + { + int t; + EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR; + + for (t = 0; t < data->cStrings; t++) + { + char* str = malloc(data->aemrtext[t].nChars + 1); + memcpy(str, ((unsigned char*)data) + data->aemrtext[t].offString, data->aemrtext[t].nChars + 1); + str[data->aemrtext[t].nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str); + + free(str); + } + break; + } + case EMR_POLYTEXTOUTW: + { + int t; + EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR; + char str[256]; + + for (t = 0; t < data->cStrings; t++) + { + WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->aemrtext[t].offString), data->aemrtext[t].nChars, str, 256, NULL, NULL); + str[data->aemrtext[t].nChars] = 0; + cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str); + } + break; + } + } + + return 1; +} + + +static cdSizeCB cdsizecbWMF = NULL; + +int cdregistercallbackWMF(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecbWMF = (cdSizeCB)func; + return CD_OK; + } + + return CD_ERROR; +} + + +/*********************************************************************** +Read the metafile bits, metafile header and placeable +metafile header of a placeable metafile. +************************************************************************/ + +static HANDLE GetPlaceableMetaFile(int fh) +{ + HANDLE hMF; + HANDLE hMem; + LPSTR lpMem; + int wBytesRead; + APMFILEHEADER aldusMFHeader; + METAHEADER mfHeader; + + /* seek to beginning of file and read aldus header */ + lseek(fh, 0, 0); + + /* read the placeable header */ + wBytesRead = read(fh, (LPSTR)&aldusMFHeader, sizeof(APMFILEHEADER)); + + /* if there is an error, return */ + if(wBytesRead == -1 || wBytesRead < sizeof(APMFILEHEADER)) + return NULL; + + /* read the metafile header */ + wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER)); + + /* if there is an error return */ + if( wBytesRead == -1 || wBytesRead < sizeof(METAHEADER) ) + return NULL; + + /* allocate memory for the metafile bits */ + if (!(hMem = GlobalAlloc(GHND, mfHeader.mtSize * 2L))) + return NULL; + + /* lock the memory */ + if (!(lpMem = GlobalLock(hMem))) + { + GlobalFree(hMem); + return NULL; + } + + /* seek to the metafile bits */ + lseek(fh, sizeof(APMFILEHEADER), 0); + + /* read metafile bits */ + wBytesRead = read(fh, lpMem, (WORD)(mfHeader.mtSize * 2L)); + + /* if there was an error */ + if( wBytesRead == -1 ) + { + GlobalUnlock(hMem); + GlobalFree(hMem); + return NULL; + } + + if (!(hMF = SetMetaFileBitsEx(mfHeader.mtSize * 2L, lpMem))) + return NULL; + + GlobalUnlock(hMem); + GlobalFree(hMem); + + return hMF; +} + + +/* +%F cdPlay para WMF. +Interpreta os dados do WMF. +*/ +int cdplayWMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + int fh; + int wBytesRead; + DWORD dwIsAldus; + HANDLE hMF; + HENHMETAFILE hEMF; + ENHMETAHEADER emh; + BYTE* buffer; + int size; + + /* try to open the file. */ + fh = open(filename, O_BINARY | O_RDONLY); + + /* if opened failed */ + if (fh == -1) + return CD_ERROR; + + /* read the first dword of the file to see if it is a placeable wmf */ + wBytesRead = read(fh,(LPSTR)&dwIsAldus, sizeof(dwIsAldus)); + if (wBytesRead == -1 || wBytesRead < sizeof(dwIsAldus)) + { + close(fh); + return CD_ERROR; + } + + /* if this is windows metafile, not a placeable wmf */ + if (dwIsAldus != ALDUSKEY) + { + METAHEADER mfHeader; + + /* seek to the beginning of the file */ + lseek(fh, 0, 0); + + /* read the wmf header */ + wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER)); + + /* done with file so close it */ + close(fh); + + /* if read failed */ + if (wBytesRead == -1 || wBytesRead < sizeof(METAHEADER)) + return CD_ERROR; + + hMF = GetMetaFile(filename); + } + else /* this is a placeable metafile */ + { + /* convert the placeable format into something that can + be used with GDI metafile functions */ + hMF = GetPlaceableMetaFile(fh); + + /* close the file */ + close(fh); + } + + if (!hMF) + return CD_ERROR; + + size = GetMetaFileBitsEx(hMF, 0, NULL); + + buffer = malloc(size); + + GetMetaFileBitsEx(hMF, size, buffer); + + hEMF = SetWinMetaFileBits(size, buffer, NULL, NULL); + + GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh); + + /* when converted from WMF, only rclBounds is available */ + wmf_bottom = emh.rclBounds.bottom; + wmf_left = emh.rclBounds.left; + wmf_top = emh.rclBounds.top; + wmf_right = emh.rclBounds.right; + + if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */ + EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL); + + if ((wmf_bottom-wmf_top)>1 && + (wmf_right-wmf_left)>1 && + (xmax-xmin+1)>1 && + (ymax-ymin+1)>1) + { + wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */ + wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left); + wmf_xmin = xmin; + wmf_ymin = ymin; + } + else + { + wmf_yfactor = -1; /* negative because top-down orientation */ + wmf_xfactor = 1; + wmf_xmin = 0; + wmf_ymin = 0; + } + + free(buffer); + + if (cdsizecbWMF && dwIsAldus == ALDUSKEY) + { + int err; + err = cdsizecbWMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0); + if (err) + { + DeleteEnhMetaFile (hEMF); + return CD_ERROR; + } + } + + EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL); + + DeleteEnhMetaFile (hEMF); + + DeleteMetaFile (hMF); + + return CD_OK; +} + + +static cdSizeCB cdsizecbEMF = NULL; + +int cdregistercallbackEMF(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecbEMF = (cdSizeCB)func; + return CD_OK; + } + + return CD_ERROR; +} + + +int cdplayEMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + HENHMETAFILE hEMF; + ENHMETAHEADER emh; + double xres, yres; + + hEMF = GetEnhMetaFile(filename); + + GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh); + + /* this is obtained from the hdcRef of CreateEnhMetaFile */ + xres = ((double)emh.szlDevice.cx) / emh.szlMillimeters.cx; + yres = ((double)emh.szlDevice.cy) / emh.szlMillimeters.cy; + + /* this is the same as used in RECT of CreateEnhMetaFile */ + wmf_bottom = (int)((emh.rclFrame.bottom * yres) / 100); + wmf_left = (int)((emh.rclFrame.left * xres) / 100); + wmf_top = (int)((emh.rclFrame.top * yres) / 100); + wmf_right = (int)((emh.rclFrame.right * xres) / 100); + + if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */ + EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL); + + if ((wmf_bottom-wmf_top)>1 && + (wmf_right-wmf_left)>1 && + (xmax-xmin+1)>1 && + (ymax-ymin+1)>1) + { + wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */ + wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left); + wmf_xmin = xmin; + wmf_ymin = ymin; + } + else + { + wmf_yfactor = -1; /* negative because top-down orientation */ + wmf_xfactor = 1; + wmf_xmin = 0; + wmf_ymin = 0; + } + + if (cdsizecbEMF) + { + int err; + err = cdsizecbEMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0); + if (err) + { + DeleteEnhMetaFile (hEMF); + return CD_ERROR; + } + } + + EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL); + + DeleteEnhMetaFile (hEMF); + + return CD_OK; +} + +/* +%F Calculo do CheckSum. +*/ +static WORD sAPMChecksum(APMFILEHEADER* papm) +{ + WORD* pw = (WORD*)papm; + WORD wSum = 0; + int i; + + /* The checksum in a Placeable Metafile header is calculated */ + /* by XOR-ing the first 10 words of the header. */ + + for (i = 0; i < 10; i++) + wSum ^= *pw++; + + return wSum; +} + + + +/* +Aldus placeable metafile format + + DWORD key; + HANDLE hmf; + RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; + char metafileData[]; + + These fields have the following meanings: + + Field Definition + + key Binary key that uniquely identifies this + file type. This must be 0x9AC6CDD7L. + + hmf Unused; must be zero. + + bbox The coordinates of a rectangle that tightly + bounds the picture. These coordinates are in + metafile units as defined below. + + inch The number of metafile units to the inch. To + avoid numeric overflow in PageMaker, this value + should be less than 1440. + + reserved A reserved double word. Must be zero. + + checksum A checksum of the 10 words that precede it, + calculated by XORing zero with these 10 words + and putting the result in the checksum field. + + metafileData The actual content of the Windows metafile + retrieved by copying the data returned by + GetMetafileBits to the file. The number of + bytes should be equal to the MS-DOS file length + minus 22. The content of a PageMaker placeable + metafile cannot currently exceed 64K (this may + have changed in 4.0). +*/ + +/* +%F Cria um APM em arquivo a partir de um WMF em memoria. +*/ +void wmfMakePlaceableMetafile(HMETAFILE hmf, char* filename, int w, int h) +{ + int fh, nSize; + LPSTR lpData; + APMFILEHEADER APMHeader; + + fh = open(filename, O_CREAT | O_BINARY | O_WRONLY); + + APMHeader.key1 = 0xCDD7; + APMHeader.key2 = 0x9AC6; + APMHeader.hmf = 0; + APMHeader.bleft = 0; + APMHeader.btop = 0; + APMHeader.bright = (short)w; + APMHeader.bbottom = (short)h; + APMHeader.inch = 100; /* this number works fine in Word, etc.. */ + APMHeader.reserved1 = 0; + APMHeader.reserved2 = 0; + APMHeader.checksum = sAPMChecksum(&APMHeader); + + write(fh, (LPSTR)&APMHeader, sizeof(APMFILEHEADER)); + + nSize = GetMetaFileBitsEx(hmf, 0, NULL); + lpData = malloc(nSize); + GetMetaFileBitsEx(hmf, nSize, lpData); + + write(fh, lpData, nSize); + free(lpData); + + close(fh); +} + +void wmfWritePlacebleFile(HANDLE hFile, char* buffer, DWORD dwSize, LONG mm, LONG xExt, LONG yExt) +{ + DWORD nBytesWrite; + APMFILEHEADER APMHeader; + int w = xExt, h = yExt; + + if (mm == MM_ANISOTROPIC || mm == MM_ISOTROPIC) + { + int res = 30; + w = xExt / res; + h = yExt / res; + } + + APMHeader.key1 = 0xCDD7; + APMHeader.key2 = 0x9AC6; + APMHeader.hmf = 0; + APMHeader.bleft = 0; + APMHeader.btop = 0; + APMHeader.bright = (short)w; + APMHeader.bbottom = (short)h; + APMHeader.inch = 100; /* this number works fine in Word, etc.. */ + APMHeader.reserved1 = 0; + APMHeader.reserved2 = 0; + APMHeader.checksum = sAPMChecksum(&APMHeader); + + WriteFile(hFile, (LPSTR)&APMHeader, sizeof(APMFILEHEADER), &nBytesWrite, NULL); + WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL); +} + diff --git a/src/x11/cdx11.c b/src/x11/cdx11.c new file mode 100644 index 0000000..62e81ed --- /dev/null +++ b/src/x11/cdx11.c @@ -0,0 +1,2447 @@ +/** \file + * \brief X-Windows Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <math.h> + +#include "cdx11.h" +#include "xvertex.h" + +#include <X11/Xproto.h> + +unsigned long (*cdxGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb); /* acesso a tabela de cores */ +void (*cdxGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel, + unsigned char* red, + unsigned char* green, + unsigned char* blue); /* acesso a tabela de cores */ +static XGCValues gcval; + +static int cdxDirectColorTable[256]; /* used with directColor visuals */ + +#define NUM_HATCHES 6 +#define HATCH_WIDTH 8 +#define HATCH_HEIGHT 8 +/* +** 6 padroes pre-definidos a serem acessados atraves de cdHatch( + CD_HORIZONTAL | CD_VERTICAL | CD_FDIAGONAL | CD_BDIAGONAL | + CD_CROSS | CD_DIAGCROSS) + +*/ +static char hatches[NUM_HATCHES][8] = { + {0x00,0x00,0xFF,0x00,0x00,0x00,0xFF,0x00}, /* HORIZONTAL */ + {0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22}, /* VERTICAL */ + {0x08,0x10,0x20,0x40,0x80,0x01,0x02,0x04}, /* FDIAGONAL */ + {0x10,0x08,0x04,0x02,0x01,0x80,0x40,0x20}, /* BDIAGONAL */ + {0x22,0x22,0xFF,0x22,0x22,0x22,0xFF,0x22}, /* CROSS */ + {0x18,0x18,0x24,0x42,0x81,0x81,0x42,0x24} /* DIAGCROSS */ +}; + +/******************************************************/ + +static int cdxErrorHandler(Display* dpy, XErrorEvent *err) +{ + char msg[80]; + + /* Se for erro de BadMatch em XGetImage, tudo bem */ + if (err->request_code==X_GetImage && err->error_code==BadMatch) + return 0; + + /* Se for erro de BadAcess em XFreeColors, tudo bem */ + if (err->request_code==X_FreeColors && err->error_code==BadAccess) + return 0; + + XGetErrorText(dpy, err->error_code, msg, 80 ); + fprintf(stderr,"CanvasDraw: Xlib request %d: %s\n", err->request_code, msg); + + return 0; +} + +static void update_colors(cdCtxCanvas *ctxcanvas) +{ + XQueryColors(ctxcanvas->dpy, ctxcanvas->colormap, ctxcanvas->color_table, ctxcanvas->num_colors); +} + +static int find_color(cdCtxCanvas *ctxcanvas, XColor* xc1) +{ + int pos = 0, i; + unsigned long min_dist = ULONG_MAX, this_dist; + int dr, dg, db; + XColor* xc2; + + for (i=0; i<ctxcanvas->num_colors; i++) + { + xc2 = &(ctxcanvas->color_table[i]); + + dr = (xc1->red - xc2->red) / 850; /* 0.30 / 255 */ + dg = (xc1->green - xc2->green) / 432; /* 0.59 / 255 */ + db = (xc1->blue - xc2->blue) / 2318; /* 0.11 / 255 */ + + this_dist = dr*dr + dg*dg + db*db; + + if (this_dist < min_dist) + { + min_dist = this_dist; + pos = i; + } + } + + return pos; +} + +/* Busca o RGB mais proximo na tabela de cores */ +static unsigned long nearest_rgb(cdCtxCanvas *ctxcanvas, XColor* xc) +{ + static int nearest_try = 0; + + int pos = find_color(ctxcanvas, xc); + + /* verifico se a cor ainda esta alocada */ + /* Try to allocate the closest match color. + This should fail only if the cell is read/write. + Otherwise, we're incrementing the cell's reference count. + (comentario extraido da biblioteca Mesa) */ + if (!XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &(ctxcanvas->color_table[pos]))) + { + /* nao esta, preciso atualizar a tabela e procurar novamente */ + /* isto acontece porque a cor encontrada pode ter sido de uma aplicacao que nao existe mais */ + /* uma vez atualizada, o problema nao ocorrera' na nova procura */ + /* ou a celula e' read write */ + + if (nearest_try == 1) + { + nearest_try = 0; + return ctxcanvas->color_table[pos].pixel; + } + + /* o que e' mais lento? + Dar um query colors em todo o nearest, --> Isso deve ser mais lento + ou fazer a busca acima antes e arriscar uma repeticao? */ + + update_colors(ctxcanvas); + + nearest_try = 1; /* garante que so' vai tentar isso uma vez */ + return nearest_rgb(ctxcanvas, xc); + } + + return ctxcanvas->color_table[pos].pixel; +} + +/* Funcao get_pixel usando tabela de conversao. \ + Usada quando nao estamos em TrueColor. */ +static unsigned long not_truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb) +{ + unsigned long pixel; + XColor xc; + xc.red = cdCOLOR8TO16(cdRed(rgb)); + xc.green = cdCOLOR8TO16(cdGreen(rgb)); + xc.blue = cdCOLOR8TO16(cdBlue(rgb)); + xc.flags = DoRed | DoGreen | DoBlue; + + /* verificamos se a nova cor ja' esta' disponivel */ + if (!XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc)) + { + /* nao estava disponivel, procuro pela mais proxima na tabela de cores */ + pixel = nearest_rgb(ctxcanvas, &xc); + } + else + { + /* ja' estava disponivel */ + /* atualizo a tabela de cores */ + ctxcanvas->color_table[xc.pixel] = xc; + pixel = xc.pixel; + } + + return pixel; +} + +/* +%F Funcao usando tabela de conversao. \ + Usada quando nao estamos em TrueColor. +*/ +static void not_truecolor_get_rgb(cdCtxCanvas *ctxcanvas, unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + XColor xc; + xc.pixel = pixel; + XQueryColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc); + *red = cdCOLOR16TO8(xc.red); + *green = cdCOLOR16TO8(xc.green); + *blue = cdCOLOR16TO8(xc.blue); +} + +/* +%F Funcao get_rgb usada quando estamos em TrueColor. +*/ +static void truecolor_get_rgb(cdCtxCanvas *ctxcanvas, unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + unsigned long r = pixel & ctxcanvas->vis->red_mask; + unsigned long g = pixel & ctxcanvas->vis->green_mask; + unsigned long b = pixel & ctxcanvas->vis->blue_mask; + if (ctxcanvas->rshift<0) r = r >> (-ctxcanvas->rshift); + else r = r << ctxcanvas->rshift; + if (ctxcanvas->gshift<0) g = g >> (-ctxcanvas->gshift); + else g = g << ctxcanvas->gshift; + if (ctxcanvas->bshift<0) b = b >> (-ctxcanvas->bshift); + else b = b << ctxcanvas->bshift; + *red = cdCOLOR16TO8(r); + *green = cdCOLOR16TO8(g); + *blue = cdCOLOR16TO8(b); +} + +/* +%F Funcao get_pixel usada quando estamos em TrueColor. +*/ +static unsigned long truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb) +{ + unsigned long r = cdCOLOR8TO16(cdRed(rgb)); + unsigned long g = cdCOLOR8TO16(cdGreen(rgb)); + unsigned long b = cdCOLOR8TO16(cdBlue(rgb)); + + if (ctxcanvas->rshift<0) + r = r << (-ctxcanvas->rshift); + else + r = r >> ctxcanvas->rshift; + + if (ctxcanvas->gshift<0) + g = g << (-ctxcanvas->gshift); + else + g = g >> ctxcanvas->gshift; + + if (ctxcanvas->bshift<0) + b = b << (-ctxcanvas->bshift); + else + b = b >> ctxcanvas->bshift; + + r = r & ctxcanvas->vis->red_mask; + g = g & ctxcanvas->vis->green_mask; + b = b & ctxcanvas->vis->blue_mask; + + return r | g | b; +} + +static int highbit(unsigned long ul) +{ +/* returns position of highest set bit in 'ul' as an integer (0-31), + or -1 if none */ + int i; unsigned long hb; + + hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */ + for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1); + return i; +} + +static void makeDirectCmap(cdCtxCanvas *ctxcanvas, Colormap cmap) +{ + int i, cmaplen, numgot; + unsigned char origgot[256]; + XColor c; + unsigned long rmask, gmask, bmask; + int rshift, gshift, bshift; + + rmask = ctxcanvas->vis->red_mask; + gmask = ctxcanvas->vis->green_mask; + bmask = ctxcanvas->vis->blue_mask; + + rshift = highbit(rmask) - 15; + gshift = highbit(gmask) - 15; + bshift = highbit(bmask) - 15; + + if (rshift<0) rmask = rmask << (-rshift); + else rmask = rmask >> rshift; + + if (gshift<0) gmask = gmask << (-gshift); + else gmask = gmask >> gshift; + + if (bshift<0) bmask = bmask << (-bshift); + else bmask = bmask >> bshift; + + cmaplen = ctxcanvas->vis->map_entries; + if (cmaplen>256) cmaplen=256; + + /* try to alloc a 'cmaplen' long grayscale colormap. May not get all + entries for whatever reason. Build table 'cdxDirectColorTable[]' that + maps range [0..(cmaplen-1)] into set of colors we did get */ + + for (i=0; i<256; i++) { origgot[i] = 0; cdxDirectColorTable[i] = i; } + + for (i=numgot=0; i<cmaplen; i++) + { + c.red = c.green = c.blue = (unsigned short)((i * 0xffff) / (cmaplen - 1)); + c.red = (unsigned short)(c.red & rmask); + c.green = (unsigned short)(c.green & gmask); + c.blue = (unsigned short)(c.blue & bmask); + c.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(ctxcanvas->dpy, cmap, &c)) + { + origgot[i] = 1; + numgot++; + } + } + + if (numgot == 0) + return; + + /* cdxDirectColorTable may or may not have holes in it. */ + for (i=0; i<cmaplen; i++) + { + if (!origgot[i]) + { + int numbak, numfwd; + numbak = numfwd = 0; + while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++; + while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++; + + if (i-numbak<0 || !origgot[i-numbak]) numbak = 999; + if (i+numfwd>=cmaplen || !origgot[i+numfwd]) numfwd = 999; + + if (numbak<numfwd) cdxDirectColorTable[i] = cdxDirectColorTable[i-numbak]; + else if (numfwd<999) cdxDirectColorTable[i] = cdxDirectColorTable[i+numfwd]; + } + } +} + +/******************************************************/ + +void cdxKillCanvas(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->canvas->bpp <= 8) + { + unsigned long pixels[256]; + int i; + + /* libera todas as cores usadas na palette */ + for(i = 0; i < ctxcanvas->num_colors; i++) + pixels[i] = ctxcanvas->color_table[i].pixel; + + if (ctxcanvas->colormap != DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr)) + XFreeColormap(ctxcanvas->dpy, ctxcanvas->colormap); + } + + if (ctxcanvas->xidata) free(ctxcanvas->xidata); + if (ctxcanvas->font) XFreeFont(ctxcanvas->dpy, ctxcanvas->font); + if (ctxcanvas->last_hatch) XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_hatch); + if (ctxcanvas->clip_polygon) XFreePixmap(ctxcanvas->dpy, ctxcanvas->clip_polygon); + + if (ctxcanvas->new_region) + { + XFreeGC(ctxcanvas->dpy, ctxcanvas->region_aux_gc); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->region_aux); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->new_region); + } + + if (ctxcanvas->last_pattern) + { + XFreeGC(ctxcanvas->dpy, ctxcanvas->last_pattern_gc); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_pattern); + } + + if (ctxcanvas->last_stipple) + { + XFreeGC(ctxcanvas->dpy, ctxcanvas->last_stipple_gc); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_stipple); + } + + XFreeGC(ctxcanvas->dpy, ctxcanvas->gc); + + free(ctxcanvas); +} + +/******************************************************/ + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + XFlush(ctxcanvas->dpy); +} + +/******************************************************/ + +static Pixmap build_clip_polygon(cdCtxCanvas *ctxcanvas, XPoint* pnt, int n) +{ + Pixmap pix = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1); + GC gc = XCreateGC(ctxcanvas->dpy, pix, 0, NULL); + + XSetForeground(ctxcanvas->dpy, gc, 0); + XFillRectangle(ctxcanvas->dpy, pix, gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + + XSetForeground(ctxcanvas->dpy, gc, 1); + XSetFillRule(ctxcanvas->dpy, gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule); + XFillPolygon(ctxcanvas->dpy, pix, gc, pnt, n, Complex, CoordModeOrigin); + + XFreeGC(ctxcanvas->dpy, gc); + return pix; +} + +static void xsetclip_area(cdCtxCanvas *ctxcanvas) +{ + cdRect* clip_rect = &ctxcanvas->canvas->clip_rect; + if (ctxcanvas->canvas->use_matrix) + { + cdPoint poly[4]; + poly[0].x = clip_rect->xmin; poly[0].y = clip_rect->ymin; + poly[1].x = clip_rect->xmin; poly[1].y = clip_rect->ymax; + poly[2].x = clip_rect->xmax; poly[2].y = clip_rect->ymax; + poly[3].x = clip_rect->xmax; poly[3].y = clip_rect->ymin; + ctxcanvas->canvas->cxPoly(ctxcanvas, CD_CLIP, poly, 4); + } + else + { + XRectangle rect; + rect.x = (short)clip_rect->xmin; + rect.y = (short)clip_rect->ymin; + rect.width = (unsigned short)(clip_rect->xmax - clip_rect->xmin + 1); + rect.height = (unsigned short)(clip_rect->ymax - clip_rect->ymin + 1); + XSetClipRectangles(ctxcanvas->dpy, ctxcanvas->gc, 0, 0, &rect, 1, Unsorted); + } +} + +int cdxClip(cdCtxCanvas *ctxcanvas, int clip_mode) +{ + switch (clip_mode) + { + case CD_CLIPOFF: + XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, None); + break; + case CD_CLIPAREA: + xsetclip_area(ctxcanvas); + break; + case CD_CLIPPOLYGON: + if (ctxcanvas->clip_polygon) + XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->clip_polygon); + break; + case CD_CLIPREGION: + if (ctxcanvas->new_region) + XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->new_region); + break; + } + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymax = ymax; + cdxClip(ctxcanvas, CD_CLIPAREA); + } +} + +static void cdnewregion(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->new_region) + { + XFreeGC(ctxcanvas->dpy, ctxcanvas->region_aux_gc); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->region_aux); + XFreePixmap(ctxcanvas->dpy, ctxcanvas->new_region); + } + + ctxcanvas->new_region = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1); + + { + GC gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->new_region, 0, NULL); + XSetForeground(ctxcanvas->dpy, gc, 0); + XFillRectangle(ctxcanvas->dpy, ctxcanvas->new_region, gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + XFreeGC(ctxcanvas->dpy, gc); + } + + ctxcanvas->region_aux = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1); + ctxcanvas->region_aux_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->region_aux, 0, NULL); + XSetBackground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 0); +} + +static int cdispointinregion(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return 0; + + if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h) + { + long p; + XImage* img = XGetImage(ctxcanvas->dpy, ctxcanvas->new_region, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1, XYPixmap); + p = XGetPixel(img, x, y); + XDestroyImage(img); + + if (p) return 1; + } + + return 0; +} + +static void cdgetregionbox(cdCtxCanvas *ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + if (!ctxcanvas->new_region) + return; + + *xmin = ctxcanvas->canvas->w-1; + *xmax = 0; + *ymin = ctxcanvas->canvas->h-1; + *ymax = 0; + + { + int x, y; + long p; + XImage* img = XGetImage(ctxcanvas->dpy, ctxcanvas->new_region, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1, XYPixmap); + + for (y = 0; y < ctxcanvas->canvas->h; y++) + { + for (x = 0; x < ctxcanvas->canvas->w; x++) + { + p = XGetPixel(img, x, y); + + if (p) + { + if (x < *xmin) *xmin = x; + if (x > *xmax) *xmax = x; + if (y < *ymin) *ymin = y; + if (y > *ymax) *ymax = y; + break; + } + } + + if (x != ctxcanvas->canvas->w-1) + { + for (x = ctxcanvas->canvas->w-1; x >= 0; x--) + { + p = XGetPixel(img, x, y); + + if (p) + { + if (x < *xmin) *xmin = x; + if (x > *xmax) *xmax = x; + if (y < *ymin) *ymin = y; + if (y > *ymax) *ymax = y; + break; + } + } + } + } + + XDestroyImage(img); + } +} + +static void sPrepareRegion(cdCtxCanvas *ctxcanvas) +{ + if (!ctxcanvas->new_region) + return; + + XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXcopy); + XSetForeground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 0); + XFillRectangle(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + XSetForeground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 1); +} + +static void sCombineRegion(cdCtxCanvas *ctxcanvas) +{ + switch(ctxcanvas->canvas->combine_mode) + { + case CD_UNION: + XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXor); + break; + case CD_INTERSECT: + XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXand); + break; + case CD_DIFFERENCE: + XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXandInverted); + break; + case CD_NOTINTERSECT: + XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXxor); + break; + } + + XCopyArea(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->new_region, ctxcanvas->region_aux_gc, + 0, 0, + ctxcanvas->canvas->w, ctxcanvas->canvas->h, + 0, 0); +} + +static void cdoffsetregion(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return; + + sPrepareRegion(ctxcanvas); + + XCopyArea(ctxcanvas->dpy, ctxcanvas->new_region, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, + 0, 0, + ctxcanvas->canvas->w-x, ctxcanvas->canvas->h-y, + x, y); + + XCopyArea(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->new_region, ctxcanvas->region_aux_gc, + 0, 0, + ctxcanvas->canvas->w, ctxcanvas->canvas->h, + 0, 0); +} + +/******************************************************/ + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode) +{ + switch (write_mode) + { + case CD_REPLACE: + XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXcopy); + break; + case CD_XOR: + XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXxor); + break; + case CD_NOT_XOR: + XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXequiv); + break; + } + + return write_mode; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + int sty = FillSolid; + + switch (style) + { + case CD_SOLID: + sty = FillSolid; + break; + case CD_HATCH : + if (!ctxcanvas->last_hatch) + return ctxcanvas->canvas->interior_style; + + XSetStipple(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_hatch); + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + sty = FillOpaqueStippled; + else + sty = FillStippled; + break; + case CD_STIPPLE: + XSetStipple(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_stipple); + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + sty = FillOpaqueStippled; + else + sty = FillStippled; + break; + case CD_PATTERN: + XSetTile(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_pattern); + sty = FillTiled; + break; + } + + XSetFillStyle(ctxcanvas->dpy, ctxcanvas->gc, sty); + + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int hatch_style) +{ + if (ctxcanvas->last_hatch) + XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_hatch); + + ctxcanvas->last_hatch = XCreatePixmapFromBitmapData(ctxcanvas->dpy, + ctxcanvas->wnd, hatches[hatch_style], + HATCH_WIDTH, HATCH_HEIGHT, 1, 0, 1); + + cdinteriorstyle(ctxcanvas, CD_HATCH); + + return hatch_style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *data) +{ + int x, y; + + if (ctxcanvas->last_stipple == 0 || (ctxcanvas->last_stipple_w != w || ctxcanvas->last_stipple_h != h)) + { + if (ctxcanvas->last_stipple != 0) + { + XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_stipple); + XFreeGC(ctxcanvas->dpy, ctxcanvas->last_stipple_gc); + } + + ctxcanvas->last_stipple = XCreatePixmap(ctxcanvas->dpy,ctxcanvas->wnd,w,h,1); + if (!ctxcanvas->last_stipple) return; + ctxcanvas->last_stipple_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->last_stipple, 0, 0); + ctxcanvas->last_stipple_w = w; + ctxcanvas->last_stipple_h = h; + } + + for (y=0; y<h; y++) + { + for (x=0; x<w; x++) + { + XSetForeground(ctxcanvas->dpy, ctxcanvas->last_stipple_gc, data[y*w+x]? 1: 0); + XDrawPoint(ctxcanvas->dpy, ctxcanvas->last_stipple, ctxcanvas->last_stipple_gc, x, h-y-1); + } + } + + cdinteriorstyle(ctxcanvas, CD_STIPPLE); +} + +static int find_match(unsigned long* palette, int pal_size, unsigned long color, unsigned char *match) +{ + int i; + + for (i=0;i<pal_size;i++) + { + if (palette[i] == color) + { + *match = (unsigned char)i; + return 1; + } + } + + return 0; +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *colors) +{ + int x, y, i; + int size = w*h; + unsigned long *pixels; + + if (ctxcanvas->last_pattern == 0 || (ctxcanvas->last_pattern_w != w || ctxcanvas->last_pattern_h != h)) + { + if (ctxcanvas->last_pattern != 0) + { + XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_pattern); + XFreeGC(ctxcanvas->dpy, ctxcanvas->last_pattern_gc); + } + + ctxcanvas->last_pattern = XCreatePixmap(ctxcanvas->dpy,ctxcanvas->wnd,w,h,ctxcanvas->depth); + if (!ctxcanvas->last_pattern) return; + ctxcanvas->last_pattern_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->last_pattern, 0, 0); + ctxcanvas->last_pattern_w = w; + ctxcanvas->last_pattern_h = h; + } + + pixels = (unsigned long*)malloc(w*h*sizeof(long)); + + if (ctxcanvas->canvas->bpp <= 8) + { + long int match_table[256]; /* X colors */ + unsigned long palette[256]; /* CD colors */ + unsigned char *index = (unsigned char*)malloc(size), match; + int pal_size = 1; + palette[0] = colors[0]; + + /* encontra as n primeiras cores diferentes da imagem (ate 256) */ + for(i=0;i<size;i++) + { + if (!find_match(palette, pal_size, colors[i], &match)) + { + palette[pal_size] = colors[i]; + index[i] = (unsigned char)pal_size; + pal_size++; + + if (pal_size == 256) + break; + } + else + index[i] = match; + } + + /* de cores do CD para cores do X */ + for (i = 0; i < pal_size; i++) + match_table[i] = cdxGetPixel(ctxcanvas, palette[i]); + + /* de imagem do CD para imagem do X */ + for(i=0;i<size;i++) + pixels[i] = match_table[index[i]]; + + free(index); + } + else + { + for(i=0;i<size;i++) + pixels[i] = cdxGetPixel(ctxcanvas, colors[i]); + } + + for (y=0; y<h; y++) + { + for (x=0; x<w; x++) + { + XSetForeground(ctxcanvas->dpy, ctxcanvas->last_pattern_gc, pixels[y*w+x]); + XDrawPoint(ctxcanvas->dpy, ctxcanvas->last_pattern, ctxcanvas->last_pattern_gc, x, h-y-1); + } + } + + cdinteriorstyle(ctxcanvas, CD_PATTERN); + + free(pixels); +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + gcval.line_style = LineSolid; + break; + case CD_DASHED: + case CD_DOTTED: + case CD_DASH_DOT: + case CD_DASH_DOT_DOT: + { + static struct { + int size; + char list[6]; + } dashes[4] = { + { 2, { 6, 2 } }, + { 2, { 2, 2 } }, + { 4, { 6, 2, 2, 2 } }, + { 6, { 6, 2, 2, 2, 2, 2 } } + }; + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + gcval.line_style = LineDoubleDash; + else + gcval.line_style = LineOnOffDash; + + XSetDashes(ctxcanvas->dpy, ctxcanvas->gc, 0, dashes[style-CD_DASHED].list, + dashes[style-CD_DASHED].size); + break; + } + case CD_CUSTOM: + { + int i; + char* dash_style = (char*)malloc(ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + dash_style[i] = (char)ctxcanvas->canvas->line_dashes[i]; + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + gcval.line_style = LineDoubleDash; + else + gcval.line_style = LineOnOffDash; + + XSetDashes(ctxcanvas->dpy, ctxcanvas->gc, 0, dash_style, + ctxcanvas->canvas->line_dashes_count); + free(dash_style); + break; + } + } + XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCLineStyle, &gcval); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + if (width == 1) + gcval.line_width = 0; + else + gcval.line_width = width; + + XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCLineWidth, &gcval); + + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2x_cap[] = {CapButt, CapProjecting, CapRound}; + + gcval.cap_style = cd2x_cap[cap]; + XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCCapStyle, &gcval); + + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2x_join[] = {JoinMiter, JoinBevel, JoinRound}; + + gcval.join_style = cd2x_join[join]; + XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCJoinStyle, &gcval); + + return join; +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque) +{ + ctxcanvas->canvas->back_opacity = opaque; + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + cdlinestyle(ctxcanvas, ctxcanvas->canvas->line_style); + return opaque; +} + +static int cdxGetFontSize(char* font_name) +{ + int i = 0; + while (i < 8) + { + font_name = strchr(font_name, '-')+1; + i++; + } + + *(strchr(font_name, '-')) = 0; + return atoi(font_name); +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + XFontStruct *font; + char **font_names_list; + char font_name[1024]; + char* foundry = "*"; + int i, num_fonts, font_size, near_size, change_italic = 0; + + /* no underline or strikeout support */ + + static char * type[] = + { + "medium-r", /* CD_PLAIN */ + "bold-r", /* CD_BOLD */ + "medium-i", /* CD_ITALIC */ + "bold-i" /* CD_BOLD_ITALIC */ + }; + + if (cdStrEqualNoCase(type_face, "System")) + type_face = "fixed"; + else if (cdStrEqualNoCase(type_face, "Monospace") || cdStrEqualNoCase(type_face, "Courier New")) + type_face = "courier"; + else if (cdStrEqualNoCase(type_face, "Serif") || cdStrEqualNoCase(type_face, "Times New Roman")) + type_face = "times"; + else if (cdStrEqualNoCase(type_face, "Sans") || cdStrEqualNoCase(type_face, "Arial")) + type_face = "helvetica"; + + if (cdStrEqualNoCase(type_face, "Fixed")) + foundry = "misc"; + + sprintf(font_name,"-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", foundry, type_face, type[style&3]); + + font_names_list = XListFonts(ctxcanvas->dpy, font_name, 32767, &num_fonts); + if (!num_fonts) + { + /* try changing 'i' to 'o', for italic */ + if (style&CD_ITALIC) + { + change_italic = 1; + strstr(font_name, "-i-")[1] = 'o'; + font_names_list = XListFonts(ctxcanvas->dpy, font_name, 32767, &num_fonts); + } + + if (!num_fonts) + return 0; + } + + size = cdGetFontSizePoints(ctxcanvas->canvas, size); + + size *= 10; /* convert to deci-points */ + + near_size = -1000; + for (i=0; i<num_fonts; i++) + { + font_size = cdxGetFontSize(font_names_list[i]); + + if (font_size == size) + { + near_size = font_size; + break; + } + + if (abs(font_size-size) < abs(near_size-size)) + near_size = font_size; + } + + XFreeFontNames(font_names_list); + + sprintf(font_name,"-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", foundry, type_face, type[style&3], near_size); + if (change_italic) strstr(font_name, "-i-")[1] = 'o'; + + font = XLoadQueryFont(ctxcanvas->dpy, font_name); + if (!font) + return 0; + + if (ctxcanvas->font) + XFreeFont(ctxcanvas->dpy, ctxcanvas->font); + + ctxcanvas->font = font; + XSetFont(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->font->fid); + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont) +{ + int size = 12, style = CD_PLAIN; + char type_face[1024]; + + if (nativefont[0] == '-') + { + XFontStruct *font = XLoadQueryFont(ctxcanvas->dpy, nativefont); + if (!font) + return 0; + + if (!cdParseXWinFont(nativefont, type_face, &style, &size)) + { + XFreeFont(ctxcanvas->dpy, font); + return 0; + } + + if (ctxcanvas->font) XFreeFont(ctxcanvas->dpy, ctxcanvas->font); + ctxcanvas->font = font; + XSetFont(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->font->fid); + } + else + { + if (!cdParsePangoFont(nativefont, type_face, &style, &size)) + return 0; + + if (!cdfont(ctxcanvas, type_face, style, size)) + return 0; + } + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, type_face); + + return 1; +} + +static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + if (!ctxcanvas->font) return; + if (max_width) *max_width = ctxcanvas->font->max_bounds.width; + if (height) *height = ctxcanvas->font->ascent + ctxcanvas->font->descent; + if (ascent) *ascent = ctxcanvas->font->ascent; + if (descent) *descent = ctxcanvas->font->descent; +} + +static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + XSetBackground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, color)); + return color; +} + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->fg = cdxGetPixel(ctxcanvas, color); + XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->fg); + return color; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + unsigned long pixels[256]; + int i; + + for(i = 0; i < ctxcanvas->num_colors; i++) + pixels[i] = ctxcanvas->color_table[i].pixel; + + XFreeColors(ctxcanvas->dpy, ctxcanvas->colormap, pixels, ctxcanvas->num_colors, 0); + + if (mode == CD_FORCE) + { + XColor xc; + int tokeep; + + /* se antes era POLITE aloca palette propria */ + if (ctxcanvas->colormap == DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr)) + ctxcanvas->colormap = XCreateColormap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->vis, AllocNone); + + /* se for FORCE ira' alocar todas as cores, + mas se o numero de cores desejado e' menor que o maximo + entao uso a diferenca para preservar as primeiras cores alocadas no colormap default. */ + tokeep = ctxcanvas->num_colors - n; + if (tokeep) + { + for (i=0; i<tokeep; i++) + ctxcanvas->color_table[i].pixel=i; + + XQueryColors(ctxcanvas->dpy, DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr), ctxcanvas->color_table, tokeep); + + /* reservo estas cores para o CD tambem */ + for (i=0; i<tokeep; i++) + XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &(ctxcanvas->color_table[i])); + } + + /*aloco todas as cores da palette para o CD */ + for (i=0; i<n; i++) + { + xc.red = cdCOLOR8TO16(cdRed(palette[i])); + xc.green = cdCOLOR8TO16(cdGreen(palette[i])); + xc.blue = cdCOLOR8TO16(cdBlue(palette[i])); + xc.flags = DoRed | DoGreen | DoBlue; + XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc); + } + + /* atualizo toda a tabela de cores */ + XSetWindowColormap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->colormap); + update_colors(ctxcanvas); + } + else + { + /* se antes era FORCE, remove palette propria */ + if (ctxcanvas->colormap != DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr)) + { + XFreeColormap(ctxcanvas->dpy, ctxcanvas->colormap); + ctxcanvas->colormap = DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr); + } + + /* atualizo a tabela antes de acrescentar novas cores afinal liberamos todas as que podiamos antes disso */ + update_colors(ctxcanvas); + + /* se for POLITE apenas tento alocar todas as cores da palette */ + for (i=0; i<n; i++) + cdxGetPixel(ctxcanvas, palette[i]); + } +} + +/******************************************************/ + +static void cdxCheckSolidStyle(cdCtxCanvas *ctxcanvas, int set) +{ + if (ctxcanvas->canvas->interior_style == CD_SOLID) + return; + + if (set) + XSetFillStyle(ctxcanvas->dpy, ctxcanvas->gc, FillSolid); + else + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + cdxCheckSolidStyle(ctxcanvas, 1); + XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, ctxcanvas->canvas->background)); + XFillRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, ctxcanvas->canvas->foreground)); + cdxCheckSolidStyle(ctxcanvas, 0); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdMatrixTransformPoint(ctxcanvas->xmatrix, x1, y1, &x1, &y1); + cdMatrixTransformPoint(ctxcanvas->xmatrix, x2, y2, &x2, &y2); + } + + cdxCheckSolidStyle(ctxcanvas, 1); + XDrawLine(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x1, y1, x2, y2); + cdxCheckSolidStyle(ctxcanvas, 0); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdarcSIM(ctxcanvas, xc, yc, w, h, a1, a2); + return; + } + + cdxCheckSolidStyle(ctxcanvas, 1); + XDrawArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + cdxCheckSolidStyle(ctxcanvas, 0); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2); + return; + } + + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XSetArcMode(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ArcPieSlice); + XFillArc(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + sCombineRegion(ctxcanvas); + } + else + { + XSetArcMode(ctxcanvas->dpy, ctxcanvas->gc, ArcPieSlice); + XFillArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2); + return; + } + + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XSetArcMode(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ArcChord); + XFillArc(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + sCombineRegion(ctxcanvas); + } + else + { + XSetArcMode(ctxcanvas->dpy, ctxcanvas->gc, ArcChord); + XFillArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + } +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdrectSIM(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + cdxCheckSolidStyle(ctxcanvas, 1); + XDrawRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xmin, ymin, xmax-xmin, ymax-ymin); + cdxCheckSolidStyle(ctxcanvas, 0); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XFillRectangle(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xmin, ymin, xmax-xmin+1, ymax-ymin+1); + sCombineRegion(ctxcanvas); + } + else + XFillRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xmin, ymin, xmax-xmin+1, ymax-ymin+1); +} + +static int cd2xvertex [12] = {XR_TCENTRE, XR_BCENTRE, + XR_MRIGHT, XR_MLEFT, + XR_TRIGHT, XR_TLEFT, + XR_BRIGHT, XR_BLEFT, + XR_MCENTRE, XR_LEFT, + XR_CENTRE, XR_RIGHT}; + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + int w, h, n, dir = -1; + + if (ctxcanvas->canvas->text_orientation != 0) + { + cdxCheckSolidStyle(ctxcanvas, 1); + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XRotDrawString(ctxcanvas->dpy, ctxcanvas->font, ctxcanvas->canvas->text_orientation, + ctxcanvas->region_aux, ctxcanvas->region_aux_gc, x, y, s, + cd2xvertex[ctxcanvas->canvas->text_alignment], 0); + sCombineRegion(ctxcanvas); + } + else + XRotDrawString(ctxcanvas->dpy, ctxcanvas->font, ctxcanvas->canvas->text_orientation, + ctxcanvas->wnd, ctxcanvas->gc, x, y, s, + cd2xvertex[ctxcanvas->canvas->text_alignment], 0); + + cdxCheckSolidStyle(ctxcanvas, 0); + + return; + } + + n = strlen(s); + w = XTextWidth(ctxcanvas->font, s, n); + h = ctxcanvas->font->ascent + ctxcanvas->font->descent; + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + x = x - w; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + x = x - w/2; + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + x = x; + break; + } + + if (ctxcanvas->canvas->invert_yaxis) + dir = 1; + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + y = y; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + y = y - dir*ctxcanvas->font->descent; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + y = y + dir*(h - ctxcanvas->font->descent); + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + y = y + dir*(h/2 - ctxcanvas->font->descent); + break; + } + + cdxCheckSolidStyle(ctxcanvas, 1); + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XSetFont(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ctxcanvas->font->fid); + XDrawString(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, x, y+1, s, n); + sCombineRegion(ctxcanvas); + } + else + XDrawString(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x, y+1, s, n); + + cdxCheckSolidStyle(ctxcanvas, 0); +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + if (!ctxcanvas->font) return; + if (width) *width = XTextWidth(ctxcanvas->font, s, strlen(s)); + if (height) *height = ctxcanvas->font->ascent + ctxcanvas->font->descent; +} + +void cdxPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + XPoint* pnt = NULL; + + if (mode != CD_BEZIER) + { + pnt = (XPoint*)malloc((n+1) * sizeof(XPoint)); /* XPoint uses short for coordinates */ + + for (i = 0; i < n; i++) + { + int x = poly[i].x, + y = poly[i].y; + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + pnt[i].x = (short)x; + pnt[i].y = (short)y; + } + } + + switch( mode ) + { + case CD_FILL: + if (ctxcanvas->canvas->new_region) + { + sPrepareRegion(ctxcanvas); + XSetFillRule(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule); + XFillPolygon(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, + pnt, n, Complex, CoordModeOrigin); + sCombineRegion(ctxcanvas); + } + else + { + XSetFillRule(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule); + XFillPolygon(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, + pnt, n, Complex, CoordModeOrigin); + } + break; + case CD_CLOSED_LINES: + pnt[n].x = pnt[0].x; + pnt[n].y = pnt[0].y; + n++; + /* continua */ + case CD_OPEN_LINES: + { + cdxCheckSolidStyle(ctxcanvas, 1); + XDrawLines(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, pnt, n, CoordModeOrigin); + cdxCheckSolidStyle(ctxcanvas, 0); + break; + } + case CD_CLIP: + if (ctxcanvas->clip_polygon) XFreePixmap(ctxcanvas->dpy, ctxcanvas->clip_polygon); + ctxcanvas->clip_polygon = build_clip_polygon(ctxcanvas, pnt, n); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdxClip(ctxcanvas, CD_CLIPPOLYGON); + break; + case CD_BEZIER: + cdSimPolyBezier(ctxcanvas->canvas, poly, n); + break; + } + + if (pnt) free(pnt); +} + +/******************************************************/ + +static int byte_order(void) +{ + unsigned short us = 0xFF00; + unsigned char *uc = (unsigned char *)&us; + return (uc[0]==0xFF) ? MSBFirst : LSBFirst; +} + +static void cdgetimagergb(cdCtxCanvas *ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + int col, lin, pos; + XImage *xi = XGetImage(ctxcanvas->dpy, ctxcanvas->wnd, x, y-h+1, w, h, ULONG_MAX, ZPixmap); + if (!xi) + { + fprintf(stderr, "CanvasDraw: error getting image\n"); + return; + } + + for (lin=0; lin<h; lin++) + { + for (col=0; col<w; col++) + { + pos = (h-lin-1)*w+col; + cdxGetRGB(ctxcanvas, XGetPixel(xi, col, lin), r+pos, g+pos, b+pos); + } + } + + XDestroyImage(xi); +} + +static long int* get_data_buffer(cdCtxCanvas *ctxcanvas, int size) +{ + if (!ctxcanvas->xidata) + { + ctxcanvas->xisize = size; + ctxcanvas->xidata = (long int *)malloc(ctxcanvas->xisize); + } + else if (ctxcanvas->xisize < size) + { + ctxcanvas->xisize = size; + ctxcanvas->xidata = (long int *)realloc(ctxcanvas->xidata, ctxcanvas->xisize); + } + + if (!ctxcanvas->xidata) + ctxcanvas->xisize = 0; + + return ctxcanvas->xidata; +} + +static XImage *map2ximage(cdCtxCanvas *ctxcanvas, int ew, int eh, const unsigned char *index, const long int * colors, int by, int bx, int bw, int bh, int iw) +{ + long int match_table[256]; + int i, j, pal_size; + unsigned long xcol; + XImage *xim; + int *fx, *fy, src, dst; + unsigned char idx; + + xim = (XImage *) NULL; + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = 0; + + for (i=0; i<bh; i++) + { + for (j=0; j<bw; j++) + { + src = (i+by)*iw + j+bx; + idx = index[src]; + if (idx > pal_size) + pal_size = idx; + } + } + + pal_size++; + + for (i = 0; i < pal_size; i++) + match_table[i] = cdxGetPixel(ctxcanvas, colors[i]); + + fx = cdGetZoomTable(ew, bw, bx); + fy = cdGetZoomTable(eh, bh, by); + + switch (ctxcanvas->depth) + { + case 8: + { + unsigned char *imagedata, *ip; + int imew, nullCount; + + nullCount = (4 - (ew % 4)) & 0x03; /* # of padding bytes per line */ + imew = ew + nullCount; + + /* Now get the image data - pad each scanline as necessary */ + imagedata = (unsigned char*)get_data_buffer(ctxcanvas, eh * imew); + if (!imagedata) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + for (i=0; i<eh; i++) + { + ip = imagedata + (eh-1-i)*imew; + + for (j=0; j<ew; j++, ip++) + { + src = (fy[i])*iw + fx[j]; + *ip = (unsigned char) match_table[index[src]]; + } + } + + xim = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, imew); + if (!xim) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + } + break; + + case 12: + case 15: + case 16: + { + unsigned char *imagedata; + unsigned short *ip, *tip; + + /* Now get the image data - pad each scanline as necessary */ + imagedata = (unsigned char*)get_data_buffer(ctxcanvas, 2*ew*eh); + if (!imagedata) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + xim = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 16, 0); + if (!xim) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + if (ctxcanvas->depth == 12 && xim->bits_per_pixel != 16) + { + xim->data = NULL; + XDestroyImage(xim); + fprintf(stderr,"No code for this type of display (depth=%d, bperpix=%d)", ctxcanvas->depth, xim->bits_per_pixel); + return NULL; + } + + ip = (unsigned short*)(imagedata + (eh-1)*xim->bytes_per_line); + + for (i=0; i<eh; i++) + { + for (j=0, tip=ip; j<ew; j++) + { + src = (fy[i])*iw + fx[j]; + xcol = match_table[index[src]]; + + if (xim->byte_order == MSBFirst) + { + *tip++ = (unsigned short)(xcol & 0xffff); + } + else + { + /* WAS *tip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8); */ + *tip++ = (unsigned short)(xcol); + } + } + + ip -= ew; + } + } + break; + + case 24: + case 32: + { + unsigned char *imagedata, *ip, *tip; + int do32; + + /* Now get the image data - pad each scanline as necessary */ + imagedata = (unsigned char*)get_data_buffer(ctxcanvas, 4*ew*eh); + if (!imagedata) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + xim = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, 0); + if (!xim) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + do32 = (xim->bits_per_pixel == 32? 1: 0); + + ip = imagedata + (eh-1)*xim->bytes_per_line; + + for (i=0; i<eh; i++) + { + for (j=0, tip=ip; j<ew; j++) + { + src = (fy[i])*iw + fx[j]; + xcol = match_table[index[src]]; + + if (xim->byte_order == MSBFirst) + { + if (do32) *tip++ = 0; + *tip++ = (unsigned char)((xcol>>16) & 0xff); + *tip++ = (unsigned char)((xcol>>8) & 0xff); + *tip++ = (unsigned char)( xcol & 0xff); + } + else + { /* LSBFirst */ + *tip++ = (unsigned char)( xcol & 0xff); + *tip++ = (unsigned char)((xcol>>8) & 0xff); + *tip++ = (unsigned char)((xcol>>16) & 0xff); + if (do32) *tip++ = 0; + } + } + + ip -= xim->bytes_per_line; + } + } + break; + default: + { + /* Now get the image data - pad each scanline as necessary */ + unsigned long* imagedata = (unsigned long*)get_data_buffer(ctxcanvas, 4*ew*eh); + if (!imagedata) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + xim = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, ew*4); + if (!xim) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + xim->bits_per_pixel = 32; + xim->bytes_per_line = 4 * iw; + xim->byte_order = byte_order(); + xim->bitmap_bit_order = MSBFirst; + + for (i=0; i<eh; i++) + { + for (j=0; j<ew; j++) + { + src = (fy[i])*iw + fx[j]; + dst = (eh-1 - i)*ew + j; + imagedata[dst] = match_table[index[src]]; + } + } + } + break; + } + + free(fx); + free(fy); + + return(xim); +} + +static XImage *rgb2ximage(cdCtxCanvas *ctxcanvas, int ew, int eh, + const unsigned char *red, const unsigned char *green, const unsigned char *blue, + const unsigned char *alpha, XImage *oxi, + int by, int bx, int bw, int bh, int iw) +{ +/* +* if we're displaying on a TrueColor +* or DirectColor display, we've got all the colors we're going to need, +* and 'all we have to do' is convert 24-bit RGB pixels into whatever +* variation of RGB the X device in question wants. No color allocation +* is involved. +*/ + int i,j; + XImage *xim; + unsigned long r, g, b, rmask, gmask, bmask, xcol; + int rshift, gshift, bshift, bperpix, bperline, byte_order, cshift; + int maplen, src; + unsigned char *lip, *ip, *imagedata, or, ob, og, al; + int *fx, *fy; + + /* compute various shifting constants that we'll need... */ + rmask = ctxcanvas->vis->red_mask; + gmask = ctxcanvas->vis->green_mask; + bmask = ctxcanvas->vis->blue_mask; + rshift = 7 - highbit(rmask); + gshift = 7 - highbit(gmask); + bshift = 7 - highbit(bmask); + + maplen = ctxcanvas->vis->map_entries; + if (maplen>256) maplen=256; + cshift = 7 - highbit((unsigned long) (maplen-1)); + + xim = XCreateImage(ctxcanvas->dpy, ctxcanvas->vis, ctxcanvas->depth, ZPixmap, 0, NULL, ew, eh, 32, 0); + if (!xim) + { + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + bperline = xim->bytes_per_line; + bperpix = xim->bits_per_pixel; + byte_order = xim->byte_order; + + if (bperpix != 8 && bperpix != 16 && bperpix != 24 && bperpix != 32) + { + XDestroyImage(xim); + fprintf(stderr, "CanvasDraw: bpp=%d not supported!\n", bperpix); + return NULL; + } + + imagedata = (unsigned char*)get_data_buffer(ctxcanvas, eh * bperline); + if (!imagedata) + { + XDestroyImage(xim); + fprintf(stderr, "CanvasDraw: not enough memory putting image\n"); + return NULL; + } + + fx = cdGetZoomTable(ew, bw, bx); + fy = cdGetZoomTable(eh, bh, by); + + xim->data = (char *) imagedata; + + lip = imagedata + (eh-1)*bperline; + + for (i=0; i<eh; i++, lip -= bperline) + { + for (j=0, ip=lip; j<ew; j++) + { + src = fy[i]*iw + fx[j]; + + if (alpha) + { + cdxGetRGB(ctxcanvas, XGetPixel(oxi, j, eh-i-1), &or, &og, &ob); + al = alpha[src]; + r = CD_ALPHA_BLEND(red[src], or, al); + g = CD_ALPHA_BLEND(green[src], og, al); + b = CD_ALPHA_BLEND(blue[src], ob, al); + } + else + { + r = red[src]; + g = green[src]; + b = blue[src]; + } + + /* shift r,g,b so that high bit of 8-bit color specification is + * aligned with high bit of r,g,b-mask in visual, + * AND each component with its mask, + * and OR the three components together + */ + +#ifdef __cplusplus + if (ctxcanvas->vis->c_class == DirectColor) +#else + if (ctxcanvas->vis->class == DirectColor) +#endif + { + r = (unsigned long) cdxDirectColorTable[(r>>cshift) & 0xff] << cshift; + g = (unsigned long) cdxDirectColorTable[(g>>cshift) & 0xff] << cshift; + b = (unsigned long) cdxDirectColorTable[(b>>cshift) & 0xff] << cshift; + } + + /* shift the bits around */ + if (rshift<0) r = r << (-rshift); + else r = r >> rshift; + + if (gshift<0) g = g << (-gshift); + else g = g >> gshift; + + if (bshift<0) b = b << (-bshift); + else b = b >> bshift; + + r = r & rmask; + g = g & gmask; + b = b & bmask; + + xcol = r | g | b; + + if (bperpix == 32) + { + if (byte_order == MSBFirst) { + *ip++ = (unsigned char)((xcol>>24) & 0xff); + *ip++ = (unsigned char)((xcol>>16) & 0xff); + *ip++ = (unsigned char)((xcol>>8) & 0xff); + *ip++ = (unsigned char)( xcol & 0xff); + } + else + { /* LSBFirst */ + *ip++ = (unsigned char)( xcol & 0xff); + *ip++ = (unsigned char)((xcol>>8) & 0xff); + *ip++ = (unsigned char)((xcol>>16) & 0xff); + *ip++ = (unsigned char)((xcol>>24) & 0xff); + } + } + else if (bperpix == 24) + { + if (byte_order == MSBFirst) + { + *ip++ = (unsigned char)((xcol>>16) & 0xff); + *ip++ = (unsigned char)((xcol>>8) & 0xff); + *ip++ = (unsigned char)( xcol & 0xff); + } + else + { /* LSBFirst */ + *ip++ = (unsigned char)( xcol & 0xff); + *ip++ = (unsigned char)((xcol>>8) & 0xff); + *ip++ = (unsigned char)((xcol>>16) & 0xff); + } + } + else if (bperpix == 16) + { + if (byte_order == MSBFirst) + { + *ip++ = (unsigned char)((xcol>>8) & 0xff); + *ip++ = (unsigned char)( xcol & 0xff); + } + else { /* LSBFirst */ + *ip++ = (unsigned char)( xcol & 0xff); + *ip++ = (unsigned char)((xcol>>8) & 0xff); + } + } + else if (bperpix == 8) + { + *ip++ = (unsigned char)(xcol & 0xff); + } + } + } + + free(fx); + free(fy); + + return xim; +} + +static void cdputimagerectrgba_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, ew, eh, + t_x, t_y, dst_offset, size, nc, doff, rect[8]; + float i_x, i_y, xfactor, yfactor; + unsigned char *dst_r, *dst_g, *dst_b, *dst_a = NULL; + double inv_matrix[6]; + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, rect); + + /* Setup inverse transform (use the original transform here, NOT ctxcanvas->xmatrix) */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* create an image for the destination area */ + ew = (t_xmax-t_xmin+1); + eh = (t_ymax-t_ymin+1); + size = ew*eh; + nc = 3; + if (a) nc = 4; + dst_r = malloc(nc*size); + if (!dst_r) + { + fprintf(stderr, "CanvasDraw: no enough memory\n"); + return; + } + dst_g = dst_r + size; + dst_b = dst_g + size; + if (a) dst_a = dst_b + size; + memset(dst_r, 0, nc*size); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = (t_y-t_ymin) * ew; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + doff = (t_x-t_xmin) + dst_offset; + *(dst_r+doff) = cdBilinearInterpolation(iw, ih, r, i_x, i_y); + *(dst_g+doff) = cdBilinearInterpolation(iw, ih, g, i_x, i_y); + *(dst_b+doff) = cdBilinearInterpolation(iw, ih, b, i_x, i_y); + if (a) *(dst_a+doff) = cdBilinearInterpolation(iw, ih, a, i_x, i_y); + } + } + } + + { + int ex = t_xmin, + ey = t_ymin + eh-1; /* XImage origin is at top-left */ + XImage *xi, *oxi = NULL; + Pixmap clip_polygon, clip_mask = 0; + XPoint pnt[4]; + + /* Since the transformation used was the original transformation, */ + /* must invert the Y axis here. */ + ey = _cdInvertYAxis(ctxcanvas->canvas, ey); + + /* use clipping to select only the transformed rectangle */ + pnt[0].x = (short)rect[0]; pnt[0].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[1]); + pnt[1].x = (short)rect[2]; pnt[1].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[3]); + pnt[2].x = (short)rect[4]; pnt[2].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[5]); + pnt[3].x = (short)rect[6]; pnt[3].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[7]); + clip_polygon = build_clip_polygon(ctxcanvas, pnt, 4); + + /* combine with the existing clipping */ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA || ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + clip_mask = ctxcanvas->clip_polygon; + else if (ctxcanvas->canvas->clip_mode == CD_CLIPREGION) + clip_mask = ctxcanvas->new_region; + XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXand); + XCopyArea(ctxcanvas->dpy, clip_mask, clip_polygon, ctxcanvas->gc, + 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0); + XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, clip_polygon); + cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset XSetFunction */ + + if (a) + { + oxi = XGetImage(ctxcanvas->dpy, ctxcanvas->wnd, ex, ey, ew, eh, ULONG_MAX, ZPixmap); + if (!oxi) + { + fprintf(stderr, "CanvasDraw: error getting image\n"); + free(dst_r); + return; + } + } + + xi = rgb2ximage(ctxcanvas, ew, eh, dst_r, dst_g, dst_b, dst_a, oxi, 0, 0, ew, eh, ew); + if (!xi) + return; + + XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh); + + /* reset cliping */ + XFreePixmap(ctxcanvas->dpy, clip_polygon); + cdxClip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + xi->data = NULL; + XDestroyImage(xi); + if (oxi) XDestroyImage(oxi); + } + + free(dst_r); +} + +static void cdputimagerectmap_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, ew, eh, + t_x, t_y, dst_offset, size, doff, rect[8]; + float i_x, i_y, xfactor, yfactor; + unsigned char *dst_index; + double inv_matrix[6]; + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, rect); + + /* Setup inverse transform (use the original transform here, NOT ctxcanvas->xmatrix) */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* create an image for the destination area */ + ew = (t_xmax-t_xmin+1); + eh = (t_ymax-t_ymin+1); + size = ew*eh; + dst_index = malloc(size); + if (!dst_index) + { + fprintf(stderr, "CanvasDraw: no enough memory\n"); + return; + } + memset(dst_index, 0, size); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = (t_y-t_ymin) * ew; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + doff = (t_x-t_xmin) + dst_offset; + *(dst_index+doff) = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y); + } + } + } + + { + int ex = t_xmin, + ey = t_ymin + eh-1; /* XImage origin is at top-left */ + XImage *xi; + Pixmap clip_polygon, clip_mask = 0; + XPoint pnt[4]; + + /* Since the transformation used was the original transformation, */ + /* must invert the Y axis here. */ + ey = _cdInvertYAxis(ctxcanvas->canvas, ey); + + /* use clipping to select only the transformed rectangle */ + pnt[0].x = (short)rect[0]; pnt[0].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[1]); + pnt[1].x = (short)rect[2]; pnt[1].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[3]); + pnt[2].x = (short)rect[4]; pnt[2].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[5]); + pnt[3].x = (short)rect[6]; pnt[3].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[7]); + clip_polygon = build_clip_polygon(ctxcanvas, pnt, 4); + + /* combine with the existing clipping */ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA || ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + clip_mask = ctxcanvas->clip_polygon; + else if (ctxcanvas->canvas->clip_mode == CD_CLIPREGION) + clip_mask = ctxcanvas->new_region; + XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXand); + XCopyArea(ctxcanvas->dpy, clip_mask, clip_polygon, ctxcanvas->gc, + 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0); + XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, clip_polygon); + cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset XSetFunction */ + + xi = map2ximage(ctxcanvas, ew, eh, dst_index, colors, 0, 0, ew, eh, ew); + if (!xi) + return; + + XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh); + + /* reset cliping */ + XFreePixmap(ctxcanvas->dpy, clip_polygon); + cdxClip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + xi->data = NULL; + XDestroyImage(xi); + } + + free(dst_index); +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + XImage *xi; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* XImage origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + xi = rgb2ximage(ctxcanvas, ew, eh, r, g, b, NULL, NULL, by, bx, bw, bh, iw); + if (!xi) + return; + + XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh); + + xi->data = NULL; + XDestroyImage(xi); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + XImage *xi, *oxi; + int ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* XImage origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + oxi = XGetImage(ctxcanvas->dpy, ctxcanvas->wnd, ex, ey, ew, eh, ULONG_MAX, ZPixmap); + if (!oxi) + { + fprintf(stderr, "CanvasDraw: error getting image\n"); + return; + } + + xi = rgb2ximage(ctxcanvas, ew, eh, r, g, b, a, oxi, by, bx, bw, bh, iw); + if (!xi) + return; + + XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh); + + xi->data = NULL; + XDestroyImage(xi); + XDestroyImage(oxi); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + XImage *xi; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* XImage origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + xi = map2ximage(ctxcanvas, ew, eh, index, colors, by, bx, bw, bh, iw); + if (!xi) + return; + + XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh); + + xi->data = NULL; + XDestroyImage(xi); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + if (ctxcanvas->canvas->foreground != color) + XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, color)); + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + XDrawPoint(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x, y); + + if (ctxcanvas->canvas->foreground != color) + XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->fg); +} + +static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h) +{ + GC gc; + cdCtxImage *ctximage = (cdCtxImage *)malloc(sizeof(cdCtxImage)); + + ctximage->w = w; + ctximage->h = h; + ctximage->depth = ctxcanvas->depth; + ctximage->dpy = ctxcanvas->dpy; + ctximage->scr = ctxcanvas->scr; + ctximage->vis = ctxcanvas->vis; + + ctximage->img = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, w, h, ctxcanvas->depth); + if (!ctximage->img) + { + free(ctximage); + return (void *)0; + } + + gc = XCreateGC(ctximage->dpy, ctximage->img, 0, NULL); + XSetForeground(ctximage->dpy, gc, cdxGetPixel(ctxcanvas, CD_WHITE)); + XFillRectangle(ctximage->dpy, ctximage->img, gc, 0, 0, ctximage->w, ctxcanvas->canvas->h); + XFreeGC(ctximage->dpy, gc); + + return (void *)ctximage; +} + +static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + XCopyArea(ctxcanvas->dpy, ctxcanvas->wnd, ctximage->img, ctxcanvas->gc, + x, y - ctximage->h+1, ctximage->w, ctximage->h, 0, 0); +} + +static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + XCopyArea(ctxcanvas->dpy, ctximage->img, ctxcanvas->wnd, ctxcanvas->gc, + xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1, x, y-(ymax-ymin+1)+1); +} + +static void cdkillimage (cdCtxImage *ctximage) +{ + XFreePixmap(ctximage->dpy, ctximage->img); + free(ctximage); +} + +static void cdscrollarea (cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + XCopyArea(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->wnd, ctxcanvas->gc, + xmin, ymin, + xmax-xmin+1, ymax-ymin+1, + xmin+dx, ymin+dy); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + { + /* configure a bottom-up coordinate system */ + ctxcanvas->xmatrix[0] = 1; + ctxcanvas->xmatrix[1] = 0; + ctxcanvas->xmatrix[2] = 0; + ctxcanvas->xmatrix[3] = -1; + ctxcanvas->xmatrix[4] = 0; + ctxcanvas->xmatrix[5] = (ctxcanvas->canvas->h-1); + cdMatrixMultiply(matrix, ctxcanvas->xmatrix); + + ctxcanvas->canvas->invert_yaxis = 0; + } + else + { + ctxcanvas->canvas->invert_yaxis = 1; + } +} + +/******************************************************************/ + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + + cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle); + cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + + cdCanvasTransform(ctxcanvas->canvas, NULL); + } +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static char* get_gc_attrib(cdCtxCanvas *ctxcanvas) +{ + return (char*)ctxcanvas->gc; +} + +static cdAttribute gc_attrib = +{ + "GC", + NULL, + get_gc_attrib +}; + +static void get_geometry(Display *dpy, Drawable wnd, cdCtxCanvas *ctxcanvas) +{ + Window root; + int x, y; + unsigned int w, h, b, d; + XGetGeometry(dpy, wnd, &root, &x, &y, &w, &h, &b, &d); + ctxcanvas->canvas->w = w; + ctxcanvas->canvas->h = h; + ctxcanvas->depth = d; +} + +cdCtxCanvas *cdxCreateCanvas(cdCanvas* canvas, Display *dpy, int scr, Drawable wnd, Visual *vis) +{ + static int first = 1; + cdCtxCanvas *ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->dpy = dpy; + ctxcanvas->scr = scr; + ctxcanvas->wnd = wnd; + ctxcanvas->vis = vis; + ctxcanvas->gc = XCreateGC(dpy, wnd, 0, NULL); + if (ctxcanvas->gc == 0) + { + free(canvas); + return NULL; + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + get_geometry(dpy, wnd, ctxcanvas); + + canvas->bpp = ctxcanvas->depth; + canvas->xres = ((double)DisplayWidth(dpy, scr) / (double)DisplayWidthMM(dpy, scr)); + canvas->yres = ((double)DisplayHeight(dpy, scr) / (double)DisplayHeightMM(dpy, scr)); + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + canvas->invert_yaxis = 1; + + if (first) + { + if (canvas->bpp > 8) + { + cdxGetRGB = truecolor_get_rgb; + cdxGetPixel = truecolor_get_pixel; + + /* make linear colormap for DirectColor visual */ +#ifdef __cplusplus + if (ctxcanvas->vis->c_class == DirectColor) +#else + if (ctxcanvas->vis->class == DirectColor) +#endif + makeDirectCmap(ctxcanvas, DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr)); + } + else + { + cdxGetRGB = not_truecolor_get_rgb; + cdxGetPixel = not_truecolor_get_pixel; + } + } + + if (canvas->bpp > 8) + { + ctxcanvas->rshift = 15 - highbit(ctxcanvas->vis->red_mask); + ctxcanvas->gshift = 15 - highbit(ctxcanvas->vis->green_mask); + ctxcanvas->bshift = 15 - highbit(ctxcanvas->vis->blue_mask); + + ctxcanvas->num_colors = 0; + ctxcanvas->colormap = (Colormap)0; + + /* para canvas bpp <= 8 RGBA e' simulado com cdGetImageRGB */ + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + } + else + { + int i; + + ctxcanvas->colormap = DefaultColormap(dpy, scr); + ctxcanvas->num_colors = 1L << canvas->bpp; + + for (i=0; i<ctxcanvas->num_colors; i++) + ctxcanvas->color_table[i].pixel = i; + + update_colors(ctxcanvas); + } + + if (first) + { + if(!getenv("CD_XERROR")) + XSetErrorHandler(cdxErrorHandler); + } + + cdRegisterAttribute(canvas, &gc_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + + first = 0; + + return ctxcanvas; +} + +void cdxInitTable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdxPoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + canvas->cxClip = cdxClip; + canvas->cxClipArea = cdcliparea; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxTransform = cdtransform; + + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxScrollArea = cdscrollarea; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + + if (canvas->bpp > 8) + canvas->cxPutImageRectRGBA = cdputimagerectrgba; +} diff --git a/src/x11/cdx11.h b/src/x11/cdx11.h new file mode 100644 index 0000000..a68fdf9 --- /dev/null +++ b/src/x11/cdx11.h @@ -0,0 +1,85 @@ +/** \file + * \brief X-Windows Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDX11_H +#define __CDX11_H + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "cd.h" +#include "cd_private.h" + + +/* Hidden declaration for the Context Plus driver */ +typedef struct _cdxContextPlus cdxContextPlus; + +struct _cdCtxImage { + unsigned int w, h, depth; + Pixmap img; + Display *dpy; + int scr; + Visual *vis; +}; + +struct _cdCtxCanvas { + cdCanvas* canvas; + Display* dpy; /* display da aplicacao no X */ + Visual* vis; /* visual usado pela aplicacao */ + int scr; /* screen da aplicacao */ + GC gc; /* contexto grafico */ + Drawable wnd; /* drawable */ + long int fg; + Pixmap last_hatch; /* ultimo hatch setado pelo usuario */ + Pixmap last_stipple; /* ultimo stipple setado pelo usuario */ + Pixmap last_pattern; /* ultimo pattern setado pelo usuario */ + GC last_stipple_gc; + int last_stipple_w; + int last_stipple_h; + GC last_pattern_gc; + int last_pattern_w; + int last_pattern_h; + XFontStruct *font; /* fonte de caracteres no X */ + unsigned int depth; /* depth do canvas */ + Pixmap clip_polygon; /* poligono de clipping */ + Pixmap new_region, region_aux; + GC region_aux_gc; + void *data; /* informacoes especificas do driver */ + long int *xidata; /* ximage cache */ + int xisize; + Colormap colormap; /* colormap para todos os canvas */ + XColor color_table[256]; /* tabela de cores do colormap */ + int num_colors; /* tamanho maximo da tabela de cores */ + int rshift; /* constante red para calculo truecolor */ + int gshift; /* constante green para calculo truecolor */ + int bshift; /* constante blue para calculo truecolor */ + double xmatrix[6]; /* transformation matrix that includes axis inversion */ + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + cdImage* image_dbuffer; /* utilizado pelo driver de Double buffer */ + cdCanvas* canvas_dbuffer; + + cdxContextPlus* ctxplus; +}; + +#define cdCOLOR8TO16(_x) (_x*257) /* 65535/255 = 257 */ +#define cdCOLOR16TO8(_x) ((unsigned char)(_x/257)) + +extern unsigned long (*cdxGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb); +extern void (*cdxGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel, + unsigned char* red, + unsigned char* green, + unsigned char* blue); + +cdCtxCanvas *cdxCreateCanvas(cdCanvas* canvas, Display *dpy, int scr, Drawable wnd, Visual *vis); +void cdxInitTable(cdCanvas* canvas); +void cdxKillCanvas(cdCtxCanvas *ctxcanvas); +int cdxClip(cdCtxCanvas *ctxcanvas, int clip_mode); +void cdxPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n); + +#endif diff --git a/src/x11/cdxclp.c b/src/x11/cdxclp.c new file mode 100644 index 0000000..d775fde --- /dev/null +++ b/src/x11/cdxclp.c @@ -0,0 +1,136 @@ +/** \file + * \brief X-Windows Clipboard Driver + * + * See Copyright Notice in cd.h + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "cd.h" +#include "cd_private.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdmf_private.h" + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + char* buffer; + long dwSize; + FILE* file; + char filename[10240]; + cdCanvasMF* mfcanvas = (cdCanvasMF*)ctxcanvas; + Display* dpy = (Display*)mfcanvas->data; + + /* guardar antes de remover o canvas */ + strcpy(filename, mfcanvas->filename); + + cdkillcanvasMF(mfcanvas); + + file = fopen(filename, "r"); + fseek(file, 0, SEEK_END); + dwSize = ftell(file); + fseek(file, 0, SEEK_SET); + + buffer = (char*)malloc(dwSize); + fread(buffer, dwSize, 1, file); + + fclose(file); + + remove(filename); + + XStoreBytes(dpy, buffer, dwSize); +} + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char filename[1024]; + char* buffer; + int dwSize; + FILE* file; + + buffer = XFetchBytes((Display*)data, &dwSize); + if (!buffer) + return CD_ERROR; + + tmpnam(filename); + file = fopen(filename, "w"); + fwrite(buffer, dwSize, 1, file); + fclose(file); + + cdCanvasPlay(canvas, CD_METAFILE, xmin, xmax, ymin, ymax, filename); + + remove(filename); + + XFree(buffer); + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char tmpPath[512]; + char* str = (char*)data; + Display* dpy = NULL; + + /* Inicializa parametros */ + if (str == NULL) + return; + +#ifdef SunOS_OLD + sscanf(str, "%d", &dpy); +#else + sscanf(str, "%p", &dpy); +#endif + + if (!dpy) + return; + + str = strstr(str, " "); + if (!str) + return; + + str++; + tmpnam(tmpPath); + + strcat(tmpPath, " "); + strcat(tmpPath, str); + + cdcreatecanvasMF(canvas, str); + if (!canvas->ctxcanvas) + return; + + { + cdCanvasMF* mfcanvas = (cdCanvasMF*)canvas->ctxcanvas; + mfcanvas->data = dpy; + } +} + +static void cdinittable(cdCanvas* canvas) +{ + cdinittableMF(canvas); + canvas->cxKillCanvas = cdkillcanvas; +} + + +static cdContext cdClipboardContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvas, + cdinittable, + cdplay, + NULL +}; + +cdContext* cdContextClipboard(void) +{ + return &cdClipboardContext; +} + + diff --git a/src/x11/cdxdbuf.c b/src/x11/cdxdbuf.c new file mode 100644 index 0000000..1c92da5 --- /dev/null +++ b/src/x11/cdxdbuf.c @@ -0,0 +1,156 @@ +/** \file + * \brief X-Windows Double Buffer Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdx11.h" +#include "cddbuf.h" +#include <stdlib.h> +#include <stdio.h> + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdKillImage(ctxcanvas->image_dbuffer); + cdxKillCanvas(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + int old_writemode; + cdImage* image_dbuffer = ctxcanvas->image_dbuffer; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* flush the writing in the image */ + XFlush(ctxcanvas->dpy); + + /* this is done in the canvas_dbuffer context */ + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + cdCanvasPutImageRect(canvas_dbuffer, image_dbuffer, 0, 0, 0, 0, 0, 0); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static void cdcreatecanvas(cdCanvas* canvas, cdCanvas* canvas_dbuffer) +{ + cdCtxCanvas* ctxcanvas; + cdImage* image_dbuffer; + cdCtxImage* ctximage; + + /* this is done in the canvas_dbuffer context */ + image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, canvas_dbuffer->w, canvas_dbuffer->h); + if (!image_dbuffer) + return; + + ctximage = image_dbuffer->ctximage; + + /* Inicializa driver DBuffer */ + ctxcanvas = cdxCreateCanvas(canvas, ctximage->dpy, ctximage->scr, ctximage->img, ctximage->vis); + if (!ctxcanvas) + return; + + ctxcanvas->image_dbuffer = image_dbuffer; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->image_dbuffer->w || + canvas_dbuffer->h != ctxcanvas->image_dbuffer->h) + { + cdCanvas* canvas = ctxcanvas->canvas; + /* save the current, if the rebuild fail */ + cdImage* old_image_dbuffer = ctxcanvas->image_dbuffer; + cdCtxCanvas* old_ctxcanvas = ctxcanvas; + + /* if the image is rebuild, the canvas that uses the image must be also rebuild */ + + /* rebuild the image and the canvas */ + canvas->ctxcanvas = NULL; + canvas->context->cxCreateCanvas(canvas, canvas_dbuffer); + if (!canvas->ctxcanvas) + { + canvas->ctxcanvas = old_ctxcanvas; + return CD_ERROR; + } + + /* remove the old image and canvas */ + cdKillImage(old_image_dbuffer); + cdxKillCanvas(old_ctxcanvas); + + ctxcanvas = canvas->ctxcanvas; + + /* update canvas attributes */ + canvas->cxBackground(ctxcanvas, canvas->background); + canvas->cxForeground(ctxcanvas, canvas->foreground); + canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity); + canvas->cxWriteMode(ctxcanvas, canvas->write_mode); + canvas->cxLineStyle(ctxcanvas, canvas->line_style); + canvas->cxLineWidth(ctxcanvas, canvas->line_width); + canvas->cxLineCap(ctxcanvas, canvas->line_cap); + canvas->cxLineJoin(ctxcanvas, canvas->line_join); + canvas->cxHatch(ctxcanvas, canvas->hatch_style); + if (canvas->stipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple); + if (canvas->pattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern); + canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style); + if (canvas->native_font[0] == 0) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + else canvas->cxNativeFont(ctxcanvas, canvas->native_font); +/* canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); */ +/* canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); */ + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax); +/* if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); */ + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n); +/* if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); */ + if (canvas->clip_mode != CD_CLIPOFF) canvas->cxClip(ctxcanvas, canvas->clip_mode); + } + + return CD_OK; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdxInitTable(canvas); + + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxFlush = cdflush; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdDBufferContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDBuffer(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_DBUFFER); + if (ctx != NULL) + return ctx; + } + + return &cdDBufferContext; +} diff --git a/src/x11/cdximg.c b/src/x11/cdximg.c new file mode 100644 index 0000000..8131f78 --- /dev/null +++ b/src/x11/cdximg.c @@ -0,0 +1,52 @@ +/** \file + * \brief X-Windows Image Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> + +#include "cdx11.h" +#include "cdimage.h" + + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdxKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxImage *ctximage = ((cdImage*)data)->ctximage; + cdxCreateCanvas(canvas, ctximage->dpy, ctximage->scr, ctximage->img, ctximage->vis); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdxInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + + +cdContext* cdContextImage(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_IMAGE); + if (ctx != NULL) + return ctx; + } + + return &cdImageContext; +} diff --git a/src/x11/cdxnative.c b/src/x11/cdxnative.c new file mode 100644 index 0000000..c708d20 --- /dev/null +++ b/src/x11/cdxnative.c @@ -0,0 +1,165 @@ +/** \file + * \brief X-Windows Native Window Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "cdx11.h" +#include "cdnative.h" + + +int cdGetScreenColorPlanes(void) +{ + static int first = 1; + static int bpp; + + if (first) + { + int nitems; + XVisualInfo info; + Display* drv_display = XOpenDisplay(NULL); + + info.depth = 24; + if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL) + { + bpp = 24; + XCloseDisplay(drv_display); + return bpp; + } + + info.depth = 16; + if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL) + { + bpp = 16; + XCloseDisplay(drv_display); + return bpp; + } + + info.depth = 8; + if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL) + { + bpp = 8; + XCloseDisplay(drv_display); + return bpp; + } + + info.depth = 4; + if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL) + { + bpp = 4; + XCloseDisplay(drv_display); + return bpp; + } + + bpp = 2; + XCloseDisplay(drv_display); + + first = 0; + } + + return bpp; +} + +void cdGetScreenSize(int *width, int *height, double *width_mm, double *height_mm) +{ + static int first = 1; + static int dpy_width, dpy_height, dpy_width_mm, dpy_height_mm; + + if (first) + { + Display* drv_display = XOpenDisplay(NULL); + int drv_screen = DefaultScreen (drv_display); + + dpy_width = DisplayWidth(drv_display,drv_screen); + dpy_height = DisplayHeight(drv_display,drv_screen); + dpy_width_mm = DisplayWidthMM(drv_display,drv_screen); + dpy_height_mm = DisplayHeightMM(drv_display,drv_screen); + + XCloseDisplay(drv_display); + + first = 0; + } + + if (width) *width = dpy_width; + if (height) *height = dpy_height; + if (width_mm) *width_mm = dpy_width_mm; + if (height_mm) *height_mm = dpy_height_mm; +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdxKillCanvas(ctxcanvas); +} + +static int cdactivate(cdCtxCanvas *ctxcanvas) +{ + Window root; + int x, y; + unsigned int bw, d; + XGetGeometry(ctxcanvas->dpy, ctxcanvas->wnd, &root, &x, &y, + (unsigned int*)&ctxcanvas->canvas->w, (unsigned int*)&ctxcanvas->canvas->h, &bw, &d); + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + if (ctxcanvas->canvas->use_matrix) + ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char* data_str = (char*)data; + Window wnd; + Display *dpy; + XWindowAttributes wa; + +#ifdef SunOS_OLD + sscanf(data_str, "%d %lu", &dpy, &wnd); +#else + sscanf(data_str, "%p %lu", &dpy, &wnd); +#endif + + if (!dpy || !wnd) + return; + + XGetWindowAttributes(dpy, wnd, &wa); + cdxCreateCanvas(canvas, dpy, XScreenNumberOfScreen(wa.screen), wnd, wa.visual); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdxInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +/******************************************************/ + +static cdContext cdNativeWindowContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + + +cdContext* cdContextNativeWindow(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_NATIVEWINDOW); + if (ctx != NULL) + return ctx; + } + + return &cdNativeWindowContext; +} diff --git a/src/x11/xvertex.c b/src/x11/xvertex.c new file mode 100644 index 0000000..87a05e9 --- /dev/null +++ b/src/x11/xvertex.c @@ -0,0 +1,1440 @@ +/* ********************************************************************** */ + +/* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) +* +* Permission to use, copy, modify, and distribute this software and its +* documentation for any purpose and without fee is hereby granted, provided +* that the above copyright notice appear in all copies and that both the +* copyright notice and this permission notice appear in supporting +* documentation. All work developed as a consequence of the use of +* this program should duly acknowledge such use. No representations are +* made about the suitability of this software for any purpose. It is +* provided "as is" without express or implied warranty. +*/ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "xvertex.h" + + +/* ---------------------------------------------------------------------- */ + + +/* Make sure cache size is set */ + +#ifndef CACHE_SIZE_LIMIT +#define CACHE_SIZE_LIMIT 300 +#endif /*CACHE_SIZE_LIMIT */ + +/* Make sure a cache method is specified */ + +#ifndef CACHE_XIMAGES +#ifndef CACHE_BITMAPS +#define CACHE_BITMAPS +#endif /*CACHE_BITMAPS*/ +#endif /*CACHE_XIMAGES*/ + + +/* ---------------------------------------------------------------------- */ + + +/* Debugging macros */ + +#ifdef DEBUG +static int debug=1; +#else +static int debug=0; +#endif /*DEBUG*/ + +#define DEBUG_PRINT1(a) if (debug) printf (a) +#define DEBUG_PRINT2(a, b) if (debug) printf (a, b) +#define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c) +#define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d) +#define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e) + + +/* ---------------------------------------------------------------------- */ + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/* ---------------------------------------------------------------------- */ + + +/* A structure holding everything needed for a rotated string */ + +typedef struct rotated_text_item_template { + Pixmap bitmap; + XImage *ximage; + + char *text; + char *font_name; + Font fid; + double angle; + int align; + double magnify; + + int cols_in; + int rows_in; + int cols_out; + int rows_out; + + int nl; + int max_width; + double *corners_x; + double *corners_y; + + long int size; + int cached; + + struct rotated_text_item_template *next; +} RotatedTextItem; + +static RotatedTextItem *first_text_item=NULL; + + +/* ---------------------------------------------------------------------- */ + + +/* A structure holding current magnification and bounding box padding */ + +static struct style_template { + double magnify; + int bbx_pad; +} style={ + 1., + 0 +}; + + +/* ---------------------------------------------------------------------- */ + +static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, double angle, char *text, int align); +static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item); +static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage); +static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item); + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Routine to mimic `strdup()' (some machines don't have it) */ +/**************************************************************************/ + +static char *my_strdup(const char *str) +{ + char *s; + + if(str==NULL) + return NULL; + + s=(char *)malloc((unsigned)(strlen(str)+1)); + if(s!=NULL) + strcpy(s, str); + + return s; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Routine to replace `strtok' : this one returns a zero length string if */ +/* it encounters two consecutive delimiters */ +/**************************************************************************/ + +static char *my_strtok(char *str1, const char *str2) +{ + char *ret; + int i, j, stop; + static int start, len; + static char *stext; + + if(str2==NULL) + return NULL; + + /* initialise if str1 not NULL */ + if(str1!=NULL) + { + start=0; + stext=str1; + len=strlen(str1); + } + + /* run out of tokens ? */ + if(start>=len) + return NULL; + + /* loop through characters */ + for(i=start; i<len; i++) + { + /* loop through delimiters */ + stop=0; + for(j=0; j<strlen(str2); j++) + if(stext[i]==str2[j]) + stop=1; + + if(stop) + break; + } + + stext[i]='\0'; + + ret=stext+start; + + start=i+1; + + return ret; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Create an XImage structure and allocate memory for it */ +/**************************************************************************/ + +static XImage *MakeXImage(Display *dpy, int w, int h) +{ + XImage *I; + char *data; + + /* reserve memory for image */ + data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1); + if(data==NULL) + return NULL; + + /* create the XImage */ + I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, data, w, h, 8, 0); + if(I==NULL) + return NULL; + + I->byte_order=I->bitmap_bit_order=MSBFirst; + return I; +} + +/* ---------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Draw a horizontal string in a quick fashion */ +/**************************************************************************/ + +static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, const char *text, int align, int bg) +{ + GC my_gc; + int nl=1, i; + int height; + int xp, yp; + char *str1, *str2, *str3; + char *str2_a="\0", *str2_b="\n\0"; + int dir, asc, desc; + XCharStruct overall; + + DEBUG_PRINT1("**\nHorizontal text.\n"); + + /* this gc has similar properties to the user's gc (including stipple) */ + my_gc=XCreateGC(dpy, drawable, 0, 0); + XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle| GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc); + XSetFont(dpy, my_gc, font->fid); + + /* count number of sections in string */ + if(align!=XR_LEFT) + for(i=0; i<strlen(text)-1; i++) + if(text[i]=='\n') + nl++; + + /* ignore newline characters if not doing alignment */ + if(align==XR_LEFT) + str2=str2_a; + else + str2=str2_b; + + /* overall font height */ + height=font->ascent+font->descent; + + /* y position */ + if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT) + yp=y+font->ascent; + else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT) + yp=y-nl*height/2+font->ascent; + else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT) + yp=y-nl*height+font->ascent; + else + yp=y; + + str1=my_strdup(text); + if(str1==NULL) + return 1; + + str3=my_strtok(str1, str2); + + /* loop through each section in the string */ + do { + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, + &overall); + + /* where to draw section in x ? */ + if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT) + xp=x; + else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE) + xp=x-overall.rbearing/2; + else + xp=x-overall.rbearing; + + /* draw string onto bitmap */ + if(!bg) + XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); + else + XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); + + /* move to next line */ + yp+=height; + + str3=my_strtok((char *)NULL, str2); + } + while(str3!=NULL); + + free(str1); + XFreeGC(dpy, my_gc); + + return 0; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Query cache for a match with this font/text/angle/alignment */ +/* request, otherwise arrange for its creation */ +/**************************************************************************/ + +static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, double angle, const char *text, int align) +{ + Font fid; + char *font_name=NULL; + unsigned long name_value; + RotatedTextItem *item=NULL; + RotatedTextItem *i1=first_text_item; + + /* get font name, if it exists */ + if(XGetFontProperty(font, XA_FONT, &name_value)) { + DEBUG_PRINT1("got font name OK\n"); + font_name=XGetAtomName(dpy, name_value); + fid=0; + } +#ifdef CACHE_FID + /* otherwise rely (unreliably?) on font ID */ + else { + DEBUG_PRINT1("can't get fontname, caching FID\n"); + font_name=NULL; + fid=font->fid; + } +#else + /* not allowed to cache font ID's */ + else { + DEBUG_PRINT1("can't get fontname, can't cache\n"); + font_name=NULL; + fid=0; + } +#endif /*CACHE_FID*/ + + /* look for a match in cache */ + + /* matching formula: + identical text; + identical fontname (if defined, font ID's if not); + angles close enough (<0.00001 here, could be smaller); + HORIZONTAL alignment matches, OR it's a one line string; + magnifications the same */ + + while(i1 && !item) + { + /* match everything EXCEPT fontname/ID */ + if(strcmp(text, i1->text)==0 && + fabs(angle-i1->angle)<0.00001 && + style.magnify==i1->magnify && + (i1->nl==1 || + ((align==0)?9:(align-1))%3== + ((i1->align==0)?9:(i1->align-1))%3)) + { + + /* now match fontname/ID */ + if(font_name!=NULL && i1->font_name!=NULL) + { + if(strcmp(font_name, i1->font_name)==0) + { + item=i1; + DEBUG_PRINT1("Matched against font names\n"); + } + else + i1=i1->next; + } +#ifdef CACHE_FID + else if(font_name==NULL && i1->font_name==NULL) + { + if(fid==i1->fid) + { + item=i1; + DEBUG_PRINT1("Matched against FID's\n"); + } + else + i1=i1->next; + } +#endif /*CACHE_FID*/ + else + i1=i1->next; + } + else + i1=i1->next; + } + + if(item) + DEBUG_PRINT1("**\nFound target in cache.\n"); + if(!item) + DEBUG_PRINT1("**\nNo match in cache.\n"); + + /* no match */ + if(!item) + { + /* create new item */ + item=XRotCreateTextItem(dpy, font, angle, text, align); + if(!item) + return NULL; + + /* record what it shows */ + item->text=my_strdup(text); + + /* fontname or ID */ + if(font_name!=NULL) + { + item->font_name=my_strdup(font_name); + item->fid=0; + } + else + { + item->font_name=NULL; + item->fid=fid; + } + + item->angle=angle; + item->align=align; + item->magnify=style.magnify; + + /* cache it */ + XRotAddToLinkedList(dpy, item); + } + + if(font_name) + XFree(font_name); + + /* if XImage is cached, need to recreate the bitmap */ + +#ifdef CACHE_XIMAGES + { + GC depth_one_gc; + + /* create bitmap to hold rotated text */ + item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), + item->cols_out, item->rows_out, 1); + + /* depth one gc */ + depth_one_gc=XCreateGC(dpy, item->bitmap, 0, 0); + XSetBackground(dpy, depth_one_gc, 0); + XSetForeground(dpy, depth_one_gc, 1); + + /* make the text bitmap from XImage */ + XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0, + item->cols_out, item->rows_out); + + XFreeGC(dpy, depth_one_gc); + } +#endif /*CACHE_XIMAGES*/ + + return item; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Create a rotated text item */ +/**************************************************************************/ + +static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, double angle, char *text, int align) +{ + RotatedTextItem *item=NULL; + Pixmap canvas; + GC font_gc; + XImage *I_in; + register int i, j; + char *str1, *str2, *str3; + char *str2_a="\0", *str2_b="\n\0"; + int height; + int byte_w_in, byte_w_out; + int xp, yp; + double sin_angle, cos_angle; + int it, jt; + double di, dj; + int ic=0; + double xl, xr, xinc; + int byte_out; + int dir, asc, desc; + XCharStruct overall; + int old_cols_in=0, old_rows_in=0; + + /* allocate memory */ + item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem)); + if(!item) + return NULL; + + /* count number of sections in string */ + item->nl=1; + if(align!=XR_LEFT) + for(i=0; i<strlen(text)-1; i++) + if(text[i]=='\n') + item->nl++; + + /* ignore newline characters if not doing alignment */ + if(align==XR_LEFT) + str2=str2_a; + else + str2=str2_b; + + /* find width of longest section */ + str1=my_strdup(text); + if(str1==NULL) + return NULL; + + str3=my_strtok(str1, str2); + + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, + &overall); + + item->max_width=overall.rbearing; + + /* loop through each section */ + do + { + str3=my_strtok((char *)NULL, str2); + + if(str3!=NULL) + { + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, + &overall); + + if(overall.rbearing>item->max_width) + item->max_width=overall.rbearing; + } + } while(str3!=NULL); + + free(str1); + + /* overall font height */ + height=font->ascent+font->descent; + + /* dimensions horizontal text will have */ + item->cols_in=item->max_width; + item->rows_in=item->nl*height; + + /* bitmap for drawing on */ + canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy), + item->cols_in, item->rows_in, 1); + + /* create a GC for the bitmap */ + font_gc=XCreateGC(dpy, canvas, 0, 0); + XSetBackground(dpy, font_gc, 0); + XSetFont(dpy, font_gc, font->fid); + + /* make sure the bitmap is blank */ + XSetForeground(dpy, font_gc, 0); + XFillRectangle(dpy, canvas, font_gc, 0, 0, + item->cols_in+1, item->rows_in+1); + XSetForeground(dpy, font_gc, 1); + + /* pre-calculate sin and cos */ + sin_angle=sin(angle); + cos_angle=cos(angle); + + if (fabs(sin_angle)==1.0) cos_angle=0; + if (fabs(cos_angle)==1.0) sin_angle=0; + + /* text background will be drawn using XFillPolygon */ + item->corners_x= + (double *)malloc((unsigned)(4*item->nl*sizeof(double))); + if(!item->corners_x) + return NULL; + + item->corners_y= + (double *)malloc((unsigned)(4*item->nl*sizeof(double))); + if(!item->corners_y) + return NULL; + + /* draw text horizontally */ + + /* start at top of bitmap */ + yp=font->ascent; + + str1=my_strdup(text); + if(str1==NULL) + return NULL; + + str3=my_strtok(str1, str2); + + /* loop through each section in the string */ + do + { + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); + + /* where to draw section in x ? */ + if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT) + xp=0; + else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE) + xp=(item->max_width-overall.rbearing)/2; + else + xp=item->max_width-overall.rbearing; + + /* draw string onto bitmap */ + XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3)); + + /* keep a note of corner positions of this string */ + item->corners_x[ic]=((double)xp-(double)item->cols_in/2)*style.magnify; + item->corners_y[ic]=((double)(yp-font->ascent)-(double)item->rows_in/2) + *style.magnify; + item->corners_x[ic+1]=item->corners_x[ic]; + item->corners_y[ic+1]=item->corners_y[ic]+(double)height*style.magnify; + item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+ + (double)overall.rbearing*style.magnify; + item->corners_y[item->nl*4-1-ic]=item->corners_y[ic]; + item->corners_x[item->nl*4-2-ic]= + item->corners_x[item->nl*4-1-ic]; + item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1]; + + ic+=2; + + /* move to next line */ + yp+=height; + + str3=my_strtok((char *)NULL, str2); + } while(str3!=NULL); + + free(str1); + + /* create image to hold horizontal text */ + I_in=MakeXImage(dpy, item->cols_in, item->rows_in); + if(I_in==NULL) + return NULL; + + /* extract horizontal text */ + XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in, + 1, XYPixmap, I_in, 0, 0); + I_in->format=XYBitmap; + + /* magnify horizontal text */ + if(style.magnify!=1.) + { + I_in=XRotMagnifyImage(dpy, I_in); + + old_cols_in=item->cols_in; + old_rows_in=item->rows_in; + item->cols_in=(double)item->cols_in*style.magnify; + item->rows_in=(double)item->rows_in*style.magnify; + } + + /* how big will rotated text be ? */ + item->cols_out=fabs((double)item->rows_in*sin_angle) + + fabs((double)item->cols_in*cos_angle) +0.99999 +2; + + item->rows_out=fabs((double)item->rows_in*cos_angle) + + fabs((double)item->cols_in*sin_angle) +0.99999 +2; + + if(item->cols_out%2==0) + item->cols_out++; + + if(item->rows_out%2==0) + item->rows_out++; + + /* create image to hold rotated text */ + item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out); + if(item->ximage==NULL) + return NULL; + + byte_w_in=(item->cols_in-1)/8+1; + byte_w_out=(item->cols_out-1)/8+1; + + /* we try to make this bit as fast as possible - which is why it looks + a bit over-the-top */ + + /* vertical distance from centre */ + dj=0.5-(double)item->rows_out/2; + + /* where abouts does text actually lie in rotated image? */ + if(angle==0 || angle==M_PI/2 || angle==M_PI || angle==3*M_PI/2) + { + xl=0; + xr=(double)item->cols_out; + xinc=0; + } + else if(angle<M_PI) + { + xl=(double)item->cols_out/2+ + (dj-(double)item->rows_in/(2*cos_angle))/ + tan(angle)-2; + + xr=(double)item->cols_out/2+ + (dj+(double)item->rows_in/(2*cos_angle))/ + tan(angle)+2; + + xinc=1./tan(angle); + } + else + { + xl=(double)item->cols_out/2+ + (dj+(double)item->rows_in/(2*cos_angle))/ + tan(angle)-2; + + xr=(double)item->cols_out/2+ + (dj-(double)item->rows_in/(2*cos_angle))/ + tan(angle)+2; + + xinc=1./tan(angle); + } + + /* loop through all relevent bits in rotated image */ + for(j=0; j<item->rows_out; j++) + { + /* no point re-calculating these every pass */ + di=(double)((xl<0)?0:(int)xl)+0.5-(double)item->cols_out/2; + byte_out=(item->rows_out-j-1)*byte_w_out; + + /* loop through meaningful columns */ + for(i=((xl<0)?0:(int)xl);i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) + { + /* rotate coordinates */ + it=(double)item->cols_in/2 + ( di*cos_angle + dj*sin_angle); + jt=(double)item->rows_in/2 - (-di*sin_angle + dj*cos_angle); + + /* set pixel if required */ + if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in) + if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0) + item->ximage->data[byte_out+i/8]|=128>>i%8; + + di+=1; + } + + dj+=1; + xl+=xinc; + xr+=xinc; + } + + XDestroyImage(I_in); + + if(style.magnify!=1.) + { + item->cols_in=old_cols_in; + item->rows_in=old_rows_in; + } + + +#ifdef CACHE_BITMAPS + + /* create a bitmap to hold rotated text */ + item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), + item->cols_out, item->rows_out, 1); + + /* make the text bitmap from XImage */ + XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0, + item->cols_out, item->rows_out); + + XDestroyImage(item->ximage); + +#endif /*CACHE_BITMAPS*/ + + XFreeGC(dpy, font_gc); + XFreePixmap(dpy, canvas); + + return item; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Adds a text item to the end of the cache, removing as many items */ +/* from the front as required to keep cache size below limit */ +/**************************************************************************/ + +static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item) +{ + + static long int current_size=0; + static RotatedTextItem *last=NULL; + RotatedTextItem *i1=first_text_item, *i2=NULL; + +#ifdef CACHE_BITMAPS + + /* I don't know how much memory a pixmap takes in the server - + probably this + a bit more we can't account for */ + + item->size=((item->cols_out-1)/8+1)*item->rows_out; + +#else + + /* this is pretty much the size of a RotatedTextItem */ + + item->size=((item->cols_out-1)/8+1)*item->rows_out + + sizeof(XImage) + strlen(item->text) + + item->nl*8*sizeof(double) + sizeof(RotatedTextItem); + + if(item->font_name!=NULL) + item->size+=strlen(item->font_name); + else + item->size+=sizeof(Font); + +#endif /*CACHE_BITMAPS */ + +#ifdef DEBUG + /* count number of items in cache, for debugging */ + { + int i=0; + + while(i1) { + i++; + i1=i1->next; + } + DEBUG_PRINT2("Cache has %d items.\n", i); + i1=first_text_item; + } +#endif + + DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%d\n", + current_size, item->size, CACHE_SIZE_LIMIT*1024); + + /* if this item is bigger than whole cache, forget it */ + if(item->size>CACHE_SIZE_LIMIT*1024) { + DEBUG_PRINT1("Too big to cache\n\n"); + item->cached=0; + return; + } + + /* remove elements from cache as needed */ + while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) { + + DEBUG_PRINT2("Removed %ld bytes\n", i1->size); + + if(i1->font_name!=NULL) + DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n", + i1->text, i1->font_name, i1->angle, i1->align); + +#ifdef CACHE_FID + if(i1->font_name==NULL) + DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n", + i1->text, i1->fid, i1->angle, i1->align); +#endif /*CACHE_FID*/ + + current_size-=i1->size; + + i2=i1->next; + + /* free resources used by the unlucky item */ + XRotFreeTextItem(dpy, i1); + + /* remove it from linked list */ + first_text_item=i2; + i1=i2; + } + + /* add new item to end of linked list */ + if(first_text_item==NULL) { + item->next=NULL; + first_text_item=item; + last=item; + } + else { + item->next=NULL; + last->next=item; + last=item; + } + + /* new cache size */ + current_size+=item->size; + + item->cached=1; + + DEBUG_PRINT1("Added item to cache.\n"); +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Free the resources used by a text item */ +/**************************************************************************/ + +static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item) +{ + free(item->text); + + if(item->font_name!=NULL) + free(item->font_name); + + free((char *)item->corners_x); + free((char *)item->corners_y); + +#ifdef CACHE_BITMAPS + XFreePixmap(dpy, item->bitmap); +#else + XDestroyImage(item->ximage); +#endif /* CACHE_BITMAPS */ + + free((char *)item); +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Magnify an XImage using bilinear interpolation */ +/**************************************************************************/ + +static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage) +{ + int i, j; + double x, y; + double u,t; + XImage *I_out; + int cols_in, rows_in; + int cols_out, rows_out; + register int i2, j2; + double z1, z2, z3, z4; + int byte_width_in, byte_width_out; + double mag_inv; + + /* size of input image */ + cols_in=ximage->width; + rows_in=ximage->height; + + /* size of final image */ + cols_out=(double)cols_in*style.magnify; + rows_out=(double)rows_in*style.magnify; + + /* this will hold final image */ + I_out=MakeXImage(dpy, cols_out, rows_out); + if(I_out==NULL) + return NULL; + + /* width in bytes of input, output images */ + byte_width_in=(cols_in-1)/8+1; + byte_width_out=(cols_out-1)/8+1; + + /* for speed */ + mag_inv=1./style.magnify; + + y=0.; + + /* loop over magnified image */ + for(j2=0; j2<rows_out; j2++) + { + x=0; + j=y; + + for(i2=0; i2<cols_out; i2++) + { + i=x; + + /* bilinear interpolation - where are we on bitmap ? */ + /* right edge */ + if(i==cols_in-1 && j!=rows_in-1) + { + t=0; + u=y-(double)j; + + z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; + z2=z1; + z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; + z4=z3; + } + /* top edge */ + else if(i!=cols_in-1 && j==rows_in-1) + { + t=x-(double)i; + u=0; + + z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; + z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; + z3=z2; + z4=z1; + } + /* top right corner */ + else if(i==cols_in-1 && j==rows_in-1) + { + u=0; + t=0; + + z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; + z2=z1; + z3=z1; + z4=z1; + } + /* somewhere `safe' */ + else + { + t=x-(double)i; + u=y-(double)j; + + z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; + z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; + z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] & + 128>>((i+1)%8))>0; + z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; + } + + /* if interpolated value is greater than 0.5, set bit */ + if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5) + I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8; + + x+=mag_inv; + } + y+=mag_inv; + } + + /* destroy original */ + XDestroyImage(ximage); + + /* return big image */ + return I_out; +} + + + + +/**************************************************************************/ +/* Return version/copyright information */ +/**************************************************************************/ + +double XRotVersion(char* str, int n) +{ + if(str!=NULL) + strncpy(str, XV_COPYRIGHT, n); + return XV_VERSION; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Set the font magnification factor for all subsequent operations */ +/**************************************************************************/ + +void XRotSetMagnification(double m) +{ + if(m>0.) + style.magnify=m; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Set the padding used when calculating bounding boxes */ +/**************************************************************************/ + +void XRotSetBoundingBoxPad(int p) +{ + if(p>=0) + style.bbx_pad=p; +} + + +/* ---------------------------------------------------------------------- */ + + +/**************************************************************************/ +/* Calculate the bounding box some text will have when painted */ +/**************************************************************************/ + +XPoint *XRotTextExtents(Display* dpy, XFontStruct* font, double angle, int x, int y, const char* text, int align) +{ + register int i; + char *str1, *str2, *str3; + char *str2_a="\0", *str2_b="\n\0"; + int height; + double sin_angle, cos_angle; + int nl, max_width; + int cols_in, rows_in; + double hot_x, hot_y; + XPoint *xp_in, *xp_out; + int dir, asc, desc; + XCharStruct overall; + + /* manipulate angle to 0<=angle<360 degrees */ + while(angle<0) + angle+=360; + + while(angle>360) + angle-=360; + + angle*=M_PI/180; + + /* count number of sections in string */ + nl=1; + if(align!=XR_LEFT) + for(i=0; i<strlen(text)-1; i++) + if(text[i]=='\n') + nl++; + + /* ignore newline characters if not doing alignment */ + if(align==XR_LEFT) + str2=str2_a; + else + str2=str2_b; + + /* find width of longest section */ + str1=my_strdup(text); + if(str1==NULL) + return NULL; + + str3=my_strtok(str1, str2); + + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, + &overall); + + max_width=overall.rbearing; + + /* loop through each section */ + do + { + str3=my_strtok((char *)NULL, str2); + + if(str3!=NULL) + { + XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, + &overall); + + if(overall.rbearing>max_width) + max_width=overall.rbearing; + } + } while(str3!=NULL); + + free(str1); + + /* overall font height */ + height=font->ascent+font->descent; + + /* dimensions horizontal text will have */ + cols_in=max_width; + rows_in=nl*height; + + /* pre-calculate sin and cos */ + sin_angle=sin(angle); + cos_angle=cos(angle); + + /* y position */ + if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT) + hot_y=(double)rows_in/2*style.magnify; + else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT) + hot_y=0; + else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT) + hot_y=-(double)rows_in/2*style.magnify; + else + hot_y=-((double)rows_in/2-(double)font->descent)*style.magnify; + + /* x position */ + if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT) + hot_x=-(double)max_width/2*style.magnify; + else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE) + hot_x=0; + else + hot_x=(double)max_width/2*style.magnify; + + /* reserve space for XPoints */ + xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); + if(!xp_in) + return NULL; + + xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); + if(!xp_out) + return NULL; + + /* bounding box when horizontal, relative to bitmap centre */ + xp_in[0].x=-(double)cols_in*style.magnify/2-style.bbx_pad; + xp_in[0].y= (double)rows_in*style.magnify/2+style.bbx_pad; + xp_in[1].x= (double)cols_in*style.magnify/2+style.bbx_pad; + xp_in[1].y= (double)rows_in*style.magnify/2+style.bbx_pad; + xp_in[2].x= (double)cols_in*style.magnify/2+style.bbx_pad; + xp_in[2].y=-(double)rows_in*style.magnify/2-style.bbx_pad; + xp_in[3].x=-(double)cols_in*style.magnify/2-style.bbx_pad; + xp_in[3].y=-(double)rows_in*style.magnify/2-style.bbx_pad; + xp_in[4].x=xp_in[0].x; + xp_in[4].y=xp_in[0].y; + + /* rotate and translate bounding box */ + for(i=0; i<5; i++) + { + xp_out[i].x=(double)x + ( ((double)xp_in[i].x-hot_x)*cos_angle + + ((double)xp_in[i].y+hot_y)*sin_angle); + + xp_out[i].y=(double)y + (-((double)xp_in[i].x-hot_x)*sin_angle + + ((double)xp_in[i].y+hot_y)*cos_angle); + } + + free((char *)xp_in); + + return xp_out; +} + +/* ---------------------------------------------------------------------- */ + +/**************************************************************************/ +/* Aligns and paints a rotated string */ +/**************************************************************************/ + +int XRotDrawString(Display* dpy, XFontStruct* font, double angle, Drawable drawable, GC gc, int x, int y, const char* text, int align, int bg) +{ + int i; + GC my_gc; + int xp, yp; + double hot_x, hot_y; + double hot_xp, hot_yp; + double sin_angle, cos_angle; + RotatedTextItem *item; + Pixmap bitmap_to_paint; + + /* return early for NULL/empty strings */ + if(text==NULL) + return 0; + + if(strlen(text)==0) + return 0; + + /* manipulate angle to 0<=angle<360 degrees */ + while(angle<0) + angle+=360; + + while(angle>=360) + angle-=360; + + angle*=M_PI/180; + + /* horizontal text made easy */ + if(angle==0. && style.magnify==1.) + return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text, align, bg)); + + /* get a rotated bitmap */ + item=XRotRetrieveFromCache(dpy, font, angle, text, align); + if(item==NULL) + return 0; + + /* this gc has similar properties to the user's gc */ + my_gc=XCreateGC(dpy, drawable, 0, 0); + XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask, my_gc); + + /* alignment : which point (hot_x, hot_y) relative to bitmap centre + coincides with user's specified point? */ + + /* y position */ + if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT) + hot_y=(double)item->rows_in/2*style.magnify; + else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT) + hot_y=0; + else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT) + hot_y=-(double)item->rows_in/2*style.magnify; + else + hot_y=-((double)item->rows_in/2-(double)font->descent)*style.magnify; + + /* x position */ + if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT) + hot_x=-(double)item->max_width/2*style.magnify; + else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE) + hot_x=0; + else + hot_x=(double)item->max_width/2*style.magnify; + + /* pre-calculate sin and cos */ + sin_angle=sin(angle); + cos_angle=cos(angle); + + /* rotate hot_x and hot_y around bitmap centre */ + hot_xp= hot_x*cos_angle - hot_y*sin_angle; + hot_yp= hot_x*sin_angle + hot_y*cos_angle; + + /* text background will be drawn using XFillPolygon */ + if(bg) + { + GC depth_one_gc; + XPoint *xpoints; + Pixmap empty_stipple; + + /* reserve space for XPoints */ + xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint))); + if(!xpoints) + return 1; + + /* rotate corner positions */ + for(i=0; i<4*item->nl; i++) + { + xpoints[i].x=(double)x + ( (item->corners_x[i]-hot_x)*cos_angle + + (item->corners_y[i]+hot_y)*sin_angle); + + xpoints[i].y=(double)y + (-(item->corners_x[i]-hot_x)*sin_angle + + (item->corners_y[i]+hot_y)*cos_angle); + } + + /* we want to swap foreground and background colors here; + XGetGCValues() is only available in R4+ */ + + empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1); + + depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0); + XSetForeground(dpy, depth_one_gc, 0); + XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2); + + XSetStipple(dpy, my_gc, empty_stipple); + XSetFillStyle(dpy, my_gc, FillOpaqueStippled); + + XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex, + CoordModeOrigin); + + /* free our resources */ + free((char *)xpoints); + XFreeGC(dpy, depth_one_gc); + XFreePixmap(dpy, empty_stipple); + } + + /* where should top left corner of bitmap go ? */ + xp=(double)x-((double)item->cols_out/2 +hot_xp); + yp=(double)y-((double)item->rows_out/2 -hot_yp); + + /* by default we draw the rotated bitmap, solid */ + bitmap_to_paint=item->bitmap; + + /* handle user stippling */ +#ifndef X11R3 + { + GC depth_one_gc; + XGCValues values; + Pixmap new_bitmap, inverse; + + /* try and get some GC properties */ + if(XGetGCValues(dpy, gc, + GCStipple|GCFillStyle|GCForeground|GCBackground| + GCTileStipXOrigin|GCTileStipYOrigin, + &values)) + { + /* only do this if stippling requested */ + if((values.fill_style==FillStippled || + values.fill_style==FillOpaqueStippled) && !bg) + { + /* opaque stipple: draw rotated text in background colour */ + if(values.fill_style==FillOpaqueStippled) + { + XSetForeground(dpy, my_gc, values.background); + XSetFillStyle(dpy, my_gc, FillStippled); + XSetStipple(dpy, my_gc, item->bitmap); + XSetTSOrigin(dpy, my_gc, xp, yp); + XFillRectangle(dpy, drawable, my_gc, xp, yp, + item->cols_out, item->rows_out); + XSetForeground(dpy, my_gc, values.foreground); + } + + /* this will merge the rotated text and the user's stipple */ + new_bitmap=XCreatePixmap(dpy, drawable, + item->cols_out, item->rows_out, 1); + + /* create a GC */ + depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0); + XSetForeground(dpy, depth_one_gc, 1); + XSetBackground(dpy, depth_one_gc, 0); + + /* set the relative stipple origin */ + XSetTSOrigin(dpy, depth_one_gc, + values.ts_x_origin-xp, values.ts_y_origin-yp); + + /* fill the whole bitmap with the user's stipple */ + XSetStipple(dpy, depth_one_gc, values.stipple); + XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled); + XFillRectangle(dpy, new_bitmap, depth_one_gc, + 0, 0, item->cols_out, item->rows_out); + + /* set stipple origin back to normal */ + XSetTSOrigin(dpy, depth_one_gc, 0, 0); + + /* this will contain an inverse copy of the rotated text */ + inverse=XCreatePixmap(dpy, drawable, + item->cols_out, item->rows_out, 1); + + /* invert text */ + XSetFillStyle(dpy, depth_one_gc, FillSolid); + XSetFunction(dpy, depth_one_gc, GXcopyInverted); + XCopyArea(dpy, item->bitmap, inverse, depth_one_gc, + 0, 0, item->cols_out, item->rows_out, 0, 0); + + /* now delete user's stipple everywhere EXCEPT on text */ + XSetForeground(dpy, depth_one_gc, 0); + XSetBackground(dpy, depth_one_gc, 1); + XSetStipple(dpy, depth_one_gc, inverse); + XSetFillStyle(dpy, depth_one_gc, FillStippled); + XSetFunction(dpy, depth_one_gc, GXcopy); + XFillRectangle(dpy, new_bitmap, depth_one_gc, + 0, 0, item->cols_out, item->rows_out); + + /* free resources */ + XFreePixmap(dpy, inverse); + XFreeGC(dpy, depth_one_gc); + + /* this is the new bitmap */ + bitmap_to_paint=new_bitmap; + } + } + } +#endif /*X11R3*/ + + /* paint text using stipple technique */ + XSetFillStyle(dpy, my_gc, FillStippled); + XSetStipple(dpy, my_gc, bitmap_to_paint); + XSetTSOrigin(dpy, my_gc, xp, yp); + XFillRectangle(dpy, drawable, my_gc, xp, yp, + item->cols_out, item->rows_out); + + /* free our resources */ + XFreeGC(dpy, my_gc); + + /* stippled bitmap no longer needed */ + if(bitmap_to_paint!=item->bitmap) + XFreePixmap(dpy, bitmap_to_paint); + +#ifdef CACHE_XIMAGES + XFreePixmap(dpy, item->bitmap); +#endif /*CACHE_XIMAGES*/ + + /* if item isn't cached, destroy it completely */ + if(!item->cached) + XRotFreeTextItem(dpy,item); + + /* we got to the end OK! */ + return 0; +} + + diff --git a/src/x11/xvertex.h b/src/x11/xvertex.h new file mode 100644 index 0000000..b1b4e3a --- /dev/null +++ b/src/x11/xvertex.h @@ -0,0 +1,31 @@ +/* ************************************************************************ */ +/* Header file for the `xvertext 5.0' routines. + + Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */ +/* ************************************************************************ */ + +#ifndef __XVERTEXT_H +#define __XVERTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define XV_VERSION 5.0 +#define XV_COPYRIGHT \ + "xvertext routines Copyright (c) 1993 Alan Richardson" + +/* text alignment */ +enum {XR_LEFT, XR_CENTRE, XR_RIGHT, XR_TLEFT, XR_TCENTRE, XR_TRIGHT, XR_MLEFT, XR_MCENTRE, XR_MRIGHT, XR_BLEFT, XR_BCENTRE, XR_BRIGHT}; + +double XRotVersion(char* str, int n); +void XRotSetMagnification(double m); +void XRotSetBoundingBoxPad(int p); +XPoint *XRotTextExtents(Display* dpy, XFontStruct* font, double angle, int x, int y, const char* text, int align); +int XRotDrawString(Display* dpy, XFontStruct* font, double angle, Drawable drawable, GC gc, int x, int y, const char* text, int align, int bg); + +#ifdef __cplusplus +} +#endif + +#endif /* _XVERTEXT_INCLUDED_ */ diff --git a/src/xrender/cdxrender.c b/src/xrender/cdxrender.c new file mode 100644 index 0000000..98f65aa --- /dev/null +++ b/src/xrender/cdxrender.c @@ -0,0 +1,1139 @@ +/** file + * brief XRender Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <math.h> + +#include <X11/Xft/Xft.h> +#include <X11/extensions/Xrender.h> + +#include "cdx11.h" +#include "cddbuf.h" +#include "cdimage.h" +#include "cdnative.h" +#include "truetype.h" +#include "sim.h" + +#include <X11/Xproto.h> + +#define NUM_HATCHES 6 +static unsigned char hatches[NUM_HATCHES][8] = { + {0x00,0x00,0xFF,0x00,0x00,0x00,0xFF,0x00}, /* HORIZONTAL */ + {0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22}, /* VERTICAL */ + {0x08,0x10,0x20,0x40,0x80,0x01,0x02,0x04}, /* FDIAGONAL */ + {0x10,0x08,0x04,0x02,0x01,0x80,0x40,0x20}, /* BDIAGONAL */ + {0x22,0x22,0xFF,0x22,0x22,0x22,0xFF,0x22}, /* CROSS */ + {0x18,0x18,0x24,0x42,0x81,0x81,0x42,0x24} /* DIAGCROSS */ +}; + +struct _cdxContextPlus +{ + XftDraw* draw; + Picture solid_pic, pattern_pic, fill_picture, dst_picture; + XftFont *font, + *flat_font; /* used only for text size when orientation!=0 */ + XRenderPictFormat* maskFormat; + + int antialias; + +#if (RENDER_MAJOR>0 || RENDER_MINOR>=10) + XLinearGradient linegradient; + Picture linegradient_pic; +#endif + + void (*cxKillCanvas)(cdCtxCanvas* ctxcanvas); +}; + + +static void xrInitColor(XRenderColor *rendercolor, long color) +{ + rendercolor->red = cdCOLOR8TO16(cdRed(color)); + rendercolor->green = cdCOLOR8TO16(cdGreen(color)); + rendercolor->blue = cdCOLOR8TO16(cdBlue(color)); + rendercolor->alpha = cdCOLOR8TO16(cdAlpha(color)); +} + +static void xrPolyFill(cdCtxCanvas* ctxcanvas, XPointDouble* fpoly, int n) +{ + XRenderCompositeDoublePoly(ctxcanvas->dpy, PictOpOver, ctxcanvas->ctxplus->fill_picture, + ctxcanvas->ctxplus->dst_picture, ctxcanvas->ctxplus->maskFormat, 0, 0, 0, 0, + fpoly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule); +} + +static void xrLine(cdCtxCanvas *ctxcanvas, XPointDouble* fpoly) +{ + XRenderCompositeDoublePoly(ctxcanvas->dpy, PictOpOver, ctxcanvas->ctxplus->solid_pic, + ctxcanvas->ctxplus->dst_picture, ctxcanvas->ctxplus->maskFormat, 0, 0, 0, 0, + fpoly, 4, 0); +} + +static void xrSetClipMask(cdCtxCanvas* ctxcanvas, Pixmap clip_mask) +{ + XRenderPictureAttributes pa; + pa.clip_mask = clip_mask; + XRenderChangePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->dst_picture, CPClipMask, &pa); +} + +static void xrSetClipArea(cdCtxCanvas* ctxcanvas) +{ + cdRect* clip_rect = &ctxcanvas->canvas->clip_rect; + XRectangle rect; + rect.x = (short)clip_rect->xmin; + rect.y = (short)clip_rect->ymin; + rect.width = (unsigned short)(clip_rect->xmax - clip_rect->xmin + 1); + rect.height = (unsigned short)(clip_rect->ymax - clip_rect->ymin + 1); + XRenderSetPictureClipRectangles(ctxcanvas->dpy, ctxcanvas->ctxplus->dst_picture, 0, 0, &rect, 1); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int clip_mode) +{ + switch (clip_mode) + { + case CD_CLIPOFF: + xrSetClipMask(ctxcanvas, None); + break; + case CD_CLIPAREA: + xrSetClipArea(ctxcanvas); + break; + case CD_CLIPPOLYGON: + if (ctxcanvas->clip_polygon) + xrSetClipMask(ctxcanvas, ctxcanvas->clip_polygon); + break; + case CD_CLIPREGION: + if (ctxcanvas->new_region) + xrSetClipMask(ctxcanvas, ctxcanvas->new_region); + break; + } + + /* call original method, to set the clipping for the PutImage* methods */ + cdxClip(ctxcanvas, clip_mode); + + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymax = ymax; + cdclip(ctxcanvas, CD_CLIPAREA); + } +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + int ix1, ix2, iy1, iy2; + +#ifndef CD_XRENDER_MATRIX + if (ctxcanvas->canvas->use_matrix) + { + cdfMatrixTransformPoint(ctxcanvas->xmatrix, x1, y1, &x1, &y1); + cdfMatrixTransformPoint(ctxcanvas->xmatrix, x2, y2, &x2, &y2); + } +#endif + + ix1 = _cdRound(x1); + ix2 = _cdRound(x2); + iy1 = _cdRound(y1); + iy2 = _cdRound(y2); + if ((ctxcanvas->canvas->line_width == 1) && + ((ix1 == ix2 && ix1==x1) || (iy1 == iy2 && iy1==y1))) + { + XRenderColor rendercolor; + xrInitColor(&rendercolor, ctxcanvas->canvas->foreground); + if (ix2 < ix1) _cdSwapInt(ix2, ix1); + if (iy2 < iy1) _cdSwapInt(iy2, iy1); + XRenderFillRectangle(ctxcanvas->dpy, PictOpSrc, ctxcanvas->ctxplus->dst_picture, &rendercolor, ix1, iy1, ix2-ix1+1, iy2-iy1+1); + } + else + { + double half_width = ctxcanvas->canvas->line_width/2.0; + XPointDouble fpoly[4]; + + /* XRender does not have a function to draw lines. + So we have to draw a poligon that covers the line area. */ + + double dx = x2-x1; + double dy = y2-y1; + double d = half_width/hypot(dx, dy); + double dnx = d*dx; + double dny = d*dy; + + fpoly[0].x = x1 + dny; + fpoly[0].y = y1 - dnx; + fpoly[1].x = x1 - dny; + fpoly[1].y = y1 + dnx; + fpoly[2].x = fpoly[1].x + dx; + fpoly[2].y = fpoly[1].y + dy; + fpoly[3].x = fpoly[0].x + dx; + fpoly[3].y = fpoly[0].y + dy; + + xrLine(ctxcanvas, fpoly); + } +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfSimRect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfSimBox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void xrFixAngles(cdCtxCanvas *ctxcanvas, double *angle1, double *angle2) +{ + if (ctxcanvas->canvas->invert_yaxis) + { + double temp = 360 - *angle1; + *angle1 = 360 - *angle2; + *angle2 = temp; + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimArc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimArc(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimElipse(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, 1); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + xrFixAngles(ctxcanvas, &a1, &a2); + cdfSimElipse(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, 0); +} + +static void cdfpoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* fpoly, int n) +{ + int i; + + switch(mode) + { + case CD_CLOSED_LINES: + fpoly[n] = fpoly[0]; + n++; + /* continue */ + case CD_OPEN_LINES: + for (i = 0; i< n - 1; i++) + cdfline(ctxcanvas, fpoly[i].x, fpoly[i].y, fpoly[i+1].x, fpoly[i+1].y); + break; + case CD_BEZIER: + cdfSimPolyBezier(ctxcanvas->canvas, fpoly, n); + break; + case CD_FILL: + { + if (ctxcanvas->canvas->new_region) + { + cdPoint* poly = malloc(sizeof(cdPoint)*n); + + for (i = 0; i<n; i++) + { + poly[i].x = _cdRound(fpoly[i].x); + poly[i].y = _cdRound(fpoly[i].y); + } + + cdxPoly(ctxcanvas, CD_FILL, poly, n); + + free(poly); + } + else + { + XPointDouble* poly = malloc(sizeof(XPointDouble)*n); + + for (i = 0; i<n; i++) + { + poly[i].x = fpoly[i].x; + poly[i].y = fpoly[i].y; + +#ifndef CD_XRENDER_MATRIX + if (ctxcanvas->canvas->use_matrix) + cdfMatrixTransformPoint(ctxcanvas->xmatrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); +#endif + } + + xrPolyFill(ctxcanvas, poly, n); + + free(poly); + } + } + break; + case CD_CLIP: + { + cdPoint* poly = malloc(sizeof(cdPoint)*n); + + for (i = 0; i<n; i++) + { + poly[i].x = _cdRound(fpoly[i].x); + poly[i].y = _cdRound(fpoly[i].y); + } + + cdxPoly(ctxcanvas, CD_CLIP, poly, n); + + free(poly); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdclip(ctxcanvas, CD_CLIPPOLYGON); + } + break; + } +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + switch(mode) + { + case CD_CLOSED_LINES: + poly[n] = poly[0]; + n++; + /* continue */ + case CD_OPEN_LINES: + for (i = 0; i<n-1; i++) + cdfline(ctxcanvas, (int)poly[i].x, (int)poly[i].y, (int)poly[i+1].x, (int)poly[i+1].y); + break; + case CD_BEZIER: + { + cdfPoint* fpoly = malloc(sizeof(cdfPoint)*n); + + for (i = 0; i<n; i++) + { + fpoly[i].x = (double)poly[i].x; + fpoly[i].y = (double)poly[i].y; + } + + cdfSimPolyBezier(ctxcanvas->canvas, fpoly, n); + + free(fpoly); + } + break; + case CD_FILL: + { + if (ctxcanvas->canvas->new_region) + { + cdxPoly(ctxcanvas, CD_FILL, poly, n); + } + else + { + XPointDouble* fpoly = malloc(sizeof(XPointDouble)*n); + + for (i = 0; i<n; i++) + { + fpoly[i].x = (double)poly[i].x; + fpoly[i].y = (double)poly[i].y; + +#ifndef CD_XRENDER_MATRIX + if (ctxcanvas->canvas->use_matrix) + cdfMatrixTransformPoint(ctxcanvas->xmatrix, fpoly[i].x, fpoly[i].y, &fpoly[i].x, &fpoly[i].y); +#endif + } + + xrPolyFill(ctxcanvas, fpoly, n); + + free(fpoly); + } + } + break; + case CD_CLIP: + cdxPoly(ctxcanvas, CD_CLIP, poly, n); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdclip(ctxcanvas, CD_CLIPPOLYGON); + break; + } +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ +#ifndef CD_XRENDER_MATRIX + if (matrix) + { + /* configure a bottom-up coordinate system */ + ctxcanvas->xmatrix[0] = 1; + ctxcanvas->xmatrix[1] = 0; + ctxcanvas->xmatrix[2] = 0; + ctxcanvas->xmatrix[3] = -1; + ctxcanvas->xmatrix[4] = 0; + ctxcanvas->xmatrix[5] = (ctxcanvas->canvas->h-1); + cdMatrixMultiply(matrix, ctxcanvas->xmatrix); + + ctxcanvas->canvas->invert_yaxis = 0; + } + else + { + ctxcanvas->canvas->invert_yaxis = 1; + } +#else + XTransform transform; + double identity[6] = {1, 0, 0, 1, 0, 0}; + + if (!matrix) + matrix = &identity[0]; + + transform.matrix[0][0] = XDoubleToFixed(matrix[0]); /* |m0 m2 m4| |00 01 02| */ + transform.matrix[0][1] = XDoubleToFixed(matrix[2]); /* |m1 m3 m5| = |10 11 12| */ + transform.matrix[0][2] = XDoubleToFixed(matrix[4]); /* |0 0 1| |20 21 22| */ + transform.matrix[1][0] = XDoubleToFixed(matrix[1]); + transform.matrix[1][1] = XDoubleToFixed(matrix[3]); + transform.matrix[1][2] = XDoubleToFixed(matrix[5]); + transform.matrix[2][0] = XDoubleToFixed(0); + transform.matrix[2][1] = XDoubleToFixed(0); + transform.matrix[2][2] = XDoubleToFixed(1); + + /* TODO: This is not working. It gives a BadPicture error */ + XRenderSetPictureTransform(ctxcanvas->dpy, ctxcanvas->ctxplus->dst_picture, &transform); +#endif +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_SOLID: + if (!ctxcanvas->ctxplus->solid_pic) + return ctxcanvas->canvas->interior_style; + ctxcanvas->ctxplus->fill_picture = ctxcanvas->ctxplus->solid_pic; + break; + case CD_HATCH: + case CD_STIPPLE: + case CD_PATTERN: + if (!ctxcanvas->ctxplus->pattern_pic) + return ctxcanvas->canvas->interior_style; + ctxcanvas->ctxplus->fill_picture = ctxcanvas->ctxplus->pattern_pic; + break; + } + return style; +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *colors) +{ + int x, y; + Pixmap pixmap; + XRenderPictureAttributes pa; + XRenderPictFormat* format; + + if (ctxcanvas->ctxplus->pattern_pic) + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->pattern_pic); + + format = XRenderFindStandardFormat(ctxcanvas->dpy, PictStandardARGB32); + pixmap = XCreatePixmap(ctxcanvas->dpy, DefaultRootWindow(ctxcanvas->dpy), w, h, format->depth); + pa.repeat = 1; + ctxcanvas->ctxplus->pattern_pic = XRenderCreatePicture(ctxcanvas->dpy, pixmap, format, CPRepeat, &pa); + + for (y=0; y<h; y++) + { + for (x=0; x<w; x++) + { + XRenderColor rendercolor; + xrInitColor(&rendercolor, colors[y*w+x]); + XRenderFillRectangle(ctxcanvas->dpy, PictOpSrc, ctxcanvas->ctxplus->pattern_pic, &rendercolor, x, h-y-1, 1, 1); + } + } + + cdinteriorstyle(ctxcanvas, CD_PATTERN); +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *data) +{ + int x, y, i; + long transparent = cdEncodeAlpha(0, 0); + long int *colors = malloc(sizeof(long)*w*h); + + for (y=0; y<h; y++) + { + for (x=0; x<w; x++) + { + i = y*w+x; + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + { + if (data[i]) + colors[i] = ctxcanvas->canvas->foreground; + else + colors[i] = ctxcanvas->canvas->background; + } + else + { + if (data[i]) + colors[i] = ctxcanvas->canvas->foreground; + else + colors[i] = transparent; + } + } + } + + cdpattern(ctxcanvas, w, h, colors); + free(colors); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int hatch_style) +{ + int y; + unsigned char data[8*8]; + unsigned char *hatch = hatches[hatch_style]; + + for (y=0; y<8; y++) + { + int i = y*8; + unsigned char c = hatch[y]; + data[i+7] = (c&0x01)>>0; + data[i+6] = (c&0x02)>>1; + data[i+5] = (c&0x04)>>2; + data[i+4] = (c&0x08)>>3; + data[i+3] = (c&0x10)>>4; + data[i+2] = (c&0x20)>>5; + data[i+1] = (c&0x40)>>6; + data[i+0] = (c&0x80)>>7; + } + + cdstipple(ctxcanvas, 8, 8, data); + return hatch_style; +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int back_opacity) +{ + ctxcanvas->canvas->back_opacity = back_opacity; + if (ctxcanvas->canvas->interior_style == CD_STIPPLE) + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + else if (ctxcanvas->canvas->interior_style == CD_HATCH) + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + return back_opacity; +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + XRenderColor rendercolor; + xrInitColor(&rendercolor, ctxcanvas->canvas->background); + XRenderFillRectangle(ctxcanvas->dpy, PictOpSrc, ctxcanvas->ctxplus->dst_picture, &rendercolor, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + XRenderColor rendercolor; + xrInitColor(&rendercolor, color); + XRenderFillRectangle(ctxcanvas->dpy, PictOpSrc, ctxcanvas->ctxplus->dst_picture, &rendercolor, x, y, 1, 1); +} + +#if (RENDER_MAJOR==0 && RENDER_MINOR<10) +static Picture XRenderCreateSolidFill(Display *dpy, const XRenderColor *color) +{ + Picture pict; + XRenderPictureAttributes pa; + XRenderPictFormat* format = XRenderFindStandardFormat(dpy, PictStandardARGB32); + Pixmap pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), 1, 1, format->depth); + pa.repeat = True; + pict = XRenderCreatePicture(dpy, pix, format, CPRepeat, &pa); + XFreePixmap(dpy, pix); + + XRenderFillRectangle(dpy, PictOpSrc, pict, color, 0, 0, 1, 1); + return pict; +} +#endif + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + XRenderPictureAttributes pa; + XRenderColor rendercolor; + xrInitColor(&rendercolor, color); + if (ctxcanvas->ctxplus->solid_pic) + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->solid_pic); + ctxcanvas->ctxplus->solid_pic = XRenderCreateSolidFill(ctxcanvas->dpy, &rendercolor); + pa.repeat = 1; + XRenderChangePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->solid_pic, CPRepeat, &pa); + if (ctxcanvas->canvas->interior_style == CD_STIPPLE) + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + else if (ctxcanvas->canvas->interior_style == CD_HATCH) + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + else if (ctxcanvas->canvas->interior_style == CD_SOLID) + cdinteriorstyle(ctxcanvas, CD_SOLID); + return color; +} + +static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + { + if (ctxcanvas->canvas->interior_style == CD_STIPPLE) + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + else if (ctxcanvas->canvas->interior_style == CD_HATCH) + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + } + return color; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + char font_name[1024]; + XftFont *font; + char matrix[200] = ""; + + /* no underline or strikeout support */ + + static char* type_style[] = + { + "", /* CD_PLAIN */ + ":bold", /* CD_BOLD */ + ":slant=italic,oblique", /* CD_ITALIC */ + ":bold:slant=italic,oblique" /* CD_BOLD_ITALIC */ + }; + + if (cdStrEqualNoCase(type_face, "Fixed") || cdStrEqualNoCase(type_face, "System")) + type_face = "monospace"; + else if (cdStrEqualNoCase(type_face, "Courier") || cdStrEqualNoCase(type_face, "Courier New")) + type_face = "monospace"; + else if (cdStrEqualNoCase(type_face, "Times") || cdStrEqualNoCase(type_face, "Times New Roman")) + type_face = "serif"; + else if (cdStrEqualNoCase(type_face, "Helvetica") || cdStrEqualNoCase(type_face, "Arial")) + type_face = "sans"; + + if (ctxcanvas->canvas->text_orientation) + { + double angle = CD_DEG2RAD*ctxcanvas->canvas->text_orientation; + double cos_angle = cos(angle); + double sin_angle = sin(angle); + + sprintf(matrix,":matrix=%f %f %f %f", cos_angle, -sin_angle, sin_angle, cos_angle); + } + + size = cdGetFontSizePoints(ctxcanvas->canvas, size); + + sprintf(font_name,"%s-%d%s%s", type_face, size, type_style[style&3], matrix); + font = XftFontOpenName(ctxcanvas->dpy, ctxcanvas->scr, font_name); + if (!font) + return 0; + + if (ctxcanvas->ctxplus->font) + XftFontClose(ctxcanvas->dpy, ctxcanvas->ctxplus->font); + + if (ctxcanvas->canvas->text_orientation) + { + /* XftTextExtents8 will return the size of the rotated text, but we want the size without orientation. + So create a font without orientation just to return the correct text size. */ + + if (ctxcanvas->ctxplus->flat_font) + XftFontClose(ctxcanvas->dpy, ctxcanvas->ctxplus->flat_font); + + sprintf(font_name,"%s-%d%s", type_face, size, type_style[style&3]); + ctxcanvas->ctxplus->flat_font = XftFontOpenName(ctxcanvas->dpy, ctxcanvas->scr, font_name); + } + + ctxcanvas->ctxplus->font = font; + + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont) +{ + int size = 12, style = CD_PLAIN; + char type_face[1024]; + + if (nativefont[0] == '-') + { + XftFont *font = XftFontOpenXlfd(ctxcanvas->dpy, ctxcanvas->scr, nativefont); + if (!font) + return 0; + + if (!cdParseXWinFont(nativefont, type_face, &style, &size)) + { + XftFontClose(ctxcanvas->dpy, font); + return 0; + } + + if (ctxcanvas->ctxplus->font) + XftFontClose(ctxcanvas->dpy, ctxcanvas->ctxplus->font); + + ctxcanvas->canvas->text_orientation = 0; /* orientation not supported when using XLFD */ + + ctxcanvas->ctxplus->font = font; + } + else + { + if (!cdParsePangoFont(nativefont, type_face, &style, &size)) + return 0; + + if (!cdfont(ctxcanvas, type_face, style, size)) + return 0; + } + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, type_face); + + return 1; +} + +static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle) +{ + /* must recriate the font if orientation changes */ + ctxcanvas->canvas->text_orientation = angle; + cdfont(ctxcanvas, ctxcanvas->canvas->font_type_face, ctxcanvas->canvas->font_style, ctxcanvas->canvas->font_size); + return angle; +} + +static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + if (!ctxcanvas->ctxplus->font) + return; + + if (max_width) *max_width = ctxcanvas->ctxplus->font->max_advance_width; + if (height) *height = ctxcanvas->ctxplus->font->ascent + ctxcanvas->ctxplus->font->descent; + if (ascent) *ascent = ctxcanvas->ctxplus->font->ascent; + if (descent) *descent = ctxcanvas->ctxplus->font->descent; +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *text, int *width, int *height) +{ + XGlyphInfo extents; + if (!ctxcanvas->ctxplus->font) + return; + + if (ctxcanvas->canvas->text_orientation) + XftTextExtents8(ctxcanvas->dpy, ctxcanvas->ctxplus->flat_font, (XftChar8*)text, strlen(text), &extents); + else + XftTextExtents8(ctxcanvas->dpy, ctxcanvas->ctxplus->font, (XftChar8*)text, strlen(text), &extents); + + if (width) *width = extents.width+extents.x; + if (height) *height = extents.height+extents.y; +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + XGlyphInfo extents; + int ox, oy, w, h, len, descent, dir = -1; + + if (!ctxcanvas->ctxplus->font) + return; + + len = strlen(text); + + if (ctxcanvas->canvas->text_orientation) + XftTextExtents8(ctxcanvas->dpy, ctxcanvas->ctxplus->flat_font, (XftChar8*)text, len, &extents); + else + XftTextExtents8(ctxcanvas->dpy, ctxcanvas->ctxplus->font, (XftChar8*)text, len, &extents); + w = extents.width+extents.x; + h = extents.height+extents.y; + + descent = ctxcanvas->ctxplus->font->descent; + + ox = x; + oy = y; + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + x = x - w; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + x = x - w/2; + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + x = x; + break; + } + + if (ctxcanvas->canvas->invert_yaxis) + dir = 1; + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + y = y; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + y = y - dir*descent; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + y = y + dir*(h - descent); + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + y = y + dir*(h/2 - descent); + break; + } + + if (ctxcanvas->canvas->text_orientation) + { + double angle = CD_DEG2RAD*ctxcanvas->canvas->text_orientation; + double cos_angle = cos(angle); + double sin_angle = sin(angle); + + /* manually rotate the initial point */ + cdRotatePoint(ctxcanvas->canvas, x, y, ox, oy, &x, &y, sin_angle, cos_angle); + } + +#ifndef CD_XRENDER_MATRIX + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); +#endif + + if (!ctxcanvas->canvas->new_region) + { + XftColor xftcolor; + XRenderColor rendercolor; + xrInitColor(&rendercolor, ctxcanvas->canvas->foreground); + XftColorAllocValue(ctxcanvas->dpy, ctxcanvas->vis, ctxcanvas->colormap, &rendercolor, &xftcolor); + XftDrawString8(ctxcanvas->ctxplus->draw, &xftcolor, ctxcanvas->ctxplus->font, x, y, (XftChar8*)text, len); + } +} + +/******************************************************************/ + +#if (RENDER_MAJOR>0 || RENDER_MINOR>=10) +static void set_linegradient_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (ctxcanvas->ctxplus->linegradient_pic) + { + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->linegradient_pic); + ctxcanvas->ctxplus->linegradient_pic = 0; + } + + if (data) + { + XRenderPictureAttributes pa; + XFixed stops[2]; + XRenderColor colors[2]; + int x1, y1, x2, y2; + sscanf(data, "%d %d %d %d", &x1, &y1, &x2, &y2); + + if (ctxcanvas->canvas->invert_yaxis) + { + y1 = _cdInvertYAxis(ctxcanvas->canvas, y1); + y2 = _cdInvertYAxis(ctxcanvas->canvas, y2); + } + + stops[0] = XDoubleToFixed(0.0); + stops[1] = XDoubleToFixed(1.0); + + xrInitColor(&colors[0], ctxcanvas->canvas->foreground); + xrInitColor(&colors[1], ctxcanvas->canvas->background); + + ctxcanvas->ctxplus->linegradient.p1.x = XDoubleToFixed((double)x1); + ctxcanvas->ctxplus->linegradient.p1.y = XDoubleToFixed((double)y1); + ctxcanvas->ctxplus->linegradient.p2.x = XDoubleToFixed((double)x2); + ctxcanvas->ctxplus->linegradient.p2.y = XDoubleToFixed((double)y2); + + ctxcanvas->ctxplus->linegradient_pic = XRenderCreateLinearGradient(ctxcanvas->dpy, &ctxcanvas->ctxplus->linegradient, stops, colors, 2); + pa.repeat = 1; + XRenderChangePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->linegradient_pic, CPRepeat, &pa); + + ctxcanvas->ctxplus->fill_picture = ctxcanvas->ctxplus->linegradient_pic; + } + else + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); +} + +static char* get_linegradient_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + sprintf(data, "%d %d %d %d", (int)XFixedToDouble(ctxcanvas->ctxplus->linegradient.p1.x), + (int)XFixedToDouble(ctxcanvas->ctxplus->linegradient.p1.y), + (int)XFixedToDouble(ctxcanvas->ctxplus->linegradient.p2.x), + (int)XFixedToDouble(ctxcanvas->ctxplus->linegradient.p2.y)); + + return data; +} + +static cdAttribute linegradient_attrib = +{ + "LINEGRADIENT", + set_linegradient_attrib, + get_linegradient_attrib +}; +#endif + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data || data[0] == '0') + ctxcanvas->ctxplus->antialias = 0; + else + ctxcanvas->ctxplus->antialias = 1; + + ctxcanvas->ctxplus->maskFormat = XRenderFindStandardFormat(ctxcanvas->dpy, ctxcanvas->ctxplus->antialias? PictStandardA8: PictStandardA1); +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->ctxplus->antialias) + return "1"; + else + return "0"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static char cdxXRenderVersion[50] = ""; + +static char* get_version_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->ctxplus) + return cdxXRenderVersion; + else + return "0"; +} + +static cdAttribute version_attrib = +{ + "XRENDERVERSION", + NULL, + get_version_attrib +}; + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + /* fill_picture is NOT released, since it is a pointer to one of the other pictures */ + if (ctxcanvas->ctxplus->solid_pic) + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->solid_pic); + + if (ctxcanvas->ctxplus->pattern_pic) + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->pattern_pic); + +#if (RENDER_MAJOR>0 || RENDER_MINOR>=10) + if (ctxcanvas->ctxplus->linegradient_pic) + XRenderFreePicture(ctxcanvas->dpy, ctxcanvas->ctxplus->linegradient_pic); +#endif + + if (ctxcanvas->ctxplus->flat_font) + XftFontClose(ctxcanvas->dpy, ctxcanvas->ctxplus->flat_font); + + if (ctxcanvas->ctxplus->font) + XftFontClose(ctxcanvas->dpy, ctxcanvas->ctxplus->font); + + XftDrawDestroy(ctxcanvas->ctxplus->draw); + free(ctxcanvas->ctxplus); + + /* call original method */ + ctxcanvas->ctxplus->cxKillCanvas(ctxcanvas); +} + +static void xrInitTable(cdCanvas* canvas) +{ + /* set new methods */ + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxTransform = cdtransform; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxForeground = cdforeground; + canvas->cxBackground = cdbackground; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxTextOrientation = cdtextorientation; + + canvas->cxPixel = cdpixel; + canvas->cxClear = cdclear; + canvas->cxLine = cdline; + canvas->cxFLine = cdfline; + canvas->cxRect = cdrect; + canvas->cxFRect = cdfSimRect; + canvas->cxBox = cdbox; + canvas->cxFBox = cdfSimBox; + canvas->cxArc = cdarc; + canvas->cxFArc = cdfarc; + canvas->cxSector = cdsector; + canvas->cxFSector = cdfsector; + canvas->cxChord = cdchord; + canvas->cxFChord = cdfchord; + canvas->cxPoly = cdpoly; + canvas->cxFPoly = cdfpoly; + + /* TODO: canvas->cxPutImageRectRGBA = cdputimagerectrgba; */ + + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; +} + +static void xrCreateContextPlus(cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->ctxplus = (cdxContextPlus *)malloc(sizeof(cdxContextPlus)); + memset(ctxcanvas->ctxplus, 0, sizeof(cdxContextPlus)); + + if (cdxXRenderVersion[0] == 0 && XftDefaultHasRender(ctxcanvas->dpy)) + sprintf(cdxXRenderVersion,"%d.%d", RENDER_MAJOR, RENDER_MINOR); + + cdRegisterAttribute(ctxcanvas->canvas, &aa_attrib); + cdRegisterAttribute(ctxcanvas->canvas, &version_attrib); +#if (RENDER_MAJOR>0 || RENDER_MINOR>=10) + cdRegisterAttribute(ctxcanvas->canvas, &linegradient_attrib); +#endif + + ctxcanvas->ctxplus->draw = XftDrawCreate(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->vis, ctxcanvas->colormap); + ctxcanvas->ctxplus->dst_picture = XftDrawPicture(ctxcanvas->ctxplus->draw); + ctxcanvas->ctxplus->maskFormat = XRenderFindStandardFormat(ctxcanvas->dpy, PictStandardA8); + + ctxcanvas->ctxplus->antialias = 1; +} + +/*******************************************************************************************************/ + +static cdContext cdDBufferContext = {0,0,NULL,NULL,NULL,NULL}; +static cdContext cdNativeWindowContext = {0,0,NULL,NULL,NULL,NULL}; +static cdContext cdImageContext = {0,0,NULL,NULL,NULL,NULL}; + +static void (*cdcreatecanvasDBUFFER)(cdCanvas* canvas, void* data) = NULL; +static void (*cdcreatecanvasNATIVE)(cdCanvas* canvas, void* data) = NULL; +static void (*cdcreatecanvasIMAGE)(cdCanvas* canvas, void* data) = NULL; + +static void (*cdinittableDBUFFER)(cdCanvas* canvas) = NULL; +static void (*cdinittableNATIVE)(cdCanvas* canvas) = NULL; +static void (*cdinittableIMAGE)(cdCanvas* canvas) = NULL; + +static void (*cdkillcanvasDBUFFER)(cdCtxCanvas* ctxcanvas) = NULL; +static void (*cdkillcanvasNATIVE)(cdCtxCanvas* ctxcanvas) = NULL; +static void (*cdkillcanvasIMAGE)(cdCtxCanvas* ctxcanvas) = NULL; + +static void xrCreateCanvasDBUFFER(cdCanvas* canvas, void *data) +{ + cdcreatecanvasDBUFFER(canvas, data); /* call original first */ + xrCreateContextPlus(canvas->ctxcanvas); + canvas->ctxcanvas->ctxplus->cxKillCanvas = cdkillcanvasDBUFFER; /* must set it here since CreateContext clears the structure */ +} + +static void xrInitTableDBUFFER(cdCanvas* canvas) +{ + if (!cdkillcanvasDBUFFER) cdkillcanvasDBUFFER = canvas->cxKillCanvas; /* save original method */ + cdinittableDBUFFER(canvas); + xrInitTable(canvas); +} + +cdContext* cdContextDBufferPlus(void) +{ + if (!cdDBufferContext.plus) + { + int old_plus = cdUseContextPlus(0); /* disable context plus */ + cdDBufferContext = *cdContextDBuffer(); /* copy original context */ + cdDBufferContext.plus = 1; /* mark as plus */ + + /* save original methods */ + cdcreatecanvasDBUFFER = cdDBufferContext.cxCreateCanvas; + cdinittableDBUFFER = cdDBufferContext.cxInitTable; + + /* replace by new methods */ + cdDBufferContext.cxCreateCanvas = xrCreateCanvasDBUFFER; + cdDBufferContext.cxInitTable = xrInitTableDBUFFER; + + cdUseContextPlus(old_plus); /* enable context plus */ + } + return &cdDBufferContext; +} + +static void xrCreateCanvasNATIVE(cdCanvas* canvas, void *data) +{ + cdcreatecanvasNATIVE(canvas, data); + xrCreateContextPlus(canvas->ctxcanvas); + canvas->ctxcanvas->ctxplus->cxKillCanvas = cdkillcanvasNATIVE; +} + +static void xrInitTableNATIVE(cdCanvas* canvas) +{ + if (!cdkillcanvasNATIVE) cdkillcanvasNATIVE = canvas->cxKillCanvas; + cdinittableNATIVE(canvas); + xrInitTable(canvas); +} + +cdContext* cdContextNativeWindowPlus(void) +{ + if (!cdNativeWindowContext.plus) + { + int old_plus = cdUseContextPlus(0); + cdNativeWindowContext = *cdContextNativeWindow(); + cdcreatecanvasNATIVE = cdNativeWindowContext.cxCreateCanvas; + cdinittableNATIVE = cdNativeWindowContext.cxInitTable; + cdNativeWindowContext.cxCreateCanvas = xrCreateCanvasNATIVE; + cdNativeWindowContext.cxInitTable = xrInitTableNATIVE; + cdNativeWindowContext.plus = 1; + cdUseContextPlus(old_plus); + } + return &cdNativeWindowContext; +} + +static void xrCreateCanvasIMAGE(cdCanvas* canvas, void *data) +{ + cdcreatecanvasIMAGE(canvas, data); + xrCreateContextPlus(canvas->ctxcanvas); + canvas->ctxcanvas->ctxplus->cxKillCanvas = cdkillcanvasIMAGE; +} + +static void xrInitTableIMAGE(cdCanvas* canvas) +{ + if (!cdkillcanvasIMAGE) cdkillcanvasIMAGE = canvas->cxKillCanvas; + cdinittableIMAGE(canvas); + xrInitTable(canvas); +} + +cdContext* cdContextImagePlus(void) +{ + if (!cdImageContext.plus) + { + int old_plus = cdUseContextPlus(0); + cdImageContext = *cdContextImage(); + cdcreatecanvasIMAGE = cdImageContext.cxCreateCanvas; + cdinittableIMAGE = cdImageContext.cxInitTable; + cdImageContext.cxCreateCanvas = xrCreateCanvasIMAGE; + cdImageContext.cxInitTable = xrInitTableIMAGE; + cdImageContext.plus = 1; + cdUseContextPlus(old_plus); + } + return &cdImageContext; +} diff --git a/src/xrender/cdxrplus.c b/src/xrender/cdxrplus.c new file mode 100644 index 0000000..f938a6f --- /dev/null +++ b/src/xrender/cdxrplus.c @@ -0,0 +1,26 @@ +/** \file + * \brief X-Render Control + * + * See Copyright Notice in cd.h + */ + +#include "cd.h" +#include "cd_private.h" +#include <stdlib.h> +#include <memory.h> + +cdContext* cdContextNativeWindowPlus(void); +cdContext* cdContextImagePlus(void); +cdContext* cdContextDBufferPlus(void); + +void cdInitContextPlus(void) +{ + cdContext* ctx_list[NUM_CONTEXTPLUS]; + memset(ctx_list, 0, sizeof(ctx_list)); + + ctx_list[CD_CTX_NATIVEWINDOW] = cdContextNativeWindowPlus(); + ctx_list[CD_CTX_IMAGE] = cdContextImagePlus(); + ctx_list[CD_CTX_DBUFFER] = cdContextDBufferPlus(); + + cdInitContextPlusList(ctx_list); +} -- cgit v1.2.3